From c8c7abe6effdd6e96ab2bd51e28d9c3a3ca9b1a2 Mon Sep 17 00:00:00 2001 From: Lhcfl Date: Tue, 30 Apr 2024 19:04:39 +0800 Subject: [PATCH 01/75] fix: notifications swiper not reload --- .../client/src/components/MkNotifications.vue | 2 +- packages/client/src/pages/notifications.vue | 42 ++++++++++--------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/packages/client/src/components/MkNotifications.vue b/packages/client/src/components/MkNotifications.vue index c449f2daf7..f89ed69796 100644 --- a/packages/client/src/components/MkNotifications.vue +++ b/packages/client/src/components/MkNotifications.vue @@ -71,7 +71,7 @@ import { foldNotifications } from "@/scripts/fold"; import { defaultStore } from "@/store"; const props = defineProps<{ - includeTypes?: (typeof notificationTypes)[number][]; + includeTypes?: (typeof notificationTypes)[number][] | null; unreadOnly?: boolean; }>(); diff --git a/packages/client/src/pages/notifications.vue b/packages/client/src/pages/notifications.vue index bc35e298e6..dc0adacbe1 100644 --- a/packages/client/src/pages/notifications.vue +++ b/packages/client/src/pages/notifications.vue @@ -22,11 +22,13 @@ (deviceKind !== 'desktop' || defaultStore.state.swipeOnDesktop) " + :long-swipes-radio="1" @swiper="setSwiperRef" @slide-change="onSlideChange" > - + - + @@ -54,6 +58,7 @@ import { computed, ref, watch } from "vue"; import { Virtual } from "swiper/modules"; import { Swiper, SwiperSlide } from "swiper/vue"; +import type { Swiper as SwiperType } from "swiper/types"; import { notificationTypes } from "firefish-js"; import XNotifications from "@/components/MkNotifications.vue"; import XNotes from "@/components/MkNotes.vue"; @@ -70,7 +75,7 @@ const tabs = ["all", "reactions", "mentions", "directNotes"]; const tab = ref(tabs[0]); watch(tab, () => syncSlide(tabs.indexOf(tab.value))); -const includeTypes = ref(null); +const includeTypes = ref<(typeof notificationTypes)[number][] | null>(null); os.api("notifications/mark-all-as-read"); const MOBILE_THRESHOLD = 500; @@ -98,7 +103,7 @@ const directNotesPagination = { function setFilter(ev) { const typeItems = notificationTypes.map((t) => ({ text: i18n.t(`_notification._types.${t}`), - active: includeTypes.value && includeTypes.value.includes(t), + active: includeTypes.value?.includes(t), action: () => { includeTypes.value = [t]; }, @@ -121,25 +126,23 @@ function setFilter(ev) { } const headerActions = computed(() => - [ - tab.value === "all" - ? { + tab.value === "all" + ? [ + { text: i18n.ts.filter, icon: `${icon("ph-funnel")}`, highlighted: includeTypes.value != null, handler: setFilter, - } - : undefined, - tab.value === "all" - ? { + }, + { text: i18n.ts.markAllAsRead, icon: `${icon("ph-check")}`, handler: () => { os.apiWithDialog("notifications/mark-all-as-read"); }, - } - : undefined, - ].filter((x) => x !== undefined), + }, + ] + : [], ); const headerTabs = computed(() => [ @@ -172,18 +175,19 @@ definePageMetadata( })), ); -let swiperRef = null; +let swiperRef: SwiperType | null = null; -function setSwiperRef(swiper) { +function setSwiperRef(swiper: SwiperType) { swiperRef = swiper; syncSlide(tabs.indexOf(tab.value)); } function onSlideChange() { - tab.value = tabs[swiperRef.activeIndex]; + if (tab.value !== tabs[swiperRef!.activeIndex]) + tab.value = tabs[swiperRef!.activeIndex]; } -function syncSlide(index) { - swiperRef.slideTo(index); +function syncSlide(index: number) { + if (index !== swiperRef!.activeIndex) swiperRef!.slideTo(index); } From f40c20167086ecad65cc85bda6d98ca9b19a5635 Mon Sep 17 00:00:00 2001 From: Lhcfl Date: Tue, 30 Apr 2024 19:06:55 +0800 Subject: [PATCH 02/75] remove forgotten debug parameter --- packages/client/src/pages/notifications.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/client/src/pages/notifications.vue b/packages/client/src/pages/notifications.vue index dc0adacbe1..29f452f009 100644 --- a/packages/client/src/pages/notifications.vue +++ b/packages/client/src/pages/notifications.vue @@ -22,7 +22,6 @@ (deviceKind !== 'desktop' || defaultStore.state.swipeOnDesktop) " - :long-swipes-radio="1" @swiper="setSwiperRef" @slide-change="onSlideChange" > From 5ad9bd8cebfc0b43d7a64fca7c6bb07ec7df63ee Mon Sep 17 00:00:00 2001 From: Lhcfl Date: Tue, 30 Apr 2024 19:51:40 +0800 Subject: [PATCH 03/75] feat: add angle constraint for MkPullToRefresh --- .../client/src/components/MkPullToRefresh.vue | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/packages/client/src/components/MkPullToRefresh.vue b/packages/client/src/components/MkPullToRefresh.vue index e78c597516..0bbb9ee4d3 100644 --- a/packages/client/src/components/MkPullToRefresh.vue +++ b/packages/client/src/components/MkPullToRefresh.vue @@ -44,6 +44,7 @@ const FIRE_THRESHOLD = defaultStore.state.pullToRefreshThreshold; const RELEASE_TRANSITION_DURATION = 200; const PULL_BRAKE_BASE = 1.5; const PULL_BRAKE_FACTOR = 170; +const MAX_PULL_TAN_ANGLE = Math.tan((1 / 6) * Math.PI); // 30° const pullStarted = ref(false); const pullEnded = ref(false); @@ -53,6 +54,7 @@ const pullDistance = ref(0); let disabled = false; const supportPointerDesktop = false; let startScreenY: number | null = null; +let startScreenX: number | null = null; const rootEl = shallowRef(); let scrollEl: HTMLElement | null = null; @@ -72,11 +74,16 @@ function getScreenY(event) { if (supportPointerDesktop) return event.screenY; return event.touches[0].screenY; } +function getScreenX(event) { + if (supportPointerDesktop) return event.screenX; + return event.touches[0].screenX; +} function moveStart(event) { if (!pullStarted.value && !isRefreshing.value && !disabled) { pullStarted.value = true; startScreenY = getScreenY(event); + startScreenX = getScreenX(event); pullDistance.value = 0; } } @@ -117,6 +124,7 @@ async function closeContent() { function moveEnd() { if (pullStarted.value && !isRefreshing.value) { startScreenY = null; + startScreenX = null; if (pullEnded.value) { pullEnded.value = false; isRefreshing.value = true; @@ -146,11 +154,17 @@ function moving(event: TouchEvent | PointerEvent) { moveEnd(); return; } - if (startScreenY === null) { - startScreenY = getScreenY(event); - } + startScreenX ??= getScreenX(event); + startScreenY ??= getScreenY(event); const moveScreenY = getScreenY(event); + const moveScreenX = getScreenX(event); const moveHeight = moveScreenY - startScreenY!; + const moveWidth = moveScreenX - startScreenX!; + if (Math.abs(moveWidth) > moveHeight * MAX_PULL_TAN_ANGLE) { + if (Math.abs(moveWidth) > 30) pullStarted.value = false; + return; + } + pullDistance.value = Math.min(Math.max(moveHeight, 0), MAX_PULL_DISTANCE); if (pullDistance.value > 0) { From a4a96f00264ed43b43f85b5508cf5a0f9b660783 Mon Sep 17 00:00:00 2001 From: Lhcfl Date: Wed, 1 May 2024 11:47:14 +0800 Subject: [PATCH 04/75] fix: escape ambiguous Mfm marks from html --- packages/backend/src/mfm/from-html.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/mfm/from-html.ts b/packages/backend/src/mfm/from-html.ts index b0b8957c6d..b00d1441e0 100644 --- a/packages/backend/src/mfm/from-html.ts +++ b/packages/backend/src/mfm/from-html.ts @@ -19,6 +19,13 @@ export function fromHtml(html: string, hashtagNames?: string[]): string { return appendChildren(childNodes, background).join("").trim(); } + /** + * We only exclude text containing asterisks, since the other marks can almost be considered intentionally used. + */ + function escapeAmbiguousMfmMarks(text: string) { + return text.includes("*") ? `${text}` : text; + } + /** * Get only the text, ignoring all formatting inside * @param node @@ -62,7 +69,7 @@ export function fromHtml(html: string, hashtagNames?: string[]): string { background = "", ): (string | string[])[] { if (treeAdapter.isTextNode(node)) { - return [node.value]; + return [escapeAmbiguousMfmMarks(node.value)]; } // Skip comment or document type node From d82f212c245d4747a0cc4bd41420ec93e4a05dba Mon Sep 17 00:00:00 2001 From: naskya Date: Wed, 1 May 2024 17:48:37 +0900 Subject: [PATCH 05/75] dev: update Makefile --- Makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 55c711855c..249a070648 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ export .PHONY: pre-commit -pre-commit: format entities napi-index +pre-commit: format entities napi .PHONY: format format: @@ -11,11 +11,12 @@ format: .PHONY: entities entities: + pnpm --filter=backend run build:debug pnpm run migrate $(MAKE) -C ./packages/backend-rs regenerate-entities -.PHONY: napi-index -napi-index: +.PHONY: napi +napi: $(MAKE) -C ./packages/backend-rs update-index From caae8474a650ca70f44b5d55c9a5e992acef7bb7 Mon Sep 17 00:00:00 2001 From: naskya Date: Thu, 2 May 2024 19:31:53 +0900 Subject: [PATCH 06/75] chore (backend): drop unused database indexes Based on the PostgreSQL analitics on the following servers' database: - dvd.chat - iwshkey.com - minazukey.uk - post.naskya.net - post.sup39.dev - stelpolva.moe Thank you all for your helps! --- docs/downgrade.sql | 17 +++++ .../1714643926317-drop-unused-indexes.ts | 65 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 packages/backend/src/migration/1714643926317-drop-unused-indexes.ts diff --git a/docs/downgrade.sql b/docs/downgrade.sql index eed0079c3b..787785eb67 100644 --- a/docs/downgrade.sql +++ b/docs/downgrade.sql @@ -1,6 +1,7 @@ BEGIN; DELETE FROM "migrations" WHERE name IN ( + 'DropUnusedIndexes1714643926317', 'AlterAkaType1714099399879', 'AddDriveFileUsage1713451569342', 'ConvertCwVarcharToText1713225866247', @@ -25,6 +26,22 @@ DELETE FROM "migrations" WHERE name IN ( 'RemoveNativeUtilsMigration1705877093218' ); +-- drop-unused-indexes +CREATE INDEX "IDX_01f4581f114e0ebd2bbb876f0b" ON "note_reaction" ("createdAt"); +CREATE INDEX "IDX_0610ebcfcfb4a18441a9bcdab2" ON "poll" ("userId"); +CREATE INDEX "IDX_25dfc71b0369b003a4cd434d0b" ON "note" ("attachedFileTypes"); +CREATE INDEX "IDX_2710a55f826ee236ea1a62698f" ON "hashtag" ("mentionedUsersCount"); +CREATE INDEX "IDX_4c02d38a976c3ae132228c6fce" ON "hashtag" ("mentionedRemoteUsersCount"); +CREATE INDEX "IDX_51c063b6a133a9cb87145450f5" ON "note" ("fileIds"); +CREATE INDEX "IDX_54ebcb6d27222913b908d56fd8" ON "note" ("mentions"); +CREATE INDEX "IDX_7fa20a12319c7f6dc3aed98c0a" ON "poll" ("userHost"); +CREATE INDEX "IDX_88937d94d7443d9a99a76fa5c0" ON "note" ("tags"); +CREATE INDEX "IDX_b11a5e627c41d4dc3170f1d370" ON "notification" ("createdAt"); +CREATE INDEX "IDX_c8dfad3b72196dd1d6b5db168a" ON "drive_file" ("createdAt"); +CREATE INDEX "IDX_d57f9030cd3af7f63ffb1c267c" ON "hashtag" ("attachedUsersCount"); +CREATE INDEX "IDX_e5848eac4940934e23dbc17581" ON "drive_file" ("uri"); +CREATE INDEX "IDX_fa99d777623947a5b05f394cae" ON "user" ("tags"); + -- alter-aka-type ALTER TABLE "user" RENAME COLUMN "alsoKnownAs" TO "alsoKnownAsOld"; ALTER TABLE "user" ADD COLUMN "alsoKnownAs" text; diff --git a/packages/backend/src/migration/1714643926317-drop-unused-indexes.ts b/packages/backend/src/migration/1714643926317-drop-unused-indexes.ts new file mode 100644 index 0000000000..c4df055c82 --- /dev/null +++ b/packages/backend/src/migration/1714643926317-drop-unused-indexes.ts @@ -0,0 +1,65 @@ +import type { MigrationInterface, QueryRunner } from "typeorm"; + +export class DropUnusedIndexes1714643926317 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP INDEX "IDX_01f4581f114e0ebd2bbb876f0b"`); + await queryRunner.query(`DROP INDEX "IDX_0610ebcfcfb4a18441a9bcdab2"`); + await queryRunner.query(`DROP INDEX "IDX_25dfc71b0369b003a4cd434d0b"`); + await queryRunner.query(`DROP INDEX "IDX_2710a55f826ee236ea1a62698f"`); + await queryRunner.query(`DROP INDEX "IDX_4c02d38a976c3ae132228c6fce"`); + await queryRunner.query(`DROP INDEX "IDX_51c063b6a133a9cb87145450f5"`); + await queryRunner.query(`DROP INDEX "IDX_54ebcb6d27222913b908d56fd8"`); + await queryRunner.query(`DROP INDEX "IDX_7fa20a12319c7f6dc3aed98c0a"`); + await queryRunner.query(`DROP INDEX "IDX_88937d94d7443d9a99a76fa5c0"`); + await queryRunner.query(`DROP INDEX "IDX_b11a5e627c41d4dc3170f1d370"`); + await queryRunner.query(`DROP INDEX "IDX_c8dfad3b72196dd1d6b5db168a"`); + await queryRunner.query(`DROP INDEX "IDX_d57f9030cd3af7f63ffb1c267c"`); + await queryRunner.query(`DROP INDEX "IDX_e5848eac4940934e23dbc17581"`); + await queryRunner.query(`DROP INDEX "IDX_fa99d777623947a5b05f394cae"`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE INDEX "IDX_01f4581f114e0ebd2bbb876f0b" ON "note_reaction" ("createdAt")`, + ); + await queryRunner.query( + `CREATE INDEX "IDX_0610ebcfcfb4a18441a9bcdab2" ON "poll" ("userId")`, + ); + await queryRunner.query( + `CREATE INDEX "IDX_25dfc71b0369b003a4cd434d0b" ON "note" ("attachedFileTypes")`, + ); + await queryRunner.query( + `CREATE INDEX "IDX_2710a55f826ee236ea1a62698f" ON "hashtag" ("mentionedUsersCount")`, + ); + await queryRunner.query( + `CREATE INDEX "IDX_4c02d38a976c3ae132228c6fce" ON "hashtag" ("mentionedRemoteUsersCount")`, + ); + await queryRunner.query( + `CREATE INDEX "IDX_51c063b6a133a9cb87145450f5" ON "note" ("fileIds")`, + ); + await queryRunner.query( + `CREATE INDEX "IDX_54ebcb6d27222913b908d56fd8" ON "note" ("mentions")`, + ); + await queryRunner.query( + `CREATE INDEX "IDX_7fa20a12319c7f6dc3aed98c0a" ON "poll" ("userHost")`, + ); + await queryRunner.query( + `CREATE INDEX "IDX_88937d94d7443d9a99a76fa5c0" ON "note" ("tags")`, + ); + await queryRunner.query( + `CREATE INDEX "IDX_b11a5e627c41d4dc3170f1d370" ON "notification" ("createdAt")`, + ); + await queryRunner.query( + `CREATE INDEX "IDX_c8dfad3b72196dd1d6b5db168a" ON "drive_file" ("createdAt")`, + ); + await queryRunner.query( + `CREATE INDEX "IDX_d57f9030cd3af7f63ffb1c267c" ON "hashtag" ("attachedUsersCount")`, + ); + await queryRunner.query( + `CREATE INDEX "IDX_e5848eac4940934e23dbc17581" ON "drive_file" ("uri")`, + ); + await queryRunner.query( + `CREATE INDEX "IDX_fa99d777623947a5b05f394cae" ON "user" ("tags")`, + ); + } +} From 64c07a2406a32d5a6e9cdb25896df84ccaa965c1 Mon Sep 17 00:00:00 2001 From: naskya Date: Thu, 2 May 2024 21:45:12 +0900 Subject: [PATCH 07/75] fix (backend): tell TypeORM that some columns are no longer indexed should have done in caae8474a650ca70f44b5d55c9a5e992acef7bb7 --- packages/backend/src/models/entities/drive-file.ts | 2 -- packages/backend/src/models/entities/hashtag.ts | 3 --- packages/backend/src/models/entities/note-reaction.ts | 1 - packages/backend/src/models/entities/note.ts | 4 ---- packages/backend/src/models/entities/notification.ts | 1 - packages/backend/src/models/entities/poll.ts | 2 -- packages/backend/src/models/entities/user.ts | 1 - 7 files changed, 14 deletions(-) diff --git a/packages/backend/src/models/entities/drive-file.ts b/packages/backend/src/models/entities/drive-file.ts index c81d5d7622..e3a7d1c370 100644 --- a/packages/backend/src/models/entities/drive-file.ts +++ b/packages/backend/src/models/entities/drive-file.ts @@ -23,7 +23,6 @@ export class DriveFile { @PrimaryColumn(id()) public id: string; - @Index() @Column("timestamp without time zone", { comment: "The created date of the DriveFile.", }) @@ -147,7 +146,6 @@ export class DriveFile { }) public webpublicAccessKey: string | null; - @Index() @Column("varchar", { length: 512, nullable: true, diff --git a/packages/backend/src/models/entities/hashtag.ts b/packages/backend/src/models/entities/hashtag.ts index 7b3df1cc22..84d817bcd2 100644 --- a/packages/backend/src/models/entities/hashtag.ts +++ b/packages/backend/src/models/entities/hashtag.ts @@ -19,7 +19,6 @@ export class Hashtag { }) public mentionedUserIds: User["id"][]; - @Index() @Column("integer", { default: 0, }) @@ -43,7 +42,6 @@ export class Hashtag { }) public mentionedRemoteUserIds: User["id"][]; - @Index() @Column("integer", { default: 0, }) @@ -55,7 +53,6 @@ export class Hashtag { }) public attachedUserIds: User["id"][]; - @Index() @Column("integer", { default: 0, }) diff --git a/packages/backend/src/models/entities/note-reaction.ts b/packages/backend/src/models/entities/note-reaction.ts index fc57bb6a07..1d2fc567b5 100644 --- a/packages/backend/src/models/entities/note-reaction.ts +++ b/packages/backend/src/models/entities/note-reaction.ts @@ -17,7 +17,6 @@ export class NoteReaction { @PrimaryColumn(id()) public id: string; - @Index() @Column("timestamp without time zone", { comment: "The created date of the NoteReaction.", }) diff --git a/packages/backend/src/models/entities/note.ts b/packages/backend/src/models/entities/note.ts index 94cd8c7b66..3b7315288e 100644 --- a/packages/backend/src/models/entities/note.ts +++ b/packages/backend/src/models/entities/note.ts @@ -139,7 +139,6 @@ export class Note { // FIXME: file id is not removed from this array even if the file is deleted // TODO: drop this column and use note_files - @Index() @Column({ ...id(), array: true, @@ -147,7 +146,6 @@ export class Note { }) public fileIds: DriveFile["id"][]; - @Index() @Column("varchar", { length: 256, array: true, @@ -163,7 +161,6 @@ export class Note { }) public visibleUserIds: User["id"][]; - @Index() @Column({ ...id(), array: true, @@ -184,7 +181,6 @@ export class Note { }) public emojis: string[]; - @Index() @Column("varchar", { length: 128, array: true, diff --git a/packages/backend/src/models/entities/notification.ts b/packages/backend/src/models/entities/notification.ts index 58fc86a72c..57a2a59158 100644 --- a/packages/backend/src/models/entities/notification.ts +++ b/packages/backend/src/models/entities/notification.ts @@ -20,7 +20,6 @@ export class Notification { @PrimaryColumn(id()) public id: string; - @Index() @Column("timestamp without time zone", { comment: "The created date of the Notification.", }) diff --git a/packages/backend/src/models/entities/poll.ts b/packages/backend/src/models/entities/poll.ts index 3cc6df17cf..9ef2091566 100644 --- a/packages/backend/src/models/entities/poll.ts +++ b/packages/backend/src/models/entities/poll.ts @@ -44,14 +44,12 @@ export class Poll { }) public noteVisibility: (typeof noteVisibilities)[number]; - @Index() @Column({ ...id(), comment: "[Denormalized]", }) public userId: User["id"]; - @Index() @Column("varchar", { length: 512, nullable: true, diff --git a/packages/backend/src/models/entities/user.ts b/packages/backend/src/models/entities/user.ts index 69a2b4dc27..ad86e72422 100644 --- a/packages/backend/src/models/entities/user.ts +++ b/packages/backend/src/models/entities/user.ts @@ -116,7 +116,6 @@ export class User { }) public bannerId: DriveFile["id"] | null; - @Index() @Column("varchar", { length: 128, array: true, From a8f659ab889946f715fac35c0378627ae1579c3b Mon Sep 17 00:00:00 2001 From: naskya Date: Thu, 2 May 2024 21:46:14 +0900 Subject: [PATCH 08/75] chore: format --- packages/backend/src/remote/activitypub/misc/contexts.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/src/remote/activitypub/misc/contexts.ts b/packages/backend/src/remote/activitypub/misc/contexts.ts index 5b43bf5fc3..d0b3f56fc1 100644 --- a/packages/backend/src/remote/activitypub/misc/contexts.ts +++ b/packages/backend/src/remote/activitypub/misc/contexts.ts @@ -527,7 +527,7 @@ export const WellKnownContext = { manuallyApprovesFollowers: "as:manuallyApprovesFollowers", movedTo: { "@id": "https://www.w3.org/ns/activitystreams#movedTo", - "@type": "@id" + "@type": "@id", }, movedToUri: "as:movedTo", sensitive: "as:sensitive", From 4536ac06781377ebbb1e35affc743cb4c3feed51 Mon Sep 17 00:00:00 2001 From: Lhcfl Date: Fri, 3 May 2024 00:28:46 +0800 Subject: [PATCH 09/75] reviewed --- packages/client/src/components/MkPullToRefresh.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/components/MkPullToRefresh.vue b/packages/client/src/components/MkPullToRefresh.vue index 0bbb9ee4d3..76bed9e52f 100644 --- a/packages/client/src/components/MkPullToRefresh.vue +++ b/packages/client/src/components/MkPullToRefresh.vue @@ -160,7 +160,7 @@ function moving(event: TouchEvent | PointerEvent) { const moveScreenX = getScreenX(event); const moveHeight = moveScreenY - startScreenY!; const moveWidth = moveScreenX - startScreenX!; - if (Math.abs(moveWidth) > moveHeight * MAX_PULL_TAN_ANGLE) { + if (Math.abs(moveWidth / moveHeight) > MAX_PULL_TAN_ANGLE) { if (Math.abs(moveWidth) > 30) pullStarted.value = false; return; } From 8a2f3b3e360f3e13cef4457dd84213d823c7d4c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=81=E5=91=A8=E9=83=A8=E8=90=BD?= Date: Wed, 1 May 2024 11:37:55 +0800 Subject: [PATCH 10/75] fix: follow-me generate wrong link for other server --- packages/client/src/scripts/get-user-menu.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/client/src/scripts/get-user-menu.ts b/packages/client/src/scripts/get-user-menu.ts index 8f286ea8d6..110bbba56b 100644 --- a/packages/client/src/scripts/get-user-menu.ts +++ b/packages/client/src/scripts/get-user-menu.ts @@ -265,14 +265,18 @@ export function getUserMenu(user, router: Router = mainRouter) { icon: "ph-qr-code ph-bold ph-lg", text: i18n.ts.getQrCode, action: () => { - os.displayQrCode(`https://${host}/follow-me?acct=${user.username}`); + os.displayQrCode( + `https://${host}/follow-me?acct=${acct.toString(user)}`, + ); }, }, { icon: `${icon("ph-hand-waving")}`, text: i18n.ts.copyRemoteFollowUrl, action: () => { - copyToClipboard(`https://${host}/follow-me?acct=${user.username}`); + copyToClipboard( + `https://${host}/follow-me?acct=${acct.toString(user)}`, + ); os.success(); }, }, @@ -321,7 +325,7 @@ export function getUserMenu(user, router: Router = mainRouter) { icon: `${icon("ph-hand-waving")}`, text: i18n.ts.remoteFollow, action: () => { - router.push(`/follow-me?acct=${user.username}`); + router.push(`/follow-me?acct=${acct.toString(user)}`); }, } : undefined, From 5ab81c279923f61277d5d7806204750aafafd522 Mon Sep 17 00:00:00 2001 From: naskya Date: Fri, 3 May 2024 23:14:13 +0900 Subject: [PATCH 11/75] docs: Docker -> Podman --- dev/docs/db-container.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/docs/db-container.md b/dev/docs/db-container.md index 61e7b2609e..7e3caf7f4b 100644 --- a/dev/docs/db-container.md +++ b/dev/docs/db-container.md @@ -31,7 +31,7 @@ You can refer to [local-installation.md](./local-installation.md) to install the 1. Copy example config file ```sh cp dev/config.example.env dev/config.env - # If you use container runtime other than Docker, you need to modify the "COMPOSE" variable + # If you use container runtime other than Podman, you need to modify the "COMPOSE" variable # vim dev/config.env ``` 1. Create `.config/default.yml` with the following content From 37e03007f098ce1d52773bd33816d4468bcbe303 Mon Sep 17 00:00:00 2001 From: naskya Date: Sat, 4 May 2024 13:14:01 +0900 Subject: [PATCH 12/75] refactor (backend-rs): misc/redis_cache -> database/cache --- .../redis_cache.rs => database/cache.rs} | 32 +++++++++---------- packages/backend-rs/src/database/mod.rs | 1 + .../backend-rs/src/misc/get_image_size.rs | 28 ++++++++-------- packages/backend-rs/src/misc/mod.rs | 1 - 4 files changed, 30 insertions(+), 32 deletions(-) rename packages/backend-rs/src/{misc/redis_cache.rs => database/cache.rs} (68%) diff --git a/packages/backend-rs/src/misc/redis_cache.rs b/packages/backend-rs/src/database/cache.rs similarity index 68% rename from packages/backend-rs/src/misc/redis_cache.rs rename to packages/backend-rs/src/database/cache.rs index 81ac840b8d..aaf89bde86 100644 --- a/packages/backend-rs/src/misc/redis_cache.rs +++ b/packages/backend-rs/src/database/cache.rs @@ -3,7 +3,7 @@ use redis::{Commands, RedisError}; use serde::{Deserialize, Serialize}; #[derive(thiserror::Error, Debug)] -pub enum CacheError { +pub enum Error { #[error("Redis error: {0}")] RedisError(#[from] RedisError), #[error("Data serialization error: {0}")] @@ -16,11 +16,11 @@ fn prefix_key(key: &str) -> String { redis_key(format!("cache:{}", key)) } -pub fn set_cache Deserialize<'a> + Serialize>( +pub fn set Deserialize<'a> + Serialize>( key: &str, value: &V, expire_seconds: u64, -) -> Result<(), CacheError> { +) -> Result<(), Error> { redis_conn()?.set_ex( prefix_key(key), rmp_serde::encode::to_vec(&value)?, @@ -29,9 +29,7 @@ pub fn set_cache Deserialize<'a> + Serialize>( Ok(()) } -pub fn get_cache Deserialize<'a> + Serialize>( - key: &str, -) -> Result, CacheError> { +pub fn get Deserialize<'a> + Serialize>(key: &str) -> Result, Error> { let serialized_value: Option> = redis_conn()?.get(prefix_key(key))?; Ok(match serialized_value { Some(v) => Some(rmp_serde::from_slice::(v.as_ref())?), @@ -39,13 +37,13 @@ pub fn get_cache Deserialize<'a> + Serialize>( }) } -pub fn delete_cache(key: &str) -> Result<(), CacheError> { +pub fn delete(key: &str) -> Result<(), Error> { Ok(redis_conn()?.del(prefix_key(key))?) } #[cfg(test)] mod unit_test { - use super::{get_cache, set_cache}; + use super::{get, set}; use pretty_assertions::assert_eq; #[test] @@ -68,13 +66,13 @@ mod unit_test { kind: "prime number".to_string(), }; - set_cache(key_1, &value_1, 1).unwrap(); - set_cache(key_2, &value_2, 1).unwrap(); - set_cache(key_3, &value_3, 1).unwrap(); + set(key_1, &value_1, 1).unwrap(); + set(key_2, &value_2, 1).unwrap(); + set(key_3, &value_3, 1).unwrap(); - let cached_value_1: Vec = get_cache(key_1).unwrap().unwrap(); - let cached_value_2: String = get_cache(key_2).unwrap().unwrap(); - let cached_value_3: Data = get_cache(key_3).unwrap().unwrap(); + let cached_value_1: Vec = get(key_1).unwrap().unwrap(); + let cached_value_2: String = get(key_2).unwrap().unwrap(); + let cached_value_3: Data = get(key_3).unwrap().unwrap(); assert_eq!(value_1, cached_value_1); assert_eq!(value_2, cached_value_2); @@ -83,9 +81,9 @@ mod unit_test { // wait for the cache to expire std::thread::sleep(std::time::Duration::from_millis(1100)); - let expired_value_1: Option> = get_cache(key_1).unwrap(); - let expired_value_2: Option> = get_cache(key_2).unwrap(); - let expired_value_3: Option> = get_cache(key_3).unwrap(); + let expired_value_1: Option> = get(key_1).unwrap(); + let expired_value_2: Option> = get(key_2).unwrap(); + let expired_value_3: Option> = get(key_3).unwrap(); assert!(expired_value_1.is_none()); assert!(expired_value_2.is_none()); diff --git a/packages/backend-rs/src/database/mod.rs b/packages/backend-rs/src/database/mod.rs index 7a6277068b..f657a540af 100644 --- a/packages/backend-rs/src/database/mod.rs +++ b/packages/backend-rs/src/database/mod.rs @@ -2,5 +2,6 @@ pub use postgresql::db_conn; pub use redis::key as redis_key; pub use redis::redis_conn; +pub mod cache; pub mod postgresql; pub mod redis; diff --git a/packages/backend-rs/src/misc/get_image_size.rs b/packages/backend-rs/src/misc/get_image_size.rs index 9c55846424..ef8b7db79f 100644 --- a/packages/backend-rs/src/misc/get_image_size.rs +++ b/packages/backend-rs/src/misc/get_image_size.rs @@ -1,4 +1,4 @@ -use crate::misc::redis_cache::{get_cache, set_cache, CacheError}; +use crate::database::cache; use crate::util::http_client; use image::{io::Reader, ImageError, ImageFormat}; use nom_exif::{parse_jpeg_exif, EntryValue, ExifTag}; @@ -8,7 +8,7 @@ use tokio::sync::Mutex; #[derive(thiserror::Error, Debug)] pub enum Error { #[error("Redis cache error: {0}")] - CacheErr(#[from] CacheError), + CacheErr(#[from] cache::Error), #[error("Reqwest error: {0}")] ReqwestErr(#[from] reqwest::Error), #[error("Image decoding error: {0}")] @@ -51,10 +51,10 @@ pub async fn get_image_size_from_url(url: &str) -> Result { let _ = MTX_GUARD.lock().await; let key = format!("fetchImage:{}", url); - attempted = get_cache::(&key)?.is_some(); + attempted = cache::get::(&key)?.is_some(); if !attempted { - set_cache(&key, &true, 10 * 60)?; + cache::set(&key, &true, 10 * 60)?; } } @@ -109,7 +109,7 @@ pub async fn get_image_size_from_url(url: &str) -> Result { #[cfg(test)] mod unit_test { use super::{get_image_size_from_url, ImageSize}; - use crate::misc::redis_cache::delete_cache; + use crate::database::cache; use pretty_assertions::assert_eq; #[tokio::test] @@ -126,15 +126,15 @@ mod unit_test { // Delete caches in case you run this test multiple times // (should be disabled in CI tasks) - delete_cache(&format!("fetchImage:{}", png_url_1)).unwrap(); - delete_cache(&format!("fetchImage:{}", png_url_2)).unwrap(); - delete_cache(&format!("fetchImage:{}", png_url_3)).unwrap(); - delete_cache(&format!("fetchImage:{}", rotated_jpeg_url)).unwrap(); - delete_cache(&format!("fetchImage:{}", webp_url_1)).unwrap(); - delete_cache(&format!("fetchImage:{}", webp_url_2)).unwrap(); - delete_cache(&format!("fetchImage:{}", ico_url)).unwrap(); - delete_cache(&format!("fetchImage:{}", gif_url)).unwrap(); - delete_cache(&format!("fetchImage:{}", mp3_url)).unwrap(); + cache::delete(&format!("fetchImage:{}", png_url_1)).unwrap(); + cache::delete(&format!("fetchImage:{}", png_url_2)).unwrap(); + cache::delete(&format!("fetchImage:{}", png_url_3)).unwrap(); + cache::delete(&format!("fetchImage:{}", rotated_jpeg_url)).unwrap(); + cache::delete(&format!("fetchImage:{}", webp_url_1)).unwrap(); + cache::delete(&format!("fetchImage:{}", webp_url_2)).unwrap(); + cache::delete(&format!("fetchImage:{}", ico_url)).unwrap(); + cache::delete(&format!("fetchImage:{}", gif_url)).unwrap(); + cache::delete(&format!("fetchImage:{}", mp3_url)).unwrap(); let png_size_1 = ImageSize { width: 1024, diff --git a/packages/backend-rs/src/misc/mod.rs b/packages/backend-rs/src/misc/mod.rs index 0ba15dc8e4..7e8301ddeb 100644 --- a/packages/backend-rs/src/misc/mod.rs +++ b/packages/backend-rs/src/misc/mod.rs @@ -13,5 +13,4 @@ pub mod meta; pub mod nyaify; pub mod password; pub mod reaction; -pub mod redis_cache; pub mod remove_old_attestation_challenges; From e6ba0a002f2b78e5f43c9a43a569301d4d39fdaf Mon Sep 17 00:00:00 2001 From: naskya Date: Sat, 4 May 2024 13:19:14 +0900 Subject: [PATCH 13/75] refactor (backend-rs): add cache::{get_one, set_one, delete_one} --- packages/backend-rs/src/database/cache.rs | 32 +++++++++++++++++++ .../backend-rs/src/misc/get_image_size.rs | 23 +++++++------ 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/packages/backend-rs/src/database/cache.rs b/packages/backend-rs/src/database/cache.rs index aaf89bde86..cbc7a60ff6 100644 --- a/packages/backend-rs/src/database/cache.rs +++ b/packages/backend-rs/src/database/cache.rs @@ -2,6 +2,12 @@ use crate::database::{redis_conn, redis_key}; use redis::{Commands, RedisError}; use serde::{Deserialize, Serialize}; +#[derive(strum::Display)] +pub enum Category { + #[strum(serialize = "fetchUrl")] + FetchUrl, +} + #[derive(thiserror::Error, Debug)] pub enum Error { #[error("Redis error: {0}")] @@ -12,6 +18,10 @@ pub enum Error { DeserializeError(#[from] rmp_serde::decode::Error), } +fn categorize(category: Category, key: &str) -> String { + format!("{}:{}", category, key) +} + fn prefix_key(key: &str) -> String { redis_key(format!("cache:{}", key)) } @@ -41,6 +51,28 @@ pub fn delete(key: &str) -> Result<(), Error> { Ok(redis_conn()?.del(prefix_key(key))?) } +pub fn set_one Deserialize<'a> + Serialize>( + category: Category, + key: &str, + value: &V, + expire_seconds: u64, +) -> Result<(), Error> { + set(&categorize(category, key), value, expire_seconds) +} + +pub fn get_one Deserialize<'a> + Serialize>( + category: Category, + key: &str, +) -> Result, Error> { + get(&categorize(category, key)) +} + +pub fn delete_one(category: Category, key: &str) -> Result<(), Error> { + delete(&categorize(category, key)) +} + +// TODO: set_all(), get_all(), delete_all() + #[cfg(test)] mod unit_test { use super::{get, set}; diff --git a/packages/backend-rs/src/misc/get_image_size.rs b/packages/backend-rs/src/misc/get_image_size.rs index ef8b7db79f..ac0de89015 100644 --- a/packages/backend-rs/src/misc/get_image_size.rs +++ b/packages/backend-rs/src/misc/get_image_size.rs @@ -50,11 +50,10 @@ pub async fn get_image_size_from_url(url: &str) -> Result { { let _ = MTX_GUARD.lock().await; - let key = format!("fetchImage:{}", url); - attempted = cache::get::(&key)?.is_some(); + attempted = cache::get_one::(cache::Category::FetchUrl, url)?.is_some(); if !attempted { - cache::set(&key, &true, 10 * 60)?; + cache::set_one(cache::Category::FetchUrl, url, &true, 10 * 60)?; } } @@ -126,15 +125,15 @@ mod unit_test { // Delete caches in case you run this test multiple times // (should be disabled in CI tasks) - cache::delete(&format!("fetchImage:{}", png_url_1)).unwrap(); - cache::delete(&format!("fetchImage:{}", png_url_2)).unwrap(); - cache::delete(&format!("fetchImage:{}", png_url_3)).unwrap(); - cache::delete(&format!("fetchImage:{}", rotated_jpeg_url)).unwrap(); - cache::delete(&format!("fetchImage:{}", webp_url_1)).unwrap(); - cache::delete(&format!("fetchImage:{}", webp_url_2)).unwrap(); - cache::delete(&format!("fetchImage:{}", ico_url)).unwrap(); - cache::delete(&format!("fetchImage:{}", gif_url)).unwrap(); - cache::delete(&format!("fetchImage:{}", mp3_url)).unwrap(); + cache::delete_one(cache::Category::FetchUrl, png_url_1).unwrap(); + cache::delete_one(cache::Category::FetchUrl, png_url_2).unwrap(); + cache::delete_one(cache::Category::FetchUrl, png_url_3).unwrap(); + cache::delete_one(cache::Category::FetchUrl, rotated_jpeg_url).unwrap(); + cache::delete_one(cache::Category::FetchUrl, webp_url_1).unwrap(); + cache::delete_one(cache::Category::FetchUrl, webp_url_2).unwrap(); + cache::delete_one(cache::Category::FetchUrl, ico_url).unwrap(); + cache::delete_one(cache::Category::FetchUrl, gif_url).unwrap(); + cache::delete_one(cache::Category::FetchUrl, mp3_url).unwrap(); let png_size_1 = ImageSize { width: 1024, From 369b1d72df512ca6fc2c0a5c107068dad4fc44a5 Mon Sep 17 00:00:00 2001 From: naskya Date: Sat, 4 May 2024 14:44:20 +0900 Subject: [PATCH 14/75] fix/perf (backend): port latest version check to backend-rs, address excessive requests to firefish.dev --- docs/api-change.md | 4 + packages/backend-rs/index.d.ts | 1 + packages/backend-rs/index.js | 3 +- .../backend-rs/src/misc/latest_version.rs | 91 +++++++++++++++++++ packages/backend-rs/src/misc/mod.rs | 1 + packages/backend/src/server/api/endpoints.ts | 2 - .../server/api/endpoints/latest-version.ts | 10 +- .../src/server/api/endpoints/release.ts | 28 ------ 8 files changed, 101 insertions(+), 39 deletions(-) create mode 100644 packages/backend-rs/src/misc/latest_version.rs delete mode 100644 packages/backend/src/server/api/endpoints/release.ts diff --git a/docs/api-change.md b/docs/api-change.md index d9b7095c7c..ea5cfa4da2 100644 --- a/docs/api-change.md +++ b/docs/api-change.md @@ -2,6 +2,10 @@ Breaking changes are indicated by the :warning: icon. +## Unreleased + +- :warning: Removed `release` endpoint. + ## v20240424 - Added `antennaLimit` field to the response of `meta` and `admin/meta`, and the request of `admin/update-meta` (optional). diff --git a/packages/backend-rs/index.d.ts b/packages/backend-rs/index.d.ts index 5b9d0ee894..4f14e02b6c 100644 --- a/packages/backend-rs/index.d.ts +++ b/packages/backend-rs/index.d.ts @@ -261,6 +261,7 @@ export interface NoteLikeForGetNoteSummary { hasPoll: boolean } export function getNoteSummary(note: NoteLikeForGetNoteSummary): string +export function latestVersion(): Promise export function toMastodonId(firefishId: string): string | null export function fromMastodonId(mastodonId: string): string | null export function fetchMeta(useCache: boolean): Promise diff --git a/packages/backend-rs/index.js b/packages/backend-rs/index.js index b351840dfe..1b1ae265b1 100644 --- a/packages/backend-rs/index.js +++ b/packages/backend-rs/index.js @@ -310,7 +310,7 @@ if (!nativeBinding) { throw new Error(`Failed to load native binding`) } -const { SECOND, MINUTE, HOUR, DAY, USER_ONLINE_THRESHOLD, USER_ACTIVE_THRESHOLD, FILE_TYPE_BROWSERSAFE, loadEnv, loadConfig, stringToAcct, acctToString, addNoteToAntenna, isBlockedServer, isSilencedServer, isAllowedServer, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, getImageSizeFromUrl, getNoteSummary, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, removeOldAttestationChallenges, AntennaSrcEnum, DriveFileUsageHintEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initializeRustLogger, watchNote, unwatchNote, publishToChannelStream, ChatEvent, publishToChatStream, ChatIndexEvent, publishToChatIndexStream, publishToBroadcastStream, publishToGroupChatStream, publishToModerationStream, getTimestamp, genId, genIdAt, secureRndstr } = nativeBinding +const { SECOND, MINUTE, HOUR, DAY, USER_ONLINE_THRESHOLD, USER_ACTIVE_THRESHOLD, FILE_TYPE_BROWSERSAFE, loadEnv, loadConfig, stringToAcct, acctToString, addNoteToAntenna, isBlockedServer, isSilencedServer, isAllowedServer, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, getImageSizeFromUrl, getNoteSummary, latestVersion, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, removeOldAttestationChallenges, AntennaSrcEnum, DriveFileUsageHintEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initializeRustLogger, watchNote, unwatchNote, publishToChannelStream, ChatEvent, publishToChatStream, ChatIndexEvent, publishToChatIndexStream, publishToBroadcastStream, publishToGroupChatStream, publishToModerationStream, getTimestamp, genId, genIdAt, secureRndstr } = nativeBinding module.exports.SECOND = SECOND module.exports.MINUTE = MINUTE @@ -339,6 +339,7 @@ module.exports.safeForSql = safeForSql module.exports.formatMilliseconds = formatMilliseconds module.exports.getImageSizeFromUrl = getImageSizeFromUrl module.exports.getNoteSummary = getNoteSummary +module.exports.latestVersion = latestVersion module.exports.toMastodonId = toMastodonId module.exports.fromMastodonId = fromMastodonId module.exports.fetchMeta = fetchMeta diff --git a/packages/backend-rs/src/misc/latest_version.rs b/packages/backend-rs/src/misc/latest_version.rs new file mode 100644 index 0000000000..1994d3a921 --- /dev/null +++ b/packages/backend-rs/src/misc/latest_version.rs @@ -0,0 +1,91 @@ +use crate::database::cache; +use crate::util::http_client::http_client; +use serde::{Deserialize, Serialize}; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Cache error: {0}")] + CacheErr(#[from] cache::Error), + #[error("Reqwest error: {0}")] + ReqwestErr(#[from] reqwest::Error), + #[error("Failed to deserialize JSON: {0}")] + JsonErr(#[from] serde_json::Error), +} + +const UPSTREAM_PACKAGE_JSON_URL: &'static str = + "https://firefish.dev/firefish/firefish/-/raw/main/package.json"; + +async fn get_latest_version() -> Result { + #[derive(Debug, Deserialize, Serialize)] + struct Response { + version: String, + } + + let res = http_client()? + .get(UPSTREAM_PACKAGE_JSON_URL) + .send() + .await? + .text() + .await?; + let res_parsed: Response = serde_json::from_str(&res)?; + + Ok(res_parsed.version) +} + +#[crate::export] +pub async fn latest_version() -> Result { + let version: Option = + cache::get_one(cache::Category::FetchUrl, UPSTREAM_PACKAGE_JSON_URL)?; + + if let Some(v) = version { + tracing::trace!("use cached value: {}", v); + Ok(v) + } else { + tracing::trace!("cache is expired, fetching the latest version"); + let fetched_version = get_latest_version().await?; + tracing::trace!("fetched value: {}", fetched_version); + + cache::set_one( + cache::Category::FetchUrl, + UPSTREAM_PACKAGE_JSON_URL, + &fetched_version, + 3 * 60 * 60, + )?; + Ok(fetched_version) + } +} + +#[cfg(test)] +mod unit_test { + use super::{latest_version, UPSTREAM_PACKAGE_JSON_URL}; + use crate::database::cache; + + fn validate_version(version: String) { + // version: YYYYMMDD + assert!(version.len() == 8); + assert!(version.chars().all(|c| c.is_ascii_digit())); + + // YYYY + assert!(&version[..4] >= "2024"); + + // MM + assert!(&version[4..6] >= "01"); + assert!(&version[4..6] <= "12"); + + // DD + assert!(&version[6..] >= "01"); + assert!(&version[6..] <= "31"); + } + + #[tokio::test] + async fn check_version() { + // TODO: don't need to do this in CI tasks + cache::delete_one(cache::Category::FetchUrl, UPSTREAM_PACKAGE_JSON_URL).unwrap(); + + // fetch from firefish.dev + validate_version(latest_version().await.unwrap()); + + // use cache + validate_version(latest_version().await.unwrap()); + } +} diff --git a/packages/backend-rs/src/misc/mod.rs b/packages/backend-rs/src/misc/mod.rs index 7e8301ddeb..8d0a272e5c 100644 --- a/packages/backend-rs/src/misc/mod.rs +++ b/packages/backend-rs/src/misc/mod.rs @@ -8,6 +8,7 @@ pub mod escape_sql; pub mod format_milliseconds; pub mod get_image_size; pub mod get_note_summary; +pub mod latest_version; pub mod mastodon_id; pub mod meta; pub mod nyaify; diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index 734534b3ea..587a68206e 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -286,7 +286,6 @@ import * as ep___pinnedUsers from "./endpoints/pinned-users.js"; import * as ep___customMotd from "./endpoints/custom-motd.js"; import * as ep___customSplashIcons from "./endpoints/custom-splash-icons.js"; import * as ep___latestVersion from "./endpoints/latest-version.js"; -import * as ep___release from "./endpoints/release.js"; import * as ep___promo_read from "./endpoints/promo/read.js"; import * as ep___requestResetPassword from "./endpoints/request-reset-password.js"; import * as ep___resetPassword from "./endpoints/reset-password.js"; @@ -635,7 +634,6 @@ const eps = [ ["custom-motd", ep___customMotd], ["custom-splash-icons", ep___customSplashIcons], ["latest-version", ep___latestVersion], - ["release", ep___release], ["promo/read", ep___promo_read], ["request-reset-password", ep___requestResetPassword], ["reset-password", ep___resetPassword], diff --git a/packages/backend/src/server/api/endpoints/latest-version.ts b/packages/backend/src/server/api/endpoints/latest-version.ts index 2ca29429b6..e2146303b7 100644 --- a/packages/backend/src/server/api/endpoints/latest-version.ts +++ b/packages/backend/src/server/api/endpoints/latest-version.ts @@ -1,4 +1,5 @@ import define from "@/server/api/define.js"; +import { latestVersion } from "backend-rs"; export const meta = { tags: ["meta"], @@ -14,14 +15,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async () => { - let latest_version; - await fetch("https://firefish.dev/firefish/firefish/-/raw/main/package.json") - .then((response) => response.json()) - .then((data) => { - latest_version = data.version; - }); - return { - latest_version, + latest_version: await latestVersion(), }; }); diff --git a/packages/backend/src/server/api/endpoints/release.ts b/packages/backend/src/server/api/endpoints/release.ts deleted file mode 100644 index f3a2764295..0000000000 --- a/packages/backend/src/server/api/endpoints/release.ts +++ /dev/null @@ -1,28 +0,0 @@ -import define from "@/server/api/define.js"; - -export const meta = { - tags: ["meta"], - description: "Get release notes from Codeberg", - - requireCredential: false, - requireCredentialPrivateMode: false, -} as const; - -export const paramDef = { - type: "object", - properties: {}, - required: [], -} as const; - -export default define(meta, paramDef, async () => { - let release; - - await fetch( - "https://firefish.dev/firefish/firefish/-/raw/develop/release.json", - ) - .then((response) => response.json()) - .then((data) => { - release = data; - }); - return release; -}); From dbe10f88b0a4309066530683587ddaa0835c206f Mon Sep 17 00:00:00 2001 From: naskya Date: Sat, 4 May 2024 14:54:42 +0900 Subject: [PATCH 15/75] docs: update changelog --- docs/changelog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index acf5cba712..2cd973d414 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -5,6 +5,10 @@ Critical security updates are indicated by the :warning: icon. - Server administrators should check [notice-for-admins.md](./notice-for-admins.md) as well. - Third-party client/bot developers may want to check [api-change.md](./api-change.md) as well. +## Unreleased + +- Fix bugs + ## :warning: [v20240430](https://firefish.dev/firefish/firefish/-/merge_requests/10781/commits) - Add ability to group similar notifications From bf3f4906acb1e3b1426d199166b0d94ae98eb22e Mon Sep 17 00:00:00 2001 From: naskya Date: Sat, 4 May 2024 14:59:11 +0900 Subject: [PATCH 16/75] docs: update dev docs --- dev/docs/db-container.md | 20 ++++++++++++++------ dev/docs/local-installation.md | 7 +------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/dev/docs/db-container.md b/dev/docs/db-container.md index 7e3caf7f4b..465b45dd0f 100644 --- a/dev/docs/db-container.md +++ b/dev/docs/db-container.md @@ -51,12 +51,7 @@ You can refer to [local-installation.md](./local-installation.md) to install the host: localhost port: 26379 - logLevel: [ - 'error', - 'success', - 'warning', - 'info' - ] + maxlogLevel: 'debug' # or 'trace' ``` 1. Start database containers ```sh @@ -84,6 +79,19 @@ You can refer to [local-installation.md](./local-installation.md) to install the DONE * [core boot] Now listening on port 3000 on http://localhost:3000 ``` +## Update auto-generated files in `package/backend-rs` + +You need to install `sea-orm-cli` to regenerate database entities. + +```sh +cargo install sea-orm-cli +``` + +```sh +make entities +make napi +``` + ## Reset the environment You can recreate a fresh local Firefish environment by recreating the database containers: diff --git a/dev/docs/local-installation.md b/dev/docs/local-installation.md index 15c7dad7d4..cc32e94198 100644 --- a/dev/docs/local-installation.md +++ b/dev/docs/local-installation.md @@ -141,12 +141,7 @@ sudo apt install ffmpeg host: localhost port: 6379 - logLevel: [ - 'error', - 'success', - 'warning', - 'info' - ] + maxLogLevel: 'debug' # or 'trace' ``` ## 4. Build and start Firefish From 15c32d55109097391ae68b4e21a3928d8105febe Mon Sep 17 00:00:00 2001 From: naskya Date: Sat, 4 May 2024 15:28:24 +0900 Subject: [PATCH 17/75] docs: explicitly list Perl as a build dependency --- dev/docs/db-container.md | 2 ++ docs/install.md | 1 + docs/notice-for-admins.md | 34 ++++++++++++++++------------------ 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/dev/docs/db-container.md b/dev/docs/db-container.md index 465b45dd0f..b4bb73bc77 100644 --- a/dev/docs/db-container.md +++ b/dev/docs/db-container.md @@ -7,6 +7,8 @@ - Node.js - pnpm - Rust toolchain + - Python 3 + - Perl - FFmpeg - Container runtime - [Docker](https://docs.docker.com/get-docker/) diff --git a/docs/install.md b/docs/install.md index d60ad0a707..60903e26ea 100644 --- a/docs/install.md +++ b/docs/install.md @@ -24,6 +24,7 @@ Firefish depends on the following software. - `build-essential` on Debian/Ubuntu Linux - `base-devel` on Arch Linux - [Python 3](https://www.python.org/) +- [Perl](https://www.perl.org/) This document shows an example procedure for installing these dependencies and Firefish on Debian 12. Note that there is much room for customizing the server setup; this document merely demonstrates a simple installation. diff --git a/docs/notice-for-admins.md b/docs/notice-for-admins.md index 2ea21bfe85..6f979923ff 100644 --- a/docs/notice-for-admins.md +++ b/docs/notice-for-admins.md @@ -10,24 +10,22 @@ You can control the verbosity of the server log by adding `maxLogLevel` in `.con ### For systemd/pm2 users -Not only Firefish but also Node.js has recently fixed a few security issues: - -- https://nodejs.org/en/blog/vulnerability/april-2024-security-releases -- https://nodejs.org/en/blog/vulnerability/april-2024-security-releases-2 - -So, it is highly recommended that you upgrade your Node.js version as well. The new versions are - -- Node v18.20.2 (v18.x LTS) -- Node v20.12.2 (v20.x LTS) -- Node v21.7.3 (v21.x) - -You can check your Node.js version by this command: - -```sh -node --version -``` - -[Node v22](https://nodejs.org/en/blog/announcements/v22-release-announce) was also released several days ago, but we have not yet tested Firefish with this version. +- You need to install Perl to build Firefish. Since Git depends on Perl in many packaging systems, you probably already have Perl installed on your system. You can check the Perl version by this command: + ```sh + perl --version + ``` +- Not only Firefish but also Node.js has recently fixed a few security issues: + - https://nodejs.org/en/blog/vulnerability/april-2024-security-releases + - https://nodejs.org/en/blog/vulnerability/april-2024-security-releases-2 + So, it is highly recommended that you upgrade your Node.js version as well. The new versions are + - Node v18.20.2 (v18.x LTS) + - Node v20.12.2 (v20.x LTS) + - Node v21.7.3 (v21.x) + - You can check your Node.js version by this command: + ```sh + node --version + ``` + [Node v22](https://nodejs.org/en/blog/announcements/v22-release-announce) was also released several days ago, but we have not yet tested Firefish with this version. ## v20240413 From 1ee8198c6fd7d5ebf97c779275c4d63aab8a13b1 Mon Sep 17 00:00:00 2001 From: naskya Date: Sat, 4 May 2024 16:04:31 +0900 Subject: [PATCH 18/75] v20240504 --- docs/api-change.md | 2 +- docs/changelog.md | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/api-change.md b/docs/api-change.md index ea5cfa4da2..f5254955f2 100644 --- a/docs/api-change.md +++ b/docs/api-change.md @@ -2,7 +2,7 @@ Breaking changes are indicated by the :warning: icon. -## Unreleased +## v20240504 - :warning: Removed `release` endpoint. diff --git a/docs/changelog.md b/docs/changelog.md index 2cd973d414..19bbecaaec 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -5,7 +5,7 @@ Critical security updates are indicated by the :warning: icon. - Server administrators should check [notice-for-admins.md](./notice-for-admins.md) as well. - Third-party client/bot developers may want to check [api-change.md](./api-change.md) as well. -## Unreleased +## [v20240504](https://firefish.dev/firefish/firefish/-/merge_requests/10790/commits) - Fix bugs diff --git a/package.json b/package.json index 90277975f1..068353db7d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "firefish", - "version": "20240430", + "version": "20240504", "repository": { "type": "git", "url": "https://firefish.dev/firefish/firefish.git" From bc39badf51bc198539a3758b7aa977abcd2c2d6e Mon Sep 17 00:00:00 2001 From: naskya Date: Sat, 4 May 2024 16:08:41 +0900 Subject: [PATCH 19/75] chore (client): remove unused code --- packages/client/src/components/MkUpdated.vue | 33 +------------------- 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/packages/client/src/components/MkUpdated.vue b/packages/client/src/components/MkUpdated.vue index 7004be11cf..7f519b407a 100644 --- a/packages/client/src/components/MkUpdated.vue +++ b/packages/client/src/components/MkUpdated.vue @@ -10,17 +10,6 @@ {{ i18n.ts.misskeyUpdated }}
✨ {{ version }} 🚀
-
- -
- screenshot -
-
From 0f4c05a64f0c4da3f1d23ef4cf07206c54dc4c59 Mon Sep 17 00:00:00 2001 From: naskya Date: Sat, 4 May 2024 16:14:23 +0900 Subject: [PATCH 20/75] ci: add 'ci' feature flag to backend-rs --- Cargo.lock | 1 + Cargo.toml | 1 + packages/backend-rs/Cargo.toml | 2 ++ .../backend-rs/src/misc/get_image_size.rs | 25 +++++++++++-------- .../backend-rs/src/misc/latest_version.rs | 7 ++++-- 5 files changed, 23 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0a1d9aad18..98e333b6cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -202,6 +202,7 @@ dependencies = [ "argon2", "basen", "bcrypt", + "cfg-if", "chrono", "cuid2", "emojis", diff --git a/Cargo.toml b/Cargo.toml index 74d032aeae..3ada688b7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ napi-build = "2.1.3" argon2 = "0.5.3" basen = "0.1.0" bcrypt = "0.15.1" +cfg-if = "1.0.0" chrono = "0.4.38" convert_case = "0.6.0" cuid2 = "0.1.2" diff --git a/packages/backend-rs/Cargo.toml b/packages/backend-rs/Cargo.toml index c1b511b992..eb0fa82631 100644 --- a/packages/backend-rs/Cargo.toml +++ b/packages/backend-rs/Cargo.toml @@ -7,6 +7,7 @@ rust-version = "1.74" [features] default = [] napi = ["dep:napi", "dep:napi-derive"] +ci = [] [lib] crate-type = ["cdylib", "lib"] @@ -46,6 +47,7 @@ url = { workspace = true } urlencoding = { workspace = true } [dev-dependencies] +cfg-if = { workspace = true } pretty_assertions = { workspace = true } [build-dependencies] diff --git a/packages/backend-rs/src/misc/get_image_size.rs b/packages/backend-rs/src/misc/get_image_size.rs index ac0de89015..c74b70e603 100644 --- a/packages/backend-rs/src/misc/get_image_size.rs +++ b/packages/backend-rs/src/misc/get_image_size.rs @@ -123,17 +123,20 @@ mod unit_test { let gif_url = "https://firefish.dev/firefish/firefish/-/raw/b9c3dfbd3d473cb2cee20c467eeae780bc401271/packages/backend/test/resources/anime.gif"; let mp3_url = "https://firefish.dev/firefish/firefish/-/blob/5891a90f71a8b9d5ea99c683ade7e485c685d642/packages/backend/assets/sounds/aisha/1.mp3"; - // Delete caches in case you run this test multiple times - // (should be disabled in CI tasks) - cache::delete_one(cache::Category::FetchUrl, png_url_1).unwrap(); - cache::delete_one(cache::Category::FetchUrl, png_url_2).unwrap(); - cache::delete_one(cache::Category::FetchUrl, png_url_3).unwrap(); - cache::delete_one(cache::Category::FetchUrl, rotated_jpeg_url).unwrap(); - cache::delete_one(cache::Category::FetchUrl, webp_url_1).unwrap(); - cache::delete_one(cache::Category::FetchUrl, webp_url_2).unwrap(); - cache::delete_one(cache::Category::FetchUrl, ico_url).unwrap(); - cache::delete_one(cache::Category::FetchUrl, gif_url).unwrap(); - cache::delete_one(cache::Category::FetchUrl, mp3_url).unwrap(); + cfg_if::cfg_if! { + if #[cfg(not(feature = "ci"))] { + // Delete caches in case you run this test multiple times + cache::delete_one(cache::Category::FetchUrl, png_url_1).unwrap(); + cache::delete_one(cache::Category::FetchUrl, png_url_2).unwrap(); + cache::delete_one(cache::Category::FetchUrl, png_url_3).unwrap(); + cache::delete_one(cache::Category::FetchUrl, rotated_jpeg_url).unwrap(); + cache::delete_one(cache::Category::FetchUrl, webp_url_1).unwrap(); + cache::delete_one(cache::Category::FetchUrl, webp_url_2).unwrap(); + cache::delete_one(cache::Category::FetchUrl, ico_url).unwrap(); + cache::delete_one(cache::Category::FetchUrl, gif_url).unwrap(); + cache::delete_one(cache::Category::FetchUrl, mp3_url).unwrap(); + } + } let png_size_1 = ImageSize { width: 1024, diff --git a/packages/backend-rs/src/misc/latest_version.rs b/packages/backend-rs/src/misc/latest_version.rs index 1994d3a921..5620d204d1 100644 --- a/packages/backend-rs/src/misc/latest_version.rs +++ b/packages/backend-rs/src/misc/latest_version.rs @@ -79,8 +79,11 @@ mod unit_test { #[tokio::test] async fn check_version() { - // TODO: don't need to do this in CI tasks - cache::delete_one(cache::Category::FetchUrl, UPSTREAM_PACKAGE_JSON_URL).unwrap(); + cfg_if::cfg_if! { + if #[cfg(not(feature = "ci"))] { + cache::delete_one(cache::Category::FetchUrl, UPSTREAM_PACKAGE_JSON_URL).unwrap(); + } + } // fetch from firefish.dev validate_version(latest_version().await.unwrap()); From 8c22b0d07f243c869a0ab0e15aea5b66f8237abd Mon Sep 17 00:00:00 2001 From: naskya Date: Sat, 4 May 2024 16:17:33 +0900 Subject: [PATCH 21/75] test (backend-rs): fix version format --- packages/backend-rs/src/misc/latest_version.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/backend-rs/src/misc/latest_version.rs b/packages/backend-rs/src/misc/latest_version.rs index 5620d204d1..9e237aff4b 100644 --- a/packages/backend-rs/src/misc/latest_version.rs +++ b/packages/backend-rs/src/misc/latest_version.rs @@ -61,9 +61,9 @@ mod unit_test { use crate::database::cache; fn validate_version(version: String) { - // version: YYYYMMDD - assert!(version.len() == 8); - assert!(version.chars().all(|c| c.is_ascii_digit())); + // version: YYYYMMDD or YYYYMMDD-X + assert!(version.len() >= 8); + assert!(version[..8].chars().all(|c| c.is_ascii_digit())); // YYYY assert!(&version[..4] >= "2024"); @@ -73,8 +73,8 @@ mod unit_test { assert!(&version[4..6] <= "12"); // DD - assert!(&version[6..] >= "01"); - assert!(&version[6..] <= "31"); + assert!(&version[6..8] >= "01"); + assert!(&version[6..8] <= "31"); } #[tokio::test] From b185c0c87e8b80fa45535413321b70013ce77938 Mon Sep 17 00:00:00 2001 From: naskya Date: Sat, 4 May 2024 21:24:20 +0900 Subject: [PATCH 22/75] feat (backend-rs): add cache::delete_all --- Cargo.lock | 1 - Cargo.toml | 1 - packages/backend-rs/Cargo.toml | 1 - packages/backend-rs/src/database/cache.rs | 59 +++++++++++++++++-- .../backend-rs/src/misc/get_image_size.rs | 17 +----- .../backend-rs/src/misc/latest_version.rs | 7 +-- 6 files changed, 59 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 98e333b6cc..0a1d9aad18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -202,7 +202,6 @@ dependencies = [ "argon2", "basen", "bcrypt", - "cfg-if", "chrono", "cuid2", "emojis", diff --git a/Cargo.toml b/Cargo.toml index 3ada688b7f..74d032aeae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,6 @@ napi-build = "2.1.3" argon2 = "0.5.3" basen = "0.1.0" bcrypt = "0.15.1" -cfg-if = "1.0.0" chrono = "0.4.38" convert_case = "0.6.0" cuid2 = "0.1.2" diff --git a/packages/backend-rs/Cargo.toml b/packages/backend-rs/Cargo.toml index eb0fa82631..5fcf7550dd 100644 --- a/packages/backend-rs/Cargo.toml +++ b/packages/backend-rs/Cargo.toml @@ -47,7 +47,6 @@ url = { workspace = true } urlencoding = { workspace = true } [dev-dependencies] -cfg-if = { workspace = true } pretty_assertions = { workspace = true } [build-dependencies] diff --git a/packages/backend-rs/src/database/cache.rs b/packages/backend-rs/src/database/cache.rs index cbc7a60ff6..0503415481 100644 --- a/packages/backend-rs/src/database/cache.rs +++ b/packages/backend-rs/src/database/cache.rs @@ -2,10 +2,13 @@ use crate::database::{redis_conn, redis_key}; use redis::{Commands, RedisError}; use serde::{Deserialize, Serialize}; -#[derive(strum::Display)] +#[derive(strum::Display, Debug)] pub enum Category { #[strum(serialize = "fetchUrl")] FetchUrl, + #[cfg(test)] + #[strum(serialize = "usedOnlyForTesting")] + Test, } #[derive(thiserror::Error, Debug)] @@ -18,12 +21,19 @@ pub enum Error { DeserializeError(#[from] rmp_serde::decode::Error), } +#[inline] +fn prefix_key(key: &str) -> String { + redis_key(format!("cache:{}", key)) +} + +#[inline] fn categorize(category: Category, key: &str) -> String { format!("{}:{}", category, key) } -fn prefix_key(key: &str) -> String { - redis_key(format!("cache:{}", key)) +#[inline] +fn wildcard(category: Category) -> String { + prefix_key(&categorize(category, "*")) } pub fn set Deserialize<'a> + Serialize>( @@ -71,11 +81,19 @@ pub fn delete_one(category: Category, key: &str) -> Result<(), Error> { delete(&categorize(category, key)) } -// TODO: set_all(), get_all(), delete_all() +pub fn delete_all(category: Category) -> Result<(), Error> { + let mut redis = redis_conn()?; + let keys: Vec> = redis.keys(wildcard(category))?; + Ok(redis.del(keys)?) +} + +// TODO: set_all(), get_all() #[cfg(test)] mod unit_test { - use super::{get, set}; + use crate::database::cache::delete_one; + + use super::{delete_all, get, get_one, set, set_one, Category::Test}; use pretty_assertions::assert_eq; #[test] @@ -121,4 +139,35 @@ mod unit_test { assert!(expired_value_2.is_none()); assert!(expired_value_3.is_none()); } + + #[test] + fn use_category() { + let key_1 = "fire"; + let key_2 = "fish"; + let key_3 = "awawa"; + + let value_1 = "hello".to_string(); + let value_2 = 998244353u32; + let value_3 = 'あ'; + + set_one(Test, key_1, &value_1, 5 * 60).unwrap(); + set_one(Test, key_2, &value_2, 5 * 60).unwrap(); + set_one(Test, key_3, &value_3, 5 * 60).unwrap(); + + assert_eq!(get_one::(Test, key_1).unwrap().unwrap(), value_1); + assert_eq!(get_one::(Test, key_2).unwrap().unwrap(), value_2); + assert_eq!(get_one::(Test, key_3).unwrap().unwrap(), value_3); + + delete_one(Test, key_1).unwrap(); + + assert!(get_one::(Test, key_1).unwrap().is_none()); + assert!(get_one::(Test, key_2).unwrap().is_some()); + assert!(get_one::(Test, key_3).unwrap().is_some()); + + delete_all(Test).unwrap(); + + assert!(get_one::(Test, key_1).unwrap().is_none()); + assert!(get_one::(Test, key_2).unwrap().is_none()); + assert!(get_one::(Test, key_3).unwrap().is_none()); + } } diff --git a/packages/backend-rs/src/misc/get_image_size.rs b/packages/backend-rs/src/misc/get_image_size.rs index c74b70e603..4cab76b8ad 100644 --- a/packages/backend-rs/src/misc/get_image_size.rs +++ b/packages/backend-rs/src/misc/get_image_size.rs @@ -123,20 +123,9 @@ mod unit_test { let gif_url = "https://firefish.dev/firefish/firefish/-/raw/b9c3dfbd3d473cb2cee20c467eeae780bc401271/packages/backend/test/resources/anime.gif"; let mp3_url = "https://firefish.dev/firefish/firefish/-/blob/5891a90f71a8b9d5ea99c683ade7e485c685d642/packages/backend/assets/sounds/aisha/1.mp3"; - cfg_if::cfg_if! { - if #[cfg(not(feature = "ci"))] { - // Delete caches in case you run this test multiple times - cache::delete_one(cache::Category::FetchUrl, png_url_1).unwrap(); - cache::delete_one(cache::Category::FetchUrl, png_url_2).unwrap(); - cache::delete_one(cache::Category::FetchUrl, png_url_3).unwrap(); - cache::delete_one(cache::Category::FetchUrl, rotated_jpeg_url).unwrap(); - cache::delete_one(cache::Category::FetchUrl, webp_url_1).unwrap(); - cache::delete_one(cache::Category::FetchUrl, webp_url_2).unwrap(); - cache::delete_one(cache::Category::FetchUrl, ico_url).unwrap(); - cache::delete_one(cache::Category::FetchUrl, gif_url).unwrap(); - cache::delete_one(cache::Category::FetchUrl, mp3_url).unwrap(); - } - } + // Delete caches in case you run this test multiple times + #[cfg(not(feature = "ci"))] + cache::delete_all(cache::Category::FetchUrl).unwrap(); let png_size_1 = ImageSize { width: 1024, diff --git a/packages/backend-rs/src/misc/latest_version.rs b/packages/backend-rs/src/misc/latest_version.rs index 9e237aff4b..273a953296 100644 --- a/packages/backend-rs/src/misc/latest_version.rs +++ b/packages/backend-rs/src/misc/latest_version.rs @@ -79,11 +79,8 @@ mod unit_test { #[tokio::test] async fn check_version() { - cfg_if::cfg_if! { - if #[cfg(not(feature = "ci"))] { - cache::delete_one(cache::Category::FetchUrl, UPSTREAM_PACKAGE_JSON_URL).unwrap(); - } - } + #[cfg(not(feature = "ci"))] + cache::delete_one(cache::Category::FetchUrl, UPSTREAM_PACKAGE_JSON_URL).unwrap(); // fetch from firefish.dev validate_version(latest_version().await.unwrap()); From 722d090f8d4f9cd2da27b8e2ff19d3a3242bc997 Mon Sep 17 00:00:00 2001 From: naskya Date: Sat, 4 May 2024 22:49:11 +0900 Subject: [PATCH 23/75] chore (backend-rs): remove unneeded 'static --- packages/backend-rs/src/misc/latest_version.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend-rs/src/misc/latest_version.rs b/packages/backend-rs/src/misc/latest_version.rs index 273a953296..13945fcdda 100644 --- a/packages/backend-rs/src/misc/latest_version.rs +++ b/packages/backend-rs/src/misc/latest_version.rs @@ -12,7 +12,7 @@ pub enum Error { JsonErr(#[from] serde_json::Error), } -const UPSTREAM_PACKAGE_JSON_URL: &'static str = +const UPSTREAM_PACKAGE_JSON_URL: &str = "https://firefish.dev/firefish/firefish/-/raw/main/package.json"; async fn get_latest_version() -> Result { From 38c0de39b9af69a5207407aaa71ff460af7d840c Mon Sep 17 00:00:00 2001 From: naskya Date: Sat, 4 May 2024 22:50:46 +0900 Subject: [PATCH 24/75] chore (backend-rs): add docs for functions in database/cache --- packages/backend-rs/src/database/cache.rs | 119 +++++++++++++++++++++- 1 file changed, 118 insertions(+), 1 deletion(-) diff --git a/packages/backend-rs/src/database/cache.rs b/packages/backend-rs/src/database/cache.rs index 0503415481..5b29de46b2 100644 --- a/packages/backend-rs/src/database/cache.rs +++ b/packages/backend-rs/src/database/cache.rs @@ -36,6 +36,30 @@ fn wildcard(category: Category) -> String { prefix_key(&categorize(category, "*")) } +/// Sets a Redis cache. +/// +/// This overwrites the exsisting cache with the same key. +/// +/// ## Arguments +/// +/// * `key` - key (will be prefixed automatically) +/// * `value` - (de)serializable value +/// * `expire_seconds` - TTL +/// +/// ## Example +/// +/// ``` +/// use backend_rs::database::cache; +/// let key = "apple"; +/// let data = "I want to cache this string".to_string(); +/// +/// // caches the data for 10 seconds +/// cache::set(key, &data, 10); +/// +/// // get the cache +/// let cached_data = cache::get::(key).unwrap(); +/// assert_eq!(data, cached_data.unwrap()); +/// ``` pub fn set Deserialize<'a> + Serialize>( key: &str, value: &V, @@ -49,6 +73,34 @@ pub fn set Deserialize<'a> + Serialize>( Ok(()) } +/// Gets a Redis cache. +/// +/// If the Redis connection is fine, this returns `Ok(data)` where `data` +/// is the cached value. Returns `Ok(None)` if there is no value corresponding to `key`. +/// +/// ## Arguments +/// +/// * `key` - key (will be prefixed automatically) +/// +/// ## Example +/// +/// ``` +/// use backend_rs::database::cache; +/// +/// let key = "banana"; +/// let data = "I want to cache this string".to_string(); +/// +/// // set cache +/// cache::set(key, &data, 10).unwrap(); +/// +/// // get cache +/// let cached_data = cache::get::(key).unwrap(); +/// assert_eq!(data, cached_data.unwrap()); +/// +/// // get nonexistent (or expired) cache +/// let no_cache = cache::get::("nonexistent").unwrap(); +/// assert!(no_cache.is_none()); +/// ``` pub fn get Deserialize<'a> + Serialize>(key: &str) -> Result, Error> { let serialized_value: Option> = redis_conn()?.get(prefix_key(key))?; Ok(match serialized_value { @@ -57,10 +109,49 @@ pub fn get Deserialize<'a> + Serialize>(key: &str) -> Result("foo").unwrap(); +/// assert!(cached_value.is_none()); +/// ``` pub fn delete(key: &str) -> Result<(), Error> { Ok(redis_conn()?.del(prefix_key(key))?) } +/// Sets a Redis cache under a `category`. +/// +/// The usage is the same as [set], except that you need to +/// use [get_one] and [delete_one] to get/delete the cache. +/// +/// ## Arguments +/// +/// * `category` - one of [Category] +/// * `key` - key (will be prefixed automatically) +/// * `value` - (de)serializable value +/// * `expire_seconds` - TTL pub fn set_one Deserialize<'a> + Serialize>( category: Category, key: &str, @@ -70,6 +161,14 @@ pub fn set_one Deserialize<'a> + Serialize>( set(&categorize(category, key), value, expire_seconds) } +/// Gets a Redis cache under a `category`. +/// +/// The usage is basically the same as [get]. +/// +/// ## Arguments +/// +/// * `category` - one of [Category] +/// * `key` - key (will be prefixed automatically) pub fn get_one Deserialize<'a> + Serialize>( category: Category, key: &str, @@ -77,14 +176,32 @@ pub fn get_one Deserialize<'a> + Serialize>( get(&categorize(category, key)) } +/// Deletes a Redis cache under a `category`. +/// +/// The usage is basically the same as [delete]. +/// +/// ## Arguments +/// +/// * `category` - one of [Category] +/// * `key` - key (will be prefixed automatically) pub fn delete_one(category: Category, key: &str) -> Result<(), Error> { delete(&categorize(category, key)) } +/// Deletes all Redis caches under a `category`. +/// +/// ## Arguments +/// +/// * `category` - one of [Category] pub fn delete_all(category: Category) -> Result<(), Error> { let mut redis = redis_conn()?; let keys: Vec> = redis.keys(wildcard(category))?; - Ok(redis.del(keys)?) + + if !keys.is_empty() { + redis.del(keys)? + } + + Ok(()) } // TODO: set_all(), get_all() From 4992999bb7424f50ca5cf3fcae2045bf419514b4 Mon Sep 17 00:00:00 2001 From: naskya Date: Sat, 4 May 2024 22:59:49 +0900 Subject: [PATCH 25/75] test (backend-rs): add tests --- packages/backend-rs/src/misc/get_image_size.rs | 14 ++++++++++++-- packages/backend-rs/src/misc/latest_version.rs | 8 +++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/backend-rs/src/misc/get_image_size.rs b/packages/backend-rs/src/misc/get_image_size.rs index 4cab76b8ad..9b3e20171c 100644 --- a/packages/backend-rs/src/misc/get_image_size.rs +++ b/packages/backend-rs/src/misc/get_image_size.rs @@ -123,8 +123,7 @@ mod unit_test { let gif_url = "https://firefish.dev/firefish/firefish/-/raw/b9c3dfbd3d473cb2cee20c467eeae780bc401271/packages/backend/test/resources/anime.gif"; let mp3_url = "https://firefish.dev/firefish/firefish/-/blob/5891a90f71a8b9d5ea99c683ade7e485c685d642/packages/backend/assets/sounds/aisha/1.mp3"; - // Delete caches in case you run this test multiple times - #[cfg(not(feature = "ci"))] + // delete caches in case you run this test multiple times cache::delete_all(cache::Category::FetchUrl).unwrap(); let png_size_1 = ImageSize { @@ -188,4 +187,15 @@ mod unit_test { assert_eq!(gif_size, get_image_size_from_url(gif_url).await.unwrap()); assert!(get_image_size_from_url(mp3_url).await.is_err()); } + + #[tokio::test] + async fn too_many_attempts() { + let url = "https://firefish.dev/firefish/firefish/-/raw/5891a90f71a8b9d5ea99c683ade7e485c685d642/packages/backend/assets/splash.png"; + + // delete caches in case you run this test multiple times + cache::delete_one(cache::Category::FetchUrl, url).unwrap(); + + assert!(get_image_size_from_url(url).await.is_ok()); + assert!(get_image_size_from_url(url).await.is_err()); + } } diff --git a/packages/backend-rs/src/misc/latest_version.rs b/packages/backend-rs/src/misc/latest_version.rs index 13945fcdda..2b56f31055 100644 --- a/packages/backend-rs/src/misc/latest_version.rs +++ b/packages/backend-rs/src/misc/latest_version.rs @@ -75,11 +75,17 @@ mod unit_test { // DD assert!(&version[6..8] >= "01"); assert!(&version[6..8] <= "31"); + + // -X + if version.len() > 8 { + assert!(version.chars().nth(8).unwrap() == '-'); + assert!(version[9..].chars().all(|c| c.is_ascii_digit())); + } } #[tokio::test] async fn check_version() { - #[cfg(not(feature = "ci"))] + // delete caches in case you run this test multiple times cache::delete_one(cache::Category::FetchUrl, UPSTREAM_PACKAGE_JSON_URL).unwrap(); // fetch from firefish.dev From 6d643586746d0895099146971e3808daf1051ed6 Mon Sep 17 00:00:00 2001 From: naskya Date: Sun, 5 May 2024 01:15:04 +0900 Subject: [PATCH 26/75] fix (client): missing MFM function props not falling back correctly --- packages/client/src/components/mfm.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/client/src/components/mfm.ts b/packages/client/src/components/mfm.ts index 548e3d51f6..bdba3c0cbe 100644 --- a/packages/client/src/components/mfm.ts +++ b/packages/client/src/components/mfm.ts @@ -283,44 +283,44 @@ export default defineComponent({ ? "perspective(128px) rotateY" : "rotate"; const degrees = Number.parseFloat( - token.props.args.deg.toString() ?? "90", + (token.props.args.deg ?? "90").toString(), ); style = `transform: ${rotate}(${degrees}deg); transform-origin: center center;`; break; } case "position": { const x = Number.parseFloat( - token.props.args.x.toString() ?? "0", + (token.props.args.x ?? "0").toString(), ); const y = Number.parseFloat( - token.props.args.y.toString() ?? "0", + (token.props.args.y ?? "0").toString(), ); style = `transform: translateX(${x}em) translateY(${y}em);`; break; } case "crop": { const top = Number.parseFloat( - token.props.args.top.toString() ?? "0", + (token.props.args.top ?? "0").toString(), ); const right = Number.parseFloat( - token.props.args.right.toString() ?? "0", + (token.props.args.right ?? "0").toString(), ); const bottom = Number.parseFloat( - token.props.args.bottom.toString() ?? "0", + (token.props.args.bottom ?? "0").toString(), ); const left = Number.parseFloat( - token.props.args.left.toString() ?? "0", + (token.props.args.left ?? "0").toString(), ); style = `clip-path: inset(${top}% ${right}% ${bottom}% ${left}%);`; break; } case "scale": { const x = Math.min( - Number.parseFloat(token.props.args.x.toString() ?? "1"), + Number.parseFloat((token.props.args.x ?? "1").toString()), 5, ); const y = Math.min( - Number.parseFloat(token.props.args.y.toString() ?? "1"), + Number.parseFloat((token.props.args.y ?? "1").toString()), 5, ); style = `transform: scale(${x}, ${y});`; From 341b43ed71a0ce945233406ea6210e4bcaede6a4 Mon Sep 17 00:00:00 2001 From: naskya Date: Sun, 5 May 2024 02:19:58 +0900 Subject: [PATCH 27/75] refactor: replace gulp with a simple script --- Dockerfile | 2 +- docs/install.md | 2 +- gulpfile.js | 101 -- package.json | 12 +- packages/client/package.json | 2 - pnpm-lock.yaml | 2366 +--------------------------------- scripts/copy-assets.mjs | 35 + scripts/dev.mjs | 6 - 8 files changed, 75 insertions(+), 2451 deletions(-) delete mode 100644 gulpfile.js create mode 100644 scripts/copy-assets.mjs diff --git a/Dockerfile b/Dockerfile index d6b80195bb..0106cdb8a6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -45,7 +45,7 @@ COPY packages/backend-rs/index.js packages/backend-rs/built/index.js # Copy in the rest of the files to compile COPY . ./ RUN NODE_ENV='production' pnpm run --filter firefish-js build -RUN NODE_ENV='production' pnpm run --recursive --parallel --filter '!backend-rs' --filter '!firefish-js' build && pnpm run gulp +RUN NODE_ENV='production' pnpm run --recursive --parallel --filter '!backend-rs' --filter '!firefish-js' build && pnpm run build:assets # Trim down the dependencies to only those for production RUN find . -path '*/node_modules/*' -delete && pnpm install --prod --frozen-lockfile diff --git a/docs/install.md b/docs/install.md index 60903e26ea..f13a32d8eb 100644 --- a/docs/install.md +++ b/docs/install.md @@ -326,7 +326,7 @@ cd ~/firefish - To add custom locales, place them in the `./custom/locales/` directory. If you name your custom locale the same as an existing locale, it will overwrite it. If you give it a unique name, it will be added to the list. Also make sure that the first part of the filename matches the locale you're basing it on. (Example: `en-FOO.yml`) - To add custom error images, place them in the `./custom/assets/badges` directory, replacing the files already there. - To add custom sounds, place only mp3 files in the `./custom/assets/sounds` directory. -- To update custom assets without rebuilding, just run `pnpm run gulp`. +- To update custom assets without rebuilding, just run `pnpm run build:assets`. - To block ChatGPT, CommonCrawl, or other crawlers from indexing your instance, uncomment the respective rules in `./custom/robots.txt`. ## Tips & Tricks diff --git a/gulpfile.js b/gulpfile.js deleted file mode 100644 index 66f93dabb3..0000000000 --- a/gulpfile.js +++ /dev/null @@ -1,101 +0,0 @@ -/** - * Gulp tasks - */ - -const fs = require("fs"); -const gulp = require("gulp"); -const replace = require("gulp-replace"); -const terser = require("gulp-terser"); -const cssnano = require("gulp-cssnano"); - -const meta = require("./package.json"); - -gulp.task("copy:backend:views", () => - gulp - .src("./packages/backend/src/server/web/views/**/*") - .pipe(gulp.dest("./packages/backend/built/server/web/views")), -); - -gulp.task("copy:backend:custom", () => - gulp - .src("./custom/assets/**/*") - .pipe(gulp.dest("./packages/backend/assets/")), -); - -gulp.task("copy:client:fonts", () => - gulp - .src("./packages/client/node_modules/three/examples/fonts/**/*") - .pipe(gulp.dest("./built/_client_dist_/fonts/")), -); - -gulp.task("copy:client:locales", async (cb) => { - fs.mkdirSync("./built/_client_dist_/locales", { recursive: true }); - const { default: locales } = await import("./locales/index.mjs"); - - const v = { _version_: meta.version }; - - for (const [lang, locale] of Object.entries(locales)) { - fs.writeFileSync( - `./built/_client_dist_/locales/${lang}.${meta.version}.json`, - JSON.stringify({ ...locale, ...v }), - "utf-8", - ); - } - - cb(); -}); - -gulp.task("build:backend:script", async () => { - const { default: locales } = await import("./locales/index.mjs"); - - return gulp - .src([ - "./packages/backend/src/server/web/boot.js", - "./packages/backend/src/server/web/bios.js", - "./packages/backend/src/server/web/cli.js", - ]) - .pipe(replace("SUPPORTED_LANGS", JSON.stringify(Object.keys(locales)))) - .pipe( - terser({ - toplevel: true, - }), - ) - .pipe(gulp.dest("./packages/backend/built/server/web/")); -}); - -gulp.task("build:backend:style", () => { - return gulp - .src([ - "./packages/backend/src/server/web/style.css", - "./packages/backend/src/server/web/bios.css", - "./packages/backend/src/server/web/cli.css", - ]) - .pipe( - cssnano({ - zindex: false, - }), - ) - .pipe(gulp.dest("./packages/backend/built/server/web/")); -}); - -gulp.task( - "build", - gulp.parallel( - "copy:client:locales", - "copy:backend:views", - "copy:backend:custom", - "build:backend:script", - "build:backend:style", - "copy:client:fonts", - ), -); - -gulp.task("default", gulp.task("build")); - -gulp.task("watch", () => { - gulp.watch( - ["./packages/*/src/**/*"], - { ignoreInitial: false }, - gulp.task("build"), - ); -}); diff --git a/package.json b/package.json index 068353db7d..77d8ef91c5 100644 --- a/package.json +++ b/package.json @@ -9,14 +9,15 @@ "private": true, "scripts": { "rebuild": "pnpm run clean && pnpm run build", - "build": "pnpm node ./scripts/build.mjs && pnpm run gulp", + "build": "pnpm node ./scripts/build.mjs && pnpm run build:assets", + "build:assets": "pnpm node ./scripts/copy-assets.mjs", + "build:debug": "pnpm run clean && pnpm node ./scripts/dev-build.mjs && pnpm run build:assets", "start": "pnpm --filter backend run start", - "start:container": "pnpm run gulp && pnpm run migrate && pnpm run start", + "start:container": "pnpm run build:assets && pnpm run migrate && pnpm run start", "start:test": "pnpm --filter backend run start:test", "init": "pnpm run migrate", "migrate": "pnpm --filter backend run migration:run", "revertmigration": "pnpm --filter backend run migration:revert", - "gulp": "gulp build", "watch": "pnpm run dev", "dev": "pnpm node ./scripts/dev.mjs", "dev:staging": "NODE_OPTIONS=--max_old_space_size=3072 NODE_ENV=development pnpm run build && pnpm run start", @@ -24,7 +25,6 @@ "lint:ts": "pnpm --filter !firefish-js -r --parallel run lint", "lint:rs": "cargo clippy --fix --allow-dirty --allow-staged && cargo fmt --all --", "debug": "pnpm run build:debug && pnpm run start", - "build:debug": "pnpm run clean && pnpm node ./scripts/dev-build.mjs && pnpm run gulp", "mocha": "pnpm --filter backend run mocha", "test": "pnpm run test:ts && pnpm run test:rs", "test:ts": "pnpm run mocha", @@ -38,10 +38,6 @@ "clean-all": "pnpm run clean && pnpm run clean-cargo && pnpm run clean-npm" }, "dependencies": { - "gulp": "4.0.2", - "gulp-cssnano": "2.1.3", - "gulp-replace": "1.1.4", - "gulp-terser": "2.1.0", "js-yaml": "4.1.0" }, "devDependencies": { diff --git a/packages/client/package.json b/packages/client/package.json index cc679ddfb2..d3bf131cb7 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -21,8 +21,6 @@ "@syuilo/aiscript": "0.17.0", "@types/autosize": "^4.0.3", "@types/glob": "8.1.0", - "@types/gulp": "4.0.17", - "@types/gulp-rename": "2.0.6", "@types/insert-text-at-cursor": "^0.3.2", "@types/katex": "0.16.7", "@types/matter-js": "0.19.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index be9bdcb967..f8fa01118d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,18 +8,6 @@ importers: .: dependencies: - gulp: - specifier: 4.0.2 - version: 4.0.2 - gulp-cssnano: - specifier: 2.1.3 - version: 2.1.3 - gulp-replace: - specifier: 1.1.4 - version: 1.1.4 - gulp-terser: - specifier: 2.1.0 - version: 2.1.0 js-yaml: specifier: 4.1.0 version: 4.1.0 @@ -569,12 +557,6 @@ importers: '@types/glob': specifier: 8.1.0 version: 8.1.0 - '@types/gulp': - specifier: 4.0.17 - version: 4.0.17 - '@types/gulp-rename': - specifier: 2.0.6 - version: 2.0.6 '@types/insert-text-at-cursor': specifier: ^0.3.2 version: 0.3.2 @@ -3019,6 +3001,7 @@ packages: dependencies: '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.19 + dev: true /@jridgewell/sourcemap-codec@1.4.15: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} @@ -3028,6 +3011,7 @@ packages: dependencies: '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 + dev: true /@jridgewell/trace-mapping@0.3.20: resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} @@ -4039,9 +4023,6 @@ packages: resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} dev: true - /@types/expect@1.20.4: - resolution: {integrity: sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg==} - /@types/express-serve-static-core@4.17.35: resolution: {integrity: sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==} dependencies: @@ -4077,14 +4058,6 @@ packages: '@types/node': 20.12.7 dev: false - /@types/glob-stream@8.0.0: - resolution: {integrity: sha512-fxTWwdQmX9LWSHD7ZLlv3BHR992mKcVcDnT/2v+l/QZZo7TfDdyasqlSYVzOnMGWhRbrWeWkbj/mgezFjKynhw==} - dependencies: - '@types/node': 20.12.7 - '@types/picomatch': 2.3.0 - '@types/streamx': 2.9.1 - dev: true - /@types/glob@8.1.0: resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==} dependencies: @@ -4098,22 +4071,6 @@ packages: '@types/node': 20.12.7 dev: true - /@types/gulp-rename@2.0.6: - resolution: {integrity: sha512-pvZdJ004TpC4Ohk9l0CxEXzS9E0L72b5n6lkIEIaWUIy/RlqnkDMHVtEC6InDjd4rt0jZKcvTrDKxeT96WUYnw==} - dependencies: - '@types/node': 20.12.7 - '@types/vinyl': 2.0.7 - dev: true - - /@types/gulp@4.0.17: - resolution: {integrity: sha512-+pKQynu2C/HS16kgmDlAicjtFYP8kaa86eE9P0Ae7GB5W29we/E2TIdbOWtEZD5XkpY+jr8fyqfwO6SWZecLpQ==} - dependencies: - '@types/node': 20.12.7 - '@types/undertaker': 1.2.8 - '@types/vinyl-fs': 3.0.2 - chokidar: 3.5.3 - dev: true - /@types/http-assert@1.5.3: resolution: {integrity: sha512-FyAOrDuQmBi8/or3ns4rwPno7/9tJTijVW6aQQjK02+kOQ8zmoNg2XJtAuQhvQcy1ASJq38wirX5//9J1EqoUA==} @@ -4352,10 +4309,6 @@ packages: pg-types: 4.0.1 dev: true - /@types/picomatch@2.3.0: - resolution: {integrity: sha512-O397rnSS9iQI4OirieAtsDqvCj4+3eY1J+EPdNTKuHuRWIfUoGyzX294o8C4KJYaLqgSrd2o60c5EqCU8Zv02g==} - dev: true - /@types/prismjs@1.26.3: resolution: {integrity: sha512-A0D0aTXvjlqJ5ZILMz3rNfDBOx9hHxLZYv2by47Sm/pqW35zzjusrZTryatjN/Rf8Us2gZrJD+KeHbUSTux1Cw==} dev: true @@ -4443,12 +4396,6 @@ packages: resolution: {integrity: sha512-g7CK9nHdwjK2n0ymT2CW698FuWJRIx+RP6embAzZ2Qi8/ilIrA1Imt2LVSeHUzKvpoi7BhmmQcXz95eS0f2JXw==} dev: true - /@types/streamx@2.9.1: - resolution: {integrity: sha512-9bywzhouyedmci7WCIPFwJ8zASDnxt2gaVUy52X0p0Tt085IJSAEP0L6j4SSNeDMSLzpYu6cPz0GrJZ7kPJ6Bg==} - dependencies: - '@types/node': 20.12.7 - dev: true - /@types/syslog-pro@1.0.3: resolution: {integrity: sha512-tI558N5Io/04ya5eO5HJRIHLLJK/2Q1y4j6Fb0POVSNgRFxfJCOZHEyNrpcagdEtw9i25Diq3NXfs1qa0yyMIw==} dev: true @@ -4469,18 +4416,6 @@ packages: resolution: {integrity: sha512-chhaNf2oKHlRkDGt+tiKE2Z5aJ6qalm7Z9rlLdBwmOiAAf09YQvvoLXjWK4HWPF1xU/fqvMgfNfpVoBscA/tKA==} dev: true - /@types/undertaker-registry@1.0.1: - resolution: {integrity: sha512-Z4TYuEKn9+RbNVk1Ll2SS4x1JeLHecolIbM/a8gveaHsW0Hr+RQMraZACwTO2VD7JvepgA6UO1A1VrbktQrIbQ==} - dev: true - - /@types/undertaker@1.2.8: - resolution: {integrity: sha512-gW3PRqCHYpo45XFQHJBhch7L6hytPsIe0QeLujlnFsjHPnXLhJcPdN6a9368d7aIQgH2I/dUTPFBlGeSNA3qOg==} - dependencies: - '@types/node': 20.12.7 - '@types/undertaker-registry': 1.0.1 - async-done: 1.3.2 - dev: true - /@types/unist@2.0.7: resolution: {integrity: sha512-cputDpIbFgLUaGQn6Vqg3/YsJwxUwHLO13v3i5ouxT4lat0khip9AEWxtERujXV9wxIB1EyF97BSJFt6vpdI8g==} dev: true @@ -4493,20 +4428,6 @@ packages: resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} dev: true - /@types/vinyl-fs@3.0.2: - resolution: {integrity: sha512-ctNcmmzbMIKooXjRkyyUCOu2Z4AyqibL+RhXoF3pb7K7j+ezItnakmpm31LymkYHSIM5ey0tjIFzTvFOTSBCGw==} - dependencies: - '@types/glob-stream': 8.0.0 - '@types/node': 20.12.7 - '@types/vinyl': 2.0.7 - dev: true - - /@types/vinyl@2.0.7: - resolution: {integrity: sha512-4UqPv+2567NhMQuMLdKAyK4yzrfCqwaTt6bLhHEs8PFcxbHILsrxaY63n4wgE/BRLDWDQeI+WcTmkXKExh9hQg==} - dependencies: - '@types/expect': 1.20.4 - '@types/node': 20.12.7 - /@types/web-push@3.6.3: resolution: {integrity: sha512-v3oT4mMJsHeJ/rraliZ+7TbZtr5bQQuxcgD7C3/1q/zkAj29c8RE0F9lVZVu3hiQe5Z9fYcBreV7TLnfKR+4mg==} dependencies: @@ -5288,17 +5209,6 @@ packages: uri-js: 4.4.1 dev: false - /alphanum-sort@1.0.2: - resolution: {integrity: sha512-0FcBfdcmaumGPQ0qPn7Q5qTgz/ooXgIyp1rf8ik5bGX8mpE2YHjC0P/eyQvxu1GURYQgq9ozf2mteQ5ZD9YiyQ==} - dev: false - - /ansi-colors@1.1.0: - resolution: {integrity: sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==} - engines: {node: '>=0.10.0'} - dependencies: - ansi-wrap: 0.1.0 - dev: false - /ansi-colors@4.1.1: resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} engines: {node: '>=6'} @@ -5311,18 +5221,6 @@ packages: type-fest: 0.21.3 dev: true - /ansi-gray@0.1.1: - resolution: {integrity: sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw==} - engines: {node: '>=0.10.0'} - dependencies: - ansi-wrap: 0.1.0 - dev: false - - /ansi-regex@2.1.1: - resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==} - engines: {node: '>=0.10.0'} - dev: false - /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -5336,11 +5234,6 @@ packages: resolution: {integrity: sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==} dev: true - /ansi-styles@2.2.1: - resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==} - engines: {node: '>=0.10.0'} - dev: false - /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} @@ -5363,24 +5256,10 @@ packages: engines: {node: '>=12'} dev: false - /ansi-wrap@0.1.0: - resolution: {integrity: sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==} - engines: {node: '>=0.10.0'} - dev: false - /any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} dev: false - /anymatch@2.0.0: - resolution: {integrity: sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==} - dependencies: - micromatch: 3.1.10 - normalize-path: 2.1.1 - transitivePeerDependencies: - - supports-color - dev: false - /anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} @@ -5394,13 +5273,6 @@ packages: engines: {node: '>= 6.0.0'} dev: false - /append-buffer@1.0.2: - resolution: {integrity: sha512-WLbYiXzD3y/ATLZFufV/rZvWdZOs+Z/+5v1rBZ463Jn398pa6kcde27cvozYnBoxXblGZTFfoPpsaEw0orU5BA==} - engines: {node: '>=0.10.0'} - dependencies: - buffer-equal: 1.0.1 - dev: false - /append-field@1.0.0: resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==} @@ -5434,10 +5306,6 @@ packages: zip-stream: 6.0.1 dev: false - /archy@1.0.0: - resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} - dev: false - /are-docs-informative@0.0.2: resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==} engines: {node: '>=14'} @@ -5450,39 +5318,11 @@ packages: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} dependencies: sprintf-js: 1.0.3 + dev: true /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - /arr-diff@4.0.0: - resolution: {integrity: sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==} - engines: {node: '>=0.10.0'} - dev: false - - /arr-filter@1.1.2: - resolution: {integrity: sha512-A2BETWCqhsecSvCkWAeVBFLH6sXEUGASuzkpjL3GR1SlL/PWL6M3J8EAAld2Uubmh39tvkJTqC9LeLHCUKmFXA==} - engines: {node: '>=0.10.0'} - dependencies: - make-iterator: 1.0.1 - dev: false - - /arr-flatten@1.1.0: - resolution: {integrity: sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==} - engines: {node: '>=0.10.0'} - dev: false - - /arr-map@2.0.2: - resolution: {integrity: sha512-tVqVTHt+Q5Xb09qRkbu+DidW1yYzz5izWS2Xm2yFm7qJnmUfz4HPzNxbHkdRJbz2lrqI7S+z17xNYdFcBBO8Hw==} - engines: {node: '>=0.10.0'} - dependencies: - make-iterator: 1.0.1 - dev: false - - /arr-union@3.1.0: - resolution: {integrity: sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==} - engines: {node: '>=0.10.0'} - dev: false - /array-buffer-byte-length@1.0.0: resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} dependencies: @@ -5490,11 +5330,6 @@ packages: is-array-buffer: 3.0.2 dev: true - /array-each@1.0.1: - resolution: {integrity: sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==} - engines: {node: '>=0.10.0'} - dev: false - /array-includes@3.1.6: resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} engines: {node: '>= 0.4'} @@ -5517,45 +5352,11 @@ packages: is-string: 1.0.7 dev: true - /array-initial@1.1.0: - resolution: {integrity: sha512-BC4Yl89vneCYfpLrs5JU2aAu9/a+xWbeKhvISg9PT7eWFB9UlRvI+rKEtk6mgxWr3dSkk9gQ8hCrdqt06NXPdw==} - engines: {node: '>=0.10.0'} - dependencies: - array-slice: 1.1.0 - is-number: 4.0.0 - dev: false - - /array-last@1.3.0: - resolution: {integrity: sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==} - engines: {node: '>=0.10.0'} - dependencies: - is-number: 4.0.0 - dev: false - - /array-slice@1.1.0: - resolution: {integrity: sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==} - engines: {node: '>=0.10.0'} - dev: false - - /array-sort@1.0.0: - resolution: {integrity: sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==} - engines: {node: '>=0.10.0'} - dependencies: - default-compare: 1.0.0 - get-value: 2.0.6 - kind-of: 5.1.0 - dev: false - /array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} dev: true - /array-unique@0.3.2: - resolution: {integrity: sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==} - engines: {node: '>=0.10.0'} - dev: false - /array.prototype.findlastindex@1.2.2: resolution: {integrity: sha512-tb5thFFlUcp7NdNF6/MpDk/1r/4awWG1FIz3YqDf+/zJSTezBb+/5WViH41obXULHVpDzoiCLpJ/ZO9YbJMsdw==} engines: {node: '>= 0.4'} @@ -5661,35 +5462,10 @@ packages: engines: {node: '>=0.8'} dev: false - /assign-symbols@1.0.0: - resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==} - engines: {node: '>=0.10.0'} - dev: false - - /async-done@1.3.2: - resolution: {integrity: sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==} - engines: {node: '>= 0.10'} - dependencies: - end-of-stream: 1.4.4 - once: 1.4.0 - process-nextick-args: 2.0.1 - stream-exhaust: 1.0.2 - - /async-each@1.0.6: - resolution: {integrity: sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==} - dev: false - /async-lock@1.4.0: resolution: {integrity: sha512-coglx5yIWuetakm3/1dsX9hxCNox22h7+V80RQOu2XUUMidtArxKoZoOtHUPuR84SycKTXzgGzAUR5hJxujyJQ==} dev: false - /async-settle@1.0.0: - resolution: {integrity: sha512-VPXfB4Vk49z1LHHodrEQ6Xf7W4gg1w0dAPROHngx7qgDjqmIQ+fXmwgGXTW/ITLai0YLSvWepJOP9EVpMnEAcw==} - engines: {node: '>= 0.10'} - dependencies: - async-done: 1.3.2 - dev: false - /async@3.2.4: resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} dev: false @@ -5705,23 +5481,13 @@ packages: resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==} engines: {node: '>= 4.5.0'} hasBin: true + dev: true /autobind-decorator@2.4.0: resolution: {integrity: sha512-OGYhWUO72V6DafbF8PM8rm3EPbfuyMZcJhtm5/n26IDwO18pohE4eNazLoCGhPiXOCD0gEGmrbU3849QvM8bbw==} engines: {node: '>=8.10', npm: '>=6.4.1'} dev: true - /autoprefixer@6.7.7: - resolution: {integrity: sha512-WKExI/eSGgGAkWAO+wMVdFObZV7hQen54UpD1kCCTN3tvlL3W1jL4+lPP/M7MwoP7Q4RHzKtO3JQ4HxYEcd+xQ==} - dependencies: - browserslist: 1.7.7 - caniuse-db: 1.0.30001519 - normalize-range: 0.1.2 - num2fraction: 1.2.2 - postcss: 5.2.18 - postcss-value-parser: 3.3.1 - dev: false - /autosize@6.0.1: resolution: {integrity: sha512-f86EjiUKE6Xvczc4ioP1JBlWG7FKrE13qe/DxBCpe8GCipCq2nFw73aO8QEBKHfSbYGDN5eB9jXWKen7tspDqQ==} dev: true @@ -5865,44 +5631,12 @@ packages: dependencies: '@babel/types': 7.22.10 - /bach@1.2.0: - resolution: {integrity: sha512-bZOOfCb3gXBXbTFXq3OZtGR88LwGeJvzu6szttaIzymOTS4ZttBNOWSv7aLZja2EMycKtRYV0Oa8SNKH/zkxvg==} - engines: {node: '>= 0.10'} - dependencies: - arr-filter: 1.1.2 - arr-flatten: 1.1.0 - arr-map: 2.0.2 - array-each: 1.0.1 - array-initial: 1.1.0 - array-last: 1.3.0 - async-done: 1.3.2 - async-settle: 1.0.0 - now-and-later: 2.0.1 - dev: false - - /balanced-match@0.4.2: - resolution: {integrity: sha512-STw03mQKnGUYtoNjmowo4F2cRmIIxYEGiMsjjwla/u5P1lxadj/05WkNaFjNiKTgJkj8KiXbgAiRTmcQRwQNtg==} - dev: false - /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} /base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - /base@0.11.2: - resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==} - engines: {node: '>=0.10.0'} - dependencies: - cache-base: 1.0.1 - class-utils: 0.3.6 - component-emitter: 1.3.1 - define-property: 1.0.0 - isobject: 3.0.1 - mixin-deep: 1.3.2 - pascalcase: 0.1.1 - dev: false - /bcrypt-pbkdf@1.0.2: resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} dependencies: @@ -5934,29 +5668,11 @@ packages: find-versions: 5.1.0 dev: true - /binary-extensions@1.13.1: - resolution: {integrity: sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==} - engines: {node: '>=0.10.0'} - dev: false - /binary-extensions@2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} dev: true - /binaryextensions@2.3.0: - resolution: {integrity: sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg==} - engines: {node: '>=0.8'} - dev: false - - /bindings@1.5.0: - resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} - requiresBuild: true - dependencies: - file-uri-to-path: 1.0.0 - dev: false - optional: true - /bl@1.2.3: resolution: {integrity: sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==} dependencies: @@ -6002,24 +5718,6 @@ packages: dependencies: balanced-match: 1.0.2 - /braces@2.3.2: - resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==} - engines: {node: '>=0.10.0'} - dependencies: - arr-flatten: 1.1.0 - array-unique: 0.3.2 - extend-shallow: 2.0.1 - fill-range: 4.0.0 - isobject: 3.0.1 - repeat-element: 1.1.4 - snapdragon: 0.8.2 - snapdragon-node: 2.1.1 - split-string: 3.1.0 - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - dev: false - /braces@3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} @@ -6046,15 +5744,6 @@ packages: pako: 0.2.9 dev: false - /browserslist@1.7.7: - resolution: {integrity: sha512-qHJblDE2bXVRYzuDetv/wAeHOJyO97+9wxC1cdCtyzgNuSozOyRCiiLaCR1f71AN66lQdVVBipWm63V+a7bPOw==} - deprecated: Browserslist 2 could fail on reading Browserslist >3.0 config used in other tools. - hasBin: true - dependencies: - caniuse-db: 1.0.30001519 - electron-to-chromium: 1.4.488 - dev: false - /browserslist@4.22.1: resolution: {integrity: sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -6113,11 +5802,6 @@ packages: resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} dev: false - /buffer-equal@1.0.1: - resolution: {integrity: sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg==} - engines: {node: '>=0.4'} - dev: false - /buffer-fill@1.0.0: resolution: {integrity: sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==} dev: false @@ -6191,21 +5875,6 @@ packages: engines: {node: '>= 0.8'} dev: false - /cache-base@1.0.1: - resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==} - engines: {node: '>=0.10.0'} - dependencies: - collection-visit: 1.0.0 - component-emitter: 1.3.1 - get-value: 2.0.6 - has-value: 1.0.0 - isobject: 3.0.1 - set-value: 2.0.1 - to-object-path: 0.3.0 - union-value: 1.0.1 - unset-value: 1.0.0 - dev: false - /cache-content-type@1.0.1: resolution: {integrity: sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==} engines: {node: '>= 6.0.0'} @@ -6278,11 +5947,6 @@ packages: quick-lru: 4.0.1 dev: true - /camelcase@3.0.0: - resolution: {integrity: sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==} - engines: {node: '>=0.10.0'} - dev: false - /camelcase@5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} @@ -6292,19 +5956,6 @@ packages: engines: {node: '>=10'} dev: true - /caniuse-api@1.6.1: - resolution: {integrity: sha512-SBTl70K0PkDUIebbkXrxWqZlHNs0wRgRD6QZ8guctShjbh63gEPfF+Wj0Yw+75f5Y8tSzqAI/NcisYv/cCah2Q==} - dependencies: - browserslist: 1.7.7 - caniuse-db: 1.0.30001519 - lodash.memoize: 4.1.2 - lodash.uniq: 4.5.0 - dev: false - - /caniuse-db@1.0.30001519: - resolution: {integrity: sha512-nY0JTY0Po8r8bNBred32hc3QMr2+I/CsJCGmH6tZaVEFUzLSfv64i1E8VwTqP3Of6yyzu4MDKus2eoR0pHCZ2A==} - dev: false - /caniuse-lite@1.0.30001551: resolution: {integrity: sha512-vtBAez47BoGMMzlbYhfXrMV1kvRF2WP/lqiMuDu1Sb4EE4LKEgjopFDSRtZfdVnslNRpOqV/woE+Xgrwj6VQlg==} @@ -6345,17 +5996,6 @@ packages: chalk: 5.3.0 dev: false - /chalk@1.1.3: - resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==} - engines: {node: '>=0.10.0'} - dependencies: - ansi-styles: 2.2.1 - escape-string-regexp: 1.0.5 - has-ansi: 2.0.0 - strip-ansi: 3.0.1 - supports-color: 2.0.0 - dev: false - /chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -6461,27 +6101,6 @@ packages: lodash.some: 4.6.0 dev: false - /chokidar@2.1.8: - resolution: {integrity: sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==} - deprecated: Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies - dependencies: - anymatch: 2.0.0 - async-each: 1.0.6 - braces: 2.3.2 - glob-parent: 3.1.0 - inherits: 2.0.4 - is-binary-path: 1.0.1 - is-glob: 4.0.3 - normalize-path: 3.0.0 - path-is-absolute: 1.0.1 - readdirp: 2.2.1 - upath: 1.2.0 - optionalDependencies: - fsevents: 1.2.13 - transitivePeerDependencies: - - supports-color - dev: false - /chokidar@3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} @@ -6537,23 +6156,6 @@ packages: resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} dev: true - /clap@1.2.3: - resolution: {integrity: sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==} - engines: {node: '>=0.10.0'} - dependencies: - chalk: 1.1.3 - dev: false - - /class-utils@0.3.6: - resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==} - engines: {node: '>=0.10.0'} - dependencies: - arr-union: 3.1.0 - define-property: 0.2.5 - isobject: 3.0.1 - static-extend: 0.1.2 - dev: false - /clean-regexp@1.0.0: resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} engines: {node: '>=4'} @@ -6586,14 +6188,6 @@ packages: engines: {node: '>=6'} dev: true - /cliui@3.2.0: - resolution: {integrity: sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==} - dependencies: - string-width: 1.0.2 - strip-ansi: 3.0.1 - wrap-ansi: 2.1.0 - dev: false - /cliui@6.0.0: resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} dependencies: @@ -6616,36 +6210,15 @@ packages: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - /clone-buffer@1.0.0: - resolution: {integrity: sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==} - engines: {node: '>= 0.10'} - dev: false - /clone-response@1.0.3: resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} dependencies: mimic-response: 1.0.1 - /clone-stats@1.0.0: - resolution: {integrity: sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==} - dev: false - /clone@1.0.4: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} - - /clone@2.1.2: - resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} - engines: {node: '>=0.8'} - dev: false - - /cloneable-readable@1.1.3: - resolution: {integrity: sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==} - dependencies: - inherits: 2.0.4 - process-nextick-args: 2.0.1 - readable-stream: 2.3.8 - dev: false + dev: true /cluster-key-slot@1.1.2: resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} @@ -6674,39 +6247,10 @@ packages: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} - /coa@1.0.4: - resolution: {integrity: sha512-KAGck/eNAmCL0dcT3BiuYwLbExK6lduR8DxM3C1TyDzaXhZHyZ8ooX5I5+na2e3dPFuibfxrGdorr0/Lr7RYCQ==} - engines: {node: '>= 0.8.0'} - dependencies: - q: 1.5.1 - dev: false - - /code-point-at@1.1.0: - resolution: {integrity: sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==} - engines: {node: '>=0.10.0'} - dev: false - /collect-v8-coverage@1.0.2: resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} dev: true - /collection-map@1.0.0: - resolution: {integrity: sha512-5D2XXSpkOnleOI21TG7p3T0bGAsZ/XknZpKBmGYyluO8pw4zA3K8ZlrBIbC4FXg3m6z/RNFiUFfT2sQK01+UHA==} - engines: {node: '>=0.10.0'} - dependencies: - arr-map: 2.0.2 - for-own: 1.0.0 - make-iterator: 1.0.1 - dev: false - - /collection-visit@1.0.0: - resolution: {integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==} - engines: {node: '>=0.10.0'} - dependencies: - map-visit: 1.0.0 - object-visit: 1.0.1 - dev: false - /color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: @@ -6724,12 +6268,6 @@ packages: /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - /color-string@0.3.0: - resolution: {integrity: sha512-sz29j1bmSDfoAxKIEU6zwoIZXN6BrFbAMIhfYCNyiZXBDuU/aiHlN84lp/xDzL2ubyFhLDobHIlU1X70XRrMDA==} - dependencies: - color-name: 1.1.4 - dev: false - /color-string@1.9.1: resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} dependencies: @@ -6737,19 +6275,6 @@ packages: simple-swizzle: 0.2.2 dev: false - /color-support@1.1.3: - resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} - hasBin: true - dev: false - - /color@0.11.4: - resolution: {integrity: sha512-Ajpjd8asqZ6EdxQeqGzU5WBhhTfJ/0cA4Wlbre7e5vXfmDSmda7Ov6jeKoru+b0vHcb1CqvuroTHp5zIWzhVMA==} - dependencies: - clone: 1.0.4 - color-convert: 1.9.3 - color-string: 0.3.0 - dev: false - /color@4.2.3: resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} engines: {node: '>=12.5.0'} @@ -6762,19 +6287,6 @@ packages: resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} dev: false - /colormin@1.1.2: - resolution: {integrity: sha512-XSEQUUQUR/lXqGyddiNH3XYFUPYlYr1vXy9rTFMsSOw+J7Q6EQkdlQIrTlYn4TccpsOaUE1PYQNjBn20gwCdgQ==} - dependencies: - color: 0.11.4 - css-color-names: 0.0.4 - has: 1.0.3 - dev: false - - /colors@1.1.2: - resolution: {integrity: sha512-ENwblkFQpqqia6b++zLD/KUWafYlVY/UNnAp7oz7LY7E924wmpye416wBOmvv/HMWzl8gL1kJlfvId/1Dg176w==} - engines: {node: '>=0.1.90'} - dev: false - /combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -6802,10 +6314,6 @@ packages: resolution: {integrity: sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==} dev: true - /component-emitter@1.3.1: - resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==} - dev: false - /compress-commons@6.0.2: resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==} engines: {node: '>= 14'} @@ -7060,18 +6568,6 @@ packages: keygrip: 1.1.0 dev: false - /copy-descriptor@0.1.1: - resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==} - engines: {node: '>=0.10.0'} - dev: false - - /copy-props@2.0.5: - resolution: {integrity: sha512-XBlx8HSqrT0ObQwmSzM7WE5k8FxTV75h1DX1Z3n6NhQ/UYYAvInWYmG06vFt7hQZArE2fuO62aihiWIVQwh1sw==} - dependencies: - each-props: 1.3.2 - is-plain-object: 5.0.0 - dev: false - /copy-to@2.0.1: resolution: {integrity: sha512-3DdaFaU/Zf1AnpLiFDeNCD4TOWe3Zl2RZaTzUvWiIk5ERzcCodOE20Vqq4fzCbNoHURFHT4/us/Lfq+S2zyY4w==} dev: false @@ -7189,10 +6685,6 @@ packages: shebang-command: 2.0.0 which: 2.0.2 - /css-color-names@0.0.4: - resolution: {integrity: sha512-zj5D7X1U2h2zsXOAM8EyUREBnnts6H+Jm+d1M2DbiQQcUtnqgQsMrdo8JW9R80YFUmIdBZeMu5wvYM7hcgWP/Q==} - dev: false - /css-select@1.2.0: resolution: {integrity: sha512-dUQOBoqdR7QwV90WysXPLXG5LO7nhYBgiWVfxF80DKPF8zx1t/pUd2FYy73emg3zrjtM6dzmYgbHKfV2rxiHQA==} dependencies: @@ -7220,52 +6712,6 @@ packages: hasBin: true dev: true - /cssnano@3.10.0: - resolution: {integrity: sha512-0o0IMQE0Ezo4b41Yrm8U6Rp9/Ag81vNXY1gZMnT1XhO4DpjEf2utKERqWJbOoz3g1Wdc1d3QSta/cIuJ1wSTEg==} - dependencies: - autoprefixer: 6.7.7 - decamelize: 1.2.0 - defined: 1.0.1 - has: 1.0.3 - object-assign: 4.1.1 - postcss: 5.2.18 - postcss-calc: 5.3.1 - postcss-colormin: 2.2.2 - postcss-convert-values: 2.6.1 - postcss-discard-comments: 2.0.4 - postcss-discard-duplicates: 2.1.0 - postcss-discard-empty: 2.1.0 - postcss-discard-overridden: 0.1.1 - postcss-discard-unused: 2.2.3 - postcss-filter-plugins: 2.0.3 - postcss-merge-idents: 2.1.7 - postcss-merge-longhand: 2.0.2 - postcss-merge-rules: 2.1.2 - postcss-minify-font-values: 1.0.5 - postcss-minify-gradients: 1.0.5 - postcss-minify-params: 1.2.2 - postcss-minify-selectors: 2.1.1 - postcss-normalize-charset: 1.1.1 - postcss-normalize-url: 3.0.8 - postcss-ordered-values: 2.2.3 - postcss-reduce-idents: 2.4.0 - postcss-reduce-initial: 1.0.1 - postcss-reduce-transforms: 1.0.4 - postcss-svgo: 2.1.6 - postcss-unique-selectors: 2.0.2 - postcss-value-parser: 3.3.1 - postcss-zindex: 2.2.0 - dev: false - - /csso@2.3.2: - resolution: {integrity: sha512-FmCI/hmqDeHHLaIQckMhMZneS84yzUZdrWDAvJVVxOwcKE1P1LF9FGmzr1ktIQSxOw6fl3PaQsmfg+GN+VvR3w==} - engines: {node: '>=0.10.0'} - hasBin: true - dependencies: - clap: 1.2.3 - source-map: 0.5.7 - dev: false - /csstype@3.1.2: resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} dev: true @@ -7373,6 +6819,7 @@ packages: /decode-uri-component@0.2.2: resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} engines: {node: '>=0.10'} + dev: true /decompress-response@6.0.0: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} @@ -7477,18 +6924,6 @@ packages: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} - /default-compare@1.0.0: - resolution: {integrity: sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==} - engines: {node: '>=0.10.0'} - dependencies: - kind-of: 5.1.0 - dev: false - - /default-resolution@2.0.0: - resolution: {integrity: sha512-2xaP6GiwVwOEbXCGoJ4ufgC76m8cj805jrghScewJC2ZDsb9U0b4BIrba+xt/Uytyd0HvQ6+WymSRTfnYj59GQ==} - engines: {node: '>= 0.10'} - dev: false - /defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} dependencies: @@ -7513,32 +6948,7 @@ packages: dependencies: has-property-descriptors: 1.0.0 object-keys: 1.1.1 - - /define-property@0.2.5: - resolution: {integrity: sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==} - engines: {node: '>=0.10.0'} - dependencies: - is-descriptor: 0.1.7 - dev: false - - /define-property@1.0.0: - resolution: {integrity: sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==} - engines: {node: '>=0.10.0'} - dependencies: - is-descriptor: 1.0.3 - dev: false - - /define-property@2.0.2: - resolution: {integrity: sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==} - engines: {node: '>=0.10.0'} - dependencies: - is-descriptor: 1.0.3 - isobject: 3.0.1 - dev: false - - /defined@1.0.1: - resolution: {integrity: sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==} - dev: false + dev: true /delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} @@ -7568,11 +6978,6 @@ packages: engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} dev: false - /detect-file@1.0.0: - resolution: {integrity: sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==} - engines: {node: '>=0.10.0'} - dev: false - /detect-libc@2.0.3: resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} engines: {node: '>=8'} @@ -7703,13 +7108,6 @@ packages: stream-shift: 1.0.1 dev: false - /each-props@1.3.2: - resolution: {integrity: sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==} - dependencies: - is-plain-object: 2.0.4 - object.defaults: 1.1.0 - dev: false - /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} dev: false @@ -7750,10 +7148,6 @@ packages: jake: 10.8.7 dev: false - /electron-to-chromium@1.4.488: - resolution: {integrity: sha512-Dv4sTjiW7t/UWGL+H8ZkgIjtUAVZDgb/PwGWvMsCT7jipzUV/u5skbLXPFKb6iV0tiddVi/bcS2/kUrczeWgIQ==} - dev: false - /electron-to-chromium@1.4.561: resolution: {integrity: sha512-eS5t4ulWOBfVHdq9SW2dxEaFarj1lPjvJ8PaYMOjY0DecBaj/t4ARziL2IPpDr4atyWwjLFGQ2vo/VCgQFezVQ==} @@ -7822,6 +7216,7 @@ packages: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: is-arrayish: 0.2.1 + dev: true /es-abstract@1.22.1: resolution: {integrity: sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==} @@ -7931,15 +7326,6 @@ packages: ext: 1.7.0 dev: false - /es6-weak-map@2.0.3: - resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==} - dependencies: - d: 1.0.1 - es5-ext: 0.10.62 - es6-iterator: 2.0.3 - es6-symbol: 3.1.3 - dev: false - /esbuild@0.20.2: resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==} engines: {node: '>=12'} @@ -8824,12 +8210,6 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /esprima@2.7.3: - resolution: {integrity: sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==} - engines: {node: '>=0.10.0'} - hasBin: true - dev: false - /esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} @@ -8945,28 +8325,6 @@ packages: engines: {node: '>= 0.8.0'} dev: true - /expand-brackets@2.1.4: - resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==} - engines: {node: '>=0.10.0'} - dependencies: - debug: 2.6.9 - define-property: 0.2.5 - extend-shallow: 2.0.1 - posix-character-classes: 0.1.1 - regex-not: 1.0.2 - snapdragon: 0.8.2 - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - dev: false - - /expand-tilde@2.0.2: - resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==} - engines: {node: '>=0.10.0'} - dependencies: - homedir-polyfill: 1.0.3 - dev: false - /expect@29.7.0: resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -9006,49 +8364,11 @@ packages: is-extendable: 0.1.1 dev: false - /extend-shallow@3.0.2: - resolution: {integrity: sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==} - engines: {node: '>=0.10.0'} - dependencies: - assign-symbols: 1.0.0 - is-extendable: 1.0.1 - dev: false - - /extend@3.0.2: - resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - dev: false - - /extglob@2.0.4: - resolution: {integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==} - engines: {node: '>=0.10.0'} - dependencies: - array-unique: 0.3.2 - define-property: 1.0.0 - expand-brackets: 2.1.4 - extend-shallow: 2.0.1 - fragment-cache: 0.2.1 - regex-not: 1.0.2 - snapdragon: 0.8.2 - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - dev: false - /extsprintf@1.3.0: resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} engines: {'0': node >=0.6.0} dev: false - /fancy-log@1.3.3: - resolution: {integrity: sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==} - engines: {node: '>= 0.10'} - dependencies: - ansi-gray: 0.1.1 - color-support: 1.1.3 - parse-node-version: 1.0.1 - time-stamp: 1.1.0 - dev: false - /fast-blurhash@1.1.2: resolution: {integrity: sha512-lJVOgYSlahqkRhrKumNx/SGB2F/qS0D1z7xjGYjb5EZJRtlzySGMniZjkQ9h9Rv8sPmM/V9orEgRiMwazDNH6A==} dev: true @@ -9090,10 +8410,6 @@ packages: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} dev: true - /fast-levenshtein@1.1.4: - resolution: {integrity: sha512-Ia0sQNrMPXXkqVFt6w6M1n1oKo3NfKs+mvaV811Jwir7vAk9a6PVV9VPYf6X3BU97QiLEmuW3uXH9u87zDFfdw==} - dev: false - /fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} dev: true @@ -9185,12 +8501,6 @@ packages: engines: {node: '>=4'} dev: false - /file-uri-to-path@1.0.0: - resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} - requiresBuild: true - dev: false - optional: true - /filelist@1.0.4: resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} dependencies: @@ -9211,16 +8521,6 @@ packages: trim-repeated: 2.0.0 dev: true - /fill-range@4.0.0: - resolution: {integrity: sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==} - engines: {node: '>=0.10.0'} - dependencies: - extend-shallow: 2.0.1 - is-number: 3.0.0 - repeat-string: 1.6.1 - to-regex-range: 2.1.1 - dev: false - /fill-range@7.0.1: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} @@ -9228,14 +8528,6 @@ packages: to-regex-range: 5.0.1 dev: true - /find-up@1.1.2: - resolution: {integrity: sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==} - engines: {node: '>=0.10.0'} - dependencies: - path-exists: 2.1.0 - pinkie-promise: 2.0.1 - dev: false - /find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -9258,41 +8550,6 @@ packages: semver-regex: 4.0.5 dev: true - /findup-sync@2.0.0: - resolution: {integrity: sha512-vs+3unmJT45eczmcAZ6zMJtxN3l/QXeccaXQx5cu/MeJMhewVfoWZqibRkOxPnmoR59+Zy5hjabfQc6JLSah4g==} - engines: {node: '>= 0.10'} - dependencies: - detect-file: 1.0.0 - is-glob: 3.1.0 - micromatch: 3.1.10 - resolve-dir: 1.0.1 - transitivePeerDependencies: - - supports-color - dev: false - - /findup-sync@3.0.0: - resolution: {integrity: sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==} - engines: {node: '>= 0.10'} - dependencies: - detect-file: 1.0.0 - is-glob: 4.0.3 - micromatch: 3.1.10 - resolve-dir: 1.0.1 - transitivePeerDependencies: - - supports-color - dev: false - - /fined@1.2.0: - resolution: {integrity: sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==} - engines: {node: '>= 0.10'} - dependencies: - expand-tilde: 2.0.2 - is-plain-object: 2.0.4 - object.defaults: 1.1.0 - object.pick: 1.3.0 - parse-filepath: 1.0.2 - dev: false - /fix-esm@1.0.1: resolution: {integrity: sha512-EZtb7wPXZS54GaGxaWxMlhd1DUDCnAg5srlYdu/1ZVeW+7wwR3Tp59nu52dXByFs3MBRq+SByx1wDOJpRvLEXw==} dependencies: @@ -9303,11 +8560,6 @@ packages: - supports-color dev: false - /flagged-respawn@1.0.1: - resolution: {integrity: sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==} - engines: {node: '>= 0.10'} - dev: false - /flat-cache@3.0.4: resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -9337,11 +8589,6 @@ packages: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} dev: true - /flatten@1.0.3: - resolution: {integrity: sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==} - deprecated: flatten is deprecated in favor of utility frameworks such as lodash. - dev: false - /fluent-ffmpeg@2.1.2: resolution: {integrity: sha512-IZTB4kq5GK0DPp7sGQ0q/BWurGHffRtQQwVkiqDgeO6wYJLLV5ZhgNOQ65loZxxuPMKZKZcICCUnaGtlxBiR0Q==} engines: {node: '>=0.8.0'} @@ -9350,13 +8597,6 @@ packages: which: 1.3.1 dev: false - /flush-write-stream@1.1.1: - resolution: {integrity: sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==} - dependencies: - inherits: 2.0.4 - readable-stream: 2.3.8 - dev: false - /focus-trap-vue@4.0.3(focus-trap@7.5.4)(vue@3.4.25): resolution: {integrity: sha512-cIX5rybkCAlNZ4IHYJ3nCFIsipDDljJHHjtTO2IgYWkVYg7X9ipUVdab3HzYp88kmHgMwjcB71LYnXRRsF6ZqQ==} peerDependencies: @@ -9408,18 +8648,6 @@ packages: dependencies: is-callable: 1.2.7 - /for-in@1.0.2: - resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==} - engines: {node: '>=0.10.0'} - dev: false - - /for-own@1.0.0: - resolution: {integrity: sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==} - engines: {node: '>=0.10.0'} - dependencies: - for-in: 1.0.2 - dev: false - /foreground-child@3.1.1: resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} engines: {node: '>=14'} @@ -9466,13 +8694,6 @@ packages: qs: 6.12.1 dev: false - /fragment-cache@0.2.1: - resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==} - engines: {node: '>=0.10.0'} - dependencies: - map-cache: 0.2.2 - dev: false - /fresh@0.5.2: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} @@ -9500,29 +8721,9 @@ packages: universalify: 0.1.2 dev: false - /fs-mkdirp-stream@1.0.0: - resolution: {integrity: sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==} - engines: {node: '>= 0.10'} - dependencies: - graceful-fs: 4.2.11 - through2: 2.0.5 - dev: false - /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - /fsevents@1.2.13: - resolution: {integrity: sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==} - engines: {node: '>= 4.0'} - os: [darwin] - deprecated: The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2 - requiresBuild: true - dependencies: - bindings: 1.5.0 - nan: 2.19.0 - dev: false - optional: true - /fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -9555,10 +8756,6 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} - /get-caller-file@1.0.3: - resolution: {integrity: sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==} - dev: false - /get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -9639,24 +8836,12 @@ packages: resolve-pkg-maps: 1.0.0 dev: true - /get-value@2.0.6: - resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==} - engines: {node: '>=0.10.0'} - dev: false - /getpass@0.1.7: resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} dependencies: assert-plus: 1.0.0 dev: false - /glob-parent@3.1.0: - resolution: {integrity: sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==} - dependencies: - is-glob: 3.1.0 - path-dirname: 1.0.2 - dev: false - /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -9671,41 +8856,10 @@ packages: is-glob: 4.0.3 dev: true - /glob-stream@6.1.0: - resolution: {integrity: sha512-uMbLGAP3S2aDOHUDfdoYcdIePUCfysbAd0IAoWVZbeGU/oNQ8asHVSshLDJUPWxfzj8zsCG7/XeHPHTtow0nsw==} - engines: {node: '>= 0.10'} - dependencies: - extend: 3.0.2 - glob: 7.2.3 - glob-parent: 3.1.0 - is-negated-glob: 1.0.0 - ordered-read-streams: 1.0.1 - pumpify: 1.5.1 - readable-stream: 2.3.8 - remove-trailing-separator: 1.1.0 - to-absolute-glob: 2.0.2 - unique-stream: 2.3.1 - dev: false - /glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} dev: true - /glob-watcher@5.0.5: - resolution: {integrity: sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==} - engines: {node: '>= 0.10'} - dependencies: - anymatch: 2.0.0 - async-done: 1.3.2 - chokidar: 2.1.8 - is-negated-glob: 1.0.0 - just-debounce: 1.1.0 - normalize-path: 3.0.0 - object.defaults: 1.1.0 - transitivePeerDependencies: - - supports-color - dev: false - /glob@10.3.10: resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} engines: {node: '>=16 || 14 >=14.17'} @@ -9727,6 +8881,7 @@ packages: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 + dev: true /glob@8.1.0: resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} @@ -9738,26 +8893,6 @@ packages: minimatch: 5.1.6 once: 1.4.0 - /global-modules@1.0.0: - resolution: {integrity: sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==} - engines: {node: '>=0.10.0'} - dependencies: - global-prefix: 1.0.2 - is-windows: 1.0.2 - resolve-dir: 1.0.1 - dev: false - - /global-prefix@1.0.2: - resolution: {integrity: sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==} - engines: {node: '>=0.10.0'} - dependencies: - expand-tilde: 2.0.2 - homedir-polyfill: 1.0.3 - ini: 1.3.8 - is-windows: 1.0.2 - which: 1.3.1 - dev: false - /globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} @@ -9800,13 +8935,6 @@ packages: slash: 3.0.0 dev: true - /glogg@1.0.2: - resolution: {integrity: sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==} - engines: {node: '>= 0.10'} - dependencies: - sparkles: 1.0.1 - dev: false - /gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: @@ -9874,84 +9002,6 @@ packages: resolution: {integrity: sha512-srBfnk4n+Oe/ZnMIOXt3gT605BX9x5+rh/prT2F1SsNJsU1XuMiP0E2aptW481OnonOGACZWBqseH5Z7csHxhQ==} dev: true - /gulp-cli@2.3.0: - resolution: {integrity: sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==} - engines: {node: '>= 0.10'} - hasBin: true - dependencies: - ansi-colors: 1.1.0 - archy: 1.0.0 - array-sort: 1.0.0 - color-support: 1.1.3 - concat-stream: 1.6.2 - copy-props: 2.0.5 - fancy-log: 1.3.3 - gulplog: 1.0.0 - interpret: 1.4.0 - isobject: 3.0.1 - liftoff: 3.1.0 - matchdep: 2.0.0 - mute-stdout: 1.0.1 - pretty-hrtime: 1.0.3 - replace-homedir: 1.0.0 - semver-greatest-satisfied-range: 1.1.0 - v8flags: 3.2.0 - yargs: 7.1.2 - transitivePeerDependencies: - - supports-color - dev: false - - /gulp-cssnano@2.1.3: - resolution: {integrity: sha512-r8qdX5pTXsBb/IRm9loE8Ijz8UiPW/URMC/bKJe4FPNHRaz4aEx8Bev03L0FYHd/7BSGu/ebmfumAkpGuTdenA==} - dependencies: - buffer-from: 1.1.2 - cssnano: 3.10.0 - object-assign: 4.1.1 - plugin-error: 1.0.1 - vinyl-sourcemaps-apply: 0.2.1 - dev: false - - /gulp-replace@1.1.4: - resolution: {integrity: sha512-SVSF7ikuWKhpAW4l4wapAqPPSToJoiNKsbDoUnRrSgwZHH7lH8pbPeQj1aOVYQrbZKhfSVBxVW+Py7vtulRktw==} - engines: {node: '>=10'} - dependencies: - '@types/node': 20.12.7 - '@types/vinyl': 2.0.7 - istextorbinary: 3.3.0 - replacestream: 4.0.3 - yargs-parser: 21.1.1 - dev: false - - /gulp-terser@2.1.0: - resolution: {integrity: sha512-lQ3+JUdHDVISAlUIUSZ/G9Dz/rBQHxOiYDQ70IVWFQeh4b33TC1MCIU+K18w07PS3rq/CVc34aQO4SUbdaNMPQ==} - engines: {node: '>=10'} - dependencies: - plugin-error: 1.0.1 - terser: 5.19.2 - through2: 4.0.2 - vinyl-sourcemaps-apply: 0.2.1 - dev: false - - /gulp@4.0.2: - resolution: {integrity: sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==} - engines: {node: '>= 0.10'} - hasBin: true - dependencies: - glob-watcher: 5.0.5 - gulp-cli: 2.3.0 - undertaker: 1.3.0 - vinyl-fs: 3.0.3 - transitivePeerDependencies: - - supports-color - dev: false - - /gulplog@1.0.0: - resolution: {integrity: sha512-hm6N8nrm3Y08jXie48jsC55eCZz9mnb4OirAStEk2deqeyhXU3C1otDVh+ccttMuc1sBi6RX6ZJ720hs9RCvgw==} - engines: {node: '>= 0.10'} - dependencies: - glogg: 1.0.2 - dev: false - /gunzip-maybe@1.4.2: resolution: {integrity: sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw==} hasBin: true @@ -9983,22 +9033,10 @@ packages: engines: {node: '>=6'} dev: true - /has-ansi@2.0.0: - resolution: {integrity: sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==} - engines: {node: '>=0.10.0'} - dependencies: - ansi-regex: 2.1.1 - dev: false - /has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} dev: true - /has-flag@1.0.0: - resolution: {integrity: sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==} - engines: {node: '>=0.10.0'} - dev: false - /has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} @@ -10011,6 +9049,7 @@ packages: resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} dependencies: get-intrinsic: 1.2.1 + dev: true /has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} @@ -10041,37 +9080,6 @@ packages: dependencies: has-symbols: 1.0.3 - /has-value@0.3.1: - resolution: {integrity: sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==} - engines: {node: '>=0.10.0'} - dependencies: - get-value: 2.0.6 - has-values: 0.1.4 - isobject: 2.1.0 - dev: false - - /has-value@1.0.0: - resolution: {integrity: sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==} - engines: {node: '>=0.10.0'} - dependencies: - get-value: 2.0.6 - has-values: 1.0.0 - isobject: 3.0.1 - dev: false - - /has-values@0.1.4: - resolution: {integrity: sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==} - engines: {node: '>=0.10.0'} - dev: false - - /has-values@1.0.0: - resolution: {integrity: sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==} - engines: {node: '>=0.10.0'} - dependencies: - is-number: 3.0.0 - kind-of: 4.0.0 - dev: false - /has@1.0.3: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} engines: {node: '>= 0.4.0'} @@ -10083,6 +9091,7 @@ packages: engines: {node: '>= 0.4'} dependencies: function-bind: 1.1.2 + dev: true /hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} @@ -10104,15 +9113,9 @@ packages: resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} dev: false - /homedir-polyfill@1.0.3: - resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} - engines: {node: '>=0.10.0'} - dependencies: - parse-passwd: 1.0.0 - dev: false - /hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} + dev: true /hosted-git-info@4.1.0: resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} @@ -10126,10 +9129,6 @@ packages: engines: {node: '>=14'} dev: false - /html-comment-regex@1.1.2: - resolution: {integrity: sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==} - dev: false - /html-entities@2.3.2: resolution: {integrity: sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==} dev: false @@ -10314,10 +9313,6 @@ packages: engines: {node: '>=8'} dev: true - /indexes-of@1.0.1: - resolution: {integrity: sha512-bup+4tap3Hympa+JBJUG7XuOsdNQ6fxt0MHyXMKuLBKn0OqsTfvUxkUrroEX1+B2VsSHvCjiIcZVxRtYa4nllA==} - dev: false - /inflation@2.0.0: resolution: {integrity: sha512-m3xv4hJYR2oXw4o4Y5l6P5P16WYmazYof+el6Al3f+YlggGj6qT9kImBAnzDelRALnP5d3h4jGBPKzYCizjZZw==} engines: {node: '>= 0.8.0'} @@ -10353,16 +9348,6 @@ packages: side-channel: 1.0.4 dev: true - /interpret@1.4.0: - resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} - engines: {node: '>= 0.10'} - dev: false - - /invert-kv@1.0.0: - resolution: {integrity: sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==} - engines: {node: '>=0.10.0'} - dev: false - /ioredis@5.4.1: resolution: {integrity: sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==} engines: {node: '>=12.22.0'} @@ -10419,26 +9404,6 @@ packages: engines: {node: '>=8'} dev: true - /is-absolute-url@2.1.0: - resolution: {integrity: sha512-vOx7VprsKyllwjSkLV79NIhpyLfr3jAp7VaTCMXOJHu4m0Ew1CZ2fcjASwmV1jI3BWuWHB013M48eyeldk9gYg==} - engines: {node: '>=0.10.0'} - dev: false - - /is-absolute@1.0.0: - resolution: {integrity: sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==} - engines: {node: '>=0.10.0'} - dependencies: - is-relative: 1.0.0 - is-windows: 1.0.2 - dev: false - - /is-accessor-descriptor@1.0.1: - resolution: {integrity: sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==} - engines: {node: '>= 0.10'} - dependencies: - hasown: 2.0.2 - dev: false - /is-alphabetical@1.0.4: resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==} dev: true @@ -10468,6 +9433,7 @@ packages: /is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + dev: true /is-arrayish@0.3.2: resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} @@ -10479,13 +9445,6 @@ packages: has-bigints: 1.0.2 dev: true - /is-binary-path@1.0.1: - resolution: {integrity: sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==} - engines: {node: '>=0.10.0'} - dependencies: - binary-extensions: 1.13.1 - dev: false - /is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} @@ -10525,13 +9484,7 @@ packages: resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} dependencies: hasown: 2.0.0 - - /is-data-descriptor@1.0.1: - resolution: {integrity: sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==} - engines: {node: '>= 0.4'} - dependencies: - hasown: 2.0.2 - dev: false + dev: true /is-date-object@1.0.5: resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} @@ -10548,22 +9501,6 @@ packages: resolution: {integrity: sha512-YDoFpuZWu1VRXlsnlYMzKyVRITXj7Ej/V9gXQ2/pAe7X1J7M/RNOqaIYi6qUn+B7nGyB9pDXrv02dsB58d2ZAQ==} dev: false - /is-descriptor@0.1.7: - resolution: {integrity: sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==} - engines: {node: '>= 0.4'} - dependencies: - is-accessor-descriptor: 1.0.1 - is-data-descriptor: 1.0.1 - dev: false - - /is-descriptor@1.0.3: - resolution: {integrity: sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==} - engines: {node: '>= 0.4'} - dependencies: - is-accessor-descriptor: 1.0.1 - is-data-descriptor: 1.0.1 - dev: false - /is-electron@2.2.2: resolution: {integrity: sha512-FO/Rhvz5tuw4MCWkpMzHFKWD2LsfHzIb7i6MdPYZ/KW7AlxawyLkqdy+jPZP1WubqEADE3O4FUENlJHDfQASRg==} dev: false @@ -10579,23 +9516,10 @@ packages: engines: {node: '>=0.10.0'} dev: false - /is-extendable@1.0.1: - resolution: {integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==} - engines: {node: '>=0.10.0'} - dependencies: - is-plain-object: 2.0.4 - dev: false - /is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - - /is-fullwidth-code-point@1.0.0: - resolution: {integrity: sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==} - engines: {node: '>=0.10.0'} - dependencies: - number-is-nan: 1.0.1 - dev: false + dev: true /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} @@ -10613,18 +9537,12 @@ packages: has-tostringtag: 1.0.0 dev: false - /is-glob@3.1.0: - resolution: {integrity: sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==} - engines: {node: '>=0.10.0'} - dependencies: - is-extglob: 2.1.1 - dev: false - /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} dependencies: is-extglob: 2.1.1 + dev: true /is-gzip@1.0.0: resolution: {integrity: sha512-rcfALRIb1YewtnksfRIHGcIY93QnK8BIQ/2c9yDYcG/Y6+vRoJuTWBmmSEbyLLYtXm7q35pHOHbZFQBaLrhlWQ==} @@ -10651,11 +9569,6 @@ packages: resolution: {integrity: sha512-Y4LTamMe0DDQIIAlaer9eKebAlDSV6huy+TWhJVPlzZh2o4tRP5SQWFlLn5N0To4mDD22/qdOq+veo1cSISLgQ==} dev: false - /is-negated-glob@1.0.0: - resolution: {integrity: sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==} - engines: {node: '>=0.10.0'} - dev: false - /is-negative-zero@2.0.2: resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} engines: {node: '>= 0.4'} @@ -10668,18 +9581,6 @@ packages: has-tostringtag: 1.0.2 dev: true - /is-number@3.0.0: - resolution: {integrity: sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==} - engines: {node: '>=0.10.0'} - dependencies: - kind-of: 3.2.2 - dev: false - - /is-number@4.0.0: - resolution: {integrity: sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==} - engines: {node: '>=0.10.0'} - dev: false - /is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -10693,19 +9594,13 @@ packages: /is-plain-obj@1.1.0: resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} engines: {node: '>=0.10.0'} + dev: true /is-plain-obj@2.1.0: resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} engines: {node: '>=8'} dev: true - /is-plain-object@2.0.4: - resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} - engines: {node: '>=0.10.0'} - dependencies: - isobject: 3.0.1 - dev: false - /is-plain-object@5.0.0: resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} engines: {node: '>=0.10.0'} @@ -10721,13 +9616,6 @@ packages: call-bind: 1.0.2 has-tostringtag: 1.0.0 - /is-relative@1.0.0: - resolution: {integrity: sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==} - engines: {node: '>=0.10.0'} - dependencies: - is-unc-path: 1.0.0 - dev: false - /is-shared-array-buffer@1.0.2: resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} dependencies: @@ -10754,13 +9642,6 @@ packages: has-tostringtag: 1.0.0 dev: true - /is-svg@2.1.0: - resolution: {integrity: sha512-Ya1giYJUkcL/94quj0+XGcmts6cETPBW1MiFz1ReJrnDJ680F52qpAEGAEGU0nq96FRGIGPx6Yo1CyPXcOoyGw==} - engines: {node: '>=0.10.0'} - dependencies: - html-comment-regex: 1.1.2 - dev: false - /is-svg@5.0.0: resolution: {integrity: sha512-sRl7J0oX9yUNamSdc8cwgzh9KBLnQXNzGmW0RVHwg/jEYjGNYHC6UvnYD8+hAeut9WwxRvhG9biK7g/wDGxcMw==} engines: {node: '>=14.16'} @@ -10793,13 +9674,6 @@ packages: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} dev: false - /is-unc-path@1.0.0: - resolution: {integrity: sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==} - engines: {node: '>=0.10.0'} - dependencies: - unc-path-regex: 0.1.2 - dev: false - /is-unicode-supported@0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} @@ -10809,15 +9683,6 @@ packages: resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==} dev: false - /is-utf8@0.2.1: - resolution: {integrity: sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==} - dev: false - - /is-valid-glob@1.0.0: - resolution: {integrity: sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==} - engines: {node: '>=0.10.0'} - dev: false - /is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: @@ -10829,11 +9694,6 @@ packages: engines: {node: '>=0.10.0'} dev: false - /is-windows@1.0.2: - resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} - engines: {node: '>=0.10.0'} - dev: false - /isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} @@ -10844,18 +9704,6 @@ packages: /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - /isobject@2.1.0: - resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==} - engines: {node: '>=0.10.0'} - dependencies: - isarray: 1.0.0 - dev: false - - /isobject@3.0.1: - resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} - engines: {node: '>=0.10.0'} - dev: false - /istanbul-lib-coverage@3.2.0: resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} engines: {node: '>=8'} @@ -10915,14 +9763,6 @@ packages: istanbul-lib-report: 3.0.1 dev: true - /istextorbinary@3.3.0: - resolution: {integrity: sha512-Tvq1W6NAcZeJ8op+Hq7tdZ434rqnMx4CCZ7H0ff83uEloDvVbqAwaMTZcafKGJT0VHkYzuXUiCY4hlXQg6WfoQ==} - engines: {node: '>=8'} - dependencies: - binaryextensions: 2.3.0 - textextensions: 3.3.0 - dev: false - /jackspeak@2.3.6: resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} engines: {node: '>=14'} @@ -11481,10 +10321,6 @@ packages: resolution: {integrity: sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==} dev: false - /js-base64@2.6.4: - resolution: {integrity: sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==} - dev: false - /js-beautify@1.14.9: resolution: {integrity: sha512-coM7xq1syLcMyuVGyToxcj2AlzhkDjmfklL8r0JgJ7A76wyGMpJ1oA35mr4APdYNO/o/4YY8H54NQIJzhMbhBg==} engines: {node: '>=12'} @@ -11515,14 +10351,6 @@ packages: esprima: 4.0.1 dev: true - /js-yaml@3.7.0: - resolution: {integrity: sha512-eIlkGty7HGmntbV6P/ZlAsoncFLGsNoM27lkTzS+oneY/EiNhj+geqD9ezg/ip+SW6Var0BJU2JtV0vEUZpWVQ==} - hasBin: true - dependencies: - argparse: 1.0.10 - esprima: 2.7.3 - dev: false - /js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true @@ -11584,6 +10412,7 @@ packages: /json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + dev: true /json-stringify-safe@5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} @@ -11683,10 +10512,6 @@ packages: is-promise: 2.2.2 promise: 7.3.1 - /just-debounce@1.1.0: - resolution: {integrity: sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==} - dev: false - /jwa@2.0.0: resolution: {integrity: sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==} dependencies: @@ -11733,21 +10558,10 @@ packages: is-buffer: 1.1.6 dev: false - /kind-of@4.0.0: - resolution: {integrity: sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==} - engines: {node: '>=0.10.0'} - dependencies: - is-buffer: 1.1.6 - dev: false - - /kind-of@5.1.0: - resolution: {integrity: sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==} - engines: {node: '>=0.10.0'} - dev: false - /kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} + dev: true /kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} @@ -12022,14 +10836,6 @@ packages: engines: {node: '>=14.16'} dev: false - /last-run@1.1.1: - resolution: {integrity: sha512-U/VxvpX4N/rFvPzr3qG5EtLKEnNI0emvIQB3/ecEwv+8GHaUKbIB8vxv1Oai5FAF0d0r7LXHhLLe5K/yChm5GQ==} - engines: {node: '>= 0.10'} - dependencies: - default-resolution: 2.0.0 - es6-weak-map: 2.0.3 - dev: false - /lazystream@1.0.1: resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} engines: {node: '>= 0.6.3'} @@ -12037,20 +10843,6 @@ packages: readable-stream: 2.3.8 dev: false - /lcid@1.0.0: - resolution: {integrity: sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==} - engines: {node: '>=0.10.0'} - dependencies: - invert-kv: 1.0.0 - dev: false - - /lead@1.0.0: - resolution: {integrity: sha512-IpSVCk9AYvLHo5ctcIXxOBpMWUe+4TKN3VPWAKUbJikkmsGp0VrSM8IttVc32D6J4WUsiPE6aEFRNmIoF/gdow==} - engines: {node: '>= 0.10'} - dependencies: - flush-write-stream: 1.1.1 - dev: false - /leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -12064,37 +10856,10 @@ packages: type-check: 0.4.0 dev: true - /liftoff@3.1.0: - resolution: {integrity: sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==} - engines: {node: '>= 0.8'} - dependencies: - extend: 3.0.2 - findup-sync: 3.0.0 - fined: 1.2.0 - flagged-respawn: 1.0.1 - is-plain-object: 2.0.4 - object.map: 1.0.1 - rechoir: 0.6.2 - resolve: 1.22.8 - transitivePeerDependencies: - - supports-color - dev: false - /lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} dev: true - /load-json-file@1.1.0: - resolution: {integrity: sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==} - engines: {node: '>=0.10.0'} - dependencies: - graceful-fs: 4.2.11 - parse-json: 2.2.0 - pify: 2.3.0 - pinkie-promise: 2.0.1 - strip-bom: 2.0.0 - dev: false - /loader-runner@4.3.0: resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} engines: {node: '>=6.11.5'} @@ -12167,6 +10932,7 @@ packages: /lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + dev: true /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} @@ -12191,10 +10957,6 @@ packages: resolution: {integrity: sha512-s8xEQdsp2Tu5zUqVdFSe9C0kR8YlnAJYLqMdkh+pIRBRxF6/apWseLdHl3/+jv2I61dhPwtI/Ff+EqvCpc+N8w==} dev: true - /lodash.uniq@4.5.0: - resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} - dev: false - /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -12285,24 +11047,12 @@ packages: /make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - /make-iterator@1.0.1: - resolution: {integrity: sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==} - engines: {node: '>=0.10.0'} - dependencies: - kind-of: 6.0.3 - dev: false - /makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} dependencies: tmpl: 1.0.5 dev: true - /map-cache@0.2.2: - resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==} - engines: {node: '>=0.10.0'} - dev: false - /map-obj@1.0.1: resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} engines: {node: '>=0.10.0'} @@ -12313,35 +11063,12 @@ packages: engines: {node: '>=8'} dev: true - /map-visit@1.0.0: - resolution: {integrity: sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==} - engines: {node: '>=0.10.0'} - dependencies: - object-visit: 1.0.1 - dev: false - /marked@4.3.0: resolution: {integrity: sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==} engines: {node: '>= 12'} hasBin: true dev: true - /matchdep@2.0.0: - resolution: {integrity: sha512-LFgVbaHIHMqCRuCZyfCtUOq9/Lnzhi7Z0KFUE2fhD54+JN2jLh3hC02RLkqauJ3U4soU6H1J3tfj/Byk7GoEjA==} - engines: {node: '>= 0.10.0'} - dependencies: - findup-sync: 2.0.0 - micromatch: 3.1.10 - resolve: 1.22.8 - stack-trace: 0.0.10 - transitivePeerDependencies: - - supports-color - dev: false - - /math-expression-evaluator@1.4.0: - resolution: {integrity: sha512-4vRUvPyxdO8cWULGTh9dZWL2tZK6LDBvj+OGHBER7poH9Qdt7kXEoj20wiz4lQUbUXQZFjPbe5mVDo9nutizCw==} - dev: false - /matter-js@0.19.0: resolution: {integrity: sha512-v2huwvQGOHTGOkMqtHd2hercCG3f6QAObTisPPHg8TZqq2lz7eIY/5i/5YUV8Ibf3mEioFEmwibcPUF2/fnKKQ==} dev: true @@ -12412,27 +11139,6 @@ packages: - supports-color dev: true - /micromatch@3.1.10: - resolution: {integrity: sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==} - engines: {node: '>=0.10.0'} - dependencies: - arr-diff: 4.0.0 - array-unique: 0.3.2 - braces: 2.3.2 - define-property: 2.0.2 - extend-shallow: 3.0.2 - extglob: 2.0.4 - fragment-cache: 0.2.1 - kind-of: 6.0.3 - nanomatch: 1.2.13 - object.pick: 1.3.0 - regex-not: 1.0.2 - snapdragon: 0.8.2 - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - dev: false - /micromatch@4.0.5: resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} engines: {node: '>=8.6'} @@ -12545,14 +11251,6 @@ packages: engines: {node: '>=16 || 14 >=14.17'} dev: false - /mixin-deep@1.3.2: - resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==} - engines: {node: '>=0.10.0'} - dependencies: - for-in: 1.0.2 - is-extendable: 1.0.1 - dev: false - /mkdirp@0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true @@ -12662,11 +11360,6 @@ packages: type-is: 1.6.18 xtend: 4.0.2 - /mute-stdout@1.0.1: - resolution: {integrity: sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==} - engines: {node: '>= 0.10'} - dev: false - /mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} dependencies: @@ -12675,12 +11368,6 @@ packages: thenify-all: 1.6.0 dev: false - /nan@2.19.0: - resolution: {integrity: sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==} - requiresBuild: true - dev: false - optional: true - /nanoid@3.3.6: resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -12692,25 +11379,6 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - /nanomatch@1.2.13: - resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==} - engines: {node: '>=0.10.0'} - dependencies: - arr-diff: 4.0.0 - array-unique: 0.3.2 - define-property: 2.0.2 - extend-shallow: 3.0.2 - fragment-cache: 0.2.1 - is-windows: 1.0.2 - kind-of: 6.0.3 - object.pick: 1.3.0 - regex-not: 1.0.2 - snapdragon: 0.8.2 - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - dev: false - /natural-compare-lite@1.4.0: resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} dev: true @@ -12853,6 +11521,7 @@ packages: resolve: 1.22.8 semver: 5.7.2 validate-npm-package-license: 3.0.4 + dev: true /normalize-package-data@3.0.3: resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} @@ -12864,32 +11533,10 @@ packages: validate-npm-package-license: 3.0.4 dev: true - /normalize-path@2.1.1: - resolution: {integrity: sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==} - engines: {node: '>=0.10.0'} - dependencies: - remove-trailing-separator: 1.1.0 - dev: false - /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - /normalize-range@0.1.2: - resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} - engines: {node: '>=0.10.0'} - dev: false - - /normalize-url@1.9.1: - resolution: {integrity: sha512-A48My/mtCklowHBlI8Fq2jFWK4tX4lJ5E6ytFsSOq1fzpvT0SQSgKhSg7lN5c2uYFOrUAOQp6zhhJnpp1eMloQ==} - engines: {node: '>=4'} - dependencies: - object-assign: 4.1.1 - prepend-http: 1.0.4 - query-string: 4.3.4 - sort-keys: 1.1.2 - dev: false - /normalize-url@6.1.0: resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} engines: {node: '>=10'} @@ -12899,13 +11546,6 @@ packages: engines: {node: '>=14.16'} dev: false - /now-and-later@2.0.1: - resolution: {integrity: sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==} - engines: {node: '>= 0.10'} - dependencies: - once: 1.4.0 - dev: false - /npm-run-path@2.0.2: resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==} engines: {node: '>=4'} @@ -12939,15 +11579,6 @@ packages: boolbase: 1.0.0 dev: true - /num2fraction@1.2.2: - resolution: {integrity: sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg==} - dev: false - - /number-is-nan@1.0.1: - resolution: {integrity: sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==} - engines: {node: '>=0.10.0'} - dev: false - /oauth@0.10.0: resolution: {integrity: sha512-1orQ9MT1vHFGQxhuy7E/0gECD3fd2fCC+PIX+/jgmU/gI3EpRocXtmtvxCO5x3WZ443FLTLFWNDjl5MPJf9u+Q==} dev: false @@ -12961,15 +11592,6 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} - /object-copy@0.1.0: - resolution: {integrity: sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==} - engines: {node: '>=0.10.0'} - dependencies: - copy-descriptor: 0.1.1 - define-property: 0.2.5 - kind-of: 3.2.2 - dev: false - /object-inspect@1.12.3: resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} dev: true @@ -12981,13 +11603,7 @@ packages: /object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} - - /object-visit@1.0.1: - resolution: {integrity: sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==} - engines: {node: '>=0.10.0'} - dependencies: - isobject: 3.0.1 - dev: false + dev: true /object.assign@4.1.4: resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} @@ -12997,16 +11613,7 @@ packages: define-properties: 1.2.0 has-symbols: 1.0.3 object-keys: 1.1.1 - - /object.defaults@1.1.0: - resolution: {integrity: sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==} - engines: {node: '>=0.10.0'} - dependencies: - array-each: 1.0.1 - array-slice: 1.1.0 - for-own: 1.0.0 - isobject: 3.0.1 - dev: false + dev: true /object.fromentries@2.0.6: resolution: {integrity: sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==} @@ -13044,29 +11651,6 @@ packages: get-intrinsic: 1.2.1 dev: true - /object.map@1.0.1: - resolution: {integrity: sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==} - engines: {node: '>=0.10.0'} - dependencies: - for-own: 1.0.0 - make-iterator: 1.0.1 - dev: false - - /object.pick@1.3.0: - resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==} - engines: {node: '>=0.10.0'} - dependencies: - isobject: 3.0.1 - dev: false - - /object.reduce@1.0.1: - resolution: {integrity: sha512-naLhxxpUESbNkRqc35oQ2scZSJueHGQNUfMW/0U37IgN6tE2dgDWg3whf+NEliy3F/QysrO48XKUz/nGPe+AQw==} - engines: {node: '>=0.10.0'} - dependencies: - for-own: 1.0.0 - make-iterator: 1.0.1 - dev: false - /object.values@1.1.6: resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==} engines: {node: '>= 0.4'} @@ -13165,12 +11749,6 @@ packages: wcwidth: 1.0.1 dev: true - /ordered-read-streams@1.0.1: - resolution: {integrity: sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==} - dependencies: - readable-stream: 2.3.8 - dev: false - /os-filter-obj@2.0.0: resolution: {integrity: sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg==} engines: {node: '>=4'} @@ -13178,13 +11756,6 @@ packages: arch: 2.2.0 dev: true - /os-locale@1.4.0: - resolution: {integrity: sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==} - engines: {node: '>=0.10.0'} - dependencies: - lcid: 1.0.0 - dev: false - /os-utils@0.0.14: resolution: {integrity: sha512-ajB8csaHLBvJOYsHJkp8YdO2FvlBbf/ZxaYQwXXRDyQ84UoE+uTuLXxqd0shekXMX6Qr/pt/DDyLMRAMsgfWzg==} dev: false @@ -13276,22 +11847,6 @@ packages: is-hexadecimal: 1.0.4 dev: true - /parse-filepath@1.0.2: - resolution: {integrity: sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==} - engines: {node: '>=0.8'} - dependencies: - is-absolute: 1.0.0 - map-cache: 0.2.2 - path-root: 0.1.1 - dev: false - - /parse-json@2.2.0: - resolution: {integrity: sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==} - engines: {node: '>=0.10.0'} - dependencies: - error-ex: 1.3.2 - dev: false - /parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} @@ -13308,16 +11863,6 @@ packages: xtend: 4.0.2 dev: false - /parse-node-version@1.0.1: - resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} - engines: {node: '>= 0.10'} - dev: false - - /parse-passwd@1.0.0: - resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} - engines: {node: '>=0.10.0'} - dev: false - /parse-srcset@1.0.2: resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==} dev: false @@ -13347,11 +11892,6 @@ packages: engines: {node: '>= 0.8'} dev: false - /pascalcase@0.1.1: - resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==} - engines: {node: '>=0.10.0'} - dev: false - /passthrough-counter@1.0.0: resolution: {integrity: sha512-Wy8PXTLqPAN0oEgBrlnsXPMww3SYJ44tQ8aVrGAI4h4JZYCS0oYqsPqtPR8OhJpv6qFbpbB7XAn0liKV7EXubA==} dev: false @@ -13360,17 +11900,6 @@ packages: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} dev: true - /path-dirname@1.0.2: - resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==} - dev: false - - /path-exists@2.1.0: - resolution: {integrity: sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==} - engines: {node: '>=0.10.0'} - dependencies: - pinkie-promise: 2.0.1 - dev: false - /path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -13396,18 +11925,6 @@ packages: /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - /path-root-regex@0.1.2: - resolution: {integrity: sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==} - engines: {node: '>=0.10.0'} - dev: false - - /path-root@0.1.1: - resolution: {integrity: sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==} - engines: {node: '>=0.10.0'} - dependencies: - path-root-regex: 0.1.2 - dev: false - /path-scurry@1.10.1: resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} engines: {node: '>=16 || 14 >=14.17'} @@ -13424,15 +11941,6 @@ packages: resolution: {integrity: sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==} dev: false - /path-type@1.1.0: - resolution: {integrity: sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==} - engines: {node: '>=0.10.0'} - dependencies: - graceful-fs: 4.2.11 - pify: 2.3.0 - pinkie-promise: 2.0.1 - dev: false - /path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -13601,16 +12109,6 @@ packages: pathe: 1.1.1 dev: true - /plugin-error@1.0.1: - resolution: {integrity: sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==} - engines: {node: '>= 0.10'} - dependencies: - ansi-colors: 1.1.0 - arr-diff: 4.0.0 - arr-union: 3.1.0 - extend-shallow: 3.0.2 - dev: false - /plur@4.0.0: resolution: {integrity: sha512-4UGewrYgqDFw9vV6zNV+ADmPAUAfJPKtGvb/VdpQAx25X5f3xXdGdyOEVFwkl8Hl/tl7+xbeHqSEM+D5/TirUg==} engines: {node: '>=10'} @@ -13637,180 +12135,11 @@ packages: hasBin: true dev: true - /posix-character-classes@0.1.1: - resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==} - engines: {node: '>=0.10.0'} - dev: false - /possible-typed-array-names@1.0.0: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} dev: false - /postcss-calc@5.3.1: - resolution: {integrity: sha512-iBcptYFq+QUh9gzP7ta2btw50o40s4uLI4UDVgd5yRAZtUDWc5APdl5yQDd2h/TyiZNbJrv0HiYhT102CMgN7Q==} - dependencies: - postcss: 5.2.18 - postcss-message-helpers: 2.0.0 - reduce-css-calc: 1.3.0 - dev: false - - /postcss-colormin@2.2.2: - resolution: {integrity: sha512-XXitQe+jNNPf+vxvQXIQ1+pvdQKWKgkx8zlJNltcMEmLma1ypDRDQwlLt+6cP26fBreihNhZxohh1rcgCH2W5w==} - dependencies: - colormin: 1.1.2 - postcss: 5.2.18 - postcss-value-parser: 3.3.1 - dev: false - - /postcss-convert-values@2.6.1: - resolution: {integrity: sha512-SE7mf25D3ORUEXpu3WUqQqy0nCbMuM5BEny+ULE/FXdS/0UMA58OdzwvzuHJRpIFlk1uojt16JhaEogtP6W2oA==} - dependencies: - postcss: 5.2.18 - postcss-value-parser: 3.3.1 - dev: false - - /postcss-discard-comments@2.0.4: - resolution: {integrity: sha512-yGbyBDo5FxsImE90LD8C87vgnNlweQkODMkUZlDVM/CBgLr9C5RasLGJxxh9GjVOBeG8NcCMatoqI1pXg8JNXg==} - dependencies: - postcss: 5.2.18 - dev: false - - /postcss-discard-duplicates@2.1.0: - resolution: {integrity: sha512-+lk5W1uqO8qIUTET+UETgj9GWykLC3LOldr7EehmymV0Wu36kyoHimC4cILrAAYpHQ+fr4ypKcWcVNaGzm0reA==} - dependencies: - postcss: 5.2.18 - dev: false - - /postcss-discard-empty@2.1.0: - resolution: {integrity: sha512-IBFoyrwk52dhF+5z/ZAbzq5Jy7Wq0aLUsOn69JNS+7YeuyHaNzJwBIYE0QlUH/p5d3L+OON72Fsexyb7OK/3og==} - dependencies: - postcss: 5.2.18 - dev: false - - /postcss-discard-overridden@0.1.1: - resolution: {integrity: sha512-IyKoDL8QNObOiUc6eBw8kMxBHCfxUaERYTUe2QF8k7j/xiirayDzzkmlR6lMQjrAM1p1DDRTvWrS7Aa8lp6/uA==} - dependencies: - postcss: 5.2.18 - dev: false - - /postcss-discard-unused@2.2.3: - resolution: {integrity: sha512-nCbFNfqYAbKCw9J6PSJubpN9asnrwVLkRDFc4KCwyUEdOtM5XDE/eTW3OpqHrYY1L4fZxgan7LLRAAYYBzwzrg==} - dependencies: - postcss: 5.2.18 - uniqs: 2.0.0 - dev: false - - /postcss-filter-plugins@2.0.3: - resolution: {integrity: sha512-T53GVFsdinJhgwm7rg1BzbeBRomOg9y5MBVhGcsV0CxurUdVj1UlPdKtn7aqYA/c/QVkzKMjq2bSV5dKG5+AwQ==} - dependencies: - postcss: 5.2.18 - dev: false - - /postcss-merge-idents@2.1.7: - resolution: {integrity: sha512-9DHmfCZ7/hNHhIKnNkz4CU0ejtGen5BbTRJc13Z2uHfCedeCUsK2WEQoAJRBL+phs68iWK6Qf8Jze71anuysWA==} - dependencies: - has: 1.0.3 - postcss: 5.2.18 - postcss-value-parser: 3.3.1 - dev: false - - /postcss-merge-longhand@2.0.2: - resolution: {integrity: sha512-ma7YvxjdLQdifnc1HFsW/AW6fVfubGyR+X4bE3FOSdBVMY9bZjKVdklHT+odknKBB7FSCfKIHC3yHK7RUAqRPg==} - dependencies: - postcss: 5.2.18 - dev: false - - /postcss-merge-rules@2.1.2: - resolution: {integrity: sha512-Wgg2FS6W3AYBl+5L9poL6ZUISi5YzL+sDCJfM7zNw/Q1qsyVQXXZ2cbVui6mu2cYJpt1hOKCGj1xA4mq/obz/Q==} - dependencies: - browserslist: 1.7.7 - caniuse-api: 1.6.1 - postcss: 5.2.18 - postcss-selector-parser: 2.2.3 - vendors: 1.0.4 - dev: false - - /postcss-message-helpers@2.0.0: - resolution: {integrity: sha512-tPLZzVAiIJp46TBbpXtrUAKqedXSyW5xDEo1sikrfEfnTs+49SBZR/xDdqCiJvSSbtr615xDsaMF3RrxS2jZlA==} - dev: false - - /postcss-minify-font-values@1.0.5: - resolution: {integrity: sha512-vFSPzrJhNe6/8McOLU13XIsERohBJiIFFuC1PolgajOZdRWqRgKITP/A4Z/n4GQhEmtbxmO9NDw3QLaFfE1dFQ==} - dependencies: - object-assign: 4.1.1 - postcss: 5.2.18 - postcss-value-parser: 3.3.1 - dev: false - - /postcss-minify-gradients@1.0.5: - resolution: {integrity: sha512-DZhT0OE+RbVqVyGsTIKx84rU/5cury1jmwPa19bViqYPQu499ZU831yMzzsyC8EhiZVd73+h5Z9xb/DdaBpw7Q==} - dependencies: - postcss: 5.2.18 - postcss-value-parser: 3.3.1 - dev: false - - /postcss-minify-params@1.2.2: - resolution: {integrity: sha512-hhJdMVgP8vasrHbkKAk+ab28vEmPYgyuDzRl31V3BEB3QOR3L5TTIVEWLDNnZZ3+fiTi9d6Ker8GM8S1h8p2Ow==} - dependencies: - alphanum-sort: 1.0.2 - postcss: 5.2.18 - postcss-value-parser: 3.3.1 - uniqs: 2.0.0 - dev: false - - /postcss-minify-selectors@2.1.1: - resolution: {integrity: sha512-e13vxPBSo3ZaPne43KVgM+UETkx3Bs4/Qvm6yXI9HQpQp4nyb7HZ0gKpkF+Wn2x+/dbQ+swNpCdZSbMOT7+TIA==} - dependencies: - alphanum-sort: 1.0.2 - has: 1.0.3 - postcss: 5.2.18 - postcss-selector-parser: 2.2.3 - dev: false - - /postcss-normalize-charset@1.1.1: - resolution: {integrity: sha512-RKgjEks83l8w4yEhztOwNZ+nLSrJ+NvPNhpS+mVDzoaiRHZQVoG7NF2TP5qjwnaN9YswUhj6m1E0S0Z+WDCgEQ==} - dependencies: - postcss: 5.2.18 - dev: false - - /postcss-normalize-url@3.0.8: - resolution: {integrity: sha512-WqtWG6GV2nELsQEFES0RzfL2ebVwmGl/M8VmMbshKto/UClBo+mznX8Zi4/hkThdqx7ijwv+O8HWPdpK7nH/Ig==} - dependencies: - is-absolute-url: 2.1.0 - normalize-url: 1.9.1 - postcss: 5.2.18 - postcss-value-parser: 3.3.1 - dev: false - - /postcss-ordered-values@2.2.3: - resolution: {integrity: sha512-5RB1IUZhkxDCfa5fx/ogp/A82mtq+r7USqS+7zt0e428HJ7+BHCxyeY39ClmkkUtxdOd3mk8gD6d9bjH2BECMg==} - dependencies: - postcss: 5.2.18 - postcss-value-parser: 3.3.1 - dev: false - - /postcss-reduce-idents@2.4.0: - resolution: {integrity: sha512-0+Ow9e8JLtffjumJJFPqvN4qAvokVbdQPnijUDSOX8tfTwrILLP4ETvrZcXZxAtpFLh/U0c+q8oRMJLr1Kiu4w==} - dependencies: - postcss: 5.2.18 - postcss-value-parser: 3.3.1 - dev: false - - /postcss-reduce-initial@1.0.1: - resolution: {integrity: sha512-jJFrV1vWOPCQsIVitawGesRgMgunbclERQ/IRGW7r93uHrVzNQQmHQ7znsOIjJPZ4yWMzs5A8NFhp3AkPHPbDA==} - dependencies: - postcss: 5.2.18 - dev: false - - /postcss-reduce-transforms@1.0.4: - resolution: {integrity: sha512-lGgRqnSuAR5i5uUg1TA33r9UngfTadWxOyL2qx1KuPoCQzfmtaHjp9PuwX7yVyRxG3BWBzeFUaS5uV9eVgnEgQ==} - dependencies: - has: 1.0.3 - postcss: 5.2.18 - postcss-value-parser: 3.3.1 - dev: false - /postcss-safe-parser@6.0.0(postcss@8.4.31): resolution: {integrity: sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==} engines: {node: '>=12.0'} @@ -13829,14 +12158,6 @@ packages: postcss: 8.4.31 dev: true - /postcss-selector-parser@2.2.3: - resolution: {integrity: sha512-3pqyakeGhrO0BQ5+/tGTfvi5IAUAhHRayGK8WFSu06aEv2BmHoXw/Mhb+w7VY5HERIuC+QoUI7wgrCcq2hqCVA==} - dependencies: - flatten: 1.0.3 - indexes-of: 1.0.1 - uniq: 1.0.1 - dev: false - /postcss-selector-parser@6.0.13: resolution: {integrity: sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==} engines: {node: '>=4'} @@ -13858,45 +12179,6 @@ packages: - supports-color dev: true - /postcss-svgo@2.1.6: - resolution: {integrity: sha512-y5AdQdgBoF4rbpdbeWAJuxE953g/ylRfVNp6mvAi61VCN/Y25Tu9p5mh3CyI42WbTRIiwR9a1GdFtmDnNPeskQ==} - dependencies: - is-svg: 2.1.0 - postcss: 5.2.18 - postcss-value-parser: 3.3.1 - svgo: 0.7.2 - dev: false - - /postcss-unique-selectors@2.0.2: - resolution: {integrity: sha512-WZX8r1M0+IyljoJOJleg3kYm10hxNYF9scqAT7v/xeSX1IdehutOM85SNO0gP9K+bgs86XERr7Ud5u3ch4+D8g==} - dependencies: - alphanum-sort: 1.0.2 - postcss: 5.2.18 - uniqs: 2.0.0 - dev: false - - /postcss-value-parser@3.3.1: - resolution: {integrity: sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==} - dev: false - - /postcss-zindex@2.2.0: - resolution: {integrity: sha512-uhRZ2hRgj0lorxm9cr62B01YzpUe63h0RXMXQ4gWW3oa2rpJh+FJAiEAytaFCPU/VgaBS+uW2SJ1XKyDNz1h4w==} - dependencies: - has: 1.0.3 - postcss: 5.2.18 - uniqs: 2.0.0 - dev: false - - /postcss@5.2.18: - resolution: {integrity: sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==} - engines: {node: '>=0.12'} - dependencies: - chalk: 1.1.3 - js-base64: 2.6.4 - source-map: 0.5.7 - supports-color: 3.2.3 - dev: false - /postcss@8.4.31: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} engines: {node: ^10 || ^12 || >=14} @@ -13977,11 +12259,6 @@ packages: engines: {node: '>= 0.8.0'} dev: true - /prepend-http@1.0.4: - resolution: {integrity: sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg==} - engines: {node: '>=0.10.0'} - dev: false - /prettier-linter-helpers@1.0.0: resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} engines: {node: '>=6.0.0'} @@ -14004,11 +12281,6 @@ packages: react-is: 18.2.0 dev: true - /pretty-hrtime@1.0.3: - resolution: {integrity: sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==} - engines: {node: '>= 0.8'} - dev: false - /pretty@2.0.0: resolution: {integrity: sha512-G9xUchgTEiNpormdYBl+Pha50gOUovT18IvAe7EYMZ1/f9W/WWMPRn+xI68yXNMUk3QXHDwo/1wV/4NejVNe1w==} engines: {node: '>=0.10.0'} @@ -14219,11 +12491,6 @@ packages: engines: {node: '>=0.6.0', teleport: '>=0.2.0'} dev: false - /q@1.5.1: - resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} - engines: {node: '>=0.6.0', teleport: '>=0.2.0'} - dev: false - /qrcode-generator@1.4.4: resolution: {integrity: sha512-HM7yY8O2ilqhmULxGMpcHSF1EhJJ9yBj8gvDEuZ6M+KGJ0YY2hKpnXvRD+hZPLrDVck3ExIGhmPtSdcjC+guuw==} dev: true @@ -14251,14 +12518,6 @@ packages: side-channel: 1.0.6 dev: false - /query-string@4.3.4: - resolution: {integrity: sha512-O2XLNDBIg1DnTOa+2XrIwSiXEV8h2KImXUnjhhn2+UsvZ+Es2uyd5CCRTNQlDGbzUQOW3aYCBx9rVA6dzsiY7Q==} - engines: {node: '>=0.10.0'} - dependencies: - object-assign: 4.1.1 - strict-uri-encode: 1.1.0 - dev: false - /querystring@0.2.0: resolution: {integrity: sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==} engines: {node: '>=0.4.x'} @@ -14328,14 +12587,6 @@ packages: resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} dev: true - /read-pkg-up@1.0.1: - resolution: {integrity: sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==} - engines: {node: '>=0.10.0'} - dependencies: - find-up: 1.1.2 - read-pkg: 1.1.0 - dev: false - /read-pkg-up@7.0.1: resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} engines: {node: '>=8'} @@ -14345,15 +12596,6 @@ packages: type-fest: 0.8.1 dev: true - /read-pkg@1.1.0: - resolution: {integrity: sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==} - engines: {node: '>=0.10.0'} - dependencies: - load-json-file: 1.1.0 - normalize-package-data: 2.5.0 - path-type: 1.1.0 - dev: false - /read-pkg@5.2.0: resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} engines: {node: '>=8'} @@ -14406,17 +12648,6 @@ packages: minimatch: 5.1.6 dev: false - /readdirp@2.2.1: - resolution: {integrity: sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==} - engines: {node: '>=0.10'} - dependencies: - graceful-fs: 4.2.11 - micromatch: 3.1.10 - readable-stream: 2.3.8 - transitivePeerDependencies: - - supports-color - dev: false - /readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -14424,13 +12655,6 @@ packages: picomatch: 2.3.1 dev: true - /rechoir@0.6.2: - resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} - engines: {node: '>= 0.10'} - dependencies: - resolve: 1.22.8 - dev: false - /reconnecting@4.4.1: resolution: {integrity: sha512-2GU8WqGpWVB0FcqJNbTDdRVSTw8W2205r+tWx8EVkFa8Oi5N2pbJeNPm9jHQNjDeQcqVILRNZfUX2RRHu6Zdog==} dev: false @@ -14473,20 +12697,6 @@ packages: - supports-color dev: false - /reduce-css-calc@1.3.0: - resolution: {integrity: sha512-0dVfwYVOlf/LBA2ec4OwQ6p3X9mYxn/wOl2xTcLwjnPYrkgEfPx3VI4eGCH3rQLlPISG5v9I9bkZosKsNRTRKA==} - dependencies: - balanced-match: 0.4.2 - math-expression-evaluator: 1.4.0 - reduce-function-call: 1.0.3 - dev: false - - /reduce-function-call@1.0.3: - resolution: {integrity: sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ==} - dependencies: - balanced-match: 1.0.2 - dev: false - /reflect-metadata@0.2.2: resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} dev: false @@ -14499,14 +12709,6 @@ packages: resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} dev: true - /regex-not@1.0.2: - resolution: {integrity: sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==} - engines: {node: '>=0.10.0'} - dependencies: - extend-shallow: 3.0.2 - safe-regex: 1.1.0 - dev: false - /regexp-tree@0.1.27: resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} hasBin: true @@ -14533,27 +12735,6 @@ packages: jsesc: 0.5.0 dev: true - /remove-bom-buffer@3.0.0: - resolution: {integrity: sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==} - engines: {node: '>=0.10.0'} - dependencies: - is-buffer: 1.1.6 - is-utf8: 0.2.1 - dev: false - - /remove-bom-stream@1.2.0: - resolution: {integrity: sha512-wigO8/O08XHb8YPzpDDT+QmRANfW6vLqxfaXm1YXhnFf3AkSLyjfG3GEFg4McZkmgL7KvCj5u2KczkvSP6NfHA==} - engines: {node: '>= 0.10'} - dependencies: - remove-bom-buffer: 3.0.0 - safe-buffer: 5.2.1 - through2: 2.0.5 - dev: false - - /remove-trailing-separator@1.1.0: - resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==} - dev: false - /rename@1.0.4: resolution: {integrity: sha512-YMM6Fn3lrFOCjhORKjj+z/yizj8WSzv3F3YUlpJA20fteWCb0HbJU19nvuRBPUM5dWgxJcHP+kix3M+5NowJyA==} dependencies: @@ -14562,38 +12743,6 @@ packages: - supports-color dev: false - /repeat-element@1.1.4: - resolution: {integrity: sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==} - engines: {node: '>=0.10.0'} - dev: false - - /repeat-string@1.6.1: - resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} - engines: {node: '>=0.10'} - dev: false - - /replace-ext@1.0.1: - resolution: {integrity: sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==} - engines: {node: '>= 0.10'} - dev: false - - /replace-homedir@1.0.0: - resolution: {integrity: sha512-CHPV/GAglbIB1tnQgaiysb8H2yCy8WQ7lcEwQ/eT+kLj0QHV8LnJW0zpqpE7RSkrMSRoa+EBoag86clf7WAgSg==} - engines: {node: '>= 0.10'} - dependencies: - homedir-polyfill: 1.0.3 - is-absolute: 1.0.0 - remove-trailing-separator: 1.1.0 - dev: false - - /replacestream@4.0.3: - resolution: {integrity: sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA==} - dependencies: - escape-string-regexp: 1.0.5 - object-assign: 4.1.1 - readable-stream: 2.3.8 - dev: false - /require-all@3.0.0: resolution: {integrity: sha512-jPGN876lc5exWYrMcgZSd7U42P0PmVQzxnQB13fCSzmyGnqQWW4WUz5DosZ/qe24hz+5o9lSvW2epBNZ1xa6Fw==} engines: {node: '>= 0.8'} @@ -14608,10 +12757,6 @@ packages: engines: {node: '>=0.10.0'} dev: false - /require-main-filename@1.0.1: - resolution: {integrity: sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==} - dev: false - /require-main-filename@2.0.0: resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} @@ -14625,14 +12770,6 @@ packages: resolve-from: 5.0.0 dev: true - /resolve-dir@1.0.1: - resolution: {integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==} - engines: {node: '>=0.10.0'} - dependencies: - expand-tilde: 2.0.2 - global-modules: 1.0.0 - dev: false - /resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -14643,13 +12780,6 @@ packages: engines: {node: '>=8'} dev: true - /resolve-options@1.1.0: - resolution: {integrity: sha512-NYDgziiroVeDC29xq7bp/CacZERYsA9bXYd1ZmcJlF3BcrZv5pTb4NG7SjdyKDnXZ84aC4vo2u6sNKIA1LCu/A==} - engines: {node: '>= 0.10'} - dependencies: - value-or-function: 3.0.0 - dev: false - /resolve-path@1.4.0: resolution: {integrity: sha512-i1xevIst/Qa+nA9olDxLWnLk8YZbi8R/7JPbCMcgyWaFR6bKWaexgJgEB5oc2PKMjYdrHynyz0NY+if+H98t1w==} engines: {node: '>= 0.8'} @@ -14662,11 +12792,6 @@ packages: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} dev: true - /resolve-url@0.2.1: - resolution: {integrity: sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==} - deprecated: https://github.com/lydell/resolve-url#deprecated - dev: false - /resolve.exports@2.0.2: resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} engines: {node: '>=10'} @@ -14694,6 +12819,7 @@ packages: is-core-module: 2.13.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + dev: true /responselike@2.0.1: resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} @@ -14715,11 +12841,6 @@ packages: signal-exit: 3.0.7 dev: true - /ret@0.1.15: - resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==} - engines: {node: '>=0.12'} - dev: false - /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -14806,12 +12927,6 @@ packages: is-regex: 1.1.4 dev: true - /safe-regex@1.1.0: - resolution: {integrity: sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==} - dependencies: - ret: 0.1.15 - dev: false - /safe-regex@2.1.1: resolution: {integrity: sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==} dependencies: @@ -14873,13 +12988,6 @@ packages: commander: 2.20.3 dev: false - /semver-greatest-satisfied-range@1.1.0: - resolution: {integrity: sha512-Ny/iyOzSSa8M5ML46IAx3iXc6tfOsYU2R4AXi2UpHk60Zrgyq6eqPj/xiOfS0rRl/iiQ/rdJkVjw/5cdUyCntQ==} - engines: {node: '>= 0.10'} - dependencies: - sver-compat: 1.5.0 - dev: false - /semver-regex@4.0.5: resolution: {integrity: sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==} engines: {node: '>=12'} @@ -14895,6 +13003,7 @@ packages: /semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true + dev: true /semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} @@ -14933,16 +13042,6 @@ packages: gopd: 1.0.1 has-property-descriptors: 1.0.2 - /set-value@2.0.1: - resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==} - engines: {node: '>=0.10.0'} - dependencies: - extend-shallow: 2.0.1 - is-extendable: 0.1.1 - is-plain-object: 2.0.4 - split-string: 3.1.0 - dev: false - /setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} dev: false @@ -15075,38 +13174,6 @@ packages: engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} dev: false - /snapdragon-node@2.1.1: - resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==} - engines: {node: '>=0.10.0'} - dependencies: - define-property: 1.0.0 - isobject: 3.0.1 - snapdragon-util: 3.0.1 - dev: false - - /snapdragon-util@3.0.1: - resolution: {integrity: sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==} - engines: {node: '>=0.10.0'} - dependencies: - kind-of: 3.2.2 - dev: false - - /snapdragon@0.8.2: - resolution: {integrity: sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==} - engines: {node: '>=0.10.0'} - dependencies: - base: 0.11.2 - debug: 2.6.9 - define-property: 0.2.5 - extend-shallow: 2.0.1 - map-cache: 0.2.2 - source-map: 0.5.7 - source-map-resolve: 0.5.3 - use: 3.1.1 - transitivePeerDependencies: - - supports-color - dev: false - /socks-proxy-agent@7.0.0: resolution: {integrity: sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==} engines: {node: '>= 10'} @@ -15138,6 +13205,7 @@ packages: engines: {node: '>=0.10.0'} dependencies: is-plain-obj: 1.1.0 + dev: true /source-map-js@1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} @@ -15148,17 +13216,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /source-map-resolve@0.5.3: - resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==} - deprecated: See https://github.com/lydell/source-map-resolve#deprecated - dependencies: - atob: 2.1.2 - decode-uri-component: 0.2.2 - resolve-url: 0.2.1 - source-map-url: 0.4.1 - urix: 0.1.0 - dev: false - /source-map-resolve@0.6.0: resolution: {integrity: sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==} deprecated: See https://github.com/lydell/source-map-resolve#deprecated @@ -15179,45 +13236,35 @@ packages: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 - - /source-map-url@0.4.1: - resolution: {integrity: sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==} - deprecated: See https://github.com/lydell/source-map-url#deprecated - dev: false - - /source-map@0.5.7: - resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} - engines: {node: '>=0.10.0'} - dev: false + dev: true /source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + dev: true /source-map@0.7.4: resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} engines: {node: '>= 8'} dev: true - /sparkles@1.0.1: - resolution: {integrity: sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==} - engines: {node: '>= 0.10'} - dev: false - /spdx-correct@3.2.0: resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} dependencies: spdx-expression-parse: 3.0.1 spdx-license-ids: 3.0.16 + dev: true /spdx-exceptions@2.3.0: resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} + dev: true /spdx-expression-parse@3.0.1: resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} dependencies: spdx-exceptions: 2.3.0 spdx-license-ids: 3.0.16 + dev: true /spdx-expression-parse@4.0.0: resolution: {integrity: sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==} @@ -15228,13 +13275,7 @@ packages: /spdx-license-ids@3.0.16: resolution: {integrity: sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==} - - /split-string@3.1.0: - resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==} - engines: {node: '>=0.10.0'} - dependencies: - extend-shallow: 3.0.2 - dev: false + dev: true /split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} @@ -15243,6 +13284,7 @@ packages: /sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + dev: true /sprintf-js@1.1.3: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} @@ -15264,10 +13306,6 @@ packages: tweetnacl: 0.14.5 dev: false - /stack-trace@0.0.10: - resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} - dev: false - /stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} @@ -15279,14 +13317,6 @@ packages: resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} dev: false - /static-extend@0.1.2: - resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==} - engines: {node: '>=0.10.0'} - dependencies: - define-property: 0.2.5 - object-copy: 0.1.0 - dev: false - /statuses@1.5.0: resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} engines: {node: '>= 0.6'} @@ -15297,9 +13327,6 @@ packages: engines: {node: '>= 0.8'} dev: false - /stream-exhaust@1.0.2: - resolution: {integrity: sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==} - /stream-parser@0.3.1: resolution: {integrity: sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==} dependencies: @@ -15327,11 +13354,6 @@ packages: resolution: {integrity: sha512-Nk/brWYpD85WlOgzw5h173aci0Teyv8YdIAEtV+N88nDB0dLlazZyJMIsN6eo1/AR61l+p6CJTG1JIyFaoNEEA==} dev: true - /strict-uri-encode@1.1.0: - resolution: {integrity: sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==} - engines: {node: '>=0.10.0'} - dev: false - /string-length@4.0.2: resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} engines: {node: '>=10'} @@ -15340,15 +13362,6 @@ packages: strip-ansi: 6.0.1 dev: true - /string-width@1.0.2: - resolution: {integrity: sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==} - engines: {node: '>=0.10.0'} - dependencies: - code-point-at: 1.1.0 - is-fullwidth-code-point: 1.0.0 - strip-ansi: 3.0.1 - dev: false - /string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -15406,13 +13419,6 @@ packages: dependencies: char-regex: 1.0.2 - /strip-ansi@3.0.1: - resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} - engines: {node: '>=0.10.0'} - dependencies: - ansi-regex: 2.1.1 - dev: false - /strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -15426,13 +13432,6 @@ packages: ansi-regex: 6.0.1 dev: false - /strip-bom@2.0.0: - resolution: {integrity: sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==} - engines: {node: '>=0.10.0'} - dependencies: - is-utf8: 0.2.1 - dev: false - /strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} @@ -15524,18 +13523,6 @@ packages: - supports-color dev: false - /supports-color@2.0.0: - resolution: {integrity: sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==} - engines: {node: '>=0.8.0'} - dev: false - - /supports-color@3.2.3: - resolution: {integrity: sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==} - engines: {node: '>=0.8.0'} - dependencies: - has-flag: 1.0.0 - dev: false - /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -15566,28 +13553,6 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - /sver-compat@1.5.0: - resolution: {integrity: sha512-aFTHfmjwizMNlNE6dsGmoAM4lHjL0CyiobWaFiXWSlD7cIxshW422Nb8KbXCmR6z+0ZEPY+daXJrDyh/vuwTyg==} - dependencies: - es6-iterator: 2.0.3 - es6-symbol: 3.1.3 - dev: false - - /svgo@0.7.2: - resolution: {integrity: sha512-jT/g9FFMoe9lu2IT6HtAxTA7RR2XOrmcrmCtGnyB/+GQnV6ZjNn+KOHZbZ35yL81+1F/aB6OeEsJztzBQ2EEwA==} - engines: {node: '>=0.10.0'} - deprecated: This SVGO version is no longer supported. Upgrade to v2.x.x. - hasBin: true - dependencies: - coa: 1.0.4 - colors: 1.1.2 - csso: 2.3.2 - js-yaml: 3.7.0 - mkdirp: 0.5.6 - sax: 1.2.4 - whet.extend: 0.9.9 - dev: false - /swc-loader@0.2.6(@swc/core@1.5.0)(webpack@5.91.0): resolution: {integrity: sha512-9Zi9UP2YmDpgmQVbyOPJClY0dwf58JDyDMQ7uRc4krmc72twNI2fvlBWHLqVekBpPc7h5NJkGVT1zNDxFrqhvg==} peerDependencies: @@ -15692,17 +13657,6 @@ packages: webpack: 5.91.0(@swc/core@1.5.0) dev: true - /terser@5.19.2: - resolution: {integrity: sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==} - engines: {node: '>=10'} - hasBin: true - dependencies: - '@jridgewell/source-map': 0.3.5 - acorn: 8.10.0 - commander: 2.20.3 - source-map-support: 0.5.21 - dev: false - /terser@5.27.0: resolution: {integrity: sha512-bi1HRwVRskAjheeYl291n3JC4GgO/Ty4z1nVs5AAsmonJulGxpSektecnNedrwK9C7vpvVtcX3cw00VSLt7U2A==} engines: {node: '>=10'} @@ -15753,11 +13707,6 @@ packages: resolution: {integrity: sha512-cXAvzO9pP5CGa6NKx0WYHl+8CHKZs8byMkt3PCJBCmq2a34YA9pO1NrQET5pzeqnBjBdToF5No4rrmkDUgQC2Q==} dev: true - /textextensions@3.3.0: - resolution: {integrity: sha512-mk82dS8eRABNbeVJrEiN5/UMSCliINAuz8mkUwH4SwslkNP//gbEzlWNS5au0z5Dpx40SQxzqZevZkn+WYJ9Dw==} - engines: {node: '>=8'} - dev: false - /thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} engines: {node: '>=0.8'} @@ -15780,13 +13729,6 @@ packages: engines: {node: '>=12.22'} dev: true - /through2-filter@3.0.0: - resolution: {integrity: sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==} - dependencies: - through2: 2.0.5 - xtend: 4.0.2 - dev: false - /through2@2.0.5: resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} dependencies: @@ -15794,21 +13736,10 @@ packages: xtend: 4.0.2 dev: false - /through2@4.0.2: - resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} - dependencies: - readable-stream: 3.6.2 - dev: false - /through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} dev: false - /time-stamp@1.1.0: - resolution: {integrity: sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==} - engines: {node: '>=0.10.0'} - dev: false - /tinycolor2@1.6.0: resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} @@ -15827,14 +13758,6 @@ packages: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} dev: true - /to-absolute-glob@2.0.2: - resolution: {integrity: sha512-rtwLUQEwT8ZeKQbyFJyomBRYXyE16U5VKuy0ftxLMK/PZb2fkOsg5r9kHdauuVDbsNdIBoC/HCthpidamQFXYA==} - engines: {node: '>=0.10.0'} - dependencies: - is-absolute: 1.0.0 - is-negated-glob: 1.0.0 - dev: false - /to-buffer@1.1.1: resolution: {integrity: sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==} dev: false @@ -15843,21 +13766,6 @@ packages: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} engines: {node: '>=4'} - /to-object-path@0.3.0: - resolution: {integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==} - engines: {node: '>=0.10.0'} - dependencies: - kind-of: 3.2.2 - dev: false - - /to-regex-range@2.1.1: - resolution: {integrity: sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==} - engines: {node: '>=0.10.0'} - dependencies: - is-number: 3.0.0 - repeat-string: 1.6.1 - dev: false - /to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -15865,23 +13773,6 @@ packages: is-number: 7.0.0 dev: true - /to-regex@3.0.2: - resolution: {integrity: sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==} - engines: {node: '>=0.10.0'} - dependencies: - define-property: 2.0.2 - extend-shallow: 3.0.2 - regex-not: 1.0.2 - safe-regex: 1.1.0 - dev: false - - /to-through@2.0.0: - resolution: {integrity: sha512-+QIz37Ly7acM4EMdw2PRN389OneM5+d844tirkGp4dPKzI5OE72V9OsbFp+CIYJDahZ41ZV05hNtcPAQUAm9/Q==} - engines: {node: '>= 0.10'} - dependencies: - through2: 2.0.5 - dev: false - /toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} @@ -16354,32 +14245,6 @@ packages: through: 2.3.8 dev: false - /unc-path-regex@0.1.2: - resolution: {integrity: sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==} - engines: {node: '>=0.10.0'} - dev: false - - /undertaker-registry@1.0.1: - resolution: {integrity: sha512-UR1khWeAjugW3548EfQmL9Z7pGMlBgXteQpr1IZeZBtnkCJQJIJ1Scj0mb9wQaPvUZ9Q17XqW6TIaPchJkyfqw==} - engines: {node: '>= 0.10'} - dev: false - - /undertaker@1.3.0: - resolution: {integrity: sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg==} - engines: {node: '>= 0.10'} - dependencies: - arr-flatten: 1.1.0 - arr-map: 2.0.2 - bach: 1.2.0 - collection-map: 1.0.0 - es6-weak-map: 2.0.3 - fast-levenshtein: 1.1.4 - last-run: 1.1.1 - object.defaults: 1.1.0 - object.reduce: 1.0.1 - undertaker-registry: 1.0.1 - dev: false - /undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} @@ -16394,31 +14259,6 @@ packages: resolution: {integrity: sha512-tAYF+EsOxa8jo/XPNYHRX7Nc8uoII+/edIpHM4DQI4nMp3AuRmwGZhL8fEBe0kUk0zHK+6wiwxxxNwfW5ap2Tg==} dev: true - /union-value@1.0.1: - resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==} - engines: {node: '>=0.10.0'} - dependencies: - arr-union: 3.1.0 - get-value: 2.0.6 - is-extendable: 0.1.1 - set-value: 2.0.1 - dev: false - - /uniq@1.0.1: - resolution: {integrity: sha512-Gw+zz50YNKPDKXs+9d+aKAjVwpjNwqzvNpLigIruT4HA9lMZNdMqs9x07kKHB/L9WRzqp4+DlTU5s4wG2esdoA==} - dev: false - - /uniqs@2.0.0: - resolution: {integrity: sha512-mZdDpf3vBV5Efh29kMw5tXoup/buMgxLzOt/XKFKcVmi+15ManNQWr6HfZ2aiZTYlYixbdNJ0KFmIZIv52tHSQ==} - dev: false - - /unique-stream@2.3.1: - resolution: {integrity: sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==} - dependencies: - json-stable-stringify-without-jsonify: 1.0.1 - through2-filter: 3.0.0 - dev: false - /unist-util-stringify-position@2.0.3: resolution: {integrity: sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==} dependencies: @@ -16444,19 +14284,6 @@ packages: engines: {node: '>= 0.8'} dev: false - /unset-value@1.0.0: - resolution: {integrity: sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==} - engines: {node: '>=0.10.0'} - dependencies: - has-value: 0.3.1 - isobject: 3.0.1 - dev: false - - /upath@1.2.0: - resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==} - engines: {node: '>=4'} - dev: false - /update-browserslist-db@1.0.13(browserslist@4.22.1): resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} hasBin: true @@ -16483,11 +14310,6 @@ packages: dependencies: punycode: 2.3.1 - /urix@0.1.0: - resolution: {integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==} - deprecated: Please see https://github.com/lydell/urix#deprecated - dev: false - /url-polyfill@1.1.12: resolution: {integrity: sha512-mYFmBHCapZjtcNHW0MDq9967t+z4Dmg5CJ0KqysK3+ZbyoNOWQHksGCTWwDhxGXllkWlOc10Xfko6v4a3ucM6A==} dev: true @@ -16499,11 +14321,6 @@ packages: querystring: 0.2.0 dev: false - /use@3.1.1: - resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==} - engines: {node: '>=0.10.0'} - dev: false - /utf-8-validate@5.0.10: resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} engines: {node: '>=6.14.2'} @@ -16556,33 +14373,18 @@ packages: convert-source-map: 2.0.0 dev: true - /v8flags@3.2.0: - resolution: {integrity: sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==} - engines: {node: '>= 0.10'} - dependencies: - homedir-polyfill: 1.0.3 - dev: false - /validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} dependencies: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 - - /value-or-function@3.0.0: - resolution: {integrity: sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg==} - engines: {node: '>= 0.10'} - dev: false + dev: true /vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} dev: false - /vendors@1.0.4: - resolution: {integrity: sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==} - dev: false - /verror@1.10.0: resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} engines: {'0': node >=0.6.0} @@ -16592,60 +14394,6 @@ packages: extsprintf: 1.3.0 dev: false - /vinyl-fs@3.0.3: - resolution: {integrity: sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==} - engines: {node: '>= 0.10'} - dependencies: - fs-mkdirp-stream: 1.0.0 - glob-stream: 6.1.0 - graceful-fs: 4.2.11 - is-valid-glob: 1.0.0 - lazystream: 1.0.1 - lead: 1.0.0 - object.assign: 4.1.4 - pumpify: 1.5.1 - readable-stream: 2.3.8 - remove-bom-buffer: 3.0.0 - remove-bom-stream: 1.2.0 - resolve-options: 1.1.0 - through2: 2.0.5 - to-through: 2.0.0 - value-or-function: 3.0.0 - vinyl: 2.2.1 - vinyl-sourcemap: 1.1.0 - dev: false - - /vinyl-sourcemap@1.1.0: - resolution: {integrity: sha512-NiibMgt6VJGJmyw7vtzhctDcfKch4e4n9TBeoWlirb7FMg9/1Ov9k+A5ZRAtywBpRPiyECvQRQllYM8dECegVA==} - engines: {node: '>= 0.10'} - dependencies: - append-buffer: 1.0.2 - convert-source-map: 1.9.0 - graceful-fs: 4.2.11 - normalize-path: 2.1.1 - now-and-later: 2.0.1 - remove-bom-buffer: 3.0.0 - vinyl: 2.2.1 - dev: false - - /vinyl-sourcemaps-apply@0.2.1: - resolution: {integrity: sha512-+oDh3KYZBoZC8hfocrbrxbLUeaYtQK7J5WU5Br9VqWqmCll3tFJqKp97GC9GmMsVIL0qnx2DgEDVxdo5EZ5sSw==} - dependencies: - source-map: 0.5.7 - dev: false - - /vinyl@2.2.1: - resolution: {integrity: sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==} - engines: {node: '>= 0.10'} - dependencies: - clone: 2.1.2 - clone-buffer: 1.0.0 - clone-stats: 1.0.0 - cloneable-readable: 1.1.3 - remove-trailing-separator: 1.1.0 - replace-ext: 1.0.1 - dev: false - /vite-plugin-compression@0.5.1(vite@5.2.10): resolution: {integrity: sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg==} peerDependencies: @@ -16954,11 +14702,6 @@ packages: tr46: 0.0.3 webidl-conversions: 3.0.1 - /whet.extend@0.9.9: - resolution: {integrity: sha512-mmIPAft2vTgEILgPeZFqE/wWh24SEsR/k+N9fJ3Jxrz44iDFy9aemCxdksfURSHYFCLmvs/d/7Iso5XjPpNfrA==} - engines: {node: '>=0.6.0'} - dev: false - /which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} dependencies: @@ -16969,10 +14712,6 @@ packages: is-symbol: 1.0.4 dev: true - /which-module@1.0.0: - resolution: {integrity: sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==} - dev: false - /which-module@2.0.1: resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} @@ -17024,14 +14763,6 @@ packages: resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==} dev: true - /wrap-ansi@2.1.0: - resolution: {integrity: sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==} - engines: {node: '>=0.10.0'} - dependencies: - string-width: 1.0.2 - strip-ansi: 3.0.1 - dev: false - /wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} @@ -17135,10 +14866,6 @@ packages: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} - /y18n@3.2.2: - resolution: {integrity: sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==} - dev: false - /y18n@4.0.3: resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} @@ -17199,13 +14926,6 @@ packages: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} - /yargs-parser@5.0.1: - resolution: {integrity: sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==} - dependencies: - camelcase: 3.0.0 - object.assign: 4.1.4 - dev: false - /yargs-unparser@2.0.0: resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} engines: {node: '>=10'} @@ -17256,24 +14976,6 @@ packages: y18n: 5.0.8 yargs-parser: 21.1.1 - /yargs@7.1.2: - resolution: {integrity: sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==} - dependencies: - camelcase: 3.0.0 - cliui: 3.2.0 - decamelize: 1.2.0 - get-caller-file: 1.0.3 - os-locale: 1.4.0 - read-pkg-up: 1.0.1 - require-directory: 2.1.1 - require-main-filename: 1.0.1 - set-blocking: 2.0.0 - string-width: 1.0.2 - which-module: 1.0.0 - y18n: 3.2.2 - yargs-parser: 5.0.1 - dev: false - /yauzl@2.10.0: resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} dependencies: diff --git a/scripts/copy-assets.mjs b/scripts/copy-assets.mjs new file mode 100644 index 0000000000..6542780d83 --- /dev/null +++ b/scripts/copy-assets.mjs @@ -0,0 +1,35 @@ +import fs from "node:fs/promises"; + +await (async () => { + await Promise.all([ + fs.cp("packages/backend/src/server/web", "packages/backend/built/server/web", { recursive: true }), + fs.cp("custom/assets", "packages/backend/assets", { recursive: true }), + fs.cp("packages/client/node_modules/three/examples/fonts", "built/_client_dist_/fonts", { recursive: true }), + fs.mkdir("built/_client_dist_/locales", { recursive: true }), + ]); + + const locales = (await import("../locales/index.mjs")).default; + const meta = (await import("../built/meta.json", { assert: { type: "json" } })).default; + + for await (const [lang, locale] of Object.entries(locales)) { + await fs.writeFile( + `built/_client_dist_/locales/${lang}.${meta.version}.json`, + JSON.stringify({ ...locale, _version_: meta.version }), + "utf-8", + ); + } + + const js_assets = [ + "packages/backend/built/server/web/boot.js", + "packages/backend/built/server/web/bios.js", + "packages/backend/built/server/web/cli.js", + ]; + + for await (const js_file of js_assets) { + const content = (await fs.readFile(js_file, "utf-8")) + .replace("SUPPORTED_LANGS", JSON.stringify(Object.keys(locales))); + await fs.writeFile(js_file, content, "utf-8"); + } + + // TODO?: minify packages/backend/built/server/web/*.css +})(); diff --git a/scripts/dev.mjs b/scripts/dev.mjs index beaa11f8e0..4fcd15753b 100644 --- a/scripts/dev.mjs +++ b/scripts/dev.mjs @@ -11,12 +11,6 @@ import { execa } from "execa"; stderr: process.stderr, }); - execa("pnpm", ["dlx", "gulp", "watch"], { - cwd: join(__dirname, "/../"), - stdout: process.stdout, - stderr: process.stderr, - }); - execa("pnpm", ["--filter", "backend", "watch"], { cwd: join(__dirname, "/../"), stdout: process.stdout, From d2471b6db736af943f519994b7a5f9dc16219192 Mon Sep 17 00:00:00 2001 From: naskya Date: Sun, 5 May 2024 14:53:45 +0900 Subject: [PATCH 28/75] refactor (backend-rs): replace reqwest with isahc reqwest is feature-rich, but we will need isahc http client for push notifications (!10760) isahc http client is also good btw :) --- Cargo.lock | 544 ++++++------------ Cargo.toml | 2 +- packages/backend-rs/Cargo.toml | 2 +- .../backend-rs/src/misc/get_image_size.rs | 20 +- .../backend-rs/src/misc/latest_version.rs | 30 +- packages/backend-rs/src/util/http_client.rs | 25 +- packages/backend-rs/src/util/mod.rs | 2 - 7 files changed, 243 insertions(+), 382 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0a1d9aad18..7d90f96896 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -124,6 +124,17 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + [[package]] name = "async-stream" version = "0.3.5" @@ -207,6 +218,7 @@ dependencies = [ "emojis", "idna", "image", + "isahc", "macro_rs", "napi", "napi-build", @@ -218,7 +230,6 @@ dependencies = [ "rand", "redis", "regex", - "reqwest", "rmp-serde", "sea-orm", "serde", @@ -445,6 +456,12 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +[[package]] +name = "castaway" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6" + [[package]] name = "cc" version = "1.0.95" @@ -519,6 +536,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "const-oid" version = "0.9.6" @@ -534,16 +560,6 @@ dependencies = [ "unicode-segmentation", ] -[[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.6" @@ -661,6 +677,37 @@ dependencies = [ "sha3", ] +[[package]] +name = "curl" +version = "0.4.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e2161dd6eba090ff1594084e95fd67aeccf04382ffea77999ea94ed42ec67b6" +dependencies = [ + "curl-sys", + "libc", + "openssl-probe", + "openssl-sys", + "schannel", + "socket2", + "windows-sys 0.52.0", +] + +[[package]] +name = "curl-sys" +version = "0.4.72+curl-8.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29cbdc8314c447d11e8fd156dcdd031d9e02a7a976163e396b548c03153bc9ea" +dependencies = [ + "cc", + "libc", + "libnghttp2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", + "windows-sys 0.52.0", +] + [[package]] name = "der" version = "0.7.9" @@ -793,6 +840,15 @@ dependencies = [ "zune-inflate", ] +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + [[package]] name = "fastrand" version = "2.0.2" @@ -929,6 +985,21 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + [[package]] name = "futures-sink" version = "0.3.30" @@ -995,25 +1066,6 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" -[[package]] -name = "h2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "816ec7294445779408f36fe57bc5b7fc1cf59664059096c65f905c1c61f58069" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "half" version = "2.4.1" @@ -1108,100 +1160,15 @@ dependencies = [ [[package]] name = "http" -version = "1.1.0" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", "itoa", ] -[[package]] -name = "http-body" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" -dependencies = [ - "bytes", - "http", -] - -[[package]] -name = "http-body-util" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" -dependencies = [ - "bytes", - "futures-core", - "http", - "http-body", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "hyper" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "itoa", - "pin-project-lite", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - -[[package]] -name = "hyper-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "http", - "http-body", - "hyper", - "pin-project-lite", - "socket2", - "tokio", - "tower", - "tower-service", - "tracing", -] - [[package]] name = "iana-time-zone" version = "0.1.60" @@ -1304,6 +1271,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + [[package]] name = "interpolate_name" version = "0.2.4" @@ -1316,10 +1292,31 @@ dependencies = [ ] [[package]] -name = "ipnet" -version = "2.9.0" +name = "isahc" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "334e04b4d781f436dc315cb1e7515bd96826426345d498149e4bde36b67f8ee9" +dependencies = [ + "async-channel", + "castaway", + "crossbeam-utils", + "curl", + "curl-sys", + "encoding_rs", + "event-listener", + "futures-lite", + "http", + "log", + "mime", + "once_cell", + "polling", + "slab", + "sluice", + "tracing", + "tracing-futures", + "url", + "waker-fn", +] [[package]] name = "itertools" @@ -1417,6 +1414,16 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "libnghttp2-sys" +version = "0.1.10+1.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "959c25552127d2e1fa72f0e52548ec04fc386e827ba71a7bd01db46a447dc135" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "libsqlite3-sys" version = "0.27.0" @@ -1428,6 +1435,18 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "libz-sys" +version = "1.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e143b5e666b2695d28f6bca6497720813f699c9602dd7f5cac91008b8ada7f9" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.4.13" @@ -1591,24 +1610,6 @@ dependencies = [ "libloading", ] -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "new_debug_unreachable" version = "1.0.6" @@ -1881,6 +1882,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + [[package]] name = "parking_lot" version = "0.12.2" @@ -2026,6 +2033,22 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -2330,49 +2353,6 @@ dependencies = [ "bytecheck", ] -[[package]] -name = "reqwest" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" -dependencies = [ - "base64 0.22.0", - "bytes", - "encoding_rs", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-tls", - "hyper-util", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls-pemfile 2.1.2", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "system-configuration", - "tokio", - "tokio-native-tls", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "winreg", -] - [[package]] name = "rgb" version = "0.8.37" @@ -2523,22 +2503,6 @@ dependencies = [ "base64 0.21.7", ] -[[package]] -name = "rustls-pemfile" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" -dependencies = [ - "base64 0.22.0", - "rustls-pki-types", -] - -[[package]] -name = "rustls-pki-types" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beb461507cee2c2ff151784c52762cf4d9ff6a61f3e80968600ed24fa837fa54" - [[package]] name = "rustls-webpki" version = "0.101.7" @@ -2680,29 +2644,6 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" -[[package]] -name = "security-framework" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "semver" version = "1.0.22" @@ -2749,18 +2690,6 @@ dependencies = [ "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_yaml" version = "0.9.34+deprecated" @@ -2876,6 +2805,17 @@ dependencies = [ "autocfg", ] +[[package]] +name = "sluice" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7400c0eff44aa2fcb5e31a5f24ba9716ed90138769e4977a2ba6014ae63eb5" +dependencies = [ + "async-channel", + "futures-core", + "futures-io", +] + [[package]] name = "smallvec" version = "1.13.2" @@ -2972,7 +2912,7 @@ dependencies = [ "percent-encoding", "rust_decimal", "rustls", - "rustls-pemfile 1.0.4", + "rustls-pemfile", "serde", "serde_json", "sha2", @@ -3229,33 +3169,6 @@ dependencies = [ "syn 2.0.60", ] -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "system-deps" version = "6.2.2" @@ -3288,7 +3201,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", - "fastrand", + "fastrand 2.0.2", "rustix", "windows-sys 0.52.0", ] @@ -3410,16 +3323,6 @@ dependencies = [ "syn 2.0.60", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-stream" version = "0.1.15" @@ -3431,20 +3334,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-util" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - [[package]] name = "toml" version = "0.8.12" @@ -3490,34 +3379,6 @@ dependencies = [ "winnow 0.6.7", ] -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "pin-project", - "pin-project-lite", - "tokio", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-layer" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - [[package]] name = "tracing" version = "0.1.40" @@ -3551,6 +3412,16 @@ dependencies = [ "valuable", ] +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + [[package]] name = "tracing-log" version = "0.2.0" @@ -3576,12 +3447,6 @@ dependencies = [ "tracing-log", ] -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - [[package]] name = "typenum" version = "1.17.0" @@ -3695,13 +3560,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] -name = "want" -version = "0.3.1" +name = "waker-fn" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] +checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" [[package]] name = "wasi" @@ -3740,18 +3602,6 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "wasm-bindgen-macro" version = "0.2.92" @@ -3781,16 +3631,6 @@ version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" -[[package]] -name = "web-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "webpki-roots" version = "0.25.4" @@ -4001,16 +3841,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "winreg" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - [[package]] name = "wyz" version = "0.5.1" diff --git a/Cargo.toml b/Cargo.toml index 74d032aeae..449f9dccb6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ cuid2 = "0.1.2" emojis = "0.6.2" idna = "0.5.0" image = "0.25.1" +isahc = "1.7.2" nom-exif = "1.2.0" once_cell = "1.19.0" openssl = "0.10.64" @@ -27,7 +28,6 @@ quote = "1.0.36" rand = "0.8.5" redis = "0.25.3" regex = "1.10.4" -reqwest = "0.12.4" rmp-serde = "1.2.0" sea-orm = "0.12.15" serde = "1.0.198" diff --git a/packages/backend-rs/Cargo.toml b/packages/backend-rs/Cargo.toml index 5fcf7550dd..936fc525cf 100644 --- a/packages/backend-rs/Cargo.toml +++ b/packages/backend-rs/Cargo.toml @@ -26,13 +26,13 @@ cuid2 = { workspace = true } emojis = { workspace = true } idna = { workspace = true } image = { workspace = true } +isahc = { workspace = true } nom-exif = { workspace = true } once_cell = { workspace = true } openssl = { workspace = true, features = ["vendored"] } rand = { workspace = true } redis = { workspace = true } regex = { workspace = true } -reqwest = { workspace = true, features = ["blocking"] } rmp-serde = { workspace = true } sea-orm = { workspace = true, features = ["sqlx-postgres", "runtime-tokio-rustls"] } serde = { workspace = true, features = ["derive"] } diff --git a/packages/backend-rs/src/misc/get_image_size.rs b/packages/backend-rs/src/misc/get_image_size.rs index 9b3e20171c..60cf84aec1 100644 --- a/packages/backend-rs/src/misc/get_image_size.rs +++ b/packages/backend-rs/src/misc/get_image_size.rs @@ -1,6 +1,7 @@ use crate::database::cache; use crate::util::http_client; use image::{io::Reader, ImageError, ImageFormat}; +use isahc::ReadResponseExt; use nom_exif::{parse_jpeg_exif, EntryValue, ExifTag}; use std::io::Cursor; use tokio::sync::Mutex; @@ -9,8 +10,12 @@ use tokio::sync::Mutex; pub enum Error { #[error("Redis cache error: {0}")] CacheErr(#[from] cache::Error), - #[error("Reqwest error: {0}")] - ReqwestErr(#[from] reqwest::Error), + #[error("HTTP client aquisition error: {0}")] + HttpClientErr(#[from] http_client::Error), + #[error("Isahc error: {0}")] + IsahcErr(#[from] isahc::Error), + #[error("HTTP error: {0}")] + HttpErr(String), #[error("Image decoding error: {0}")] ImageErr(#[from] ImageError), #[error("Image decoding error: {0}")] @@ -64,7 +69,16 @@ pub async fn get_image_size_from_url(url: &str) -> Result { tracing::info!("retrieving image size from {}", url); - let image_bytes = http_client()?.get(url).send().await?.bytes().await?; + let mut response = http_client::client()?.get(url)?; + + if !response.status().is_success() { + tracing::info!("status: {}", response.status()); + tracing::debug!("response body: {:#?}", response.body()); + return Err(Error::HttpErr(format!("Failed to get image from {}", url))); + } + + let image_bytes = response.bytes()?; + let reader = Reader::new(Cursor::new(&image_bytes)).with_guessed_format()?; let format = reader.format(); diff --git a/packages/backend-rs/src/misc/latest_version.rs b/packages/backend-rs/src/misc/latest_version.rs index 2b56f31055..5d3df0b6a8 100644 --- a/packages/backend-rs/src/misc/latest_version.rs +++ b/packages/backend-rs/src/misc/latest_version.rs @@ -1,13 +1,20 @@ use crate::database::cache; -use crate::util::http_client::http_client; +use crate::util::http_client; +use isahc::ReadResponseExt; use serde::{Deserialize, Serialize}; #[derive(thiserror::Error, Debug)] pub enum Error { #[error("Cache error: {0}")] CacheErr(#[from] cache::Error), - #[error("Reqwest error: {0}")] - ReqwestErr(#[from] reqwest::Error), + #[error("Isahc error: {0}")] + IsahcErr(#[from] isahc::Error), + #[error("HTTP client aquisition error: {0}")] + HttpClientErr(#[from] http_client::Error), + #[error("HTTP error: {0}")] + HttpErr(String), + #[error("Response parsing error: {0}")] + IoErr(#[from] std::io::Error), #[error("Failed to deserialize JSON: {0}")] JsonErr(#[from] serde_json::Error), } @@ -21,13 +28,16 @@ async fn get_latest_version() -> Result { version: String, } - let res = http_client()? - .get(UPSTREAM_PACKAGE_JSON_URL) - .send() - .await? - .text() - .await?; - let res_parsed: Response = serde_json::from_str(&res)?; + let mut response = http_client::client()? + .get(UPSTREAM_PACKAGE_JSON_URL)?; + + if !response.status().is_success() { + tracing::info!("status: {}", response.status()); + tracing::debug!("response body: {:#?}", response.body()); + return Err(Error::HttpErr("Failed to fetch version from Firefish GitLab".to_string())); + } + + let res_parsed: Response = serde_json::from_str(&response.text()?)?; Ok(res_parsed.version) } diff --git a/packages/backend-rs/src/util/http_client.rs b/packages/backend-rs/src/util/http_client.rs index 143e1a2885..eb328dc41c 100644 --- a/packages/backend-rs/src/util/http_client.rs +++ b/packages/backend-rs/src/util/http_client.rs @@ -1,24 +1,33 @@ use crate::config::CONFIG; +use isahc::{config::*, HttpClient}; use once_cell::sync::OnceCell; -use reqwest::{Client, Error, NoProxy, Proxy}; use std::time::Duration; -static CLIENT: OnceCell = OnceCell::new(); +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Isahc error: {0}")] + IsahcErr(#[from] isahc::Error), + #[error("Url parse error: {0}")] + UrlParseErr(#[from] isahc::http::uri::InvalidUri), +} -pub fn http_client() -> Result { +static CLIENT: OnceCell = OnceCell::new(); + +pub fn client() -> Result { CLIENT .get_or_try_init(|| { - let mut builder = Client::builder().timeout(Duration::from_secs(5)); + let mut builder = HttpClient::builder() + .timeout(Duration::from_secs(10)) + .dns_cache(DnsCache::Timeout(Duration::from_secs(60 * 60))); if let Some(proxy_url) = &CONFIG.proxy { - let mut proxy = Proxy::all(proxy_url)?; + builder = builder.proxy(Some(proxy_url.parse()?)); if let Some(proxy_bypass_hosts) = &CONFIG.proxy_bypass_hosts { - proxy = proxy.no_proxy(NoProxy::from_string(&proxy_bypass_hosts.join(","))); + builder = builder.proxy_blacklist(proxy_bypass_hosts); } - builder = builder.proxy(proxy); } - builder.build() + Ok(builder.build()?) }) .cloned() } diff --git a/packages/backend-rs/src/util/mod.rs b/packages/backend-rs/src/util/mod.rs index 13fb8ee64b..93a5fc5ce7 100644 --- a/packages/backend-rs/src/util/mod.rs +++ b/packages/backend-rs/src/util/mod.rs @@ -1,5 +1,3 @@ -pub use http_client::http_client; - pub mod http_client; pub mod id; pub mod random; From d114b8ec1d2ecd28fe283c9fb34c37bc2539246d Mon Sep 17 00:00:00 2001 From: naskya Date: Sun, 5 May 2024 14:58:56 +0900 Subject: [PATCH 29/75] chore: format --- packages/backend-rs/src/misc/latest_version.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/backend-rs/src/misc/latest_version.rs b/packages/backend-rs/src/misc/latest_version.rs index 5d3df0b6a8..cea6901bbe 100644 --- a/packages/backend-rs/src/misc/latest_version.rs +++ b/packages/backend-rs/src/misc/latest_version.rs @@ -28,13 +28,14 @@ async fn get_latest_version() -> Result { version: String, } - let mut response = http_client::client()? - .get(UPSTREAM_PACKAGE_JSON_URL)?; + let mut response = http_client::client()?.get(UPSTREAM_PACKAGE_JSON_URL)?; if !response.status().is_success() { tracing::info!("status: {}", response.status()); tracing::debug!("response body: {:#?}", response.body()); - return Err(Error::HttpErr("Failed to fetch version from Firefish GitLab".to_string())); + return Err(Error::HttpErr( + "Failed to fetch version from Firefish GitLab".to_string(), + )); } let res_parsed: Response = serde_json::from_str(&response.text()?)?; From 5e5d01d40746ad053e9358f69eacaf7233220fbc Mon Sep 17 00:00:00 2001 From: Linca Date: Sun, 5 May 2024 11:42:25 +0000 Subject: [PATCH 30/75] fix: Click event of MenuParent unexpectedly goes to underlying element Co-authored-by: Lhcfl --- packages/client/src/components/MkMenu.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/client/src/components/MkMenu.vue b/packages/client/src/components/MkMenu.vue index a90e42fc29..b874e29d8f 100644 --- a/packages/client/src/components/MkMenu.vue +++ b/packages/client/src/components/MkMenu.vue @@ -130,7 +130,7 @@ v-else-if="item.type === 'parent'" class="_button item parent" :class="{ childShowing: childShowingItem === item }" - @mouseenter="showChildren(item, $event)" + @mouseenter.passive="showChildren(item, $event)" @click.stop="showChildren(item, $event)" > Date: Sun, 5 May 2024 20:59:26 +0900 Subject: [PATCH 31/75] fix: remove old locale files --- scripts/copy-assets.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/copy-assets.mjs b/scripts/copy-assets.mjs index 6542780d83..469c424fa9 100644 --- a/scripts/copy-assets.mjs +++ b/scripts/copy-assets.mjs @@ -1,6 +1,7 @@ import fs from "node:fs/promises"; await (async () => { + await fs.rm("built/_client_dist_/locales", { recursive: true, force: true }); await Promise.all([ fs.cp("packages/backend/src/server/web", "packages/backend/built/server/web", { recursive: true }), fs.cp("custom/assets", "packages/backend/assets", { recursive: true }), From fda81a9f91ae4563864b3d30011b12e5a51e1f37 Mon Sep 17 00:00:00 2001 From: naskya Date: Sun, 5 May 2024 21:04:20 +0900 Subject: [PATCH 32/75] chore: use absolute path for file operations --- scripts/copy-assets.mjs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/scripts/copy-assets.mjs b/scripts/copy-assets.mjs index 469c424fa9..c5bb35272c 100644 --- a/scripts/copy-assets.mjs +++ b/scripts/copy-assets.mjs @@ -1,12 +1,17 @@ import fs from "node:fs/promises"; +import path, { join } from "node:path"; +import { fileURLToPath } from "node:url"; + +const repositoryRootDir = join(path.dirname(fileURLToPath(import.meta.url)), "../"); +const file = (relativePath) => join(repositoryRootDir, relativePath); await (async () => { - await fs.rm("built/_client_dist_/locales", { recursive: true, force: true }); + await fs.rm(file("built/_client_dist_/locales"), { recursive: true, force: true }); await Promise.all([ - fs.cp("packages/backend/src/server/web", "packages/backend/built/server/web", { recursive: true }), - fs.cp("custom/assets", "packages/backend/assets", { recursive: true }), - fs.cp("packages/client/node_modules/three/examples/fonts", "built/_client_dist_/fonts", { recursive: true }), - fs.mkdir("built/_client_dist_/locales", { recursive: true }), + fs.cp(file("packages/backend/src/server/web"), file("packages/backend/built/server/web"), { recursive: true }), + fs.cp(file("custom/assets"), file("packages/backend/assets"), { recursive: true }), + fs.cp(file("packages/client/node_modules/three/examples/fonts"), file("built/_client_dist_/fonts"), { recursive: true }), + fs.mkdir(file("built/_client_dist_/locales"), { recursive: true }), ]); const locales = (await import("../locales/index.mjs")).default; @@ -14,16 +19,16 @@ await (async () => { for await (const [lang, locale] of Object.entries(locales)) { await fs.writeFile( - `built/_client_dist_/locales/${lang}.${meta.version}.json`, + file(`built/_client_dist_/locales/${lang}.${meta.version}.json`), JSON.stringify({ ...locale, _version_: meta.version }), "utf-8", ); } const js_assets = [ - "packages/backend/built/server/web/boot.js", - "packages/backend/built/server/web/bios.js", - "packages/backend/built/server/web/cli.js", + file("packages/backend/built/server/web/boot.js"), + file("packages/backend/built/server/web/bios.js"), + file("packages/backend/built/server/web/cli.js"), ]; for await (const js_file of js_assets) { From 359fef0a4223197c47a9f92ab0deaea65a8e01f0 Mon Sep 17 00:00:00 2001 From: naskya Date: Sun, 5 May 2024 21:22:57 +0900 Subject: [PATCH 33/75] chore: replace old comments --- packages/backend-rs/index.d.ts | 25 ++++++++++++------- .../backend-rs/src/misc/check_server_block.rs | 25 ++++++++++--------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/packages/backend-rs/index.d.ts b/packages/backend-rs/index.d.ts index 4f14e02b6c..0a92da8596 100644 --- a/packages/backend-rs/index.d.ts +++ b/packages/backend-rs/index.d.ts @@ -214,19 +214,26 @@ export function stringToAcct(acct: string): Acct export function acctToString(acct: Acct): string export function addNoteToAntenna(antennaId: string, note: Note): void /** - * @param host punycoded instance host - * @returns whether the given host should be blocked -*/ + * Checks if a server is blocked. + * + * ## Argument + * `host` - punycoded instance host + */ export function isBlockedServer(host: string): Promise /** - * @param host punycoded instance host - * @returns whether the given host should be limited -*/ + * Checks if a server is silenced. + * + * ## Argument + * `host` - punycoded instance host + */ export function isSilencedServer(host: string): Promise /** - * @param host punycoded instance host - * @returns whether the given host is allowlisted (this is always true if private mode is disabled) -*/ + * Checks if a server is allowlisted. + * Returns `Ok(true)` if private mode is disabled. + * + * ## Argument + * `host` - punycoded instance host + */ export function isAllowedServer(host: string): Promise /** TODO: handle name collisions better */ export interface NoteLikeForCheckWordMute { diff --git a/packages/backend-rs/src/misc/check_server_block.rs b/packages/backend-rs/src/misc/check_server_block.rs index b5e262aa87..bb7f40078a 100644 --- a/packages/backend-rs/src/misc/check_server_block.rs +++ b/packages/backend-rs/src/misc/check_server_block.rs @@ -1,10 +1,10 @@ use crate::misc::meta::fetch_meta; use sea_orm::DbErr; -/** - * @param host punycoded instance host - * @returns whether the given host should be blocked - */ +/// Checks if a server is blocked. +/// +/// ## Argument +/// `host` - punycoded instance host #[crate::export] pub async fn is_blocked_server(host: &str) -> Result { Ok(fetch_meta(true) @@ -16,10 +16,10 @@ pub async fn is_blocked_server(host: &str) -> Result { })) } -/** - * @param host punycoded instance host - * @returns whether the given host should be limited - */ +/// Checks if a server is silenced. +/// +/// ## Argument +/// `host` - punycoded instance host #[crate::export] pub async fn is_silenced_server(host: &str) -> Result { Ok(fetch_meta(true) @@ -31,10 +31,11 @@ pub async fn is_silenced_server(host: &str) -> Result { })) } -/** - * @param host punycoded instance host - * @returns whether the given host is allowlisted (this is always true if private mode is disabled) - */ +/// Checks if a server is allowlisted. +/// Returns `Ok(true)` if private mode is disabled. +/// +/// ## Argument +/// `host` - punycoded instance host #[crate::export] pub async fn is_allowed_server(host: &str) -> Result { let meta = fetch_meta(true).await?; From 49825853c147188b6f629cb349c3108f9c8deaab Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 02:20:39 +0900 Subject: [PATCH 34/75] refactor (backend): port nodeinfo generator to backend-rs --- packages/backend-rs/index.d.ts | 2 + packages/backend-rs/index.js | 4 +- packages/backend-rs/src/service/mod.rs | 1 + packages/backend-rs/src/service/nodeinfo.rs | 327 ++++++++++++++++++ .../backend/src/prelude/undefined-to-null.ts | 16 +- packages/backend/src/server/nodeinfo.ts | 101 +----- packages/backend/src/services/note/create.ts | 4 +- 7 files changed, 354 insertions(+), 101 deletions(-) create mode 100644 packages/backend-rs/src/service/nodeinfo.rs diff --git a/packages/backend-rs/index.d.ts b/packages/backend-rs/index.d.ts index 0a92da8596..3eef51ab43 100644 --- a/packages/backend-rs/index.d.ts +++ b/packages/backend-rs/index.d.ts @@ -1155,6 +1155,8 @@ export interface Webhook { latestStatus: number | null } export function initializeRustLogger(): void +export function nodeinfo_2_1(): Promise +export function nodeinfo_2_0(): Promise export function watchNote(watcherId: string, noteAuthorId: string, noteId: string): Promise export function unwatchNote(watcherId: string, noteId: string): Promise export function publishToChannelStream(channelId: string, userId: string): void diff --git a/packages/backend-rs/index.js b/packages/backend-rs/index.js index 1b1ae265b1..c518f59a4b 100644 --- a/packages/backend-rs/index.js +++ b/packages/backend-rs/index.js @@ -310,7 +310,7 @@ if (!nativeBinding) { throw new Error(`Failed to load native binding`) } -const { SECOND, MINUTE, HOUR, DAY, USER_ONLINE_THRESHOLD, USER_ACTIVE_THRESHOLD, FILE_TYPE_BROWSERSAFE, loadEnv, loadConfig, stringToAcct, acctToString, addNoteToAntenna, isBlockedServer, isSilencedServer, isAllowedServer, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, getImageSizeFromUrl, getNoteSummary, latestVersion, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, removeOldAttestationChallenges, AntennaSrcEnum, DriveFileUsageHintEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initializeRustLogger, watchNote, unwatchNote, publishToChannelStream, ChatEvent, publishToChatStream, ChatIndexEvent, publishToChatIndexStream, publishToBroadcastStream, publishToGroupChatStream, publishToModerationStream, getTimestamp, genId, genIdAt, secureRndstr } = nativeBinding +const { SECOND, MINUTE, HOUR, DAY, USER_ONLINE_THRESHOLD, USER_ACTIVE_THRESHOLD, FILE_TYPE_BROWSERSAFE, loadEnv, loadConfig, stringToAcct, acctToString, addNoteToAntenna, isBlockedServer, isSilencedServer, isAllowedServer, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, getImageSizeFromUrl, getNoteSummary, latestVersion, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, removeOldAttestationChallenges, AntennaSrcEnum, DriveFileUsageHintEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initializeRustLogger, nodeinfo_2_1, nodeinfo_2_0, watchNote, unwatchNote, publishToChannelStream, ChatEvent, publishToChatStream, ChatIndexEvent, publishToChatIndexStream, publishToBroadcastStream, publishToGroupChatStream, publishToModerationStream, getTimestamp, genId, genIdAt, secureRndstr } = nativeBinding module.exports.SECOND = SECOND module.exports.MINUTE = MINUTE @@ -364,6 +364,8 @@ module.exports.UserEmojimodpermEnum = UserEmojimodpermEnum module.exports.UserProfileFfvisibilityEnum = UserProfileFfvisibilityEnum module.exports.UserProfileMutingnotificationtypesEnum = UserProfileMutingnotificationtypesEnum module.exports.initializeRustLogger = initializeRustLogger +module.exports.nodeinfo_2_1 = nodeinfo_2_1 +module.exports.nodeinfo_2_0 = nodeinfo_2_0 module.exports.watchNote = watchNote module.exports.unwatchNote = unwatchNote module.exports.publishToChannelStream = publishToChannelStream diff --git a/packages/backend-rs/src/service/mod.rs b/packages/backend-rs/src/service/mod.rs index 0a2644857f..f755f22b4b 100644 --- a/packages/backend-rs/src/service/mod.rs +++ b/packages/backend-rs/src/service/mod.rs @@ -1,3 +1,4 @@ pub mod log; +pub mod nodeinfo; pub mod note; pub mod stream; diff --git a/packages/backend-rs/src/service/nodeinfo.rs b/packages/backend-rs/src/service/nodeinfo.rs new file mode 100644 index 0000000000..5760d7162d --- /dev/null +++ b/packages/backend-rs/src/service/nodeinfo.rs @@ -0,0 +1,327 @@ +use crate::config::CONFIG; +use crate::database::cache; +use crate::database::db_conn; +use crate::misc::meta::fetch_meta; +use crate::model::entity::{note, user}; +use sea_orm::{ColumnTrait, DbErr, EntityTrait, PaginatorTrait, QueryFilter}; +use serde::{Deserialize, Serialize}; +use serde_json::json; +use std::collections::HashMap; + +// TODO: I want to use these macros but they don't work with rmp_serde +// - #[serde(skip_serializing_if = "Option::is_none")] (https://github.com/3Hren/msgpack-rust/issues/86) +// - #[serde(tag = "version", rename = "2.1")] (https://github.com/3Hren/msgpack-rust/issues/318) + +/// NodeInfo schema version 2.1. https://nodeinfo.diaspora.software/docson/index.html#/ns/schema/2.1 +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Nodeinfo21 { + /// The schema version, must be 2.1. + pub version: String, + /// Metadata about server software in use. + pub software: Software21, + /// The protocols supported on this server. + pub protocols: Vec, + /// The third party sites this server can connect to via their application API. + pub services: Services, + /// Whether this server allows open self-registration. + pub open_registrations: bool, + /// Usage statistics for this server. + pub usage: Usage, + /// Free form key value pairs for software specific values. Clients should not rely on any specific key present. + pub metadata: HashMap, +} + +/// NodeInfo schema version 2.0. https://nodeinfo.diaspora.software/docson/index.html#/ns/schema/2.0 +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Nodeinfo20 { + /// The schema version, must be 2.0. + pub version: String, + /// Metadata about server software in use. + pub software: Software20, + /// The protocols supported on this server. + pub protocols: Vec, + /// The third party sites this server can connect to via their application API. + pub services: Services, + /// Whether this server allows open self-registration. + pub open_registrations: bool, + /// Usage statistics for this server. + pub usage: Usage, + /// Free form key value pairs for software specific values. Clients should not rely on any specific key present. + pub metadata: HashMap, +} + +/// Metadata about server software in use (version 2.1). +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Software21 { + /// The canonical name of this server software. + pub name: String, + /// The version of this server software. + pub version: String, + /// The url of the source code repository of this server software. + pub repository: Option, + /// The url of the homepage of this server software. + pub homepage: Option, +} + +/// Metadata about server software in use (version 2.0). +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Software20 { + /// The canonical name of this server software. + pub name: String, + /// The version of this server software. + pub version: String, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "lowercase")] +pub enum Protocol { + Activitypub, + Buddycloud, + Dfrn, + Diaspora, + Libertree, + Ostatus, + Pumpio, + Tent, + Xmpp, + Zot, +} + +/// The third party sites this server can connect to via their application API. +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Services { + /// The third party sites this server can retrieve messages from for combined display with regular traffic. + pub inbound: Vec, + /// The third party sites this server can publish messages to on the behalf of a user. + pub outbound: Vec, +} + +/// The third party sites this server can retrieve messages from for combined display with regular traffic. +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "lowercase")] +pub enum Inbound { + #[serde(rename = "atom1.0")] + Atom1, + Gnusocial, + Imap, + Pnut, + #[serde(rename = "pop3")] + Pop3, + Pumpio, + #[serde(rename = "rss2.0")] + Rss2, + Twitter, +} + +/// The third party sites this server can publish messages to on the behalf of a user. +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "lowercase")] +pub enum Outbound { + #[serde(rename = "atom1.0")] + Atom1, + Blogger, + Buddycloud, + Diaspora, + Dreamwidth, + Drupal, + Facebook, + Friendica, + Gnusocial, + Google, + Insanejournal, + Libertree, + Linkedin, + Livejournal, + Mediagoblin, + Myspace, + Pinterest, + Pnut, + Posterous, + Pumpio, + Redmatrix, + #[serde(rename = "rss2.0")] + Rss2, + Smtp, + Tent, + Tumblr, + Twitter, + Wordpress, + Xmpp, +} + +/// Usage statistics for this server. +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Usage { + pub users: Users, + pub local_posts: Option, + pub local_comments: Option, +} + +/// statistics about the users of this server. +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Users { + pub total: Option, + pub active_halfyear: Option, + pub active_month: Option, +} + +impl From for Software20 { + fn from(software: Software21) -> Self { + Self { + name: software.name, + version: software.version, + } + } +} + +impl From for Nodeinfo20 { + fn from(nodeinfo: Nodeinfo21) -> Self { + Self { + version: "2.0".to_string(), + software: nodeinfo.software.into(), + protocols: nodeinfo.protocols, + services: nodeinfo.services, + open_registrations: nodeinfo.open_registrations, + usage: nodeinfo.usage, + metadata: nodeinfo.metadata, + } + } +} + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Database error: {0}")] + DbErr(#[from] DbErr), + #[error("Cache error: {0}")] + CacheErr(#[from] cache::Error), + #[error("Failed to serialize nodeinfo to JSON: {0}")] + JsonErr(#[from] serde_json::Error), +} + +async fn statistics() -> Result<(u64, u64, u64, u64), DbErr> { + let db = db_conn().await?; + + let now = chrono::Local::now().naive_local(); + const MONTH: chrono::TimeDelta = chrono::Duration::seconds(2592000000); + const HALF_YEAR: chrono::TimeDelta = chrono::Duration::seconds(15552000000); + + let local_users = user::Entity::find() + .filter(user::Column::Host.is_null()) + .count(db); + let local_active_halfyear = user::Entity::find() + .filter(user::Column::Host.is_null()) + .filter(user::Column::LastActiveDate.gt(now - HALF_YEAR)) + .count(db); + let local_active_month = user::Entity::find() + .filter(user::Column::Host.is_null()) + .filter(user::Column::LastActiveDate.gt(now - MONTH)) + .count(db); + let local_posts = note::Entity::find() + .filter(note::Column::UserHost.is_null()) + .count(db); + + tokio::try_join!( + local_users, + local_active_halfyear, + local_active_month, + local_posts + ) +} + +async fn get_new_nodeinfo_2_1() -> Result { + let (local_users, local_active_halfyear, local_active_month, local_posts) = + statistics().await?; + let meta = fetch_meta(true).await?; + let metadata = HashMap::from([ + ( + "nodeName".to_string(), + json!(meta.name.unwrap_or(CONFIG.host.clone())), + ), + ("nodeDescription".to_string(), json!(meta.description)), + ("repositoryUrl".to_string(), json!(meta.repository_url)), + ( + "enableLocalTimeline".to_string(), + json!(!meta.disable_local_timeline), + ), + ( + "enableRecommendedTimeline".to_string(), + json!(!meta.disable_recommended_timeline), + ), + ( + "enableGlobalTimeline".to_string(), + json!(!meta.disable_global_timeline), + ), + ( + "enableGuestTimeline".to_string(), + json!(meta.enable_guest_timeline), + ), + ("maintainerName".to_string(), json!(meta.maintainer_name)), + ("maintainerEmail".to_string(), json!(meta.maintainer_email)), + ("proxyAccountName".to_string(), json!(meta.proxy_account_id)), + ( + "themeColor".to_string(), + json!(meta.theme_color.unwrap_or("#31748f".to_string())), + ), + ]); + + Ok(Nodeinfo21 { + version: "2.1".to_string(), + software: Software21 { + name: "firefish".to_string(), + version: CONFIG.version.clone(), + repository: Some(meta.repository_url), + homepage: Some("https://firefish.dev/firefish/firefish".to_string()), + }, + protocols: vec![Protocol::Activitypub], + services: Services { + inbound: vec![], + outbound: vec![Outbound::Atom1, Outbound::Rss2], + }, + open_registrations: !meta.disable_registration, + usage: Usage { + users: Users { + total: Some(local_users), + active_halfyear: Some(local_active_halfyear), + active_month: Some(local_active_month), + }, + local_posts: Some(local_posts), + local_comments: None, + }, + metadata, + }) +} + +pub async fn nodeinfo_2_1() -> Result { + const NODEINFO_2_1_CACHE_KEY: &str = "nodeinfo_2_1"; + + let cached = cache::get::(NODEINFO_2_1_CACHE_KEY)?; + + if let Some(nodeinfo) = cached { + Ok(nodeinfo) + } else { + let nodeinfo = get_new_nodeinfo_2_1().await?; + cache::set(NODEINFO_2_1_CACHE_KEY, &nodeinfo, 60 * 60)?; + Ok(nodeinfo) + } +} + +pub async fn nodeinfo_2_0() -> Result { + Ok(nodeinfo_2_1().await?.into()) +} + +#[crate::export(js_name = "nodeinfo_2_1")] +pub async fn nodeinfo_2_1_as_json() -> Result { + Ok(serde_json::to_value(nodeinfo_2_1().await?)?) +} + +#[crate::export(js_name = "nodeinfo_2_0")] +pub async fn nodeinfo_2_0_as_json() -> Result { + Ok(serde_json::to_value(nodeinfo_2_0().await?)?) +} diff --git a/packages/backend/src/prelude/undefined-to-null.ts b/packages/backend/src/prelude/undefined-to-null.ts index 013be3cf9e..b241f7a653 100644 --- a/packages/backend/src/prelude/undefined-to-null.ts +++ b/packages/backend/src/prelude/undefined-to-null.ts @@ -1,7 +1,7 @@ // https://gist.github.com/tkrotoff/a6baf96eb6b61b445a9142e5555511a0 import type { Primitive } from "type-fest"; -type NullToUndefined = T extends null +export type NullToUndefined = T extends null ? undefined : T extends Primitive | Function | Date | RegExp ? T @@ -15,7 +15,7 @@ type NullToUndefined = T extends null ? { [K in keyof T]: NullToUndefined } : unknown; -type UndefinedToNull = T extends undefined +export type UndefinedToNull = T extends undefined ? null : T extends Primitive | Function | Date | RegExp ? T @@ -47,6 +47,16 @@ function _nullToUndefined(obj: T): NullToUndefined { return obj as any; } +/** + * Recursively converts all null values to undefined. + * + * @param obj object to convert + * @returns a copy of the object with all its null values converted to undefined + */ +export function fromRustObject(obj: T) { + return _nullToUndefined(structuredClone(obj)); +} + function _undefinedToNull(obj: T): UndefinedToNull { if (obj === undefined) { return null as any; @@ -71,6 +81,6 @@ function _undefinedToNull(obj: T): UndefinedToNull { * @param obj object to convert * @returns a copy of the object with all its undefined values converted to null */ -export function undefinedToNull(obj: T) { +export function toRustObject(obj: T) { return _undefinedToNull(structuredClone(obj)); } diff --git a/packages/backend/src/server/nodeinfo.ts b/packages/backend/src/server/nodeinfo.ts index 73189b73d9..511d75e254 100644 --- a/packages/backend/src/server/nodeinfo.ts +++ b/packages/backend/src/server/nodeinfo.ts @@ -1,9 +1,7 @@ import Router from "@koa/router"; import { config } from "@/config.js"; -import { fetchMeta } from "backend-rs"; -import { Users, Notes } from "@/models/index.js"; -import { IsNull, MoreThan } from "typeorm"; -import { Cache } from "@/misc/cache.js"; +import { nodeinfo_2_0, nodeinfo_2_1 } from "backend-rs"; +import { fromRustObject } from "@/prelude/undefined-to-null.js"; const router = new Router(); @@ -22,101 +20,14 @@ export const links = [ }, ]; -const nodeinfo2 = async () => { - const now = Date.now(); - const [meta, total, activeHalfyear, activeMonth, localPosts] = - await Promise.all([ - fetchMeta(false), - Users.count({ where: { host: IsNull() } }), - Users.count({ - where: { - host: IsNull(), - lastActiveDate: MoreThan(new Date(now - 15552000000)), - }, - }), - Users.count({ - where: { - host: IsNull(), - lastActiveDate: MoreThan(new Date(now - 2592000000)), - }, - }), - Notes.count({ where: { userHost: IsNull() } }), - ]); - - const proxyAccount = meta.proxyAccountId - ? await Users.pack(meta.proxyAccountId).catch(() => null) - : null; - - return { - software: { - name: "firefish", - version: config.version, - repository: meta.repositoryUrl, - homepage: "https://firefish.dev/firefish/firefish", - }, - protocols: ["activitypub"], - services: { - inbound: [] as string[], - outbound: ["atom1.0", "rss2.0"], - }, - openRegistrations: !meta.disableRegistration, - usage: { - users: { total, activeHalfyear, activeMonth }, - localPosts, - localComments: 0, - }, - metadata: { - nodeName: meta.name, - nodeDescription: meta.description, - maintainer: { - name: meta.maintainerName, - email: meta.maintainerEmail, - }, - langs: meta.langs, - tosUrl: meta.tosUrl, - repositoryUrl: meta.repositoryUrl, - feedbackUrl: meta.feedbackUrl, - disableRegistration: meta.disableRegistration, - disableLocalTimeline: meta.disableLocalTimeline, - disableRecommendedTimeline: meta.disableRecommendedTimeline, - disableGlobalTimeline: meta.disableGlobalTimeline, - emailRequiredForSignup: meta.emailRequiredForSignup, - postEditing: true, - postImports: meta.experimentalFeatures?.postImports || false, - enableHcaptcha: meta.enableHcaptcha, - enableRecaptcha: meta.enableRecaptcha, - maxNoteTextLength: config.maxNoteLength, - maxCaptionTextLength: config.maxCaptionLength, - enableEmail: meta.enableEmail, - enableServiceWorker: meta.enableServiceWorker, - proxyAccountName: proxyAccount ? proxyAccount.username : null, - themeColor: meta.themeColor || "#31748f", - }, - }; -}; - -const cache = new Cache>>( - "nodeinfo", - 60 * 10, -); - router.get(nodeinfo2_1path, async (ctx) => { - const base = await cache.fetch(null, () => nodeinfo2()); - - ctx.body = { version: "2.1", ...base }; - ctx.set("Cache-Control", "public, max-age=600"); + ctx.body = fromRustObject(await nodeinfo_2_1()); + ctx.set("Cache-Control", "public, max-age=3600"); }); router.get(nodeinfo2_0path, async (ctx) => { - const base = await cache.fetch(null, () => nodeinfo2()); - - // @ts-ignore - base.software.repository = undefined; - // @ts-ignore - base.software.homepage = undefined; - - ctx.body = { version: "2.0", ...base }; - ctx.set("Cache-Control", "public, max-age=600"); + ctx.body = fromRustObject(await nodeinfo_2_0()); + ctx.set("Cache-Control", "public, max-age=3600"); }); export default router; diff --git a/packages/backend/src/services/note/create.ts b/packages/backend/src/services/note/create.ts index 679a2f886e..2096f8b1a2 100644 --- a/packages/backend/src/services/note/create.ts +++ b/packages/backend/src/services/note/create.ts @@ -66,7 +66,7 @@ import { Mutex } from "redis-semaphore"; import { langmap } from "@/misc/langmap.js"; import Logger from "@/services/logger.js"; import { inspect } from "node:util"; -import { undefinedToNull } from "@/prelude/undefined-to-null.js"; +import { toRustObject } from "@/prelude/undefined-to-null.js"; const logger = new Logger("create-note"); @@ -404,7 +404,7 @@ export default async ( checkHitAntenna(antenna, note, user).then((hit) => { if (hit) { // TODO: do this more sanely - addNoteToAntenna(antenna.id, undefinedToNull(note) as Note); + addNoteToAntenna(antenna.id, toRustObject(note)); } }); } From 510207b101b3354a3c3bf290438672956516417f Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 04:23:38 +0900 Subject: [PATCH 35/75] refactor (backend-rs): separate nodeinfo generator and schema --- .../src/service/nodeinfo/generate.rs | 140 ++++++++++++++++++ .../backend-rs/src/service/nodeinfo/mod.rs | 2 + .../{nodeinfo.rs => nodeinfo/schema.rs} | 138 ----------------- 3 files changed, 142 insertions(+), 138 deletions(-) create mode 100644 packages/backend-rs/src/service/nodeinfo/generate.rs create mode 100644 packages/backend-rs/src/service/nodeinfo/mod.rs rename packages/backend-rs/src/service/{nodeinfo.rs => nodeinfo/schema.rs} (55%) diff --git a/packages/backend-rs/src/service/nodeinfo/generate.rs b/packages/backend-rs/src/service/nodeinfo/generate.rs new file mode 100644 index 0000000000..168b13ba1b --- /dev/null +++ b/packages/backend-rs/src/service/nodeinfo/generate.rs @@ -0,0 +1,140 @@ +use crate::config::CONFIG; +use crate::database::cache; +use crate::database::db_conn; +use crate::misc::meta::fetch_meta; +use crate::model::entity::{note, user}; +use crate::service::nodeinfo::schema::*; +use sea_orm::{ColumnTrait, DbErr, EntityTrait, PaginatorTrait, QueryFilter}; +use serde_json::json; +use std::collections::HashMap; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Database error: {0}")] + DbErr(#[from] DbErr), + #[error("Cache error: {0}")] + CacheErr(#[from] cache::Error), + #[error("Failed to serialize nodeinfo to JSON: {0}")] + JsonErr(#[from] serde_json::Error), +} + +async fn statistics() -> Result<(u64, u64, u64, u64), DbErr> { + let db = db_conn().await?; + + let now = chrono::Local::now().naive_local(); + const MONTH: chrono::TimeDelta = chrono::Duration::seconds(2592000000); + const HALF_YEAR: chrono::TimeDelta = chrono::Duration::seconds(15552000000); + + let local_users = user::Entity::find() + .filter(user::Column::Host.is_null()) + .count(db); + let local_active_halfyear = user::Entity::find() + .filter(user::Column::Host.is_null()) + .filter(user::Column::LastActiveDate.gt(now - HALF_YEAR)) + .count(db); + let local_active_month = user::Entity::find() + .filter(user::Column::Host.is_null()) + .filter(user::Column::LastActiveDate.gt(now - MONTH)) + .count(db); + let local_posts = note::Entity::find() + .filter(note::Column::UserHost.is_null()) + .count(db); + + tokio::try_join!( + local_users, + local_active_halfyear, + local_active_month, + local_posts + ) +} + +async fn get_new_nodeinfo_2_1() -> Result { + let (local_users, local_active_halfyear, local_active_month, local_posts) = + statistics().await?; + let meta = fetch_meta(true).await?; + let metadata = HashMap::from([ + ( + "nodeName".to_string(), + json!(meta.name.unwrap_or(CONFIG.host.clone())), + ), + ("nodeDescription".to_string(), json!(meta.description)), + ("repositoryUrl".to_string(), json!(meta.repository_url)), + ( + "enableLocalTimeline".to_string(), + json!(!meta.disable_local_timeline), + ), + ( + "enableRecommendedTimeline".to_string(), + json!(!meta.disable_recommended_timeline), + ), + ( + "enableGlobalTimeline".to_string(), + json!(!meta.disable_global_timeline), + ), + ( + "enableGuestTimeline".to_string(), + json!(meta.enable_guest_timeline), + ), + ("maintainerName".to_string(), json!(meta.maintainer_name)), + ("maintainerEmail".to_string(), json!(meta.maintainer_email)), + ("proxyAccountName".to_string(), json!(meta.proxy_account_id)), + ( + "themeColor".to_string(), + json!(meta.theme_color.unwrap_or("#31748f".to_string())), + ), + ]); + + Ok(Nodeinfo21 { + version: "2.1".to_string(), + software: Software21 { + name: "firefish".to_string(), + version: CONFIG.version.clone(), + repository: Some(meta.repository_url), + homepage: Some("https://firefish.dev/firefish/firefish".to_string()), + }, + protocols: vec![Protocol::Activitypub], + services: Services { + inbound: vec![], + outbound: vec![Outbound::Atom1, Outbound::Rss2], + }, + open_registrations: !meta.disable_registration, + usage: Usage { + users: Users { + total: Some(local_users), + active_halfyear: Some(local_active_halfyear), + active_month: Some(local_active_month), + }, + local_posts: Some(local_posts), + local_comments: None, + }, + metadata, + }) +} + +pub async fn nodeinfo_2_1() -> Result { + const NODEINFO_2_1_CACHE_KEY: &str = "nodeinfo_2_1"; + + let cached = cache::get::(NODEINFO_2_1_CACHE_KEY)?; + + if let Some(nodeinfo) = cached { + Ok(nodeinfo) + } else { + let nodeinfo = get_new_nodeinfo_2_1().await?; + cache::set(NODEINFO_2_1_CACHE_KEY, &nodeinfo, 60 * 60)?; + Ok(nodeinfo) + } +} + +pub async fn nodeinfo_2_0() -> Result { + Ok(nodeinfo_2_1().await?.into()) +} + +#[crate::export(js_name = "nodeinfo_2_1")] +pub async fn nodeinfo_2_1_as_json() -> Result { + Ok(serde_json::to_value(nodeinfo_2_1().await?)?) +} + +#[crate::export(js_name = "nodeinfo_2_0")] +pub async fn nodeinfo_2_0_as_json() -> Result { + Ok(serde_json::to_value(nodeinfo_2_0().await?)?) +} diff --git a/packages/backend-rs/src/service/nodeinfo/mod.rs b/packages/backend-rs/src/service/nodeinfo/mod.rs new file mode 100644 index 0000000000..563a8046d6 --- /dev/null +++ b/packages/backend-rs/src/service/nodeinfo/mod.rs @@ -0,0 +1,2 @@ +pub mod generate; +pub mod schema; diff --git a/packages/backend-rs/src/service/nodeinfo.rs b/packages/backend-rs/src/service/nodeinfo/schema.rs similarity index 55% rename from packages/backend-rs/src/service/nodeinfo.rs rename to packages/backend-rs/src/service/nodeinfo/schema.rs index 5760d7162d..51f2ebf687 100644 --- a/packages/backend-rs/src/service/nodeinfo.rs +++ b/packages/backend-rs/src/service/nodeinfo/schema.rs @@ -1,11 +1,4 @@ -use crate::config::CONFIG; -use crate::database::cache; -use crate::database::db_conn; -use crate::misc::meta::fetch_meta; -use crate::model::entity::{note, user}; -use sea_orm::{ColumnTrait, DbErr, EntityTrait, PaginatorTrait, QueryFilter}; use serde::{Deserialize, Serialize}; -use serde_json::json; use std::collections::HashMap; // TODO: I want to use these macros but they don't work with rmp_serde @@ -194,134 +187,3 @@ impl From for Nodeinfo20 { } } } - -#[derive(thiserror::Error, Debug)] -pub enum Error { - #[error("Database error: {0}")] - DbErr(#[from] DbErr), - #[error("Cache error: {0}")] - CacheErr(#[from] cache::Error), - #[error("Failed to serialize nodeinfo to JSON: {0}")] - JsonErr(#[from] serde_json::Error), -} - -async fn statistics() -> Result<(u64, u64, u64, u64), DbErr> { - let db = db_conn().await?; - - let now = chrono::Local::now().naive_local(); - const MONTH: chrono::TimeDelta = chrono::Duration::seconds(2592000000); - const HALF_YEAR: chrono::TimeDelta = chrono::Duration::seconds(15552000000); - - let local_users = user::Entity::find() - .filter(user::Column::Host.is_null()) - .count(db); - let local_active_halfyear = user::Entity::find() - .filter(user::Column::Host.is_null()) - .filter(user::Column::LastActiveDate.gt(now - HALF_YEAR)) - .count(db); - let local_active_month = user::Entity::find() - .filter(user::Column::Host.is_null()) - .filter(user::Column::LastActiveDate.gt(now - MONTH)) - .count(db); - let local_posts = note::Entity::find() - .filter(note::Column::UserHost.is_null()) - .count(db); - - tokio::try_join!( - local_users, - local_active_halfyear, - local_active_month, - local_posts - ) -} - -async fn get_new_nodeinfo_2_1() -> Result { - let (local_users, local_active_halfyear, local_active_month, local_posts) = - statistics().await?; - let meta = fetch_meta(true).await?; - let metadata = HashMap::from([ - ( - "nodeName".to_string(), - json!(meta.name.unwrap_or(CONFIG.host.clone())), - ), - ("nodeDescription".to_string(), json!(meta.description)), - ("repositoryUrl".to_string(), json!(meta.repository_url)), - ( - "enableLocalTimeline".to_string(), - json!(!meta.disable_local_timeline), - ), - ( - "enableRecommendedTimeline".to_string(), - json!(!meta.disable_recommended_timeline), - ), - ( - "enableGlobalTimeline".to_string(), - json!(!meta.disable_global_timeline), - ), - ( - "enableGuestTimeline".to_string(), - json!(meta.enable_guest_timeline), - ), - ("maintainerName".to_string(), json!(meta.maintainer_name)), - ("maintainerEmail".to_string(), json!(meta.maintainer_email)), - ("proxyAccountName".to_string(), json!(meta.proxy_account_id)), - ( - "themeColor".to_string(), - json!(meta.theme_color.unwrap_or("#31748f".to_string())), - ), - ]); - - Ok(Nodeinfo21 { - version: "2.1".to_string(), - software: Software21 { - name: "firefish".to_string(), - version: CONFIG.version.clone(), - repository: Some(meta.repository_url), - homepage: Some("https://firefish.dev/firefish/firefish".to_string()), - }, - protocols: vec![Protocol::Activitypub], - services: Services { - inbound: vec![], - outbound: vec![Outbound::Atom1, Outbound::Rss2], - }, - open_registrations: !meta.disable_registration, - usage: Usage { - users: Users { - total: Some(local_users), - active_halfyear: Some(local_active_halfyear), - active_month: Some(local_active_month), - }, - local_posts: Some(local_posts), - local_comments: None, - }, - metadata, - }) -} - -pub async fn nodeinfo_2_1() -> Result { - const NODEINFO_2_1_CACHE_KEY: &str = "nodeinfo_2_1"; - - let cached = cache::get::(NODEINFO_2_1_CACHE_KEY)?; - - if let Some(nodeinfo) = cached { - Ok(nodeinfo) - } else { - let nodeinfo = get_new_nodeinfo_2_1().await?; - cache::set(NODEINFO_2_1_CACHE_KEY, &nodeinfo, 60 * 60)?; - Ok(nodeinfo) - } -} - -pub async fn nodeinfo_2_0() -> Result { - Ok(nodeinfo_2_1().await?.into()) -} - -#[crate::export(js_name = "nodeinfo_2_1")] -pub async fn nodeinfo_2_1_as_json() -> Result { - Ok(serde_json::to_value(nodeinfo_2_1().await?)?) -} - -#[crate::export(js_name = "nodeinfo_2_0")] -pub async fn nodeinfo_2_0_as_json() -> Result { - Ok(serde_json::to_value(nodeinfo_2_0().await?)?) -} From 711618b42c6ec585968aa408d2640dafb4a13bba Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 05:16:49 +0900 Subject: [PATCH 36/75] test (backend-rs): add tests for nodeinfo (de)serialization --- .../backend-rs/src/service/nodeinfo/schema.rs | 86 ++++++++++++++++--- 1 file changed, 76 insertions(+), 10 deletions(-) diff --git a/packages/backend-rs/src/service/nodeinfo/schema.rs b/packages/backend-rs/src/service/nodeinfo/schema.rs index 51f2ebf687..ae7b5a52c2 100644 --- a/packages/backend-rs/src/service/nodeinfo/schema.rs +++ b/packages/backend-rs/src/service/nodeinfo/schema.rs @@ -6,7 +6,7 @@ use std::collections::HashMap; // - #[serde(tag = "version", rename = "2.1")] (https://github.com/3Hren/msgpack-rust/issues/318) /// NodeInfo schema version 2.1. https://nodeinfo.diaspora.software/docson/index.html#/ns/schema/2.1 -#[derive(Deserialize, Serialize, Debug)] +#[derive(Deserialize, Serialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Nodeinfo21 { /// The schema version, must be 2.1. @@ -26,7 +26,7 @@ pub struct Nodeinfo21 { } /// NodeInfo schema version 2.0. https://nodeinfo.diaspora.software/docson/index.html#/ns/schema/2.0 -#[derive(Deserialize, Serialize, Debug)] +#[derive(Deserialize, Serialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Nodeinfo20 { /// The schema version, must be 2.0. @@ -46,7 +46,7 @@ pub struct Nodeinfo20 { } /// Metadata about server software in use (version 2.1). -#[derive(Deserialize, Serialize, Debug)] +#[derive(Deserialize, Serialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Software21 { /// The canonical name of this server software. @@ -60,7 +60,7 @@ pub struct Software21 { } /// Metadata about server software in use (version 2.0). -#[derive(Deserialize, Serialize, Debug)] +#[derive(Deserialize, Serialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Software20 { /// The canonical name of this server software. @@ -69,7 +69,7 @@ pub struct Software20 { pub version: String, } -#[derive(Deserialize, Serialize, Debug)] +#[derive(Deserialize, Serialize, Debug, PartialEq)] #[serde(rename_all = "lowercase")] pub enum Protocol { Activitypub, @@ -85,7 +85,7 @@ pub enum Protocol { } /// The third party sites this server can connect to via their application API. -#[derive(Deserialize, Serialize, Debug)] +#[derive(Deserialize, Serialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Services { /// The third party sites this server can retrieve messages from for combined display with regular traffic. @@ -95,7 +95,7 @@ pub struct Services { } /// The third party sites this server can retrieve messages from for combined display with regular traffic. -#[derive(Deserialize, Serialize, Debug)] +#[derive(Deserialize, Serialize, Debug, PartialEq)] #[serde(rename_all = "lowercase")] pub enum Inbound { #[serde(rename = "atom1.0")] @@ -112,7 +112,7 @@ pub enum Inbound { } /// The third party sites this server can publish messages to on the behalf of a user. -#[derive(Deserialize, Serialize, Debug)] +#[derive(Deserialize, Serialize, Debug, PartialEq)] #[serde(rename_all = "lowercase")] pub enum Outbound { #[serde(rename = "atom1.0")] @@ -148,7 +148,7 @@ pub enum Outbound { } /// Usage statistics for this server. -#[derive(Deserialize, Serialize, Debug)] +#[derive(Deserialize, Serialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Usage { pub users: Users, @@ -157,7 +157,7 @@ pub struct Usage { } /// statistics about the users of this server. -#[derive(Deserialize, Serialize, Debug)] +#[derive(Deserialize, Serialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Users { pub total: Option, @@ -187,3 +187,69 @@ impl From for Nodeinfo20 { } } } + +#[cfg(test)] +mod unit_test { + use super::{Nodeinfo20, Nodeinfo21}; + use pretty_assertions::assert_eq; + + #[test] + fn parse_nodeinfo_2_0() { + let json_str_1 = r#"{"version":"2.0","software":{"name":"mastodon","version":"4.3.0-nightly.2024-04-30"},"protocols":["activitypub"],"services":{"outbound":[],"inbound":[]},"usage":{"users":{"total":1935016,"activeMonth":238223,"activeHalfyear":618795},"localPosts":90175135},"openRegistrations":true,"metadata":{"nodeName":"Mastodon","nodeDescription":"The original server operated by the Mastodon gGmbH non-profit"}}"#; + let parsed_1: Nodeinfo20 = serde_json::from_str(json_str_1).unwrap(); + let serialized_1 = serde_json::to_string(&parsed_1).unwrap(); + let reparsed_1: Nodeinfo20 = serde_json::from_str(&serialized_1).unwrap(); + + assert_eq!(parsed_1, reparsed_1); + assert_eq!(parsed_1.software.name, "mastodon"); + assert_eq!(parsed_1.software.version, "4.3.0-nightly.2024-04-30"); + + let json_str_2 = r#"{"version":"2.0","software":{"name":"peertube","version":"5.0.0"},"protocols":["activitypub"],"services":{"inbound":[],"outbound":["atom1.0","rss2.0"]},"openRegistrations":false,"usage":{"users":{"total":5,"activeMonth":0,"activeHalfyear":2},"localPosts":1018,"localComments":1},"metadata":{"taxonomy":{"postsName":"Videos"},"nodeName":"Blender Video","nodeDescription":"Blender Foundation PeerTube instance.","nodeConfig":{"search":{"remoteUri":{"users":true,"anonymous":false}},"plugin":{"registered":[]},"theme":{"registered":[],"default":"default"},"email":{"enabled":false},"contactForm":{"enabled":true},"transcoding":{"hls":{"enabled":true},"webtorrent":{"enabled":true},"enabledResolutions":[1080]},"live":{"enabled":false,"transcoding":{"enabled":true,"enabledResolutions":[]}},"import":{"videos":{"http":{"enabled":true},"torrent":{"enabled":false}}},"autoBlacklist":{"videos":{"ofUsers":{"enabled":false}}},"avatar":{"file":{"size":{"max":4194304},"extensions":[".png",".jpeg",".jpg",".gif",".webp"]}},"video":{"image":{"extensions":[".png",".jpg",".jpeg",".webp"],"size":{"max":4194304}},"file":{"extensions":[".webm",".ogv",".ogg",".mp4",".mkv",".mov",".qt",".mqv",".m4v",".flv",".f4v",".wmv",".avi",".3gp",".3gpp",".3g2",".3gpp2",".nut",".mts",".m2ts",".mpv",".m2v",".m1v",".mpg",".mpe",".mpeg",".vob",".mxf",".mp3",".wma",".wav",".flac",".aac",".m4a",".ac3"]}},"videoCaption":{"file":{"size":{"max":20971520},"extensions":[".vtt",".srt"]}},"user":{"videoQuota":5368709120,"videoQuotaDaily":-1},"trending":{"videos":{"intervalDays":7}},"tracker":{"enabled":true}}}}"#; + let parsed_2: Nodeinfo20 = serde_json::from_str(json_str_2).unwrap(); + let serialized_2 = serde_json::to_string(&parsed_2).unwrap(); + let reparsed_2: Nodeinfo20 = serde_json::from_str(&serialized_2).unwrap(); + + assert_eq!(parsed_2, reparsed_2); + assert_eq!(parsed_2.software.name, "peertube"); + assert_eq!(parsed_2.software.version, "5.0.0"); + + let json_str_3 = r#"{"metadata":{"nodeName":"pixelfed","software":{"homepage":"https://pixelfed.org","repo":"https://github.com/pixelfed/pixelfed"},"config":{"features":{"timelines":{"local":true,"network":true},"mobile_apis":true,"stories":true,"video":true,"import":{"instagram":false,"mastodon":false,"pixelfed":false},"label":{"covid":{"enabled":false,"org":"visit the WHO website","url":"https://www.who.int/emergencies/diseases/novel-coronavirus-2019/advice-for-public"}},"hls":{"enabled":false}}}},"protocols":["activitypub"],"services":{"inbound":[],"outbound":[]},"software":{"name":"pixelfed","version":"0.12.0"},"usage":{"localPosts":24059868,"localComments":0,"users":{"total":112832,"activeHalfyear":24366,"activeMonth":8921}},"version":"2.0","openRegistrations":true}"#; + let parsed_3: Nodeinfo20 = serde_json::from_str(json_str_3).unwrap(); + let serialized_3 = serde_json::to_string(&parsed_3).unwrap(); + let reparsed_3: Nodeinfo20 = serde_json::from_str(&serialized_3).unwrap(); + + assert_eq!(parsed_3, reparsed_3); + assert_eq!(parsed_3.software.name, "pixelfed"); + assert_eq!(parsed_3.software.version, "0.12.0"); + } + + #[test] + fn parse_nodeinfo_2_1() { + let json_str_1 = r##"{"version":"2.1","software":{"name":"catodon","version":"24.04-dev.2","repository":"https://codeberg.org/catodon/catodon","homepage":"https://codeberg.org/catodon/catodon"},"protocols":["activitypub"],"services":{"inbound":[],"outbound":["atom1.0","rss2.0"]},"openRegistrations":true,"usage":{"users":{"total":294,"activeHalfyear":292,"activeMonth":139},"localPosts":22616,"localComments":0},"metadata":{"nodeName":"Catodon Social","nodeDescription":"🌎 Home of Catodon, a new platform for fedi communities, initially based on Iceshrimp/Firefish/Misskey. Be aware that our first release is not out yet, so things are still experimental.","maintainer":{"name":"admin","email":"redacted@example.com"},"langs":[],"tosUrl":"https://example.com/redacted","repositoryUrl":"https://codeberg.org/catodon/catodon","feedbackUrl":"https://codeberg.org/catodon/catodon/issues","disableRegistration":false,"disableLocalTimeline":false,"disableRecommendedTimeline":true,"disableGlobalTimeline":false,"emailRequiredForSignup":true,"postEditing":true,"postImports":false,"enableHcaptcha":true,"enableRecaptcha":false,"maxNoteTextLength":8000,"maxCaptionTextLength":1500,"enableGithubIntegration":false,"enableDiscordIntegration":false,"enableEmail":true,"themeColor":"#31748f"}}"##; + let parsed_1: Nodeinfo21 = serde_json::from_str(json_str_1).unwrap(); + let serialized_1 = serde_json::to_string(&parsed_1).unwrap(); + let reparsed_1: Nodeinfo21 = serde_json::from_str(&serialized_1).unwrap(); + + assert_eq!(parsed_1, reparsed_1); + assert_eq!(parsed_1.software.name, "catodon"); + assert_eq!(parsed_1.software.version, "24.04-dev.2"); + + let json_str_2 = r#"{"version":"2.1","software":{"name":"meisskey","version":"10.102.699-m544","repository":"https://github.com/mei23/misskey"},"protocols":["activitypub"],"services":{"inbound":[],"outbound":["atom1.0","rss2.0"]},"openRegistrations":true,"usage":{"users":{"total":1123,"activeHalfyear":305,"activeMonth":89},"localPosts":268739,"localComments":0},"metadata":{"nodeName":"meisskey.one","nodeDescription":"ローカルタイムラインのないインスタンスなのだわ\n\n\n[通報・報告 (Report)](https://example.com/redacted)","name":"meisskey.one","description":"ローカルタイムラインのないインスタンスなのだわ\n\n\n[通報・報告 (Report)](https://example.com/redacted)","maintainer":{"name":"redacted","email":"redacted"},"langs":[],"announcements":[{"title":"問題・要望など","text":"問題・要望などは #meisskeyone要望 で投稿してなのだわ"}],"relayActor":"https://example.com/redacted","relays":[],"disableRegistration":false,"disableLocalTimeline":true,"enableRecaptcha":true,"maxNoteTextLength":5000,"enableTwitterIntegration":false,"enableGithubIntegration":false,"enableDiscordIntegration":false,"enableServiceWorker":true,"proxyAccountName":"ghost"}}"#; + let parsed_2: Nodeinfo21 = serde_json::from_str(json_str_2).unwrap(); + let serialized_2 = serde_json::to_string(&parsed_2).unwrap(); + let reparsed_2: Nodeinfo21 = serde_json::from_str(&serialized_2).unwrap(); + + assert_eq!(parsed_2, reparsed_2); + assert_eq!(parsed_2.software.name, "meisskey"); + assert_eq!(parsed_2.software.version, "10.102.699-m544"); + + let json_str_3 = r##"{"metadata":{"enableGlobalTimeline":true,"enableGuestTimeline":false,"enableLocalTimeline":true,"enableRecommendedTimeline":false,"maintainerEmail":"","maintainerName":"Firefish dev team","nodeDescription":"","nodeName":"Firefish","repositoryUrl":"https://firefish.dev/firefish/firefish","themeColor":"#F25A85"},"openRegistrations":false,"protocols":["activitypub"],"services":{"inbound":[],"outbound":["atom1.0","rss2.0"]},"software":{"homepage":"https://firefish.dev/firefish/firefish","name":"firefish","repository":"https://firefish.dev/firefish/firefish","version":"20240504"},"usage":{"localPosts":23857,"users":{"activeHalfyear":7,"activeMonth":7,"total":9}},"version":"2.1"}"##; + let parsed_3: Nodeinfo20 = serde_json::from_str(json_str_3).unwrap(); + let serialized_3 = serde_json::to_string(&parsed_3).unwrap(); + let reparsed_3: Nodeinfo20 = serde_json::from_str(&serialized_3).unwrap(); + + assert_eq!(parsed_3, reparsed_3); + assert_eq!(parsed_3.software.name, "firefish"); + assert_eq!(parsed_3.software.version, "20240504"); + } +} From dd74eabae19b3d623656470745c64751d62d6674 Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 08:12:21 +0900 Subject: [PATCH 37/75] refactor (backend): port nodeinfo fetcher to backend-rs --- packages/backend-rs/index.d.ts | 98 +++++++++++ packages/backend-rs/index.js | 6 +- .../backend-rs/src/service/nodeinfo/fetch.rs | 161 ++++++++++++++++++ .../src/service/nodeinfo/generate.rs | 18 +- .../backend-rs/src/service/nodeinfo/mod.rs | 1 + .../backend-rs/src/service/nodeinfo/schema.rs | 20 ++- packages/backend-rs/src/util/http_client.rs | 1 + .../src/services/fetch-instance-metadata.ts | 108 ++---------- 8 files changed, 308 insertions(+), 105 deletions(-) create mode 100644 packages/backend-rs/src/service/nodeinfo/fetch.rs diff --git a/packages/backend-rs/index.d.ts b/packages/backend-rs/index.d.ts index 3eef51ab43..a6c5bc29fb 100644 --- a/packages/backend-rs/index.d.ts +++ b/packages/backend-rs/index.d.ts @@ -1155,8 +1155,106 @@ export interface Webhook { latestStatus: number | null } export function initializeRustLogger(): void +export function fetchNodeinfo(host: string): Promise export function nodeinfo_2_1(): Promise export function nodeinfo_2_0(): Promise +/** NodeInfo schema version 2.0. https://nodeinfo.diaspora.software/docson/index.html#/ns/schema/2.0 */ +export interface Nodeinfo { + /** The schema version, must be 2.0. */ + version: string + /** Metadata about server software in use. */ + software: Software20 + /** The protocols supported on this server. */ + protocols: Array + /** The third party sites this server can connect to via their application API. */ + services: Services + /** Whether this server allows open self-registration. */ + openRegistrations: boolean + /** Usage statistics for this server. */ + usage: Usage + /** Free form key value pairs for software specific values. Clients should not rely on any specific key present. */ + metadata: Record +} +/** Metadata about server software in use (version 2.0). */ +export interface Software20 { + /** The canonical name of this server software. */ + name: string + /** The version of this server software. */ + version: string +} +export enum Protocol { + Activitypub = 'activitypub', + Buddycloud = 'buddycloud', + Dfrn = 'dfrn', + Diaspora = 'diaspora', + Libertree = 'libertree', + Ostatus = 'ostatus', + Pumpio = 'pumpio', + Tent = 'tent', + Xmpp = 'xmpp', + Zot = 'zot' +} +/** The third party sites this server can connect to via their application API. */ +export interface Services { + /** The third party sites this server can retrieve messages from for combined display with regular traffic. */ + inbound: Array + /** The third party sites this server can publish messages to on the behalf of a user. */ + outbound: Array +} +/** The third party sites this server can retrieve messages from for combined display with regular traffic. */ +export enum Inbound { + Atom1 = 'atom1', + Gnusocial = 'gnusocial', + Imap = 'imap', + Pnut = 'pnut', + Pop3 = 'pop3', + Pumpio = 'pumpio', + Rss2 = 'rss2', + Twitter = 'twitter' +} +/** The third party sites this server can publish messages to on the behalf of a user. */ +export enum Outbound { + Atom1 = 'atom1', + Blogger = 'blogger', + Buddycloud = 'buddycloud', + Diaspora = 'diaspora', + Dreamwidth = 'dreamwidth', + Drupal = 'drupal', + Facebook = 'facebook', + Friendica = 'friendica', + Gnusocial = 'gnusocial', + Google = 'google', + Insanejournal = 'insanejournal', + Libertree = 'libertree', + Linkedin = 'linkedin', + Livejournal = 'livejournal', + Mediagoblin = 'mediagoblin', + Myspace = 'myspace', + Pinterest = 'pinterest', + Pnut = 'pnut', + Posterous = 'posterous', + Pumpio = 'pumpio', + Redmatrix = 'redmatrix', + Rss2 = 'rss2', + Smtp = 'smtp', + Tent = 'tent', + Tumblr = 'tumblr', + Twitter = 'twitter', + Wordpress = 'wordpress', + Xmpp = 'xmpp' +} +/** Usage statistics for this server. */ +export interface Usage { + users: Users + localPosts: number | null + localComments: number | null +} +/** statistics about the users of this server. */ +export interface Users { + total: number | null + activeHalfyear: number | null + activeMonth: number | null +} export function watchNote(watcherId: string, noteAuthorId: string, noteId: string): Promise export function unwatchNote(watcherId: string, noteId: string): Promise export function publishToChannelStream(channelId: string, userId: string): void diff --git a/packages/backend-rs/index.js b/packages/backend-rs/index.js index c518f59a4b..5cf200133a 100644 --- a/packages/backend-rs/index.js +++ b/packages/backend-rs/index.js @@ -310,7 +310,7 @@ if (!nativeBinding) { throw new Error(`Failed to load native binding`) } -const { SECOND, MINUTE, HOUR, DAY, USER_ONLINE_THRESHOLD, USER_ACTIVE_THRESHOLD, FILE_TYPE_BROWSERSAFE, loadEnv, loadConfig, stringToAcct, acctToString, addNoteToAntenna, isBlockedServer, isSilencedServer, isAllowedServer, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, getImageSizeFromUrl, getNoteSummary, latestVersion, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, removeOldAttestationChallenges, AntennaSrcEnum, DriveFileUsageHintEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initializeRustLogger, nodeinfo_2_1, nodeinfo_2_0, watchNote, unwatchNote, publishToChannelStream, ChatEvent, publishToChatStream, ChatIndexEvent, publishToChatIndexStream, publishToBroadcastStream, publishToGroupChatStream, publishToModerationStream, getTimestamp, genId, genIdAt, secureRndstr } = nativeBinding +const { SECOND, MINUTE, HOUR, DAY, USER_ONLINE_THRESHOLD, USER_ACTIVE_THRESHOLD, FILE_TYPE_BROWSERSAFE, loadEnv, loadConfig, stringToAcct, acctToString, addNoteToAntenna, isBlockedServer, isSilencedServer, isAllowedServer, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, getImageSizeFromUrl, getNoteSummary, latestVersion, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, removeOldAttestationChallenges, AntennaSrcEnum, DriveFileUsageHintEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initializeRustLogger, fetchNodeinfo, nodeinfo_2_1, nodeinfo_2_0, Protocol, Inbound, Outbound, watchNote, unwatchNote, publishToChannelStream, ChatEvent, publishToChatStream, ChatIndexEvent, publishToChatIndexStream, publishToBroadcastStream, publishToGroupChatStream, publishToModerationStream, getTimestamp, genId, genIdAt, secureRndstr } = nativeBinding module.exports.SECOND = SECOND module.exports.MINUTE = MINUTE @@ -364,8 +364,12 @@ module.exports.UserEmojimodpermEnum = UserEmojimodpermEnum module.exports.UserProfileFfvisibilityEnum = UserProfileFfvisibilityEnum module.exports.UserProfileMutingnotificationtypesEnum = UserProfileMutingnotificationtypesEnum module.exports.initializeRustLogger = initializeRustLogger +module.exports.fetchNodeinfo = fetchNodeinfo module.exports.nodeinfo_2_1 = nodeinfo_2_1 module.exports.nodeinfo_2_0 = nodeinfo_2_0 +module.exports.Protocol = Protocol +module.exports.Inbound = Inbound +module.exports.Outbound = Outbound module.exports.watchNote = watchNote module.exports.unwatchNote = unwatchNote module.exports.publishToChannelStream = publishToChannelStream diff --git a/packages/backend-rs/src/service/nodeinfo/fetch.rs b/packages/backend-rs/src/service/nodeinfo/fetch.rs new file mode 100644 index 0000000000..8177663394 --- /dev/null +++ b/packages/backend-rs/src/service/nodeinfo/fetch.rs @@ -0,0 +1,161 @@ +use crate::service::nodeinfo::schema::*; +use crate::util::http_client; +use isahc::AsyncReadResponseExt; +use serde::{Deserialize, Serialize}; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Http client aquisition error: {0}")] + HttpClientErr(#[from] http_client::Error), + #[error("Http error: {0}")] + HttpErr(#[from] isahc::Error), + #[error("Bad status: {0}")] + BadStatus(String), + #[error("Failed to parse response body as text: {0}")] + ResponseErr(#[from] std::io::Error), + #[error("Failed to parse response body as json: {0}")] + JsonErr(#[from] serde_json::Error), + #[error("No nodeinfo provided")] + MissingNodeinfo, +} + +#[derive(Deserialize, Serialize, Debug)] +pub struct NodeinfoLinks { + links: Vec, +} + +#[derive(Deserialize, Serialize, Debug)] +pub struct NodeinfoLink { + rel: String, + href: String, +} + +#[inline] +fn wellknown_nodeinfo_url(host: &str) -> String { + format!("https://{}/.well-known/nodeinfo", host) +} + +async fn fetch_nodeinfo_links(host: &str) -> Result { + let client = http_client::client()?; + let wellknown_url = wellknown_nodeinfo_url(host); + let mut wellknown_response = client.get_async(&wellknown_url).await?; + + if !wellknown_response.status().is_success() { + tracing::debug!("{:#?}", wellknown_response.body()); + return Err(Error::BadStatus(format!( + "{} returned {}", + wellknown_url, + wellknown_response.status() + ))); + } + + Ok(serde_json::from_str(&wellknown_response.text().await?)?) +} + +fn check_nodeinfo_link(links: NodeinfoLinks) -> Result { + for link in links.links { + if link.rel == "http://nodeinfo.diaspora.software/ns/schema/2.1" + || link.rel == "http://nodeinfo.diaspora.software/ns/schema/2.0" + { + return Ok(link.href); + } + } + + Err(Error::MissingNodeinfo) +} + +async fn fetch_nodeinfo_impl(nodeinfo_link: &str) -> Result { + let client = http_client::client()?; + let mut response = client.get_async(nodeinfo_link).await?; + + if !response.status().is_success() { + tracing::debug!("{:#?}", response.body()); + return Err(Error::BadStatus(format!( + "{} returned {}", + nodeinfo_link, + response.status() + ))); + } + + Ok(serde_json::from_str(&response.text().await?)?) +} + +// for napi export +type Nodeinfo = Nodeinfo20; + +#[crate::export] +pub async fn fetch_nodeinfo(host: &str) -> Result { + tracing::info!("fetching from {}", host); + let links = fetch_nodeinfo_links(host).await?; + let nodeinfo_link = check_nodeinfo_link(links)?; + fetch_nodeinfo_impl(&nodeinfo_link).await +} + +#[cfg(test)] +mod unit_test { + use super::{check_nodeinfo_link, fetch_nodeinfo, NodeinfoLink, NodeinfoLinks}; + use pretty_assertions::assert_eq; + + #[test] + fn test_check_nodeinfo_link() { + let links_1 = NodeinfoLinks { + links: vec![ + NodeinfoLink { + rel: "https://example.com/incorrect/schema/2.0".to_string(), + href: "https://example.com/dummy".to_string(), + }, + NodeinfoLink { + rel: "http://nodeinfo.diaspora.software/ns/schema/2.0".to_string(), + href: "https://example.com/real".to_string(), + }, + ], + }; + assert_eq!( + check_nodeinfo_link(links_1).unwrap(), + "https://example.com/real" + ); + + let links_2 = NodeinfoLinks { + links: vec![ + NodeinfoLink { + rel: "https://example.com/incorrect/schema/2.0".to_string(), + href: "https://example.com/dummy".to_string(), + }, + NodeinfoLink { + rel: "http://nodeinfo.diaspora.software/ns/schema/2.1".to_string(), + href: "https://example.com/real".to_string(), + }, + ], + }; + assert_eq!( + check_nodeinfo_link(links_2).unwrap(), + "https://example.com/real" + ); + + let links_3 = NodeinfoLinks { + links: vec![ + NodeinfoLink { + rel: "https://example.com/incorrect/schema/2.0".to_string(), + href: "https://example.com/dummy/2.0".to_string(), + }, + NodeinfoLink { + rel: "https://example.com/incorrect/schema/2.1".to_string(), + href: "https://example.com/dummy/2.1".to_string(), + }, + ], + }; + check_nodeinfo_link(links_3).expect_err("No nodeinfo"); + } + + #[tokio::test] + async fn test_fetch_nodeinfo() { + assert_eq!( + fetch_nodeinfo("info.firefish.dev") + .await + .unwrap() + .software + .name, + "firefish" + ); + } +} diff --git a/packages/backend-rs/src/service/nodeinfo/generate.rs b/packages/backend-rs/src/service/nodeinfo/generate.rs index 168b13ba1b..3385c5a6f8 100644 --- a/packages/backend-rs/src/service/nodeinfo/generate.rs +++ b/packages/backend-rs/src/service/nodeinfo/generate.rs @@ -48,7 +48,7 @@ async fn statistics() -> Result<(u64, u64, u64, u64), DbErr> { ) } -async fn get_new_nodeinfo_2_1() -> Result { +async fn generate_nodeinfo_2_1() -> Result { let (local_users, local_active_halfyear, local_active_month, local_posts) = statistics().await?; let meta = fetch_meta(true).await?; @@ -75,8 +75,10 @@ async fn get_new_nodeinfo_2_1() -> Result { "enableGuestTimeline".to_string(), json!(meta.enable_guest_timeline), ), - ("maintainerName".to_string(), json!(meta.maintainer_name)), - ("maintainerEmail".to_string(), json!(meta.maintainer_email)), + ( + "maintainer".to_string(), + json!({"name":meta.maintainer_name,"email":meta.maintainer_email}), + ), ("proxyAccountName".to_string(), json!(meta.proxy_account_id)), ( "themeColor".to_string(), @@ -100,11 +102,11 @@ async fn get_new_nodeinfo_2_1() -> Result { open_registrations: !meta.disable_registration, usage: Usage { users: Users { - total: Some(local_users), - active_halfyear: Some(local_active_halfyear), - active_month: Some(local_active_month), + total: Some(local_users as u32), + active_halfyear: Some(local_active_halfyear as u32), + active_month: Some(local_active_month as u32), }, - local_posts: Some(local_posts), + local_posts: Some(local_posts as u32), local_comments: None, }, metadata, @@ -119,7 +121,7 @@ pub async fn nodeinfo_2_1() -> Result { if let Some(nodeinfo) = cached { Ok(nodeinfo) } else { - let nodeinfo = get_new_nodeinfo_2_1().await?; + let nodeinfo = generate_nodeinfo_2_1().await?; cache::set(NODEINFO_2_1_CACHE_KEY, &nodeinfo, 60 * 60)?; Ok(nodeinfo) } diff --git a/packages/backend-rs/src/service/nodeinfo/mod.rs b/packages/backend-rs/src/service/nodeinfo/mod.rs index 563a8046d6..e3511ba7e8 100644 --- a/packages/backend-rs/src/service/nodeinfo/mod.rs +++ b/packages/backend-rs/src/service/nodeinfo/mod.rs @@ -1,2 +1,3 @@ +pub mod fetch; pub mod generate; pub mod schema; diff --git a/packages/backend-rs/src/service/nodeinfo/schema.rs b/packages/backend-rs/src/service/nodeinfo/schema.rs index ae7b5a52c2..b2a1b67225 100644 --- a/packages/backend-rs/src/service/nodeinfo/schema.rs +++ b/packages/backend-rs/src/service/nodeinfo/schema.rs @@ -28,6 +28,7 @@ pub struct Nodeinfo21 { /// NodeInfo schema version 2.0. https://nodeinfo.diaspora.software/docson/index.html#/ns/schema/2.0 #[derive(Deserialize, Serialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] +#[crate::export(object, js_name = "Nodeinfo")] pub struct Nodeinfo20 { /// The schema version, must be 2.0. pub version: String, @@ -62,6 +63,7 @@ pub struct Software21 { /// Metadata about server software in use (version 2.0). #[derive(Deserialize, Serialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] +#[crate::export(object)] pub struct Software20 { /// The canonical name of this server software. pub name: String, @@ -71,6 +73,7 @@ pub struct Software20 { #[derive(Deserialize, Serialize, Debug, PartialEq)] #[serde(rename_all = "lowercase")] +#[crate::export(string_enum = "lowercase")] pub enum Protocol { Activitypub, Buddycloud, @@ -87,6 +90,7 @@ pub enum Protocol { /// The third party sites this server can connect to via their application API. #[derive(Deserialize, Serialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] +#[crate::export(object)] pub struct Services { /// The third party sites this server can retrieve messages from for combined display with regular traffic. pub inbound: Vec, @@ -97,6 +101,7 @@ pub struct Services { /// The third party sites this server can retrieve messages from for combined display with regular traffic. #[derive(Deserialize, Serialize, Debug, PartialEq)] #[serde(rename_all = "lowercase")] +#[crate::export(string_enum = "lowercase")] pub enum Inbound { #[serde(rename = "atom1.0")] Atom1, @@ -114,6 +119,7 @@ pub enum Inbound { /// The third party sites this server can publish messages to on the behalf of a user. #[derive(Deserialize, Serialize, Debug, PartialEq)] #[serde(rename_all = "lowercase")] +#[crate::export(string_enum = "lowercase")] pub enum Outbound { #[serde(rename = "atom1.0")] Atom1, @@ -150,19 +156,21 @@ pub enum Outbound { /// Usage statistics for this server. #[derive(Deserialize, Serialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] +#[crate::export(object)] pub struct Usage { pub users: Users, - pub local_posts: Option, - pub local_comments: Option, + pub local_posts: Option, + pub local_comments: Option, } /// statistics about the users of this server. #[derive(Deserialize, Serialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] +#[crate::export(object)] pub struct Users { - pub total: Option, - pub active_halfyear: Option, - pub active_month: Option, + pub total: Option, + pub active_halfyear: Option, + pub active_month: Option, } impl From for Software20 { @@ -243,7 +251,7 @@ mod unit_test { assert_eq!(parsed_2.software.name, "meisskey"); assert_eq!(parsed_2.software.version, "10.102.699-m544"); - let json_str_3 = r##"{"metadata":{"enableGlobalTimeline":true,"enableGuestTimeline":false,"enableLocalTimeline":true,"enableRecommendedTimeline":false,"maintainerEmail":"","maintainerName":"Firefish dev team","nodeDescription":"","nodeName":"Firefish","repositoryUrl":"https://firefish.dev/firefish/firefish","themeColor":"#F25A85"},"openRegistrations":false,"protocols":["activitypub"],"services":{"inbound":[],"outbound":["atom1.0","rss2.0"]},"software":{"homepage":"https://firefish.dev/firefish/firefish","name":"firefish","repository":"https://firefish.dev/firefish/firefish","version":"20240504"},"usage":{"localPosts":23857,"users":{"activeHalfyear":7,"activeMonth":7,"total":9}},"version":"2.1"}"##; + let json_str_3 = r##"{"metadata":{"enableGlobalTimeline":true,"enableGuestTimeline":false,"enableLocalTimeline":true,"enableRecommendedTimeline":false,"maintainer":{"name":"Firefish dev team"},"nodeDescription":"","nodeName":"Firefish","repositoryUrl":"https://firefish.dev/firefish/firefish","themeColor":"#F25A85"},"openRegistrations":false,"protocols":["activitypub"],"services":{"inbound":[],"outbound":["atom1.0","rss2.0"]},"software":{"homepage":"https://firefish.dev/firefish/firefish","name":"firefish","repository":"https://firefish.dev/firefish/firefish","version":"20240504"},"usage":{"localPosts":23857,"users":{"activeHalfyear":7,"activeMonth":7,"total":9}},"version":"2.1"}"##; let parsed_3: Nodeinfo20 = serde_json::from_str(json_str_3).unwrap(); let serialized_3 = serde_json::to_string(&parsed_3).unwrap(); let reparsed_3: Nodeinfo20 = serde_json::from_str(&serialized_3).unwrap(); diff --git a/packages/backend-rs/src/util/http_client.rs b/packages/backend-rs/src/util/http_client.rs index eb328dc41c..97967fcfd1 100644 --- a/packages/backend-rs/src/util/http_client.rs +++ b/packages/backend-rs/src/util/http_client.rs @@ -18,6 +18,7 @@ pub fn client() -> Result { .get_or_try_init(|| { let mut builder = HttpClient::builder() .timeout(Duration::from_secs(10)) + .default_header("user-agent", &CONFIG.user_agent) .dns_cache(DnsCache::Timeout(Duration::from_secs(60 * 60))); if let Some(proxy_url) = &CONFIG.proxy { diff --git a/packages/backend/src/services/fetch-instance-metadata.ts b/packages/backend/src/services/fetch-instance-metadata.ts index bb9f9d0bd1..d42f93842b 100644 --- a/packages/backend/src/services/fetch-instance-metadata.ts +++ b/packages/backend/src/services/fetch-instance-metadata.ts @@ -10,6 +10,7 @@ import { import { Instances } from "@/models/index.js"; import { getFetchInstanceMetadataLock } from "@/misc/app-lock.js"; import Logger from "@/services/logger.js"; +import { type Nodeinfo, fetchNodeinfo } from "backend-rs"; import { inspect } from "node:util"; const logger = new Logger("metadata", "cyan"); @@ -36,7 +37,7 @@ export async function fetchInstanceMetadata( try { const [info, dom, manifest] = await Promise.all([ - fetchNodeinfo(instance).catch(() => null), + fetchNodeinfo(instance.host).catch(() => null), fetchDom(instance).catch(() => null), fetchManifest(instance).catch(() => null), ]); @@ -57,30 +58,26 @@ export async function fetchInstanceMetadata( if (info) { updates.softwareName = - info.software?.name - ?.toLowerCase() + info.software.name + .toLowerCase() .substring(0, MAX_LENGTH_INSTANCE.softwareName) || null; updates.softwareVersion = - info.software?.version?.substring( + info.software.version.substring( 0, MAX_LENGTH_INSTANCE.softwareVersion, ) || null; updates.openRegistrations = info.openRegistrations; - updates.maintainerName = info.metadata - ? info.metadata.maintainer - ? info.metadata.maintainer.name?.substring( - 0, - MAX_LENGTH_INSTANCE.maintainerName, - ) || null - : null + updates.maintainerName = info.metadata.maintainer + ? info.metadata.maintainer.name?.substring( + 0, + MAX_LENGTH_INSTANCE.maintainerName, + ) || null : null; - updates.maintainerEmail = info.metadata - ? info.metadata.maintainer - ? info.metadata.maintainer.email?.substring( - 0, - MAX_LENGTH_INSTANCE.maintainerEmail, - ) || null - : null + updates.maintainerEmail = info.metadata.maintainer + ? info.metadata.maintainer.email?.substring( + 0, + MAX_LENGTH_INSTANCE.maintainerEmail, + ) || null : null; } @@ -115,75 +112,6 @@ export async function fetchInstanceMetadata( } } -type NodeInfo = { - openRegistrations?: boolean; - software?: { - name?: string; - version?: string; - }; - metadata?: { - name?: string; - nodeName?: string; - nodeDescription?: string; - description?: string; - maintainer?: { - name?: string; - email?: string; - }; - }; -}; - -async function fetchNodeinfo(instance: Instance): Promise { - logger.info(`Fetching nodeinfo of ${instance.host} ...`); - - try { - const wellknown = (await getJson( - `https://${instance.host}/.well-known/nodeinfo`, - ).catch((e) => { - if (e.statusCode === 404) { - throw new Error("No nodeinfo provided"); - } else { - throw new Error(inspect(e)); - } - })) as Record; - - if (wellknown.links == null || !Array.isArray(wellknown.links)) { - throw new Error("No wellknown links"); - } - - const links = wellknown.links as any[]; - - const lnik1_0 = links.find( - (link) => link.rel === "http://nodeinfo.diaspora.software/ns/schema/1.0", - ); - const lnik2_0 = links.find( - (link) => link.rel === "http://nodeinfo.diaspora.software/ns/schema/2.0", - ); - const lnik2_1 = links.find( - (link) => link.rel === "http://nodeinfo.diaspora.software/ns/schema/2.1", - ); - const link = lnik2_1 || lnik2_0 || lnik1_0; - - if (link == null) { - throw new Error("No nodeinfo link provided"); - } - - const info = await getJson(link.href).catch((e) => { - throw new Error(inspect(e)); - }); - - logger.info(`Successfuly fetched nodeinfo of ${instance.host}`); - - return info as NodeInfo; - } catch (e) { - logger.error( - `Failed to fetch nodeinfo of ${instance.host}:\n${inspect(e)}`, - ); - - throw e; - } -} - async function fetchDom(instance: Instance): Promise { logger.info(`Fetching HTML of ${instance.host} ...`); @@ -272,7 +200,7 @@ async function fetchIconUrl( } async function getThemeColor( - info: NodeInfo | null, + info: Nodeinfo | null, doc: Window["document"] | null, manifest: Record | null, ): Promise { @@ -290,7 +218,7 @@ async function getThemeColor( } async function getSiteName( - info: NodeInfo | null, + info: Nodeinfo | null, doc: Window["document"] | null, manifest: Record | null, ): Promise { @@ -318,7 +246,7 @@ async function getSiteName( } async function getDescription( - info: NodeInfo | null, + info: Nodeinfo | null, doc: Window["document"] | null, manifest: Record | null, ): Promise { From e7c33835b2fe9649f545deef988fad429b33097e Mon Sep 17 00:00:00 2001 From: eana Date: Mon, 6 May 2024 05:14:44 +0000 Subject: [PATCH 38/75] Add server-side per-user UI language --- docs/api-change.md | 2 ++ docs/downgrade.sql | 3 --- locales/en-US.yml | 3 +++ locales/ja-JP.yml | 3 +++ locales/zh-CN.yml | 3 +++ locales/zh-TW.yml | 3 +++ .../1714888400293-add-user-profile-language.ts | 13 +++++++++++++ .../backend/src/models/entities/user-profile.ts | 6 ++++++ packages/backend/src/models/repositories/user.ts | 1 + packages/backend/src/models/schema/user.ts | 6 ++++++ .../backend/src/server/api/endpoints/i/update.ts | 2 ++ packages/client/src/account.ts | 3 +++ packages/client/src/pages/settings/general.vue | 15 +++++++++++++++ 13 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 packages/backend/src/migration/1714888400293-add-user-profile-language.ts diff --git a/docs/api-change.md b/docs/api-change.md index f5254955f2..2ffbf3a826 100644 --- a/docs/api-change.md +++ b/docs/api-change.md @@ -2,6 +2,8 @@ Breaking changes are indicated by the :warning: icon. +- Adding `lang` from the response of `i` and the request parameter of `i/update`. + ## v20240504 - :warning: Removed `release` endpoint. diff --git a/docs/downgrade.sql b/docs/downgrade.sql index 787785eb67..6f3901006f 100644 --- a/docs/downgrade.sql +++ b/docs/downgrade.sql @@ -764,9 +764,6 @@ CREATE SEQUENCE public.__chart_day__users_id_seq CACHE 1; ALTER SEQUENCE public.__chart_day__users_id_seq OWNED BY public.__chart_day__users.id; --- drop-user-profile-language -ALTER TABLE "user_profile" ADD COLUMN "lang" character varying(32); - -- emoji-moderator ALTER TABLE "user" DROP COLUMN "emojiModPerm"; DROP TYPE "public"."user_emojimodperm_enum"; diff --git a/locales/en-US.yml b/locales/en-US.yml index 08fcc490ea..d5b81b0be1 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -766,6 +766,9 @@ confirmToUnclipAlreadyClippedNote: "This post is already part of the \"{name}\" public: "Public" i18nInfo: "Firefish is being translated into various languages by volunteers. You can help at {link}." +i18nServerInfo: "New clients will be in {language} by default." +i18nServerChange: "Use {language} instead." +i18nServerSet: "Use {language} for new clients." manageAccessTokens: "Manage access tokens" accountInfo: "Account Info" notesCount: "Number of posts" diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index ef9f9b9bfb..72b7ed2969 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -685,6 +685,9 @@ unclip: "クリップ解除" confirmToUnclipAlreadyClippedNote: "この投稿はすでにクリップ「{name}」に含まれています。投稿をこのクリップから除外しますか?" public: "公開" i18nInfo: "Firefishは有志によって様々な言語に翻訳されています。{link}で翻訳に協力できます。" +i18nServerInfo: "新しいクライアントはデフォルトで {language} で表示します。" +i18nServerChange: "{language} に変更する。" +i18nServerSet: "新しいクライアントの表示言語も {language} にする。" manageAccessTokens: "アクセストークンの管理" accountInfo: "アカウント情報" notesCount: "投稿の数" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 2b326c4066..9744bb95f7 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -667,6 +667,9 @@ unclip: "移除便签" confirmToUnclipAlreadyClippedNote: "本帖已包含在便签 \"{name}\" 里。您想要将本帖从该便签中移除吗?" public: "公开" i18nInfo: "Firefish 已经被志愿者们翻译成了各种语言。如果您也有兴趣,可以通过 {link} 帮助翻译。" +i18nServerInfo: "新客户端将默认使用 {language}。" +i18nServerChange: "改为 {language}。" +i18nServerSet: "设定新客户端使用 {language}。" manageAccessTokens: "管理访问令牌" accountInfo: "账号信息" notesCount: "帖子数量" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index 5a722933e6..556a4efb61 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -661,6 +661,9 @@ unclip: "解除摘錄" confirmToUnclipAlreadyClippedNote: "此貼文已包含在摘錄「{name}」中。 你想將貼文從這個摘錄中排除嗎?" public: "公開" i18nInfo: "Firefish已經被志願者們翻譯成各種語言版本,如果想要幫忙的話,可以進入{link}幫助翻譯。" +i18nServerInfo: "新客戶端將默認使用 {language}。" +i18nServerChange: "改爲 {language}。" +i18nServerSet: "設定新客戶端使用 {language}。" manageAccessTokens: "管理存取權杖" accountInfo: "帳戶資訊" notesCount: "貼文數量" diff --git a/packages/backend/src/migration/1714888400293-add-user-profile-language.ts b/packages/backend/src/migration/1714888400293-add-user-profile-language.ts new file mode 100644 index 0000000000..8fb6496402 --- /dev/null +++ b/packages/backend/src/migration/1714888400293-add-user-profile-language.ts @@ -0,0 +1,13 @@ +import type { MigrationInterface, QueryRunner } from "typeorm"; + +export class AddUserProfileLanguage1714888400293 implements MigrationInterface { + async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "user_profile" ADD COLUMN "lang" character varying(32)`, + ); + } + + async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "lang"`); + } +} diff --git a/packages/backend/src/models/entities/user-profile.ts b/packages/backend/src/models/entities/user-profile.ts index 2fe2b7a58a..2b9ac79195 100644 --- a/packages/backend/src/models/entities/user-profile.ts +++ b/packages/backend/src/models/entities/user-profile.ts @@ -50,6 +50,12 @@ export class UserProfile { verified?: boolean; }[]; + @Column("varchar", { + length: 32, + nullable: true, + }) + public lang: string | null; + @Column("varchar", { length: 512, nullable: true, diff --git a/packages/backend/src/models/repositories/user.ts b/packages/backend/src/models/repositories/user.ts index a5a8771645..0f4ea9f72a 100644 --- a/packages/backend/src/models/repositories/user.ts +++ b/packages/backend/src/models/repositories/user.ts @@ -512,6 +512,7 @@ export const UserRepository = db.getRepository(User).extend({ description: profile!.description, location: profile!.location, birthday: profile!.birthday, + lang: profile!.lang, fields: profile!.fields, followersCount: followersCount ?? null, followingCount: followingCount ?? null, diff --git a/packages/backend/src/models/schema/user.ts b/packages/backend/src/models/schema/user.ts index bcdd718dd1..c7417ce0e4 100644 --- a/packages/backend/src/models/schema/user.ts +++ b/packages/backend/src/models/schema/user.ts @@ -204,6 +204,12 @@ export const packedUserDetailedNotMeOnlySchema = { optional: false, example: "2018-03-12", }, + lang: { + type: "string", + nullable: true, + optional: false, + example: "ja-JP", + }, fields: { type: "array", nullable: false, diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index 9a2b49cb3d..50f0da8f8d 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -87,6 +87,7 @@ export const paramDef = { description: { ...Users.descriptionSchema, nullable: true }, location: { ...Users.locationSchema, nullable: true }, birthday: { ...Users.birthdaySchema, nullable: true }, + lang: { type: "string", nullable: true }, avatarId: { type: "string", format: "misskey:id", nullable: true }, bannerId: { type: "string", format: "misskey:id", nullable: true }, fields: { @@ -154,6 +155,7 @@ export default define(meta, paramDef, async (ps, _user, token) => { if (ps.name !== undefined) updates.name = ps.name; if (ps.description !== undefined) profileUpdates.description = ps.description; + if (typeof ps.lang === "string") profileUpdates.lang = ps.lang; if (ps.location !== undefined) profileUpdates.location = ps.location; if (ps.birthday !== undefined) profileUpdates.birthday = ps.birthday; if (ps.ffVisibility !== undefined) diff --git a/packages/client/src/account.ts b/packages/client/src/account.ts index cf6fb54915..fb3f70c34e 100644 --- a/packages/client/src/account.ts +++ b/packages/client/src/account.ts @@ -132,6 +132,9 @@ export async function signIn(token: Account["token"], redirect?: string) { if (_DEV_) console.log("logging as token ", token); const newAccount = await fetchAccount(token); localStorage.setItem("account", JSON.stringify(newAccount)); + if (newAccount.lang) { + localStorage.setItem("lang", newAccount.lang); + } document.cookie = `token=${token}; path=/; max-age=31536000`; // bull dashboardの認証とかで使う await addAccount(newAccount.id, token); diff --git a/packages/client/src/pages/settings/general.vue b/packages/client/src/pages/settings/general.vue index f6c5ffc742..0659e2b1c4 100644 --- a/packages/client/src/pages/settings/general.vue +++ b/packages/client/src/pages/settings/general.vue @@ -14,6 +14,12 @@ > + + + + @@ -404,6 +410,7 @@ import { deviceKind } from "@/scripts/device-kind"; import icon from "@/scripts/icon"; const lang = ref(localStorage.getItem("lang")); +const serverLang = ref(me?.lang); const translateLang = ref(localStorage.getItem("translateLang")); const fontSize = ref(localStorage.getItem("fontSize")); const useSystemFont = ref(localStorage.getItem("useSystemFont") !== "f"); @@ -559,6 +566,14 @@ const foldNotification = computed( // }); // } +function updateServerLang() { + os.api("i/update", { + lang: lang.value, + }).then((i) => { + serverLang.value = i.lang; + }); +} + watch(swipeOnDesktop, () => { defaultStore.set("swipeOnMobile", true); }); From ef57735e6ab7414613e0d092e6b5a540fdbf254d Mon Sep 17 00:00:00 2001 From: eana Date: Mon, 6 May 2024 05:26:38 +0000 Subject: [PATCH 39/75] fix typo --- docs/api-change.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api-change.md b/docs/api-change.md index 2ffbf3a826..6e5726804b 100644 --- a/docs/api-change.md +++ b/docs/api-change.md @@ -2,7 +2,7 @@ Breaking changes are indicated by the :warning: icon. -- Adding `lang` from the response of `i` and the request parameter of `i/update`. +- Adding `lang` to the response of `i` and the request parameter of `i/update`. ## v20240504 From e797849e9b016d990d832593087e790842650993 Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 16:57:54 +0900 Subject: [PATCH 40/75] ci: attempt to add a CI task for merge requests --- .config/ci.yml | 192 ++----------------------------------------------- .gitlab-ci.yml | 109 ++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 188 deletions(-) create mode 100644 .gitlab-ci.yml diff --git a/.config/ci.yml b/.config/ci.yml index 5534e26590..b3578fb66b 100644 --- a/.config/ci.yml +++ b/.config/ci.yml @@ -1,195 +1,11 @@ -#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -# Firefish configuration -#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -# ┌─────┐ -#───┘ URL └───────────────────────────────────────────────────── - -# Final accessible URL seen by a user. -url: https://example.tld/ - -# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE -# URL SETTINGS AFTER THAT! - -# ┌───────────────────────┐ -#───┘ Port and TLS settings └─────────────────────────────────── - -# -# Misskey requires a reverse proxy to support HTTPS connections. -# -# +----- https://example.tld/ ------------+ -# +------+ |+-------------+ +----------------+| -# | User | ---> || Proxy (443) | ---> | Misskey (3000) || -# +------+ |+-------------+ +----------------+| -# +---------------------------------------+ -# -# You need to set up a reverse proxy. (e.g. nginx) -# An encrypted connection with HTTPS is highly recommended -# because tokens may be transferred in GET requests. - -# The port that your Misskey server should listen on. +url: http://localhost:3000 port: 3000 - -# ┌──────────────────────────┐ -#───┘ PostgreSQL configuration └──────────────────────────────── - db: host: postgres port: 5432 - - # Database name - db: postgres - - # Auth - user: postgres - pass: test - - # Whether disable Caching queries - #disableCache: true - - # Extra Connection options - #extra: - # ssl: true - -# ┌─────────────────────┐ -#───┘ Redis configuration └───────────────────────────────────── - + db: firefish_db + user: firefish + pass: password redis: host: redis port: 6379 - #family: 0 # 0=Both, 4=IPv4, 6=IPv6 - #pass: example-pass - #prefix: example-prefix - #db: 1 - -# ┌─────────────────────────────┐ -#───┘ Elasticsearch configuration └───────────────────────────── - -#elasticsearch: -# host: localhost -# port: 9200 -# ssl: false -# user: -# pass: - -# ┌───────────────┐ -#───┘ ID generation └─────────────────────────────────────────── - -# You can select the ID generation method. -# You don't usually need to change this setting, but you can -# change it according to your preferences. - -# Available methods: -# aid ... Short, Millisecond accuracy -# meid ... Similar to ObjectID, Millisecond accuracy -# ulid ... Millisecond accuracy -# objectid ... This is left for backward compatibility - -# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE -# ID SETTINGS AFTER THAT! - -id: 'aid' - -# ┌─────────────────────┐ -#───┘ Other configuration └───────────────────────────────────── - -# Max note length, should be < 8000. -#maxNoteLength: 3000 - -# Whether disable HSTS -#disableHsts: true - -# Number of worker processes -#clusterLimit: 1 - -# Job concurrency per worker -# deliverJobConcurrency: 128 -# inboxJobConcurrency: 16 - -# Job rate limiter -# deliverJobPerSec: 128 -# inboxJobPerSec: 16 - -# Job attempts -# deliverJobMaxAttempts: 12 -# inboxJobMaxAttempts: 8 - -# IP address family used for outgoing request (ipv4, ipv6 or dual) -#outgoingAddressFamily: ipv4 - -# Syslog option -#syslog: -# host: localhost -# port: 514 - -# Proxy for HTTP/HTTPS -#proxy: http://127.0.0.1:3128 - -#proxyBypassHosts: [ -# 'example.com', -# '192.0.2.8' -#] - -# Proxy for SMTP/SMTPS -#proxySmtp: http://127.0.0.1:3128 # use HTTP/1.1 CONNECT -#proxySmtp: socks4://127.0.0.1:1080 # use SOCKS4 -#proxySmtp: socks5://127.0.0.1:1080 # use SOCKS5 - -# Media Proxy -#mediaProxy: https://example.com/proxy - -# Proxy remote files (default: false) -#proxyRemoteFiles: true - -#allowedPrivateNetworks: [ -# '127.0.0.1/32' -#] - -# Upload or download file size limits (bytes) -#maxFileSize: 262144000 - -# Managed hosting settings -# !!!!!!!!!! -# >>>>>> NORMAL SELF-HOSTERS, STAY AWAY! <<<<<< -# >>>>>> YOU DON'T NEED THIS! <<<<<< -# !!!!!!!!!! -# Each category is optional, but if each item in each category is mandatory! -# If you mess this up, that's on you, you've been warned... - -#maxUserSignups: 100 -#isManagedHosting: true -#deepl: -# managed: true -# authKey: '' -# isPro: false -# -#email: -# managed: true -# address: 'example@email.com' -# host: 'email.com' -# port: 587 -# user: 'example@email.com' -# pass: '' -# useImplicitSslTls: false -# -#objectStorage: -# managed: true -# baseUrl: '' -# bucket: '' -# prefix: '' -# endpoint: '' -# region: '' -# accessKey: '' -# secretKey: '' -# useSsl: true -# connnectOverProxy: false -# setPublicReadOnUpload: true -# s3ForcePathStyle: true - -# !!!!!!!!!! -# >>>>>> AGAIN, NORMAL SELF-HOSTERS, STAY AWAY! <<<<<< -# >>>>>> YOU DON'T NEED THIS, ABOVE SETTINGS ARE FOR MANAGED HOSTING ONLY! <<<<<< -# !!!!!!!!!! - -# Seriously. Do NOT fill out the above settings if you're self-hosting. -# They're much better off being set from the control panel. diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000..60808eb11e --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,109 @@ +image: docker.io/node:alpine-16 + +services: + - docker.io/groonga/pgroonga:latest-alpine-12-slim + - docker.io/redis:7-alpine + +workflow: + rules: + - if: $CI_PIPELINE_SOURCE == 'merge_request_event' + when: always + - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == 'main' + when: never + +cache: + paths: + - node_modules/ + - target/ + +stages: + - auto_update + +variables: + POSTGRES_DB: firefish_db + POSTGRES_USER: firefish + POSTGRES_PASSWORD: password + POSTGRES_HOST_AUTH_METHOD: trust + +default: + before_script: + - apk add build-base linux-headers curl ca-certificates python3 perl + - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + - . "${HOME}/.cargo/env" + - corepack enable + - corepack prepare pnpm@latest --activate + - cp .config/ci.yml .config/default.yml + - export PGPASSWORD="${POSTGRES_PASSWORD}" + - psql --host postgres --user "${POSTGRES_USER}" --dbname "${POSTGRES_DB}" --command 'CREATE EXTENSION pgroonga' + +auto_update: + stage: auto_update + script: + # setup git + - apk add git + - git config user.name "${GITLAB_USER_NAME}" + - git config user.email "${GITLAB_USER_EMAIL}" + - git remote set-url origin "${CI_MERGE_REQUEST_SOURCE_PROJECT_URL}" + - git fetch origin + - git switch "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" + # update pnpm lockfile + - pnpm install + # commit + - |- + if [ `git status -s | wc -l` -gt 0 ]; then + git add . + git commit --message 'chore: update lockfile' + git push --push-option=ci.skip origin "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" + fi + # run format + - pnpm run format + # commit + - |- + if [ `git status -s | wc -l` -gt 0 ]; then + git add . + git commit --message 'chore: format' + git push --push-option=ci.skip origin "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" + fi + # update packages/backend-rs/src/model/entity + - cargo install sea-orm-cli + - pnpm --filter backend run build:debug + - pnpm run migrate + - cd packages/backend-rs + - mv src/model/entity src/model/entity.bak + - |- + sea-orm-cli generate entity \ + --output-dir='src/model/entity' \ + --date-time-crate='chrono' \ + --model-extra-attributes='NAPI_EXTRA_ATTR_PLACEHOLDER' \ + --database-url="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}" + - |- + for file in src/model/entity/*; do + base=$(basename -- "${file}") + jsname=$(printf '%s\n' "${base%.*}" | perl -pe 's/(^|_)./uc($&)/ge;s/_//g') + attribute=$(printf 'cfg_attr(feature = "napi", napi_derive::napi(object, js_name = "%s", use_nullable = true))' "${jsname}") + sed -i "s/NAPI_EXTRA_ATTR_PLACEHOLDER/${attribute}/" "${file}" + sed -i 's/#\[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)\]/#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]\n#[serde(rename_all = "camelCase")]/' "${file}" + done + - |- + sed -i 's/#\[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)\]/#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize)]\n#[serde(rename_all = "camelCase")]\n#[cfg_attr(not(feature = "napi"), derive(Clone))]\n#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]/' \ + src/model/entity/sea_orm_active_enums.rs + - rm --recursive --force src/model/entity.bak + - cargo fmt --all -- + # commit + - |- + if [ `git status -s | wc -l` -gt 0 ]; then + git add . + git commit --message 'chore (backend-rs): regenerate entity' + git push --push-option=ci.skip origin "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" + fi + # update packages/backend-rs/index.{js,d.ts} + - pnpm run build:debug + - /bin/cp --force built/index.js index.js + - /bin/cp --force built/index.d.ts index.d.ts + - sed -i 's/^ \*r"/ */g' index.d.ts + - |- + if [ `git status -s | wc -l` -gt 0 ]; then + git add . + git commit --message 'chore (backend-rs): regenerate index' + git push --push-option=ci.skip origin "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" + fi From 73607369666a2c9e61dcd71a214da598daef1e6c Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 17:07:42 +0900 Subject: [PATCH 41/75] ci: fix typo --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 60808eb11e..ffaafa8bff 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -image: docker.io/node:alpine-16 +image: docker.io/node:18-alpine services: - docker.io/groonga/pgroonga:latest-alpine-12-slim From 766bac3dee1470f2b0b895f87c7a6a2afeadba99 Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 17:14:47 +0900 Subject: [PATCH 42/75] ci: give alias for services --- .gitlab-ci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ffaafa8bff..321cd51fb8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,8 +1,10 @@ image: docker.io/node:18-alpine services: - - docker.io/groonga/pgroonga:latest-alpine-12-slim - - docker.io/redis:7-alpine + - name: docker.io/groonga/pgroonga:latest-alpine-12-slim + alias: postgres + - name: docker.io/redis:7-alpine + alias: redis workflow: rules: From a7978e2b08a7fac3d9e163978da6cd21715845d6 Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 17:46:45 +0900 Subject: [PATCH 43/75] ci: non-interactive shell option --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 321cd51fb8..a469fe3d76 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -30,7 +30,7 @@ variables: default: before_script: - apk add build-base linux-headers curl ca-certificates python3 perl - - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y - . "${HOME}/.cargo/env" - corepack enable - corepack prepare pnpm@latest --activate From d582a84c57b00c195d337863dd833fe91a0a1bb7 Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 17:58:26 +0900 Subject: [PATCH 44/75] ci: install postgresql client --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a469fe3d76..01063289d5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -29,7 +29,7 @@ variables: default: before_script: - - apk add build-base linux-headers curl ca-certificates python3 perl + - apk add build-base linux-headers curl ca-certificates python3 perl postgresql-client - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y - . "${HOME}/.cargo/env" - corepack enable From c6212ff8f475b48f86d32daebaca0e3a3329b49a Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 18:06:56 +0900 Subject: [PATCH 45/75] ci: use CI_JOB_TOKEN --- .gitlab-ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 01063289d5..1e10e9c8b3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -43,9 +43,9 @@ auto_update: script: # setup git - apk add git - - git config user.name "${GITLAB_USER_NAME}" - - git config user.email "${GITLAB_USER_EMAIL}" - - git remote set-url origin "${CI_MERGE_REQUEST_SOURCE_PROJECT_URL}" + - git config user.name 'GitLab CI' + - git config user.email 'noreply@firefish.dev' + - git remote set-url origin "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_PROJECT_PATH}" - git fetch origin - git switch "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" # update pnpm lockfile From e6121946aace893651e59de8783ce63a6ce644a6 Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 18:11:30 +0900 Subject: [PATCH 46/75] ci: another fix --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1e10e9c8b3..37b5f6057d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -29,7 +29,7 @@ variables: default: before_script: - - apk add build-base linux-headers curl ca-certificates python3 perl postgresql-client + - apk add --update build-base linux-headers curl ca-certificates python3 perl postgresql-client pkgconfig openssl-dev - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y - . "${HOME}/.cargo/env" - corepack enable @@ -45,7 +45,7 @@ auto_update: - apk add git - git config user.name 'GitLab CI' - git config user.email 'noreply@firefish.dev' - - git remote set-url origin "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_PROJECT_PATH}" + - git remote set-url origin "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_SOURCE_PROJECT_PATH}" - git fetch origin - git switch "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" # update pnpm lockfile From 641ff742bb8aac2bc33106806175dcf665376de7 Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 18:26:50 +0900 Subject: [PATCH 47/75] ci: add dependencies of sea-orm-cli --- .gitlab-ci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 37b5f6057d..18477c8953 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -29,7 +29,7 @@ variables: default: before_script: - - apk add --update build-base linux-headers curl ca-certificates python3 perl postgresql-client pkgconfig openssl-dev + - apk add --update build-base linux-headers curl ca-certificates python3 perl postgresql-client - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y - . "${HOME}/.cargo/env" - corepack enable @@ -45,9 +45,10 @@ auto_update: - apk add git - git config user.name 'GitLab CI' - git config user.email 'noreply@firefish.dev' - - git remote set-url origin "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_SOURCE_PROJECT_PATH}" + - git remote set-url origin "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_SOURCE_PROJECT_PATH}.git" - git fetch origin - git switch "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" + - git pull --ff # update pnpm lockfile - pnpm install # commit @@ -67,6 +68,7 @@ auto_update: git push --push-option=ci.skip origin "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" fi # update packages/backend-rs/src/model/entity + - apk install pkgconfig openssl openssl-dev libssl3 - cargo install sea-orm-cli - pnpm --filter backend run build:debug - pnpm run migrate From 5b18f9761c169d800021a6174d90053748abfd6f Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 18:29:31 +0900 Subject: [PATCH 48/75] ci: fix .git --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 18477c8953..5f36b13110 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -45,7 +45,7 @@ auto_update: - apk add git - git config user.name 'GitLab CI' - git config user.email 'noreply@firefish.dev' - - git remote set-url origin "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_SOURCE_PROJECT_PATH}.git" + - git remote set-url origin "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_SOURCE_PROJECT_PATH}" - git fetch origin - git switch "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" - git pull --ff From bfdf73caeb104f4e62add065bc91789ad336e480 Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 18:38:54 +0900 Subject: [PATCH 49/75] ci: fix permisson --- .gitlab-ci.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5f36b13110..de1e0317eb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -45,10 +45,9 @@ auto_update: - apk add git - git config user.name 'GitLab CI' - git config user.email 'noreply@firefish.dev' - - git remote set-url origin "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_SOURCE_PROJECT_PATH}" - - git fetch origin - - git switch "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" - - git pull --ff + - git remote add mr_origin "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_SOURCE_PROJECT_PATH}" + - git fetch mr_origin + - git checkout -b "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" FETCH_HEAD # update pnpm lockfile - pnpm install # commit @@ -56,7 +55,7 @@ auto_update: if [ `git status -s | wc -l` -gt 0 ]; then git add . git commit --message 'chore: update lockfile' - git push --push-option=ci.skip origin "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" + git push --push-option=ci.skip "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_SOURCE_PROJECT_PATH}" "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" fi # run format - pnpm run format @@ -65,7 +64,7 @@ auto_update: if [ `git status -s | wc -l` -gt 0 ]; then git add . git commit --message 'chore: format' - git push --push-option=ci.skip origin "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" + git push --push-option=ci.skip "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_SOURCE_PROJECT_PATH}" "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" fi # update packages/backend-rs/src/model/entity - apk install pkgconfig openssl openssl-dev libssl3 @@ -98,7 +97,7 @@ auto_update: if [ `git status -s | wc -l` -gt 0 ]; then git add . git commit --message 'chore (backend-rs): regenerate entity' - git push --push-option=ci.skip origin "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" + git push --push-option=ci.skip "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_SOURCE_PROJECT_PATH}" "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" fi # update packages/backend-rs/index.{js,d.ts} - pnpm run build:debug @@ -109,5 +108,5 @@ auto_update: if [ `git status -s | wc -l` -gt 0 ]; then git add . git commit --message 'chore (backend-rs): regenerate index' - git push --push-option=ci.skip origin "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" + git push --push-option=ci.skip "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_SOURCE_PROJECT_PATH}" "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" fi From 8e497b41cf9b07e450997057607a9c91f45f3b48 Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 18:44:28 +0900 Subject: [PATCH 50/75] messed up --- .gitlab-ci.yml | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index de1e0317eb..36dc431f63 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -45,9 +45,6 @@ auto_update: - apk add git - git config user.name 'GitLab CI' - git config user.email 'noreply@firefish.dev' - - git remote add mr_origin "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_SOURCE_PROJECT_PATH}" - - git fetch mr_origin - - git checkout -b "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" FETCH_HEAD # update pnpm lockfile - pnpm install # commit @@ -55,7 +52,7 @@ auto_update: if [ `git status -s | wc -l` -gt 0 ]; then git add . git commit --message 'chore: update lockfile' - git push --push-option=ci.skip "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_SOURCE_PROJECT_PATH}" "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" + git push --push-option=ci.skip "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_SOURCE_PROJECT_PATH}" "HEAD:${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" fi # run format - pnpm run format @@ -64,7 +61,7 @@ auto_update: if [ `git status -s | wc -l` -gt 0 ]; then git add . git commit --message 'chore: format' - git push --push-option=ci.skip "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_SOURCE_PROJECT_PATH}" "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" + git push --push-option=ci.skip "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_SOURCE_PROJECT_PATH}" "HEAD:${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" fi # update packages/backend-rs/src/model/entity - apk install pkgconfig openssl openssl-dev libssl3 @@ -97,7 +94,7 @@ auto_update: if [ `git status -s | wc -l` -gt 0 ]; then git add . git commit --message 'chore (backend-rs): regenerate entity' - git push --push-option=ci.skip "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_SOURCE_PROJECT_PATH}" "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" + git push --push-option=ci.skip "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_SOURCE_PROJECT_PATH}" "HEAD:${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" fi # update packages/backend-rs/index.{js,d.ts} - pnpm run build:debug @@ -108,5 +105,5 @@ auto_update: if [ `git status -s | wc -l` -gt 0 ]; then git add . git commit --message 'chore (backend-rs): regenerate index' - git push --push-option=ci.skip "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_SOURCE_PROJECT_PATH}" "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" + git push --push-option=ci.skip "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_SOURCE_PROJECT_PATH}" "HEAD:${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" fi From c8372767faa116e53c98c05a90434ec0508742dc Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 19:00:34 +0900 Subject: [PATCH 51/75] ci: attempt to fix permission --- .gitlab-ci.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 36dc431f63..0ecdb0bae3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -45,6 +45,7 @@ auto_update: - apk add git - git config user.name 'GitLab CI' - git config user.email 'noreply@firefish.dev' + - git remote set-url origin "https://${CI_REGISTRY_USER}:${API_TOKEN}@${CI_REPOSITORY_URL#*@}" # update pnpm lockfile - pnpm install # commit @@ -52,7 +53,7 @@ auto_update: if [ `git status -s | wc -l` -gt 0 ]; then git add . git commit --message 'chore: update lockfile' - git push --push-option=ci.skip "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_SOURCE_PROJECT_PATH}" "HEAD:${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" + git push --push-option=ci.skip origin "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" fi # run format - pnpm run format @@ -61,7 +62,7 @@ auto_update: if [ `git status -s | wc -l` -gt 0 ]; then git add . git commit --message 'chore: format' - git push --push-option=ci.skip "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_SOURCE_PROJECT_PATH}" "HEAD:${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" + git push --push-option=ci.skip origin "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" fi # update packages/backend-rs/src/model/entity - apk install pkgconfig openssl openssl-dev libssl3 @@ -94,7 +95,7 @@ auto_update: if [ `git status -s | wc -l` -gt 0 ]; then git add . git commit --message 'chore (backend-rs): regenerate entity' - git push --push-option=ci.skip "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_SOURCE_PROJECT_PATH}" "HEAD:${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" + git push --push-option=ci.skip origin "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" fi # update packages/backend-rs/index.{js,d.ts} - pnpm run build:debug @@ -105,5 +106,5 @@ auto_update: if [ `git status -s | wc -l` -gt 0 ]; then git add . git commit --message 'chore (backend-rs): regenerate index' - git push --push-option=ci.skip "https://gitlab-ci-token:${CI_JOB_TOKEN}@firefish.dev/${CI_MERGE_REQUEST_SOURCE_PROJECT_PATH}" "HEAD:${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" + git push --push-option=ci.skip origin "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" fi From 442dc33a34dc5555ad905a912ab4d44e013e0765 Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 19:08:28 +0900 Subject: [PATCH 52/75] ci: exec build & cargo test only for now --- .gitlab-ci.yml | 79 +++++++------------------------------------------- 1 file changed, 10 insertions(+), 69 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0ecdb0bae3..7b42dcb24e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -19,7 +19,7 @@ cache: - target/ stages: - - auto_update + - test variables: POSTGRES_DB: firefish_db @@ -38,73 +38,14 @@ default: - export PGPASSWORD="${POSTGRES_PASSWORD}" - psql --host postgres --user "${POSTGRES_USER}" --dbname "${POSTGRES_DB}" --command 'CREATE EXTENSION pgroonga' -auto_update: - stage: auto_update +build_test: + stage: test script: - # setup git - - apk add git - - git config user.name 'GitLab CI' - - git config user.email 'noreply@firefish.dev' - - git remote set-url origin "https://${CI_REGISTRY_USER}:${API_TOKEN}@${CI_REPOSITORY_URL#*@}" - # update pnpm lockfile - - pnpm install - # commit - - |- - if [ `git status -s | wc -l` -gt 0 ]; then - git add . - git commit --message 'chore: update lockfile' - git push --push-option=ci.skip origin "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" - fi - # run format - - pnpm run format - # commit - - |- - if [ `git status -s | wc -l` -gt 0 ]; then - git add . - git commit --message 'chore: format' - git push --push-option=ci.skip origin "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" - fi - # update packages/backend-rs/src/model/entity - - apk install pkgconfig openssl openssl-dev libssl3 - - cargo install sea-orm-cli - - pnpm --filter backend run build:debug - - pnpm run migrate - - cd packages/backend-rs - - mv src/model/entity src/model/entity.bak - - |- - sea-orm-cli generate entity \ - --output-dir='src/model/entity' \ - --date-time-crate='chrono' \ - --model-extra-attributes='NAPI_EXTRA_ATTR_PLACEHOLDER' \ - --database-url="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}" - - |- - for file in src/model/entity/*; do - base=$(basename -- "${file}") - jsname=$(printf '%s\n' "${base%.*}" | perl -pe 's/(^|_)./uc($&)/ge;s/_//g') - attribute=$(printf 'cfg_attr(feature = "napi", napi_derive::napi(object, js_name = "%s", use_nullable = true))' "${jsname}") - sed -i "s/NAPI_EXTRA_ATTR_PLACEHOLDER/${attribute}/" "${file}" - sed -i 's/#\[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)\]/#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]\n#[serde(rename_all = "camelCase")]/' "${file}" - done - - |- - sed -i 's/#\[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)\]/#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize)]\n#[serde(rename_all = "camelCase")]\n#[cfg_attr(not(feature = "napi"), derive(Clone))]\n#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]/' \ - src/model/entity/sea_orm_active_enums.rs - - rm --recursive --force src/model/entity.bak - - cargo fmt --all -- - # commit - - |- - if [ `git status -s | wc -l` -gt 0 ]; then - git add . - git commit --message 'chore (backend-rs): regenerate entity' - git push --push-option=ci.skip origin "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" - fi - # update packages/backend-rs/index.{js,d.ts} + - pnpm install --frozen-lockfile - pnpm run build:debug - - /bin/cp --force built/index.js index.js - - /bin/cp --force built/index.d.ts index.d.ts - - sed -i 's/^ \*r"/ */g' index.d.ts - - |- - if [ `git status -s | wc -l` -gt 0 ]; then - git add . - git commit --message 'chore (backend-rs): regenerate index' - git push --push-option=ci.skip origin "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" - fi + - pnpm run migrate + +cargo_test: + stage: test + script: + - cargo test From ecbd8a87240f32e6cf9443431353e7d9cf0d06f8 Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 19:23:43 +0900 Subject: [PATCH 53/75] ci: save node_modules and target --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7b42dcb24e..56d3ea154d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -26,6 +26,7 @@ variables: POSTGRES_USER: firefish POSTGRES_PASSWORD: password POSTGRES_HOST_AUTH_METHOD: trust + GIT_CLEAN_FLAGS: -ffdx --exclude node_modules/ --exclude target/ default: before_script: From a3b156441a4db498b2f4ef09ca98914966bc648d Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 19:38:35 +0900 Subject: [PATCH 54/75] ci: temporary fix for cargo test failure due to missing meta.json --- .gitlab-ci.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 56d3ea154d..9810b09447 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -39,14 +39,10 @@ default: - export PGPASSWORD="${POSTGRES_PASSWORD}" - psql --host postgres --user "${POSTGRES_USER}" --dbname "${POSTGRES_DB}" --command 'CREATE EXTENSION pgroonga' -build_test: +build_and_cargo_unit_test: stage: test script: - pnpm install --frozen-lockfile - pnpm run build:debug - pnpm run migrate - -cargo_test: - stage: test - script: - cargo test From ecd8e3d109d3220c78c360370c4e0305eb5d85fa Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 22:51:42 +0900 Subject: [PATCH 55/75] ci: remove git clean flags --- .gitlab-ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9810b09447..4dab0f7531 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -26,7 +26,6 @@ variables: POSTGRES_USER: firefish POSTGRES_PASSWORD: password POSTGRES_HOST_AUTH_METHOD: trust - GIT_CLEAN_FLAGS: -ffdx --exclude node_modules/ --exclude target/ default: before_script: From 0c4826becf0bac7a0090f5b7c5243f3351b45699 Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 22:54:10 +0900 Subject: [PATCH 56/75] dev: copy backend-rs/index.{js,d.ts} to built/index.{js,d.ts} if not exist https://firefish.dev/firefish/firefish/-/merge_requests/10780#note_5685 --- scripts/dev-build.mjs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/scripts/dev-build.mjs b/scripts/dev-build.mjs index 5e8805a200..9825be3033 100644 --- a/scripts/dev-build.mjs +++ b/scripts/dev-build.mjs @@ -1,6 +1,7 @@ import path, { join } from "node:path"; import { fileURLToPath } from "node:url"; import { execa } from "execa"; +import fs from "node:fs"; (async () => { const __dirname = path.dirname(fileURLToPath(import.meta.url)); @@ -32,4 +33,18 @@ import { execa } from "execa"; stdio: "inherit", } ); + + if (!fs.existsSync(join(__dirname, "/../packages/backend-rs/built/index.js"))) { + fs.copyFileSync( + join(__dirname, "/../packages/backend-rs/index.js"), + join(__dirname, "/../packages/backend-rs/built/index.js"), + ); + console.warn("backend-rs/built/index.js has not been updated (https://github.com/napi-rs/napi-rs/issues/1768)"); + } + if (!fs.existsSync(join(__dirname, "/../packages/backend-rs/built/index.d.ts"))) { + fs.copyFileSync( + join(__dirname, "/../packages/backend-rs/index.d.ts"), + join(__dirname, "/../packages/backend-rs/built/index.d.ts"), + ); + } })(); From 7fdd44cf8d5540393b392a101ea5cc288dab2735 Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 23:07:57 +0900 Subject: [PATCH 57/75] locale: update translations --- locales/ja-JP.yml | 6 +++--- locales/zh-TW.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 72b7ed2969..b983f44806 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -685,9 +685,9 @@ unclip: "クリップ解除" confirmToUnclipAlreadyClippedNote: "この投稿はすでにクリップ「{name}」に含まれています。投稿をこのクリップから除外しますか?" public: "公開" i18nInfo: "Firefishは有志によって様々な言語に翻訳されています。{link}で翻訳に協力できます。" -i18nServerInfo: "新しいクライアントはデフォルトで {language} で表示します。" -i18nServerChange: "{language} に変更する。" -i18nServerSet: "新しいクライアントの表示言語も {language} にする。" +i18nServerInfo: "新しい端末では{language}が既定の言語になります。" +i18nServerChange: "{language}に変更する。" +i18nServerSet: "新しい端末での表示言語を{language}にします。" manageAccessTokens: "アクセストークンの管理" accountInfo: "アカウント情報" notesCount: "投稿の数" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index 556a4efb61..00a7827203 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -662,7 +662,7 @@ confirmToUnclipAlreadyClippedNote: "此貼文已包含在摘錄「{name}」中 public: "公開" i18nInfo: "Firefish已經被志願者們翻譯成各種語言版本,如果想要幫忙的話,可以進入{link}幫助翻譯。" i18nServerInfo: "新客戶端將默認使用 {language}。" -i18nServerChange: "改爲 {language}。" +i18nServerChange: "改為 {language}。" i18nServerSet: "設定新客戶端使用 {language}。" manageAccessTokens: "管理存取權杖" accountInfo: "帳戶資訊" From ddfdd038ad094820fb58a9c03724955596991f36 Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 23:10:39 +0900 Subject: [PATCH 58/75] chore: update downgrade.sql --- docs/downgrade.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/downgrade.sql b/docs/downgrade.sql index 6f3901006f..8a41b7e36d 100644 --- a/docs/downgrade.sql +++ b/docs/downgrade.sql @@ -1,6 +1,7 @@ BEGIN; DELETE FROM "migrations" WHERE name IN ( + 'AddUserProfileLanguage1714888400293', 'DropUnusedIndexes1714643926317', 'AlterAkaType1714099399879', 'AddDriveFileUsage1713451569342', From 8ed942e00f4a8cc4a308487aad1815d3e8c017d2 Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 23:13:31 +0900 Subject: [PATCH 59/75] chore: update auto-generated files --- packages/backend-rs/index.d.ts | 1 + packages/backend-rs/src/model/entity/user_profile.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/backend-rs/index.d.ts b/packages/backend-rs/index.d.ts index 4f14e02b6c..a384c22964 100644 --- a/packages/backend-rs/index.d.ts +++ b/packages/backend-rs/index.d.ts @@ -1122,6 +1122,7 @@ export interface UserProfile { preventAiLearning: boolean isIndexable: boolean mutedPatterns: Array + lang: string | null } export interface UserPublickey { userId: string diff --git a/packages/backend-rs/src/model/entity/user_profile.rs b/packages/backend-rs/src/model/entity/user_profile.rs index 644817aa8d..d461b11292 100644 --- a/packages/backend-rs/src/model/entity/user_profile.rs +++ b/packages/backend-rs/src/model/entity/user_profile.rs @@ -78,6 +78,7 @@ pub struct Model { pub is_indexable: bool, #[sea_orm(column_name = "mutedPatterns")] pub muted_patterns: Vec, + pub lang: Option, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] From 7fe7f9035083f20f71c3de6438c865d568433484 Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 6 May 2024 23:40:52 +0900 Subject: [PATCH 60/75] ci: revise build config --- .gitlab-ci.yml | 30 ++++++++++++++++++++---------- ci/cargo/config.toml | 3 +++ 2 files changed, 23 insertions(+), 10 deletions(-) create mode 100644 ci/cargo/config.toml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4dab0f7531..6261f9af0e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -image: docker.io/node:18-alpine +image: docker.io/rust:slim-bookworm services: - name: docker.io/groonga/pgroonga:latest-alpine-12-slim @@ -15,26 +15,36 @@ workflow: cache: paths: - - node_modules/ - - target/ + - node_modules + - /cache/cargo/registry/index + - /cache/cargo/registry/cache + - target/debug/deps + - target/debug/build stages: - test variables: - POSTGRES_DB: firefish_db - POSTGRES_USER: firefish - POSTGRES_PASSWORD: password - POSTGRES_HOST_AUTH_METHOD: trust + POSTGRES_DB: 'firefish_db' + POSTGRES_USER: 'firefish' + POSTGRES_PASSWORD: 'password' + POSTGRES_HOST_AUTH_METHOD: 'trust' + DEBIAN_FRONTEND: 'noninteractive' + CARGO_PROFILE_DEV_OPT_LEVEL: '0' + CARGO_PROFILE_DEV_LTO: 'off' + CARGO_PROFILE_DEV_DEBUG: 'none' + CARGO_HOME: '/cache/cargo' default: before_script: - - apk add --update build-base linux-headers curl ca-certificates python3 perl postgresql-client - - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y - - . "${HOME}/.cargo/env" + - apt-get -y install curl + - curl -fsSL 'https://deb.nodesource.com/setup_18.x' | sudo -E bash - + - apt-get update && apt-get upgrade + - apt-get install -y build-essential clang mold python3 perl nodejs postgresql-client - corepack enable - corepack prepare pnpm@latest --activate - cp .config/ci.yml .config/default.yml + - cp ci/cargo/config.toml "${CARGO_HOME}/config.toml" - export PGPASSWORD="${POSTGRES_PASSWORD}" - psql --host postgres --user "${POSTGRES_USER}" --dbname "${POSTGRES_DB}" --command 'CREATE EXTENSION pgroonga' diff --git a/ci/cargo/config.toml b/ci/cargo/config.toml new file mode 100644 index 0000000000..b0de924994 --- /dev/null +++ b/ci/cargo/config.toml @@ -0,0 +1,3 @@ +[target.x86_64-unknown-linux-gnu] +linker = "/usr/bin/clang" +rustflags = ["-C", "link-arg=--ld-path=/usr/bin/mold"] From 5b01d3574fdee373ac5ac5a05146dd1551fccb43 Mon Sep 17 00:00:00 2001 From: naskya Date: Tue, 7 May 2024 00:56:37 +0900 Subject: [PATCH 61/75] refactor (backend): port isValidUrl to backend-rs --- packages/backend-rs/index.d.ts | 1 + packages/backend-rs/index.js | 3 +- packages/backend-rs/src/misc/is_safe_url.rs | 34 +++++++++++++++++++ packages/backend-rs/src/misc/mod.rs | 1 + packages/backend/src/misc/download-url.ts | 8 ++--- packages/backend/src/misc/fetch.ts | 6 ++-- packages/backend/src/misc/is-valid-url.ts | 20 ----------- .../backend/src/remote/activitypub/request.ts | 4 +-- 8 files changed, 47 insertions(+), 30 deletions(-) create mode 100644 packages/backend-rs/src/misc/is_safe_url.rs delete mode 100644 packages/backend/src/misc/is-valid-url.ts diff --git a/packages/backend-rs/index.d.ts b/packages/backend-rs/index.d.ts index a6c5bc29fb..7d7fb71e7d 100644 --- a/packages/backend-rs/index.d.ts +++ b/packages/backend-rs/index.d.ts @@ -268,6 +268,7 @@ export interface NoteLikeForGetNoteSummary { hasPoll: boolean } export function getNoteSummary(note: NoteLikeForGetNoteSummary): string +export function isSafeUrl(url: string): boolean export function latestVersion(): Promise export function toMastodonId(firefishId: string): string | null export function fromMastodonId(mastodonId: string): string | null diff --git a/packages/backend-rs/index.js b/packages/backend-rs/index.js index 5cf200133a..0d9938f9ed 100644 --- a/packages/backend-rs/index.js +++ b/packages/backend-rs/index.js @@ -310,7 +310,7 @@ if (!nativeBinding) { throw new Error(`Failed to load native binding`) } -const { SECOND, MINUTE, HOUR, DAY, USER_ONLINE_THRESHOLD, USER_ACTIVE_THRESHOLD, FILE_TYPE_BROWSERSAFE, loadEnv, loadConfig, stringToAcct, acctToString, addNoteToAntenna, isBlockedServer, isSilencedServer, isAllowedServer, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, getImageSizeFromUrl, getNoteSummary, latestVersion, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, removeOldAttestationChallenges, AntennaSrcEnum, DriveFileUsageHintEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initializeRustLogger, fetchNodeinfo, nodeinfo_2_1, nodeinfo_2_0, Protocol, Inbound, Outbound, watchNote, unwatchNote, publishToChannelStream, ChatEvent, publishToChatStream, ChatIndexEvent, publishToChatIndexStream, publishToBroadcastStream, publishToGroupChatStream, publishToModerationStream, getTimestamp, genId, genIdAt, secureRndstr } = nativeBinding +const { SECOND, MINUTE, HOUR, DAY, USER_ONLINE_THRESHOLD, USER_ACTIVE_THRESHOLD, FILE_TYPE_BROWSERSAFE, loadEnv, loadConfig, stringToAcct, acctToString, addNoteToAntenna, isBlockedServer, isSilencedServer, isAllowedServer, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, getImageSizeFromUrl, getNoteSummary, isSafeUrl, latestVersion, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, removeOldAttestationChallenges, AntennaSrcEnum, DriveFileUsageHintEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initializeRustLogger, fetchNodeinfo, nodeinfo_2_1, nodeinfo_2_0, Protocol, Inbound, Outbound, watchNote, unwatchNote, publishToChannelStream, ChatEvent, publishToChatStream, ChatIndexEvent, publishToChatIndexStream, publishToBroadcastStream, publishToGroupChatStream, publishToModerationStream, getTimestamp, genId, genIdAt, secureRndstr } = nativeBinding module.exports.SECOND = SECOND module.exports.MINUTE = MINUTE @@ -339,6 +339,7 @@ module.exports.safeForSql = safeForSql module.exports.formatMilliseconds = formatMilliseconds module.exports.getImageSizeFromUrl = getImageSizeFromUrl module.exports.getNoteSummary = getNoteSummary +module.exports.isSafeUrl = isSafeUrl module.exports.latestVersion = latestVersion module.exports.toMastodonId = toMastodonId module.exports.fromMastodonId = fromMastodonId diff --git a/packages/backend-rs/src/misc/is_safe_url.rs b/packages/backend-rs/src/misc/is_safe_url.rs new file mode 100644 index 0000000000..2600366ab5 --- /dev/null +++ b/packages/backend-rs/src/misc/is_safe_url.rs @@ -0,0 +1,34 @@ +#[crate::export] +pub fn is_safe_url(url: &str) -> bool { + if let Ok(url) = url.parse::() { + if url.host_str().unwrap_or_default() == "unix" + || !["http", "https"].contains(&url.scheme()) + || ![None, Some(80), Some(443)].contains(&url.port()) + { + return false; + } + true + } else { + false + } +} + +#[cfg(test)] +mod unit_test { + use super::is_safe_url; + + #[test] + fn safe_url() { + assert!(is_safe_url("http://firefish.dev/firefish/firefish")); + assert!(is_safe_url("https://firefish.dev/firefish/firefish")); + assert!(is_safe_url("http://firefish.dev:80/firefish/firefish")); + assert!(is_safe_url("https://firefish.dev:80/firefish/firefish")); + assert!(is_safe_url("http://firefish.dev:443/firefish/firefish")); + assert!(is_safe_url("https://firefish.dev:443/firefish/firefish")); + assert!(!is_safe_url("https://unix/firefish/firefish")); + assert!(!is_safe_url("https://firefish.dev:35/firefish/firefish")); + assert!(!is_safe_url("ftp://firefish.dev/firefish/firefish")); + assert!(!is_safe_url("nyaa")); + assert!(!is_safe_url("")); + } +} diff --git a/packages/backend-rs/src/misc/mod.rs b/packages/backend-rs/src/misc/mod.rs index 8d0a272e5c..d0575c1282 100644 --- a/packages/backend-rs/src/misc/mod.rs +++ b/packages/backend-rs/src/misc/mod.rs @@ -8,6 +8,7 @@ pub mod escape_sql; pub mod format_milliseconds; pub mod get_image_size; pub mod get_note_summary; +pub mod is_safe_url; pub mod latest_version; pub mod mastodon_id; pub mod meta; diff --git a/packages/backend/src/misc/download-url.ts b/packages/backend/src/misc/download-url.ts index 0a47395947..08dedcd3ed 100644 --- a/packages/backend/src/misc/download-url.ts +++ b/packages/backend/src/misc/download-url.ts @@ -7,10 +7,10 @@ import chalk from "chalk"; import Logger from "@/services/logger.js"; import IPCIDR from "ip-cidr"; import PrivateIp from "private-ip"; -import { isValidUrl } from "./is-valid-url.js"; +import { isSafeUrl } from "backend-rs"; export async function downloadUrl(url: string, path: string): Promise { - if (!isValidUrl(url)) { + if (!isSafeUrl(url)) { throw new StatusError("Invalid URL", 400); } @@ -43,8 +43,8 @@ export async function downloadUrl(url: string, path: string): Promise { limit: 0, }, }) - .on("redirect", (res: Got.Response, opts: Got.NormalizedOptions) => { - if (!isValidUrl(opts.url)) { + .on("redirect", (_res: Got.Response, opts: Got.NormalizedOptions) => { + if (!isSafeUrl(opts.url)) { downloadLogger.warn(`Invalid URL: ${opts.url}`); req.destroy(); } diff --git a/packages/backend/src/misc/fetch.ts b/packages/backend/src/misc/fetch.ts index 1f8c70a196..5af3b08fa5 100644 --- a/packages/backend/src/misc/fetch.ts +++ b/packages/backend/src/misc/fetch.ts @@ -5,7 +5,7 @@ import CacheableLookup from "cacheable-lookup"; import fetch, { type RequestRedirect } from "node-fetch"; import { HttpProxyAgent, HttpsProxyAgent } from "hpagent"; import { config } from "@/config.js"; -import { isValidUrl } from "./is-valid-url.js"; +import { isSafeUrl } from "backend-rs"; export async function getJson( url: string, @@ -60,7 +60,7 @@ export async function getResponse(args: { size?: number; redirect?: RequestRedirect; }) { - if (!isValidUrl(args.url)) { + if (!isSafeUrl(args.url)) { throw new StatusError("Invalid URL", 400); } @@ -83,7 +83,7 @@ export async function getResponse(args: { }); if (args.redirect === "manual" && [301, 302, 307, 308].includes(res.status)) { - if (!isValidUrl(res.url)) { + if (!isSafeUrl(res.url)) { throw new StatusError("Invalid URL", 400); } return res; diff --git a/packages/backend/src/misc/is-valid-url.ts b/packages/backend/src/misc/is-valid-url.ts deleted file mode 100644 index 5aebefcb71..0000000000 --- a/packages/backend/src/misc/is-valid-url.ts +++ /dev/null @@ -1,20 +0,0 @@ -export function isValidUrl(url: string | URL | undefined): boolean { - if (process.env.NODE_ENV !== "production") return true; - - try { - if (url == null) return false; - - const u = typeof url === "string" ? new URL(url) : url; - if (!u.protocol.match(/^https?:$/) || u.hostname === "unix") { - return false; - } - - if (u.port !== "" && !["80", "443"].includes(u.port)) { - return false; - } - - return true; - } catch { - return false; - } -} diff --git a/packages/backend/src/remote/activitypub/request.ts b/packages/backend/src/remote/activitypub/request.ts index 8e3bc764d3..f1f496273d 100644 --- a/packages/backend/src/remote/activitypub/request.ts +++ b/packages/backend/src/remote/activitypub/request.ts @@ -5,8 +5,8 @@ import { StatusError, getResponse } from "@/misc/fetch.js"; import { createSignedPost, createSignedGet } from "./ap-request.js"; import type { Response } from "node-fetch"; import type { IObject } from "./type.js"; -import { isValidUrl } from "@/misc/is-valid-url.js"; import { apLogger } from "@/remote/activitypub/logger.js"; +import { isSafeUrl } from "backend-rs"; export default async (user: { id: User["id"] }, url: string, object: any) => { const body = JSON.stringify(object); @@ -44,7 +44,7 @@ export async function apGet( user?: ILocalUser, redirects: boolean = true, ): Promise<{ finalUrl: string; content: IObject }> { - if (!isValidUrl(url)) { + if (!isSafeUrl(url)) { throw new StatusError("Invalid URL", 400); } From baa5c402db7b4f136e791ba2431158156f861bd2 Mon Sep 17 00:00:00 2001 From: naskya Date: Tue, 7 May 2024 01:50:10 +0900 Subject: [PATCH 62/75] ci: apt-get update first & fix paths --- .gitlab-ci.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6261f9af0e..59c56bb524 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,8 +16,8 @@ workflow: cache: paths: - node_modules - - /cache/cargo/registry/index - - /cache/cargo/registry/cache + # - /usr/local/cargo/registry/index + # - /usr/local/cargo/registry/cache - target/debug/deps - target/debug/build @@ -33,18 +33,18 @@ variables: CARGO_PROFILE_DEV_OPT_LEVEL: '0' CARGO_PROFILE_DEV_LTO: 'off' CARGO_PROFILE_DEV_DEBUG: 'none' - CARGO_HOME: '/cache/cargo' default: before_script: - - apt-get -y install curl - - curl -fsSL 'https://deb.nodesource.com/setup_18.x' | sudo -E bash - - - apt-get update && apt-get upgrade - - apt-get install -y build-essential clang mold python3 perl nodejs postgresql-client + - mkdir -p "${CARGO_HOME}" + - apt-get update && apt-get -y upgrade + - apt-get -y --no-install-recommends install curl + - curl -fsSL 'https://deb.nodesource.com/setup_18.x' | bash - + - apt-get install -y --no-install-recommends build-essential clang mold python3 perl nodejs postgresql-client - corepack enable - corepack prepare pnpm@latest --activate - cp .config/ci.yml .config/default.yml - - cp ci/cargo/config.toml "${CARGO_HOME}/config.toml" + - cp ci/cargo/config.toml /usr/local/cargo/config.toml - export PGPASSWORD="${POSTGRES_PASSWORD}" - psql --host postgres --user "${POSTGRES_USER}" --dbname "${POSTGRES_DB}" --command 'CREATE EXTENSION pgroonga' From d440e9b3885d5e8749b4dc7d2ae66a19bd52e18b Mon Sep 17 00:00:00 2001 From: naskya Date: Tue, 7 May 2024 04:58:59 +0900 Subject: [PATCH 63/75] ci: revise tasks --- .gitlab-ci.yml | 44 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 59c56bb524..0b566ed27c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,13 +6,6 @@ services: - name: docker.io/redis:7-alpine alias: redis -workflow: - rules: - - if: $CI_PIPELINE_SOURCE == 'merge_request_event' - when: always - - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == 'main' - when: never - cache: paths: - node_modules @@ -48,10 +41,45 @@ default: - export PGPASSWORD="${POSTGRES_PASSWORD}" - psql --host postgres --user "${POSTGRES_USER}" --dbname "${POSTGRES_DB}" --command 'CREATE EXTENSION pgroonga' -build_and_cargo_unit_test: +build_test: stage: test script: - pnpm install --frozen-lockfile - pnpm run build:debug - pnpm run migrate + +build_and_cargo_unit_test: + stage: test + rules: + - if: $CI_PIPELINE_SOURCE == 'merge_request_event' + changes: + paths: + - packages/backend-rs/**/* + - packages/macro-rs/**/* + - Cargo.toml + - Cargo.lock + - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == 'main' + when: never + script: + - cargo check --features napi + - pnpm install --frozen-lockfile + - mkdir packages/backend-rs/built + - cp packages/backend-rs/index.js packages/backend-rs/built/index.js + - cp packages/backend-rs/index.d.ts packages/backend-rs/built/index.d.ts + - pnpm --filter='!backend-rs' run build:debug - cargo test + +clippy: + stage: test + rules: + - if: $CI_PIPELINE_SOURCE == 'merge_request_event' + changes: + paths: + - packages/backend-rs/**/* + - packages/macro-rs/**/* + - Cargo.toml + - Cargo.lock + - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == 'main' + when: never + script: + - cargo clippy -- -D warnings From 5261eb24b61ebaf0db5eadcdba7ae026ccf92f8d Mon Sep 17 00:00:00 2001 From: naskya Date: Tue, 7 May 2024 05:24:45 +0900 Subject: [PATCH 64/75] ci: restrict project path --- .gitlab-ci.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0b566ed27c..830208441a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,6 +6,14 @@ services: - name: docker.io/redis:7-alpine alias: redis +workflow: + rules: + - if: $CI_PROJECT_PATH == 'firefish/firefish' + when: always + - if: $CI_MERGE_REQUEST_PROJECT_PATH == 'firefish/firefish' + when: always + - when: never + cache: paths: - node_modules From bf2b624bc9a0e6f93e200439b4bc6c28773819e2 Mon Sep 17 00:00:00 2001 From: naskya Date: Tue, 7 May 2024 05:49:22 +0900 Subject: [PATCH 65/75] ci: build OCI container image on develop --- .gitlab-ci.yml | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 830208441a..d3262ead6c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -24,6 +24,7 @@ cache: stages: - test + - build variables: POSTGRES_DB: 'firefish_db' @@ -37,7 +38,6 @@ variables: default: before_script: - - mkdir -p "${CARGO_HOME}" - apt-get update && apt-get -y upgrade - apt-get -y --no-install-recommends install curl - curl -fsSL 'https://deb.nodesource.com/setup_18.x' | bash - @@ -56,7 +56,20 @@ build_test: - pnpm run build:debug - pnpm run migrate -build_and_cargo_unit_test: +container_image_build: + stage: build + image: docker.io/debian:bookworm-slim + before_script: [] + rules: + - if: $CI_COMMIT_BRANCH == 'develop' + script: + - apt-get update && apt-get -y upgrade + - apt-get install -y --no-install-recommends buildah + - echo "${CI_REGISTRY_PASSWORD}" | buildah login "${CI_REGISTRY}" --username "${CI_REGISTRY_USER}" --password-stdin + - buildah build --tag "${CI_REGISTRY}/${CI_PROJECT_PATH}/develop:not-for-production" --platform linux/amd64 . + - buildah push "${CI_REGISTRY}/${CI_PROJECT_PATH}/develop:not-for-production" + +cargo_unit_test: stage: test rules: - if: $CI_PIPELINE_SOURCE == 'merge_request_event' @@ -77,7 +90,7 @@ build_and_cargo_unit_test: - pnpm --filter='!backend-rs' run build:debug - cargo test -clippy: +cargo_clippy: stage: test rules: - if: $CI_PIPELINE_SOURCE == 'merge_request_event' From 4d9c0f8e7bc12a21801162074dd85eef94b16c54 Mon Sep 17 00:00:00 2001 From: naskya Date: Tue, 7 May 2024 06:11:31 +0900 Subject: [PATCH 66/75] ci: fix syntax --- .gitlab-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d3262ead6c..6e2c742cbf 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -59,13 +59,14 @@ build_test: container_image_build: stage: build image: docker.io/debian:bookworm-slim + services: [] before_script: [] rules: - if: $CI_COMMIT_BRANCH == 'develop' script: - apt-get update && apt-get -y upgrade - apt-get install -y --no-install-recommends buildah - - echo "${CI_REGISTRY_PASSWORD}" | buildah login "${CI_REGISTRY}" --username "${CI_REGISTRY_USER}" --password-stdin + - buildah login --username "${CI_REGISTRY_USER}" --password "${CI_REGISTRY_PASSWORD}" "${CI_REGISTRY}" - buildah build --tag "${CI_REGISTRY}/${CI_PROJECT_PATH}/develop:not-for-production" --platform linux/amd64 . - buildah push "${CI_REGISTRY}/${CI_PROJECT_PATH}/develop:not-for-production" From 5b3f93457bbb715f50f3d71016022509da36efb9 Mon Sep 17 00:00:00 2001 From: naskya Date: Tue, 7 May 2024 06:53:03 +0900 Subject: [PATCH 67/75] dev: add renovate --- .gitlab-ci.yml | 15 ++++++++++++++- renovate.json | 15 +++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 renovate.json diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6e2c742cbf..9ea1dd4d18 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -25,6 +25,7 @@ cache: stages: - test - build + - dependency variables: POSTGRES_DB: 'firefish_db' @@ -65,7 +66,7 @@ container_image_build: - if: $CI_COMMIT_BRANCH == 'develop' script: - apt-get update && apt-get -y upgrade - - apt-get install -y --no-install-recommends buildah + - apt-get install -y --no-install-recommends buildah ca-certificates - buildah login --username "${CI_REGISTRY_USER}" --password "${CI_REGISTRY_PASSWORD}" "${CI_REGISTRY}" - buildah build --tag "${CI_REGISTRY}/${CI_PROJECT_PATH}/develop:not-for-production" --platform linux/amd64 . - buildah push "${CI_REGISTRY}/${CI_PROJECT_PATH}/develop:not-for-production" @@ -105,3 +106,15 @@ cargo_clippy: when: never script: - cargo clippy -- -D warnings + +renovate: + stage: dependency + image: + name: docker.io/renovate/renovate:37-slim + entrypoint: [""] + rules: + - if: $RENOVATE && $CI_PIPELINE_SOURCE == 'schedule' + services: [] + before_script: [] + script: + - renovate --platform gitlab --token "${API_TOKEN}" --endpoint "${CI_SERVER_URL}/api/v4" "${CI_PROJECT_PATH}" diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000000..d6f15c4854 --- /dev/null +++ b/renovate.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": ["config:base"], + "rangeStrategy": "bump", + "branchConcurrentLimit": 5, + "enabledManagers": ["npm", "cargo"], + "baseBranches": ["develop"], + "lockFileMaintenance": { + "enabled": true, + "recreateWhen": "always", + "rebaseStalePrs": true, + "branchTopic": "lock-file-maintenance", + "commitMessageAction": "Lock file maintenance" + } +} From 82c98ae72f23306adc2a05523e39577ea39e6495 Mon Sep 17 00:00:00 2001 From: naskya Date: Tue, 7 May 2024 07:22:12 +0900 Subject: [PATCH 68/75] ci: modify buildah args --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9ea1dd4d18..276ba71db2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -68,8 +68,8 @@ container_image_build: - apt-get update && apt-get -y upgrade - apt-get install -y --no-install-recommends buildah ca-certificates - buildah login --username "${CI_REGISTRY_USER}" --password "${CI_REGISTRY_PASSWORD}" "${CI_REGISTRY}" - - buildah build --tag "${CI_REGISTRY}/${CI_PROJECT_PATH}/develop:not-for-production" --platform linux/amd64 . - - buildah push "${CI_REGISTRY}/${CI_PROJECT_PATH}/develop:not-for-production" + - buildah build --security-opt seccomp=unconfined --cap-add all --tag "${CI_REGISTRY}/${CI_PROJECT_PATH}/develop:not-for-production" --platform linux/amd64 . + - buildah push "${CI_REGISTRY}/${CI_PROJECT_PATH}/develop:not-for-production" "docker://${CI_REGISTRY}/${CI_PROJECT_PATH}/develop:not-for-production" cargo_unit_test: stage: test From 1b8748bc8c6622c9be95ea9b39943892d6b9b065 Mon Sep 17 00:00:00 2001 From: naskya Date: Tue, 7 May 2024 17:30:57 +0900 Subject: [PATCH 69/75] another attempt to build an image inside container inside container --- .gitlab-ci.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 276ba71db2..44a4ca36b6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -61,15 +61,17 @@ container_image_build: stage: build image: docker.io/debian:bookworm-slim services: [] - before_script: [] rules: - if: $CI_COMMIT_BRANCH == 'develop' - script: + before_script: - apt-get update && apt-get -y upgrade - - apt-get install -y --no-install-recommends buildah ca-certificates + - apt-get install -y --no-install-recommends buildah ca-certificates fuse-overlayfs - buildah login --username "${CI_REGISTRY_USER}" --password "${CI_REGISTRY_PASSWORD}" "${CI_REGISTRY}" - - buildah build --security-opt seccomp=unconfined --cap-add all --tag "${CI_REGISTRY}/${CI_PROJECT_PATH}/develop:not-for-production" --platform linux/amd64 . - - buildah push "${CI_REGISTRY}/${CI_PROJECT_PATH}/develop:not-for-production" "docker://${CI_REGISTRY}/${CI_PROJECT_PATH}/develop:not-for-production" + - export IMAGE_TAG="${CI_REGISTRY}/${CI_PROJECT_PATH}/develop:not-for-production" + script: + - buildah build --isolation chroot --device /dev/fuse:rw --security-opt seccomp=unconfined --security-opt apparmor=unconfined --cap-add all --tag "${IMAGE_TAG}" --platform linux/amd64 . + - buildah inspect "${IMAGE_TAG}" + - buildah push "${IMAGE_TAG}" "docker://${IMAGE_TAG}" cargo_unit_test: stage: test From 09ef64290595e15c7f8df658f89bf11590a42b18 Mon Sep 17 00:00:00 2001 From: naskya Date: Tue, 7 May 2024 17:36:23 +0900 Subject: [PATCH 70/75] ci: skip builds if unneeded --- .gitlab-ci.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 44a4ca36b6..d4afbb640d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -52,6 +52,17 @@ default: build_test: stage: test + rules: + - if: $CI_PIPELINE_SOURCE == 'push' || $CI_PIPELINE_SOURCE == 'merge_request_event' + changes: + paths: + - packages/**/* + - scripts/**/* + - locales/**/* + - package.json + - pnpm-lock.yaml + - Cargo.toml + - Cargo.lock script: - pnpm install --frozen-lockfile - pnpm run build:debug From 39e08f57e8cba136c4efe375976b1cdf20cf30d1 Mon Sep 17 00:00:00 2001 From: naskya Date: Tue, 7 May 2024 18:00:53 +0900 Subject: [PATCH 71/75] ci: remove unneeded argument --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d4afbb640d..8c78fae3b6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -82,7 +82,7 @@ container_image_build: script: - buildah build --isolation chroot --device /dev/fuse:rw --security-opt seccomp=unconfined --security-opt apparmor=unconfined --cap-add all --tag "${IMAGE_TAG}" --platform linux/amd64 . - buildah inspect "${IMAGE_TAG}" - - buildah push "${IMAGE_TAG}" "docker://${IMAGE_TAG}" + - buildah push "${IMAGE_TAG}" cargo_unit_test: stage: test From 1128e243d363b96d1a07b50e73ed063c59f73961 Mon Sep 17 00:00:00 2001 From: naskya Date: Tue, 7 May 2024 18:00:22 +0900 Subject: [PATCH 72/75] container: fix dockerignore --- .dockerignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.dockerignore b/.dockerignore index 3819d675c8..ad0a69759d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -51,6 +51,7 @@ title.svg /dev /docs /scripts +!/scripts/copy-assets.mjs biome.json COPYING CODE_OF_CONDUCT.md From 3b3d457c3e272fcb55d3fffc3573f5bdebf8e551 Mon Sep 17 00:00:00 2001 From: naskya Date: Tue, 7 May 2024 18:34:18 +0900 Subject: [PATCH 73/75] ci: restrict paths --- .gitlab-ci.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8c78fae3b6..8f4f4d54c7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -74,6 +74,17 @@ container_image_build: services: [] rules: - if: $CI_COMMIT_BRANCH == 'develop' + changes: + paths: + - packages/**/* + - locales/**/* + - scripts/copy-assets.mjs + - package.json + - pnpm-lock.yaml + - Cargo.toml + - Cargo.lock + - Dockerfile + - .dockerignore before_script: - apt-get update && apt-get -y upgrade - apt-get install -y --no-install-recommends buildah ca-certificates fuse-overlayfs @@ -87,7 +98,7 @@ container_image_build: cargo_unit_test: stage: test rules: - - if: $CI_PIPELINE_SOURCE == 'merge_request_event' + - if: $CI_PIPELINE_SOURCE == 'merge_request_event' || $CI_COMMIT_BRANCH == 'develop' changes: paths: - packages/backend-rs/**/* From fc65d8c1c387424e207aef4e31ad6cd0163c9fda Mon Sep 17 00:00:00 2001 From: naskya Date: Tue, 7 May 2024 20:52:11 +0900 Subject: [PATCH 74/75] docs: update api-change.md --- docs/api-change.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/api-change.md b/docs/api-change.md index 6e5726804b..5cbf3922d4 100644 --- a/docs/api-change.md +++ b/docs/api-change.md @@ -2,6 +2,8 @@ Breaking changes are indicated by the :warning: icon. +## Unreleased + - Adding `lang` to the response of `i` and the request parameter of `i/update`. ## v20240504 From 4277ad0b59c18d77ed06569a766f9bbcb82f9c88 Mon Sep 17 00:00:00 2001 From: naskya Date: Tue, 7 May 2024 20:54:47 +0900 Subject: [PATCH 75/75] meta: update COPYING & include LICENSE in pre-built images --- .dockerignore | 2 -- COPYING | 4 ---- 2 files changed, 6 deletions(-) diff --git a/.dockerignore b/.dockerignore index ad0a69759d..30e75f6237 100644 --- a/.dockerignore +++ b/.dockerignore @@ -53,11 +53,9 @@ title.svg /scripts !/scripts/copy-assets.mjs biome.json -COPYING CODE_OF_CONDUCT.md CONTRIBUTING.md Dockerfile -LICENSE Procfile README.md SECURITY.md diff --git a/COPYING b/COPYING index 0621b4a8e6..96d91510d3 100644 --- a/COPYING +++ b/COPYING @@ -26,10 +26,6 @@ RsaSignature2017 implementation by Transmute Industries Inc License: MIT https://github.com/transmute-industries/RsaSignature2017/blob/master/LICENSE -Machine learning model for sensitive images by Infinite Red, Inc. -License: MIT -https://github.com/infinitered/nsfwjs/blob/master/LICENSE - Chiptune2.js by Simon Gündling License: MIT https://github.com/deskjet/chiptune2.js#license