summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormisskey-release-bot[bot] <157398866+misskey-release-bot[bot]@users.noreply.github.com>2024-07-31 11:20:31 +0000
committerGitHub <noreply@github.com>2024-07-31 11:20:31 +0000
commite98f66db51aabef925ea1a8faee6c37f67071107 (patch)
tree168fcc9219f7511bbf9bc198568406bd49fc31bb
parentfix: remove unreleased section (#14246) (diff)
parentRelease: 2024.7.0 (diff)
downloadsharkey-e98f66db51aabef925ea1a8faee6c37f67071107.tar.gz
sharkey-e98f66db51aabef925ea1a8faee6c37f67071107.tar.bz2
sharkey-e98f66db51aabef925ea1a8faee6c37f67071107.zip
Merge pull request #14233 from misskey-dev/develop
Release: 2024.7.0
-rw-r--r--.config/docker_example.env6
-rw-r--r--.config/docker_example.yml3
-rw-r--r--.devcontainer/compose.yml (renamed from .devcontainer/docker-compose.yml)4
-rw-r--r--.devcontainer/devcontainer.json6
-rwxr-xr-x.devcontainer/init.sh3
-rw-r--r--.dockerignore5
-rw-r--r--.github/ISSUE_TEMPLATE/01_bug-report.yml8
-rw-r--r--.github/ISSUE_TEMPLATE/config.yml4
-rw-r--r--.github/workflows/api-misskey-js.yml5
-rw-r--r--.github/workflows/changelog-check.yml2
-rw-r--r--.github/workflows/check-misskey-js-autogen.yml2
-rw-r--r--.github/workflows/check-misskey-js-version.yml3
-rw-r--r--.github/workflows/docker-develop.yml2
-rw-r--r--.github/workflows/docker.yml2
-rw-r--r--.github/workflows/dockle.yml8
-rw-r--r--.github/workflows/get-api-diff.yml5
-rw-r--r--.github/workflows/lint.yml24
-rw-r--r--.github/workflows/locale.yml5
-rw-r--r--.github/workflows/on-release-created.yml4
-rw-r--r--.github/workflows/release-edit-with-push.yml19
-rw-r--r--.github/workflows/release-with-dispatch.yml20
-rw-r--r--.github/workflows/release-with-ready.yml13
-rw-r--r--.github/workflows/storybook.yml4
-rw-r--r--.github/workflows/test-backend.yml11
-rw-r--r--.github/workflows/test-frontend.yml12
-rw-r--r--.github/workflows/test-misskey-js.yml7
-rw-r--r--.github/workflows/test-production.yml4
-rw-r--r--.github/workflows/validate-api-json.yml7
-rw-r--r--.gitignore5
-rw-r--r--.gitmodules3
-rw-r--r--.node-version2
-rw-r--r--CHANGELOG.md125
-rw-r--r--CONTRIBUTING.md107
-rw-r--r--Dockerfile6
-rw-r--r--compose.local-db.yml (renamed from docker-compose.local-db.yml)2
-rw-r--r--compose_example.yml (renamed from docker-compose_example.yml)4
-rw-r--r--locales/ar-SA.yml6
-rw-r--r--locales/bn-BD.yml6
-rw-r--r--locales/ca-ES.yml6
-rw-r--r--locales/cs-CZ.yml7
-rw-r--r--locales/de-DE.yml7
-rw-r--r--locales/el-GR.yml2
-rw-r--r--locales/en-US.yml79
-rw-r--r--locales/es-ES.yml9
-rw-r--r--locales/fr-FR.yml6
-rw-r--r--locales/id-ID.yml17
-rw-r--r--locales/index.d.ts230
-rw-r--r--locales/index.js6
-rw-r--r--locales/it-IT.yml64
-rw-r--r--locales/ja-JP.yml71
-rw-r--r--locales/ja-KS.yml13
-rw-r--r--locales/kab-KAB.yml4
-rw-r--r--locales/ko-GS.yml4
-rw-r--r--locales/ko-KR.yml126
-rw-r--r--locales/lo-LA.yml196
-rw-r--r--locales/no-NO.yml4
-rw-r--r--locales/pl-PL.yml7
-rw-r--r--locales/pt-PT.yml4
-rw-r--r--locales/ro-RO.yml4
-rw-r--r--locales/ru-RU.yml6
-rw-r--r--locales/sk-SK.yml6
-rw-r--r--locales/sv-SE.yml5
-rw-r--r--locales/th-TH.yml567
-rw-r--r--locales/uk-UA.yml6
-rw-r--r--locales/uz-UZ.yml4
-rw-r--r--locales/vi-VN.yml10
-rw-r--r--locales/zh-CN.yml96
-rw-r--r--locales/zh-TW.yml74
m---------misskey-assets0
-rw-r--r--package.json32
-rw-r--r--packages/backend/.eslintignore4
-rw-r--r--packages/backend/.eslintrc.cjs32
-rw-r--r--packages/backend/assets/api-doc.html20
-rw-r--r--packages/backend/assets/redoc.html24
-rw-r--r--packages/backend/eslint.config.js46
-rw-r--r--packages/backend/migration/1713656541000-abuse-report-notification.js62
-rw-r--r--packages/backend/migration/1716197366117-MediaSilenceForHosts.js16
-rw-r--r--packages/backend/migration/1721666053703-fixDriveUrl.js24
-rw-r--r--packages/backend/package.json109
-rw-r--r--packages/backend/scripts/dev.mjs2
-rw-r--r--packages/backend/scripts/generate_api_json.js35
-rw-r--r--packages/backend/src/NestLogger.ts2
-rw-r--r--packages/backend/src/boot/entry.ts2
-rw-r--r--packages/backend/src/boot/master.ts2
-rw-r--r--packages/backend/src/boot/worker.ts23
-rw-r--r--packages/backend/src/config.ts18
-rw-r--r--packages/backend/src/core/AbuseReportNotificationService.ts405
-rw-r--r--packages/backend/src/core/AbuseReportService.ts128
-rw-r--r--packages/backend/src/core/ClipService.ts4
-rw-r--r--packages/backend/src/core/CoreModule.ts56
-rw-r--r--packages/backend/src/core/DriveService.ts3
-rw-r--r--packages/backend/src/core/EmailService.ts2
-rw-r--r--packages/backend/src/core/FanoutTimelineEndpointService.ts12
-rw-r--r--packages/backend/src/core/FederatedInstanceService.ts1
-rw-r--r--packages/backend/src/core/GlobalEventService.ts32
-rw-r--r--packages/backend/src/core/LoggerService.ts4
-rw-r--r--packages/backend/src/core/MfmService.ts44
-rw-r--r--packages/backend/src/core/NoteCreateService.ts29
-rw-r--r--packages/backend/src/core/QueueModule.ts38
-rw-r--r--packages/backend/src/core/QueueService.ts63
-rw-r--r--packages/backend/src/core/ReactionService.ts17
-rw-r--r--packages/backend/src/core/RoleService.ts38
-rw-r--r--packages/backend/src/core/SignupService.ts5
-rw-r--r--packages/backend/src/core/SystemWebhookService.ts233
-rw-r--r--packages/backend/src/core/UserBlockingService.ts6
-rw-r--r--packages/backend/src/core/UserFollowingService.ts18
-rw-r--r--packages/backend/src/core/UserListService.ts2
-rw-r--r--packages/backend/src/core/UserRenoteMutingService.ts52
-rw-r--r--packages/backend/src/core/UserSearchService.ts205
-rw-r--r--packages/backend/src/core/UserService.ts24
-rw-r--r--packages/backend/src/core/UserWebhookService.ts99
-rw-r--r--packages/backend/src/core/UtilityService.ts6
-rw-r--r--packages/backend/src/core/WebhookService.ts97
-rw-r--r--packages/backend/src/core/activitypub/ApAudienceService.ts3
-rw-r--r--packages/backend/src/core/activitypub/ApInboxService.ts13
-rw-r--r--packages/backend/src/core/activitypub/ApMfmService.ts2
-rw-r--r--packages/backend/src/core/activitypub/ApRendererService.ts5
-rw-r--r--packages/backend/src/core/activitypub/models/ApMentionService.ts3
-rw-r--r--packages/backend/src/core/activitypub/models/ApNoteService.ts3
-rw-r--r--packages/backend/src/core/activitypub/models/ApPersonService.ts11
-rw-r--r--packages/backend/src/core/activitypub/models/ApQuestionService.ts7
-rw-r--r--packages/backend/src/core/activitypub/models/tag.ts3
-rw-r--r--packages/backend/src/core/chart/ChartLoggerService.ts2
-rw-r--r--packages/backend/src/core/chart/charts/federation.ts6
-rw-r--r--packages/backend/src/core/entities/AbuseReportNotificationRecipientEntityService.ts87
-rw-r--r--packages/backend/src/core/entities/AbuseUserReportEntityService.ts3
-rw-r--r--packages/backend/src/core/entities/ClipEntityService.ts2
-rw-r--r--packages/backend/src/core/entities/DriveFileEntityService.ts7
-rw-r--r--packages/backend/src/core/entities/InstanceEntityService.ts1
-rw-r--r--packages/backend/src/core/entities/InviteCodeEntityService.ts5
-rw-r--r--packages/backend/src/core/entities/MetaEntityService.ts22
-rw-r--r--packages/backend/src/core/entities/NoteEntityService.ts9
-rw-r--r--packages/backend/src/core/entities/NotificationEntityService.ts13
-rw-r--r--packages/backend/src/core/entities/PageEntityService.ts3
-rw-r--r--packages/backend/src/core/entities/SystemWebhookEntityService.ts74
-rw-r--r--packages/backend/src/core/entities/UserEntityService.ts17
-rw-r--r--packages/backend/src/di-symbols.ts2
-rw-r--r--packages/backend/src/logger.ts14
-rw-r--r--packages/backend/src/misc/is-not-null.ts8
-rw-r--r--packages/backend/src/misc/is-user-related.ts4
-rw-r--r--packages/backend/src/misc/json-schema.ts28
-rw-r--r--packages/backend/src/misc/json-value.ts8
-rw-r--r--packages/backend/src/misc/prelude/array.ts38
-rw-r--r--packages/backend/src/misc/prelude/maybe.ts25
-rw-r--r--packages/backend/src/misc/prelude/string.ts20
-rw-r--r--packages/backend/src/models/AbuseReportNotificationRecipient.ts100
-rw-r--r--packages/backend/src/models/DriveFile.ts6
-rw-r--r--packages/backend/src/models/Meta.ts5
-rw-r--r--packages/backend/src/models/RepositoryModule.ts98
-rw-r--r--packages/backend/src/models/SystemWebhook.ts100
-rw-r--r--packages/backend/src/models/_.ts36
-rw-r--r--packages/backend/src/models/json-schema/abuse-report-notification-recipient.ts50
-rw-r--r--packages/backend/src/models/json-schema/drive-file.ts2
-rw-r--r--packages/backend/src/models/json-schema/federation-instance.ts4
-rw-r--r--packages/backend/src/models/json-schema/meta.ts6
-rw-r--r--packages/backend/src/models/json-schema/note.ts1
-rw-r--r--packages/backend/src/models/json-schema/role.ts4
-rw-r--r--packages/backend/src/models/json-schema/system-webhook.ts54
-rw-r--r--packages/backend/src/postgres.ts10
-rw-r--r--packages/backend/src/queue/QueueProcessorModule.ts6
-rw-r--r--packages/backend/src/queue/QueueProcessorService.ts502
-rw-r--r--packages/backend/src/queue/const.ts3
-rw-r--r--packages/backend/src/queue/processors/DeliverProcessorService.ts6
-rw-r--r--packages/backend/src/queue/processors/EndedPollNotificationProcessorService.ts11
-rw-r--r--packages/backend/src/queue/processors/SystemWebhookDeliverProcessorService.ts87
-rw-r--r--packages/backend/src/queue/processors/UserWebhookDeliverProcessorService.ts (renamed from packages/backend/src/queue/processors/WebhookDeliverProcessorService.ts)6
-rw-r--r--packages/backend/src/queue/types.ts12
-rw-r--r--packages/backend/src/server/FileServerService.ts2
-rw-r--r--packages/backend/src/server/ServerService.ts2
-rw-r--r--packages/backend/src/server/api/ApiCallService.ts42
-rw-r--r--packages/backend/src/server/api/EndpointsModule.ts42
-rw-r--r--packages/backend/src/server/api/RateLimiterService.ts36
-rw-r--r--packages/backend/src/server/api/endpoints.ts38
-rw-r--r--packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/create.ts122
-rw-r--r--packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/delete.ts44
-rw-r--r--packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/list.ts55
-rw-r--r--packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/show.ts64
-rw-r--r--packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/update.ts128
-rw-r--r--packages/backend/src/server/api/endpoints/admin/ad/update.ts6
-rw-r--r--packages/backend/src/server/api/endpoints/admin/announcements/list.ts9
-rw-r--r--packages/backend/src/server/api/endpoints/admin/drive/show-file.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/admin/meta.ts11
-rw-r--r--packages/backend/src/server/api/endpoints/admin/queue/stats.ts5
-rw-r--r--packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts53
-rw-r--r--packages/backend/src/server/api/endpoints/admin/roles/update.ts14
-rw-r--r--packages/backend/src/server/api/endpoints/admin/system-webhook/create.ts85
-rw-r--r--packages/backend/src/server/api/endpoints/admin/system-webhook/delete.ts44
-rw-r--r--packages/backend/src/server/api/endpoints/admin/system-webhook/list.ts60
-rw-r--r--packages/backend/src/server/api/endpoints/admin/system-webhook/show.ts62
-rw-r--r--packages/backend/src/server/api/endpoints/admin/system-webhook/update.ts91
-rw-r--r--packages/backend/src/server/api/endpoints/admin/update-meta.ts15
-rw-r--r--packages/backend/src/server/api/endpoints/antennas/create.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/clips/update.ts4
-rw-r--r--packages/backend/src/server/api/endpoints/drive/folders/update.ts9
-rw-r--r--packages/backend/src/server/api/endpoints/federation/instances.ts4
-rw-r--r--packages/backend/src/server/api/endpoints/gallery/posts/create.ts3
-rw-r--r--packages/backend/src/server/api/endpoints/gallery/posts/update.ts25
-rw-r--r--packages/backend/src/server/api/endpoints/i/import-antennas.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/i/update.ts32
-rw-r--r--packages/backend/src/server/api/endpoints/i/webhooks/create.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/i/webhooks/update.ts6
-rw-r--r--packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts14
-rw-r--r--packages/backend/src/server/api/endpoints/notes/reactions/create.ts7
-rw-r--r--packages/backend/src/server/api/endpoints/notes/timeline.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/pages/update.ts23
-rw-r--r--packages/backend/src/server/api/endpoints/pinned-users.ts3
-rw-r--r--packages/backend/src/server/api/endpoints/renote-mute/create.ts23
-rw-r--r--packages/backend/src/server/api/endpoints/renote-mute/delete.ts8
-rw-r--r--packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/users/lists/create.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/users/reactions.ts19
-rw-r--r--packages/backend/src/server/api/endpoints/users/report-abuse.ts54
-rw-r--r--packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts101
-rw-r--r--packages/backend/src/server/api/endpoints/users/search.ts108
-rw-r--r--packages/backend/src/server/api/openapi/OpenApiServerService.ts2
-rw-r--r--packages/backend/src/server/api/openapi/gen-spec.ts1
-rw-r--r--packages/backend/src/server/api/stream/Connection.ts57
-rw-r--r--packages/backend/src/server/api/stream/channel.ts13
-rw-r--r--packages/backend/src/server/api/stream/channels/admin.ts3
-rw-r--r--packages/backend/src/server/api/stream/channels/antenna.ts6
-rw-r--r--packages/backend/src/server/api/stream/channels/channel.ts6
-rw-r--r--packages/backend/src/server/api/stream/channels/drive.ts3
-rw-r--r--packages/backend/src/server/api/stream/channels/global-timeline.ts7
-rw-r--r--packages/backend/src/server/api/stream/channels/hashtag.ts7
-rw-r--r--packages/backend/src/server/api/stream/channels/home-timeline.ts11
-rw-r--r--packages/backend/src/server/api/stream/channels/hybrid-timeline.ts21
-rw-r--r--packages/backend/src/server/api/stream/channels/local-timeline.ts9
-rw-r--r--packages/backend/src/server/api/stream/channels/main.ts3
-rw-r--r--packages/backend/src/server/api/stream/channels/queue-stats.ts10
-rw-r--r--packages/backend/src/server/api/stream/channels/reversi-game.ts33
-rw-r--r--packages/backend/src/server/api/stream/channels/reversi.ts3
-rw-r--r--packages/backend/src/server/api/stream/channels/role-timeline.ts6
-rw-r--r--packages/backend/src/server/api/stream/channels/server-stats.ts8
-rw-r--r--packages/backend/src/server/api/stream/channels/user-list.ts10
-rw-r--r--packages/backend/src/server/web/ClientServerService.ts17
-rw-r--r--packages/backend/src/server/web/FeedService.ts6
-rw-r--r--packages/backend/src/server/web/boot.js12
-rw-r--r--packages/backend/src/types.ts32
-rw-r--r--packages/backend/test-server/.eslintrc.cjs32
-rw-r--r--packages/backend/test-server/eslint.config.js43
-rw-r--r--packages/backend/test/.eslintrc.cjs11
-rw-r--r--packages/backend/test/compose.yml (renamed from packages/backend/test/docker-compose.yml)2
-rw-r--r--packages/backend/test/e2e/2fa.ts30
-rw-r--r--packages/backend/test/e2e/antennas.ts3
-rw-r--r--packages/backend/test/e2e/api-visibility.ts16
-rw-r--r--packages/backend/test/e2e/block.ts12
-rw-r--r--packages/backend/test/e2e/clips.ts19
-rw-r--r--packages/backend/test/e2e/drive.ts6
-rw-r--r--packages/backend/test/e2e/endpoints.ts91
-rw-r--r--packages/backend/test/e2e/exports.ts70
-rw-r--r--packages/backend/test/e2e/fetch-resource.ts17
-rw-r--r--packages/backend/test/e2e/move.ts73
-rw-r--r--packages/backend/test/e2e/mute.ts72
-rw-r--r--packages/backend/test/e2e/note.ts79
-rw-r--r--packages/backend/test/e2e/renote-mute.ts25
-rw-r--r--packages/backend/test/e2e/streaming.ts62
-rw-r--r--packages/backend/test/e2e/synalio/abuse-report.ts360
-rw-r--r--packages/backend/test/e2e/synalio/user-create.ts130
-rw-r--r--packages/backend/test/e2e/thread-mute.ts10
-rw-r--r--packages/backend/test/e2e/timelines.ts533
-rw-r--r--packages/backend/test/e2e/user-notes.ts4
-rw-r--r--packages/backend/test/e2e/users.ts13
-rw-r--r--packages/backend/test/eslint.config.js22
-rw-r--r--packages/backend/test/prelude/maybe.ts23
-rw-r--r--packages/backend/test/resources/192.jpgbin0 -> 5131 bytes
-rw-r--r--packages/backend/test/resources/192.pngbin0 -> 26568 bytes
-rw-r--r--packages/backend/test/resources/Lenna.jpgbin25360 -> 0 bytes
-rw-r--r--packages/backend/test/resources/Lenna.pngbin473831 -> 0 bytes
-rw-r--r--packages/backend/test/unit/AbuseReportNotificationService.ts343
-rw-r--r--packages/backend/test/unit/ApMfmService.ts8
-rw-r--r--packages/backend/test/unit/FileInfoService.ts111
-rw-r--r--packages/backend/test/unit/RoleService.ts140
-rw-r--r--packages/backend/test/unit/SystemWebhookService.ts516
-rw-r--r--packages/backend/test/unit/UserSearchService.ts265
-rw-r--r--packages/backend/test/utils.ts98
-rw-r--r--packages/frontend/.eslintrc.cjs82
-rw-r--r--packages/frontend/.storybook/changes.ts2
-rw-r--r--packages/frontend/.storybook/charts.ts48
-rw-r--r--packages/frontend/.storybook/fakes.ts117
-rw-r--r--packages/frontend/.storybook/generate.tsx5
-rw-r--r--packages/frontend/.storybook/main.ts1
-rw-r--r--packages/frontend/.storybook/preview.ts10
-rw-r--r--packages/frontend/eslint.config.js95
-rw-r--r--packages/frontend/package.json130
-rw-r--r--packages/frontend/src/account.ts18
-rw-r--r--packages/frontend/src/boot/main-boot.ts67
-rw-r--r--packages/frontend/src/boot/sub-boot.ts3
-rw-r--r--packages/frontend/src/components/MkAchievements.vue4
-rw-r--r--packages/frontend/src/components/MkAntennaEditor.stories.impl.ts62
-rw-r--r--packages/frontend/src/components/MkAntennaEditor.vue (renamed from packages/frontend/src/pages/my-antennas/editor.vue)75
-rw-r--r--packages/frontend/src/components/MkAntennaEditorDialog.stories.impl.ts63
-rw-r--r--packages/frontend/src/components/MkAntennaEditorDialog.vue63
-rw-r--r--packages/frontend/src/components/MkButton.vue3
-rw-r--r--packages/frontend/src/components/MkCaptcha.vue1
-rw-r--r--packages/frontend/src/components/MkChannelFollowButton.stories.impl.ts71
-rw-r--r--packages/frontend/src/components/MkChannelFollowButton.vue17
-rw-r--r--packages/frontend/src/components/MkChannelList.stories.impl.ts65
-rw-r--r--packages/frontend/src/components/MkChannelPreview.stories.impl.ts43
-rw-r--r--packages/frontend/src/components/MkChannelPreview.vue19
-rw-r--r--packages/frontend/src/components/MkChart.stories.impl.ts80
-rw-r--r--packages/frontend/src/components/MkChart.vue101
-rw-r--r--packages/frontend/src/components/MkChartLegend.stories.impl.ts (renamed from packages/backend/src/misc/prelude/math.ts)5
-rw-r--r--packages/frontend/src/components/MkChartTooltip.stories.impl.ts7
-rw-r--r--packages/frontend/src/components/MkClickerGame.stories.impl.ts77
-rw-r--r--packages/frontend/src/components/MkClickerGame.vue6
-rw-r--r--packages/frontend/src/components/MkClipPreview.stories.impl.ts44
-rw-r--r--packages/frontend/src/components/MkClipPreview.vue25
-rw-r--r--packages/frontend/src/components/MkCode.core.stories.impl.ts7
-rw-r--r--packages/frontend/src/components/MkCode.stories.impl.ts44
-rw-r--r--packages/frontend/src/components/MkCode.vue2
-rw-r--r--packages/frontend/src/components/MkCodeEditor.stories.impl.ts62
-rw-r--r--packages/frontend/src/components/MkCodeInline.stories.impl.ts37
-rw-r--r--packages/frontend/src/components/MkColorInput.stories.impl.ts50
-rw-r--r--packages/frontend/src/components/MkContainer.stories.impl.ts7
-rw-r--r--packages/frontend/src/components/MkContextMenu.stories.impl.ts58
-rw-r--r--packages/frontend/src/components/MkContextMenu.vue2
-rw-r--r--packages/frontend/src/components/MkCropperDialog.stories.impl.ts75
-rw-r--r--packages/frontend/src/components/MkCustomEmojiDetailedDialog.stories.impl.ts38
-rw-r--r--packages/frontend/src/components/MkCwButton.stories.impl.ts79
-rw-r--r--packages/frontend/src/components/MkCwButton.vue4
-rw-r--r--packages/frontend/src/components/MkDateSeparatedList.stories.impl.ts7
-rw-r--r--packages/frontend/src/components/MkDateSeparatedList.vue2
-rw-r--r--packages/frontend/src/components/MkDialog.stories.impl.ts159
-rw-r--r--packages/frontend/src/components/MkDialog.vue36
-rw-r--r--packages/frontend/src/components/MkDivider.stories.impl.ts (renamed from packages/backend/src/misc/prelude/symbol.ts)3
-rw-r--r--packages/frontend/src/components/MkDivider.vue32
-rw-r--r--packages/frontend/src/components/MkDonation.stories.impl.ts54
-rw-r--r--packages/frontend/src/components/MkDrive.file.stories.impl.ts48
-rw-r--r--packages/frontend/src/components/MkDrive.file.vue32
-rw-r--r--packages/frontend/src/components/MkDrive.folder.stories.impl.ts70
-rw-r--r--packages/frontend/src/components/MkDrive.folder.vue79
-rw-r--r--packages/frontend/src/components/MkDrive.navFolder.stories.impl.ts7
-rw-r--r--packages/frontend/src/components/MkDrive.stories.impl.ts82
-rw-r--r--packages/frontend/src/components/MkDrive.vue6
-rw-r--r--packages/frontend/src/components/MkDriveFileThumbnail.stories.impl.ts41
-rw-r--r--packages/frontend/src/components/MkDriveFileThumbnail.vue2
-rw-r--r--packages/frontend/src/components/MkDriveSelectDialog.stories.impl.ts7
-rw-r--r--packages/frontend/src/components/MkDriveWindow.stories.impl.ts7
-rw-r--r--packages/frontend/src/components/MkEmojiPicker.section.stories.impl.ts7
-rw-r--r--packages/frontend/src/components/MkEmojiPicker.stories.impl.ts54
-rw-r--r--packages/frontend/src/components/MkEmojiPicker.vue37
-rw-r--r--packages/frontend/src/components/MkEmojiPickerDialog.stories.impl.ts7
-rw-r--r--packages/frontend/src/components/MkEmojiPickerDialog.vue3
-rw-r--r--packages/frontend/src/components/MkFlashPreview.vue6
-rw-r--r--packages/frontend/src/components/MkFolder.vue16
-rw-r--r--packages/frontend/src/components/MkFollowButton.vue20
-rw-r--r--packages/frontend/src/components/MkGalleryPostPreview.vue4
-rw-r--r--packages/frontend/src/components/MkImgWithBlurhash.vue14
-rw-r--r--packages/frontend/src/components/MkInput.vue4
-rw-r--r--packages/frontend/src/components/MkInstanceCardMini.stories.impl.ts65
-rw-r--r--packages/frontend/src/components/MkInstanceCardMini.vue4
-rw-r--r--packages/frontend/src/components/MkInviteCode.vue2
-rw-r--r--packages/frontend/src/components/MkKeyValue.vue2
-rw-r--r--packages/frontend/src/components/MkLaunchPad.vue2
-rw-r--r--packages/frontend/src/components/MkLink.vue6
-rw-r--r--packages/frontend/src/components/MkMediaAudio.vue89
-rw-r--r--packages/frontend/src/components/MkMediaBanner.vue26
-rw-r--r--packages/frontend/src/components/MkMediaImage.vue12
-rw-r--r--packages/frontend/src/components/MkMediaList.vue62
-rw-r--r--packages/frontend/src/components/MkMediaVideo.vue73
-rw-r--r--packages/frontend/src/components/MkMenu.child.vue5
-rw-r--r--packages/frontend/src/components/MkMenu.vue366
-rw-r--r--packages/frontend/src/components/MkModal.vue38
-rw-r--r--packages/frontend/src/components/MkModalWindow.vue29
-rw-r--r--packages/frontend/src/components/MkNote.vue135
-rw-r--r--packages/frontend/src/components/MkNoteDetailed.vue120
-rw-r--r--packages/frontend/src/components/MkNotePreview.vue2
-rw-r--r--packages/frontend/src/components/MkNotification.vue12
-rw-r--r--packages/frontend/src/components/MkPagePreview.vue19
-rw-r--r--packages/frontend/src/components/MkPageWindow.vue2
-rw-r--r--packages/frontend/src/components/MkPoll.vue9
-rw-r--r--packages/frontend/src/components/MkPollEditor.vue2
-rw-r--r--packages/frontend/src/components/MkPopupMenu.vue6
-rw-r--r--packages/frontend/src/components/MkPostForm.vue60
-rw-r--r--packages/frontend/src/components/MkPostFormAttaches.vue5
-rw-r--r--packages/frontend/src/components/MkPostFormDialog.vue2
-rw-r--r--packages/frontend/src/components/MkPreview.vue150
-rw-r--r--packages/frontend/src/components/MkRadio.vue10
-rw-r--r--packages/frontend/src/components/MkRadios.vue4
-rw-r--r--packages/frontend/src/components/MkRange.vue10
-rw-r--r--packages/frontend/src/components/MkReactionIcon.vue6
-rw-r--r--packages/frontend/src/components/MkReactionsViewer.details.vue1
-rw-r--r--packages/frontend/src/components/MkReactionsViewer.reaction.vue14
-rw-r--r--packages/frontend/src/components/MkSelect.vue27
-rw-r--r--packages/frontend/src/components/MkSignin.vue150
-rw-r--r--packages/frontend/src/components/MkSigninDialog.vue9
-rw-r--r--packages/frontend/src/components/MkSuperMenu.vue10
-rw-r--r--packages/frontend/src/components/MkSwitch.vue15
-rw-r--r--packages/frontend/src/components/MkSystemWebhookEditor.impl.ts46
-rw-r--r--packages/frontend/src/components/MkSystemWebhookEditor.vue238
-rw-r--r--packages/frontend/src/components/MkTimeline.vue3
-rw-r--r--packages/frontend/src/components/MkTutorialDialog.PostNote.vue2
-rw-r--r--packages/frontend/src/components/MkTutorialDialog.Sensitive.vue2
-rw-r--r--packages/frontend/src/components/MkTutorialDialog.Timeline.vue11
-rw-r--r--packages/frontend/src/components/MkTutorialDialog.vue2
-rw-r--r--packages/frontend/src/components/MkUrlPreview.vue11
-rw-r--r--packages/frontend/src/components/MkUserInfo.vue6
-rw-r--r--packages/frontend/src/components/MkUserPopup.vue3
-rw-r--r--packages/frontend/src/components/MkUserSelectDialog.vue8
-rw-r--r--packages/frontend/src/components/MkUserSetupDialog.vue8
-rw-r--r--packages/frontend/src/components/MkVisibilityPicker.vue2
-rw-r--r--packages/frontend/src/components/MkVisitorDashboard.vue23
-rw-r--r--packages/frontend/src/components/MkYouTubePlayer.vue3
-rw-r--r--packages/frontend/src/components/global/MkA.stories.impl.ts2
-rw-r--r--packages/frontend/src/components/global/MkA.vue2
-rw-r--r--packages/frontend/src/components/global/MkAd.stories.impl.ts87
-rw-r--r--packages/frontend/src/components/global/MkCustomEmoji.vue6
-rw-r--r--packages/frontend/src/components/global/MkEmoji.vue2
-rw-r--r--packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts2
-rw-r--r--packages/frontend/src/components/global/MkStickyContainer.vue6
-rw-r--r--packages/frontend/src/components/global/MkTime.vue4
-rw-r--r--packages/frontend/src/components/global/MkUrl.vue6
-rw-r--r--packages/frontend/src/components/global/RouterView.vue4
-rw-r--r--packages/frontend/src/const.ts1
-rw-r--r--packages/frontend/src/directives/hotkey.ts6
-rw-r--r--packages/frontend/src/directives/ripple.ts4
-rw-r--r--packages/frontend/src/directives/tooltip.ts6
-rw-r--r--packages/frontend/src/directives/user-preview.ts5
-rw-r--r--packages/frontend/src/filters/user.ts4
-rw-r--r--packages/frontend/src/i18n.ts1
-rw-r--r--packages/frontend/src/os.ts203
-rw-r--r--packages/frontend/src/pages/about-misskey.vue31
-rw-r--r--packages/frontend/src/pages/about.federation.vue6
-rw-r--r--packages/frontend/src/pages/about.overview.vue205
-rw-r--r--packages/frontend/src/pages/about.vue201
-rw-r--r--packages/frontend/src/pages/admin-user.vue12
-rw-r--r--packages/frontend/src/pages/admin/_header_.vue5
-rw-r--r--packages/frontend/src/pages/admin/abuse-report/notification-recipient.editor.vue321
-rw-r--r--packages/frontend/src/pages/admin/abuse-report/notification-recipient.item.vue114
-rw-r--r--packages/frontend/src/pages/admin/abuse-report/notification-recipient.vue177
-rw-r--r--packages/frontend/src/pages/admin/abuses.vue85
-rw-r--r--packages/frontend/src/pages/admin/announcements.vue160
-rw-r--r--packages/frontend/src/pages/admin/federation.vue6
-rw-r--r--packages/frontend/src/pages/admin/index.vue5
-rw-r--r--packages/frontend/src/pages/admin/instance-block.vue27
-rw-r--r--packages/frontend/src/pages/admin/invites.vue2
-rw-r--r--packages/frontend/src/pages/admin/modlog.ModLog.vue48
-rw-r--r--packages/frontend/src/pages/admin/roles.editor.vue20
-rw-r--r--packages/frontend/src/pages/admin/roles.vue11
-rw-r--r--packages/frontend/src/pages/admin/system-webhook.item.vue117
-rw-r--r--packages/frontend/src/pages/admin/system-webhook.vue96
-rw-r--r--packages/frontend/src/pages/announcement.vue9
-rw-r--r--packages/frontend/src/pages/antenna-timeline.vue5
-rw-r--r--packages/frontend/src/pages/channel.vue2
-rw-r--r--packages/frontend/src/pages/clip.vue2
-rw-r--r--packages/frontend/src/pages/contact.vue26
-rw-r--r--packages/frontend/src/pages/custom-emojis-manager.vue10
-rw-r--r--packages/frontend/src/pages/drive.file.info.vue49
-rw-r--r--packages/frontend/src/pages/drop-and-fusion.game.vue16
-rw-r--r--packages/frontend/src/pages/emoji-edit-dialog.vue6
-rw-r--r--packages/frontend/src/pages/emojis.emoji.vue10
-rw-r--r--packages/frontend/src/pages/flash/flash-edit.vue11
-rw-r--r--packages/frontend/src/pages/flash/flash.vue5
-rw-r--r--packages/frontend/src/pages/follow.vue71
-rw-r--r--packages/frontend/src/pages/gallery/post.vue2
-rw-r--r--packages/frontend/src/pages/games.vue11
-rw-r--r--packages/frontend/src/pages/instance-info.vue15
-rw-r--r--packages/frontend/src/pages/lookup.vue97
-rw-r--r--packages/frontend/src/pages/my-antennas/create.vue32
-rw-r--r--packages/frontend/src/pages/my-antennas/edit.vue17
-rw-r--r--packages/frontend/src/pages/my-clips/index.vue2
-rw-r--r--packages/frontend/src/pages/my-lists/list.vue31
-rw-r--r--packages/frontend/src/pages/page.vue3
-rw-r--r--packages/frontend/src/pages/preview.vue26
-rw-r--r--packages/frontend/src/pages/reset-password.vue4
-rw-r--r--packages/frontend/src/pages/reversi/game.board.vue2
-rw-r--r--packages/frontend/src/pages/reversi/game.vue3
-rw-r--r--packages/frontend/src/pages/search.note.vue202
-rw-r--r--packages/frontend/src/pages/search.stories.impl.ts88
-rw-r--r--packages/frontend/src/pages/search.user.vue72
-rw-r--r--packages/frontend/src/pages/search.vue34
-rw-r--r--packages/frontend/src/pages/settings/2fa.vue6
-rw-r--r--packages/frontend/src/pages/settings/accounts.vue10
-rw-r--r--packages/frontend/src/pages/settings/api.vue5
-rw-r--r--packages/frontend/src/pages/settings/avatar-decoration.vue5
-rw-r--r--packages/frontend/src/pages/settings/drive-cleaner.vue6
-rw-r--r--packages/frontend/src/pages/settings/drive.vue2
-rw-r--r--packages/frontend/src/pages/settings/general.vue11
-rw-r--r--packages/frontend/src/pages/settings/plugin.vue2
-rw-r--r--packages/frontend/src/pages/settings/preferences-backups.vue2
-rw-r--r--packages/frontend/src/pages/settings/profile.vue1
-rw-r--r--packages/frontend/src/pages/settings/sounds.sound.vue44
-rw-r--r--packages/frontend/src/pages/settings/sounds.vue12
-rw-r--r--packages/frontend/src/pages/settings/statusbar.statusbar.vue4
-rw-r--r--packages/frontend/src/pages/settings/theme.manage.vue2
-rw-r--r--packages/frontend/src/pages/settings/theme.vue6
-rw-r--r--packages/frontend/src/pages/settings/webhook.edit.vue2
-rw-r--r--packages/frontend/src/pages/settings/webhook.new.vue2
-rw-r--r--packages/frontend/src/pages/timeline.vue73
-rw-r--r--packages/frontend/src/pages/user/home.vue23
-rw-r--r--packages/frontend/src/pages/welcome.timeline.note.vue109
-rw-r--r--packages/frontend/src/pages/welcome.timeline.vue98
-rw-r--r--packages/frontend/src/router/definition.ts26
-rw-r--r--packages/frontend/src/scripts/array.ts38
-rw-r--r--packages/frontend/src/scripts/check-permissions.ts19
-rw-r--r--packages/frontend/src/scripts/copy-to-clipboard.ts31
-rw-r--r--packages/frontend/src/scripts/focus-trap.ts78
-rw-r--r--packages/frontend/src/scripts/focus.ts94
-rw-r--r--packages/frontend/src/scripts/get-dom-node-or-null.ts19
-rw-r--r--packages/frontend/src/scripts/get-drive-file-menu.ts20
-rw-r--r--packages/frontend/src/scripts/get-note-menu.ts20
-rw-r--r--packages/frontend/src/scripts/get-user-menu.ts50
-rw-r--r--packages/frontend/src/scripts/hotkey.ts201
-rw-r--r--packages/frontend/src/scripts/install-plugin.ts5
-rw-r--r--packages/frontend/src/scripts/keycode.ts24
-rw-r--r--packages/frontend/src/scripts/lookup.ts2
-rw-r--r--packages/frontend/src/scripts/merge.ts2
-rw-r--r--packages/frontend/src/scripts/mfm-function-picker.ts29
-rw-r--r--packages/frontend/src/scripts/player-url-transform.ts26
-rw-r--r--packages/frontend/src/scripts/please-login.ts46
-rw-r--r--packages/frontend/src/scripts/scroll.ts8
-rw-r--r--packages/frontend/src/scripts/sound.ts46
-rw-r--r--packages/frontend/src/scripts/url.ts5
-rw-r--r--packages/frontend/src/scripts/use-chart-tooltip.ts10
-rw-r--r--packages/frontend/src/store.ts16
-rw-r--r--packages/frontend/src/style.scss25
-rw-r--r--packages/frontend/src/timelines.ts56
-rw-r--r--packages/frontend/src/ui/_common_/common.ts28
-rw-r--r--packages/frontend/src/ui/_common_/common.vue2
-rw-r--r--packages/frontend/src/ui/_common_/navbar-for-mobile.vue11
-rw-r--r--packages/frontend/src/ui/_common_/navbar.vue91
-rw-r--r--packages/frontend/src/ui/classic.header.vue5
-rw-r--r--packages/frontend/src/ui/classic.sidebar.vue6
-rw-r--r--packages/frontend/src/ui/deck.vue29
-rw-r--r--packages/frontend/src/ui/deck/antenna-column.vue38
-rw-r--r--packages/frontend/src/ui/deck/channel-column.vue3
-rw-r--r--packages/frontend/src/ui/deck/column.vue4
-rw-r--r--packages/frontend/src/ui/deck/deck-store.ts24
-rw-r--r--packages/frontend/src/ui/deck/direct-column.vue2
-rw-r--r--packages/frontend/src/ui/deck/list-column.vue41
-rw-r--r--packages/frontend/src/ui/deck/mentions-column.vue2
-rw-r--r--packages/frontend/src/ui/deck/notifications-column.vue7
-rw-r--r--packages/frontend/src/ui/deck/role-timeline-column.vue4
-rw-r--r--packages/frontend/src/ui/deck/tl-column.vue33
-rw-r--r--packages/frontend/src/ui/visitor.vue12
-rw-r--r--packages/frontend/src/widgets/WidgetCalendar.vue2
-rw-r--r--packages/frontend/src/widgets/WidgetInstanceInfo.vue7
-rw-r--r--packages/frontend/src/widgets/WidgetNotifications.vue5
-rw-r--r--packages/frontend/src/widgets/WidgetProfile.vue7
-rw-r--r--packages/frontend/src/widgets/WidgetTimeline.vue34
-rw-r--r--packages/frontend/tsconfig.json4
-rw-r--r--packages/frontend/vite.config.local-dev.ts21
-rw-r--r--packages/frontend/vite.config.ts2
-rw-r--r--packages/misskey-bubble-game/.eslintignore8
-rw-r--r--packages/misskey-bubble-game/.eslintrc.cjs9
-rw-r--r--packages/misskey-bubble-game/build.js1
-rw-r--r--packages/misskey-bubble-game/eslint.config.js27
-rw-r--r--packages/misskey-bubble-game/package.json4
-rw-r--r--packages/misskey-js/.eslintignore8
-rw-r--r--packages/misskey-js/.eslintrc.cjs9
-rw-r--r--packages/misskey-js/README.md2
-rw-r--r--packages/misskey-js/build.js33
-rw-r--r--packages/misskey-js/eslint.config.js29
-rw-r--r--packages/misskey-js/etc/misskey-js.api.md152
-rw-r--r--packages/misskey-js/generator/.eslintrc.cjs9
-rw-r--r--packages/misskey-js/generator/eslint.config.js17
-rw-r--r--packages/misskey-js/generator/package.json4
-rw-r--r--packages/misskey-js/generator/src/generator.ts57
-rw-r--r--packages/misskey-js/package.json26
-rw-r--r--packages/misskey-js/src/acct.ts3
-rw-r--r--packages/misskey-js/src/api.ts54
-rw-r--r--packages/misskey-js/src/api.types.ts9
-rw-r--r--packages/misskey-js/src/autogen/apiClientJSDoc.ts120
-rw-r--r--packages/misskey-js/src/autogen/endpoint.ts410
-rw-r--r--packages/misskey-js/src/autogen/entities.ts18
-rw-r--r--packages/misskey-js/src/autogen/models.ts2
-rw-r--r--packages/misskey-js/src/autogen/types.ts787
-rw-r--r--packages/misskey-js/src/consts.ts120
-rw-r--r--packages/misskey-js/src/entities.ts35
-rw-r--r--packages/misskey-js/src/streaming.ts34
-rw-r--r--packages/misskey-js/src/streaming.types.ts18
-rw-r--r--packages/misskey-js/test/api.ts92
-rw-r--r--packages/misskey-js/tsconfig.json1
-rw-r--r--packages/misskey-reversi/.eslintignore8
-rw-r--r--packages/misskey-reversi/.eslintrc.cjs10
-rw-r--r--packages/misskey-reversi/build.js1
-rw-r--r--packages/misskey-reversi/eslint.config.js23
-rw-r--r--packages/misskey-reversi/package.json4
-rw-r--r--packages/shared/.eslintrc.js7
-rw-r--r--packages/shared/eslint.config.js28
-rw-r--r--packages/shared/package.json3
-rw-r--r--packages/sw/.eslintrc.cjs20
-rw-r--r--packages/sw/build.js2
-rw-r--r--packages/sw/eslint.config.js32
-rw-r--r--packages/sw/package.json10
-rw-r--r--packages/sw/tsconfig.json1
-rw-r--r--pnpm-lock.yaml10138
-rw-r--r--scripts/build-assets.mjs2
-rw-r--r--scripts/changelog-checker/.eslintrc.cjs9
-rw-r--r--scripts/changelog-checker/eslint.config.js17
-rw-r--r--scripts/tarball.mjs2
591 files changed, 23051 insertions, 9370 deletions
diff --git a/.config/docker_example.env b/.config/docker_example.env
index 4fe8e76b78..c61248da2e 100644
--- a/.config/docker_example.env
+++ b/.config/docker_example.env
@@ -1,5 +1,11 @@
+# misskey settings
+# MISSKEY_URL=https://example.tld/
+
# db settings
POSTGRES_PASSWORD=example-misskey-pass
+# DATABASE_PASSWORD=${POSTGRES_PASSWORD}
POSTGRES_USER=example-misskey-user
+# DATABASE_USER=${POSTGRES_USER}
POSTGRES_DB=misskey
+# DATABASE_DB=${POSTGRES_DB}
DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}"
diff --git a/.config/docker_example.yml b/.config/docker_example.yml
index 42ac18de1b..d347882d1a 100644
--- a/.config/docker_example.yml
+++ b/.config/docker_example.yml
@@ -6,6 +6,7 @@
#───┘ URL └─────────────────────────────────────────────────────
# Final accessible URL seen by a user.
+# You can set url from an environment variable instead.
url: https://example.tld/
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
@@ -38,9 +39,11 @@ db:
port: 5432
# Database name
+ # You can set db from an environment variable instead.
db: misskey
# Auth
+ # You can set user and pass from environment variables instead.
user: example-misskey-user
pass: example-misskey-pass
diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/compose.yml
index 2809cd2ca4..d02d2a8f4a 100644
--- a/.devcontainer/docker-compose.yml
+++ b/.devcontainer/compose.yml
@@ -1,5 +1,3 @@
-version: '3.8'
-
services:
app:
build:
@@ -8,6 +6,7 @@ services:
volumes:
- ../:/workspace:cached
+ - node_modules:/workspace/node_modules
command: sleep infinity
@@ -46,6 +45,7 @@ services:
volumes:
postgres-data:
redis-data:
+ node_modules:
networks:
internal_network:
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 31b6212cb5..fbf959d449 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -1,16 +1,16 @@
{
"name": "Misskey",
- "dockerComposeFile": "docker-compose.yml",
+ "dockerComposeFile": "compose.yml",
"service": "app",
"workspaceFolder": "/workspace",
"features": {
"ghcr.io/devcontainers/features/node:1": {
- "version": "20.12.2"
+ "version": "20.16.0"
},
"ghcr.io/devcontainers-contrib/features/corepack:1": {}
},
"forwardPorts": [3000],
- "postCreateCommand": "sudo chmod 755 .devcontainer/init.sh && .devcontainer/init.sh",
+ "postCreateCommand": "/bin/bash .devcontainer/init.sh",
"customizations": {
"vscode": {
"extensions": [
diff --git a/.devcontainer/init.sh b/.devcontainer/init.sh
index 729e1a9d2d..55fb1e6fa6 100755
--- a/.devcontainer/init.sh
+++ b/.devcontainer/init.sh
@@ -2,7 +2,8 @@
set -xe
-sudo chown -R node /workspace
+sudo chown node node_modules
+git config --global --add safe.directory /workspace
git submodule update --init
corepack install
corepack enable
diff --git a/.dockerignore b/.dockerignore
index 1de0c7982b..f204349160 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -7,12 +7,11 @@ Dockerfile
build/
built/
db/
-docker-compose.yml
+.devcontainer/compose.yml
node_modules/
packages/*/node_modules
redis/
files/
-misskey-assets/
fluent-emojis/
.pnp.*
@@ -28,4 +27,4 @@ fluent-emojis/
.idea/
packages/*/.vscode/
-packages/backend/test/docker-compose.yml
+packages/backend/test/compose.yml
diff --git a/.github/ISSUE_TEMPLATE/01_bug-report.yml b/.github/ISSUE_TEMPLATE/01_bug-report.yml
index ac2b39cc12..315e712c30 100644
--- a/.github/ISSUE_TEMPLATE/01_bug-report.yml
+++ b/.github/ISSUE_TEMPLATE/01_bug-report.yml
@@ -53,8 +53,8 @@ body:
Examples:
* Model and OS of the device(s): MacBook Pro (14inch, 2021), macOS Ventura 13.4
* Browser: Chrome 113.0.5672.126
- * Server URL: misskey.io
- * Misskey: 13.x.x
+ * Server URL: misskey.example.com
+ * Misskey: 2024.x.x
value: |
* Model and OS of the device(s):
* Browser:
@@ -74,11 +74,11 @@ body:
Examples:
* Installation Method or Hosting Service: docker compose, k8s/docker, systemd, "Misskey install shell script", development environment
- * Misskey: 13.x.x
+ * Misskey: 2024.x.x
* Node: 20.x.x
* PostgreSQL: 15.x.x
* Redis: 7.x.x
- * OS and Architecture: Ubuntu 22.04.2 LTS aarch64
+ * OS and Architecture: Ubuntu 24.04.2 LTS aarch64
value: |
* Installation Method or Hosting Service:
* Misskey:
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index e8b65dc3b9..5acad83336 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -2,3 +2,7 @@ contact_links:
- name: 💬 Misskey official Discord
url: https://discord.gg/Wp8gVStHW3
about: Chat freely about Misskey
+ # ä»®
+ - name: 💬 Start discussion
+ url: https://github.com/misskey-dev/misskey/discussions
+ about: The official forum to join conversation and ask question
diff --git a/.github/workflows/api-misskey-js.yml b/.github/workflows/api-misskey-js.yml
index 1b7b68b14f..e7db18316c 100644
--- a/.github/workflows/api-misskey-js.yml
+++ b/.github/workflows/api-misskey-js.yml
@@ -4,10 +4,11 @@ on:
push:
paths:
- packages/misskey-js/**
+ - .github/workflows/api-misskey-js.yml
pull_request:
paths:
- packages/misskey-js/**
-
+ - .github/workflows/api-misskey-js.yml
jobs:
report:
@@ -20,7 +21,7 @@ jobs:
- run: corepack enable
- name: Setup Node.js
- uses: actions/setup-node@v4.0.2
+ uses: actions/setup-node@v4.0.3
with:
node-version-file: '.node-version'
cache: 'pnpm'
diff --git a/.github/workflows/changelog-check.yml b/.github/workflows/changelog-check.yml
index f254af0d1f..d4e99f966e 100644
--- a/.github/workflows/changelog-check.yml
+++ b/.github/workflows/changelog-check.yml
@@ -14,7 +14,7 @@ jobs:
- name: Checkout head
uses: actions/checkout@v4.1.1
- name: Setup Node.js
- uses: actions/setup-node@v4.0.2
+ uses: actions/setup-node@v4.0.3
with:
node-version-file: '.node-version'
diff --git a/.github/workflows/check-misskey-js-autogen.yml b/.github/workflows/check-misskey-js-autogen.yml
index 39acad8bc3..3a2a2d5f8d 100644
--- a/.github/workflows/check-misskey-js-autogen.yml
+++ b/.github/workflows/check-misskey-js-autogen.yml
@@ -28,7 +28,7 @@ jobs:
- name: setup node
id: setup-node
- uses: actions/setup-node@v4.0.2
+ uses: actions/setup-node@v4.0.3
with:
node-version-file: '.node-version'
cache: pnpm
diff --git a/.github/workflows/check-misskey-js-version.yml b/.github/workflows/check-misskey-js-version.yml
index 325a893605..99c29ac974 100644
--- a/.github/workflows/check-misskey-js-version.yml
+++ b/.github/workflows/check-misskey-js-version.yml
@@ -6,12 +6,13 @@ on:
paths:
- packages/misskey-js/package.json
- package.json
+ - .github/workflows/check-misskey-js-version.yml
pull_request:
branches: [ develop ]
paths:
- packages/misskey-js/package.json
- package.json
-
+ - .github/workflows/check-misskey-js-version.yml
jobs:
check-version:
# ルート㮠package.json 㨠packages/misskey-js/package.json ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ãŒä¸€è‡´ã—ã¦ã„ã‚‹ã‹ã‚’確èªã™ã‚‹
diff --git a/.github/workflows/docker-develop.yml b/.github/workflows/docker-develop.yml
index cb84849580..ac2b1b4d35 100644
--- a/.github/workflows/docker-develop.yml
+++ b/.github/workflows/docker-develop.yml
@@ -37,7 +37,7 @@ jobs:
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push by digest
id: build
- uses: docker/build-push-action@v5
+ uses: docker/build-push-action@v6
with:
context: .
push: true
diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index 23c1bdbc16..db899ba386 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -48,7 +48,7 @@ jobs:
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push to Docker Hub
id: build
- uses: docker/build-push-action@v5
+ uses: docker/build-push-action@v6
with:
context: .
push: true
diff --git a/.github/workflows/dockle.yml b/.github/workflows/dockle.yml
index eee7a78fed..c3dba4213d 100644
--- a/.github/workflows/dockle.yml
+++ b/.github/workflows/dockle.yml
@@ -13,14 +13,16 @@ jobs:
runs-on: ubuntu-latest
env:
DOCKER_CONTENT_TRUST: 1
+ DOCKLE_VERSION: 0.4.14
steps:
- uses: actions/checkout@v4.1.1
- - run: |
- curl -L -o dockle.deb "https://github.com/goodwithtech/dockle/releases/download/v0.4.10/dockle_0.4.10_Linux-64bit.deb"
+ - name: Download and install dockle v${{ env.DOCKLE_VERSION }}
+ run: |
+ curl -L -o dockle.deb "https://github.com/goodwithtech/dockle/releases/download/v${DOCKLE_VERSION}/dockle_${DOCKLE_VERSION}_Linux-64bit.deb"
sudo dpkg -i dockle.deb
- run: |
cp .config/docker_example.env .config/docker.env
- cp ./docker-compose_example.yml ./docker-compose.yml
+ cp ./compose_example.yml ./compose.yml
- run: |
docker compose up -d web
docker tag "$(docker compose images web | awk 'OFS=":" {print $4}' | tail -n +2)" misskey-web:latest
diff --git a/.github/workflows/get-api-diff.yml b/.github/workflows/get-api-diff.yml
index 9b9c8f11c4..81e8134fb7 100644
--- a/.github/workflows/get-api-diff.yml
+++ b/.github/workflows/get-api-diff.yml
@@ -9,7 +9,6 @@ on:
paths:
- packages/backend/**
- .github/workflows/get-api-diff.yml
-
jobs:
get-from-misskey:
runs-on: ubuntu-latest
@@ -18,7 +17,7 @@ jobs:
strategy:
matrix:
- node-version: [20.12.2]
+ node-version: [20.16.0]
api-json-name: [api-base.json, api-head.json]
include:
- api-json-name: api-base.json
@@ -34,7 +33,7 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v4.0.2
+ uses: actions/setup-node@v4.0.3
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 76616ec5a7..c21fc95123 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -10,15 +10,16 @@ on:
- packages/frontend/**
- packages/sw/**
- packages/misskey-js/**
- - packages/shared/.eslintrc.js
+ - packages/shared/eslint.config.js
+ - .github/workflows/lint.yml
pull_request:
paths:
- packages/backend/**
- packages/frontend/**
- packages/sw/**
- packages/misskey-js/**
- - packages/shared/.eslintrc.js
-
+ - packages/shared/eslint.config.js
+ - .github/workflows/lint.yml
jobs:
pnpm_install:
runs-on: ubuntu-latest
@@ -28,7 +29,7 @@ jobs:
fetch-depth: 0
submodules: true
- uses: pnpm/action-setup@v4
- - uses: actions/setup-node@v4.0.2
+ - uses: actions/setup-node@v4.0.3
with:
node-version-file: '.node-version'
cache: 'pnpm'
@@ -39,6 +40,8 @@ jobs:
needs: [pnpm_install]
runs-on: ubuntu-latest
continue-on-error: true
+ env:
+ eslint-cache-version: v1
strategy:
matrix:
workspace:
@@ -52,13 +55,20 @@ jobs:
fetch-depth: 0
submodules: true
- uses: pnpm/action-setup@v4
- - uses: actions/setup-node@v4.0.2
+ - uses: actions/setup-node@v4.0.3
with:
node-version-file: '.node-version'
cache: 'pnpm'
- run: corepack enable
- run: pnpm i --frozen-lockfile
- - run: pnpm --filter ${{ matrix.workspace }} run eslint
+ - name: Restore eslint cache
+ uses: actions/cache@v4.0.2
+ with:
+ path: node_modules/.cache/eslint
+ key: eslint-${{ env.eslint-cache-version }}-${{ hashFiles('/pnpm-lock.yaml') }}-${{ github.ref_name }}-${{ github.sha }}
+ restore-keys: |
+ eslint-${{ env.eslint-cache-version }}-${{ hashFiles('/pnpm-lock.yaml') }}-
+ - run: pnpm --filter ${{ matrix.workspace }} run eslint --cache --cache-location node_modules/.cache/eslint --cache-strategy content
typecheck:
needs: [pnpm_install]
@@ -75,7 +85,7 @@ jobs:
fetch-depth: 0
submodules: true
- uses: pnpm/action-setup@v4
- - uses: actions/setup-node@v4.0.2
+ - uses: actions/setup-node@v4.0.3
with:
node-version-file: '.node-version'
cache: 'pnpm'
diff --git a/.github/workflows/locale.yml b/.github/workflows/locale.yml
index de2247e772..95251bfe31 100644
--- a/.github/workflows/locale.yml
+++ b/.github/workflows/locale.yml
@@ -4,10 +4,11 @@ on:
push:
paths:
- locales/**
+ - .github/workflows/locale.yml
pull_request:
paths:
- locales/**
-
+ - .github/workflows/locale.yml
jobs:
locale_verify:
runs-on: ubuntu-latest
@@ -18,7 +19,7 @@ jobs:
fetch-depth: 0
submodules: true
- uses: pnpm/action-setup@v4
- - uses: actions/setup-node@v4.0.2
+ - uses: actions/setup-node@v4.0.3
with:
node-version-file: '.node-version'
cache: 'pnpm'
diff --git a/.github/workflows/on-release-created.yml b/.github/workflows/on-release-created.yml
index edfdab99e9..8dd9ed2513 100644
--- a/.github/workflows/on-release-created.yml
+++ b/.github/workflows/on-release-created.yml
@@ -17,7 +17,7 @@ jobs:
strategy:
matrix:
- node-version: [20.12.2]
+ node-version: [20.16.0]
steps:
- uses: actions/checkout@v4.1.1
@@ -26,7 +26,7 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v4.0.2
+ uses: actions/setup-node@v4.0.3
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
diff --git a/.github/workflows/release-edit-with-push.yml b/.github/workflows/release-edit-with-push.yml
index 86ee0b3fb5..f86c1948f8 100644
--- a/.github/workflows/release-edit-with-push.yml
+++ b/.github/workflows/release-edit-with-push.yml
@@ -3,10 +3,10 @@ name: "Release Manager: sync changelog with PR"
on:
push:
branches:
- - release/**
+ - develop
paths:
- 'CHANGELOG.md'
-
+ # - .github/workflows/release-edit-with-push.yml
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -20,24 +20,29 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- # headãŒrelease/ã‹ã¤openã®PRã‚’1ã¤å–å¾—
+ # headãŒ$GITHUB_REF_NAME, baseãŒ$STABLE_BRANCHã‹ã¤openã®PRã‚’1ã¤å–å¾—
- name: Get PR
run: |
- echo "pr_number=$(gh pr list --limit 1 --head "$GITHUB_REF_NAME" --json number --jq '.[] | .number')" >> $GITHUB_OUTPUT
+ echo "pr_number=$(gh pr list --limit 1 --search "head:$GITHUB_REF_NAME base:$STABLE_BRANCH is:open" --json number --jq '.[] | .number')" >> $GITHUB_OUTPUT
id: get_pr
+ env:
+ STABLE_BRANCH: ${{ vars.STABLE_BRANCH }}
- name: Get target version
- uses: misskey-dev/release-manager-actions/.github/actions/get-target-version@v1
+ if: steps.get_pr.outputs.pr_number != ''
+ uses: misskey-dev/release-manager-actions/.github/actions/get-target-version@v2
id: v
# CHANGELOG.mdã®å†…容をå–å¾—
- name: Get changelog
- uses: misskey-dev/release-manager-actions/.github/actions/get-changelog@v1
+ if: steps.get_pr.outputs.pr_number != ''
+ uses: misskey-dev/release-manager-actions/.github/actions/get-changelog@v2
with:
version: ${{ steps.v.outputs.target_version }}
id: changelog
# PRã®notesã‚’æ›´æ–°
- name: Update PR
+ if: steps.get_pr.outputs.pr_number != ''
run: |
gh pr edit "$PR_NUMBER" --body "$CHANGELOG"
env:
- CHANGELOG: ${{ steps.changelog.outputs.changelog }}
PR_NUMBER: ${{ steps.get_pr.outputs.pr_number }}
+ CHANGELOG: ${{ steps.changelog.outputs.changelog }}
diff --git a/.github/workflows/release-with-dispatch.yml b/.github/workflows/release-with-dispatch.yml
index bc6448cb37..0936bc0ae8 100644
--- a/.github/workflows/release-with-dispatch.yml
+++ b/.github/workflows/release-with-dispatch.yml
@@ -33,18 +33,21 @@ jobs:
pr_number: ${{ steps.get_pr.outputs.pr_number }}
steps:
- uses: actions/checkout@v4
- # headãŒrelease/ã‹ã¤openã®PRã‚’1ã¤å–å¾—
+ # headãŒ$GITHUB_REF_NAME, baseãŒ$STABLE_BRANCHã‹ã¤openã®PRã‚’1ã¤å–å¾—
- name: Get PRs
run: |
- echo "pr_number=$(gh pr list --limit 1 --search "head:release/ is:open" --json number --jq '.[] | .number')" >> $GITHUB_OUTPUT
+ echo "pr_number=$(gh pr list --limit 1 --search "head:$GITHUB_REF_NAME base:$STABLE_BRANCH is:open" --json number --jq '.[] | .number')" >> $GITHUB_OUTPUT
id: get_pr
+ env:
+ STABLE_BRANCH: ${{ vars.STABLE_BRANCH }}
merge:
- uses: misskey-dev/release-manager-actions/.github/workflows/merge.yml@v1
+ uses: misskey-dev/release-manager-actions/.github/workflows/merge.yml@v2
needs: get-pr
if: ${{ needs.get-pr.outputs.pr_number != '' && inputs.merge == true }}
with:
pr_number: ${{ needs.get-pr.outputs.pr_number }}
+ user: 'github-actions[bot]'
package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }}
# Text to prepend to the changelog
# The first line must be `## Unreleased`
@@ -65,15 +68,14 @@ jobs:
secrets:
RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }}
RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
- RULESET_EDIT_APP_ID: ${{ secrets.RULESET_EDIT_APP_ID }}
- RULESET_EDIT_APP_PRIVATE_KEY: ${{ secrets.RULESET_EDIT_APP_PRIVATE_KEY }}
create-prerelease:
- uses: misskey-dev/release-manager-actions/.github/workflows/create-prerelease.yml@v1
+ uses: misskey-dev/release-manager-actions/.github/workflows/create-prerelease.yml@v2
needs: get-pr
if: ${{ needs.get-pr.outputs.pr_number != '' && inputs.merge != true }}
with:
pr_number: ${{ needs.get-pr.outputs.pr_number }}
+ user: 'github-actions[bot]'
package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }}
use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }}
indent: ${{ vars.INDENT }}
@@ -82,10 +84,11 @@ jobs:
RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
create-target:
- uses: misskey-dev/release-manager-actions/.github/workflows/create-target.yml@v1
+ uses: misskey-dev/release-manager-actions/.github/workflows/create-target.yml@v2
needs: get-pr
if: ${{ needs.get-pr.outputs.pr_number == '' }}
with:
+ user: 'github-actions[bot]'
# The script for version increment.
# process.env.CURRENT_VERSION: The current version.
#
@@ -118,8 +121,7 @@ jobs:
package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }}
use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }}
indent: ${{ vars.INDENT }}
+ stable_branch: ${{ vars.STABLE_BRANCH }}
secrets:
RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }}
RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
- RULESET_EDIT_APP_ID: ${{ secrets.RULESET_EDIT_APP_ID }}
- RULESET_EDIT_APP_PRIVATE_KEY: ${{ secrets.RULESET_EDIT_APP_PRIVATE_KEY }}
diff --git a/.github/workflows/release-with-ready.yml b/.github/workflows/release-with-ready.yml
index a0fad0e336..79b6ade012 100644
--- a/.github/workflows/release-with-ready.yml
+++ b/.github/workflows/release-with-ready.yml
@@ -16,23 +16,26 @@ jobs:
check:
runs-on: ubuntu-latest
outputs:
- ref: ${{ steps.get_pr.outputs.ref }}
+ head: ${{ steps.get_pr.outputs.head }}
+ base: ${{ steps.get_pr.outputs.base }}
steps:
- uses: actions/checkout@v4
# PR情報をå–å¾—
- name: Get PR
run: |
- pr_json=$(gh pr view "$PR_NUMBER" --json isDraft,headRefName)
- echo "ref=$(echo $pr_json | jq -r '.headRefName')" >> $GITHUB_OUTPUT
+ pr_json=$(gh pr view "$PR_NUMBER" --json isDraft,headRefName,baseRefName)
+ echo "head=$(echo $pr_json | jq -r '.headRefName')" >> $GITHUB_OUTPUT
+ echo "base=$(echo $pr_json | jq -r '.baseRefName')" >> $GITHUB_OUTPUT
id: get_pr
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
release:
- uses: misskey-dev/release-manager-actions/.github/workflows/create-prerelease.yml@v1
+ uses: misskey-dev/release-manager-actions/.github/workflows/create-prerelease.yml@v2
needs: check
- if: startsWith(needs.check.outputs.ref, 'release/')
+ if: needs.check.outputs.head == github.event.repository.default_branch && needs.check.outputs.base == vars.STABLE_BRANCH
with:
pr_number: ${{ github.event.pull_request.number }}
+ user: 'github-actions[bot]'
package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }}
use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }}
indent: ${{ vars.INDENT }}
diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml
index c52883ffdd..68452aacaf 100644
--- a/.github/workflows/storybook.yml
+++ b/.github/workflows/storybook.yml
@@ -36,7 +36,7 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Use Node.js 20.x
- uses: actions/setup-node@v4.0.2
+ uses: actions/setup-node@v4.0.3
with:
node-version-file: '.node-version'
cache: 'pnpm'
@@ -88,7 +88,7 @@ jobs:
if [ "$BRANCH" = "misskey-dev:$HEAD_REF" ]; then
BRANCH="$HEAD_REF"
fi
- pnpm --filter frontend chromatic --exit-once-uploaded -d storybook-static --branch-name $BRANCH $(echo "$CHROMATIC_PARAMETER")
+ pnpm --filter frontend chromatic --exit-once-uploaded -d storybook-static --branch-name "$BRANCH" $(echo "$CHROMATIC_PARAMETER")
env:
HEAD_REF: ${{ github.event.pull_request.head.ref }}
CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
diff --git a/.github/workflows/test-backend.yml b/.github/workflows/test-backend.yml
index b1c54bb3e7..026550025c 100644
--- a/.github/workflows/test-backend.yml
+++ b/.github/workflows/test-backend.yml
@@ -9,19 +9,20 @@ on:
- packages/backend/**
# for permissions
- packages/misskey-js/**
+ - .github/workflows/test-backend.yml
pull_request:
paths:
- packages/backend/**
# for permissions
- packages/misskey-js/**
-
+ - .github/workflows/test-backend.yml
jobs:
unit:
runs-on: ubuntu-latest
strategy:
matrix:
- node-version: [20.12.2]
+ node-version: [20.16.0]
services:
postgres:
@@ -45,7 +46,7 @@ jobs:
- name: Install FFmpeg
uses: FedericoCarboni/setup-ffmpeg@v3
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v4.0.2
+ uses: actions/setup-node@v4.0.3
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
@@ -70,7 +71,7 @@ jobs:
strategy:
matrix:
- node-version: [20.12.2]
+ node-version: [20.16.0]
services:
postgres:
@@ -92,7 +93,7 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v4.0.2
+ uses: actions/setup-node@v4.0.3
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
diff --git a/.github/workflows/test-frontend.yml b/.github/workflows/test-frontend.yml
index 9d5053b82a..fcaef52969 100644
--- a/.github/workflows/test-frontend.yml
+++ b/.github/workflows/test-frontend.yml
@@ -11,7 +11,7 @@ on:
- packages/misskey-js/**
# for e2e
- packages/backend/**
-
+ - .github/workflows/test-frontend.yml
pull_request:
paths:
- packages/frontend/**
@@ -19,14 +19,14 @@ on:
- packages/misskey-js/**
# for e2e
- packages/backend/**
-
+ - .github/workflows/test-frontend.yml
jobs:
vitest:
runs-on: ubuntu-latest
strategy:
matrix:
- node-version: [20.12.2]
+ node-version: [20.16.0]
steps:
- uses: actions/checkout@v4.1.1
@@ -35,7 +35,7 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v4.0.2
+ uses: actions/setup-node@v4.0.3
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
@@ -61,7 +61,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- node-version: [20.12.2]
+ node-version: [20.16.0]
browser: [chrome]
services:
@@ -90,7 +90,7 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v4.0.2
+ uses: actions/setup-node@v4.0.3
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
diff --git a/.github/workflows/test-misskey-js.yml b/.github/workflows/test-misskey-js.yml
index 2589d908b8..9ad71919df 100644
--- a/.github/workflows/test-misskey-js.yml
+++ b/.github/workflows/test-misskey-js.yml
@@ -8,11 +8,12 @@ on:
branches: [ develop ]
paths:
- packages/misskey-js/**
+ - .github/workflows/test-misskey-js.yml
pull_request:
branches: [ develop ]
paths:
- packages/misskey-js/**
-
+ - .github/workflows/test-misskey-js.yml
jobs:
test:
@@ -20,7 +21,7 @@ jobs:
strategy:
matrix:
- node-version: [20.12.2]
+ node-version: [20.16.0]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
@@ -30,7 +31,7 @@ jobs:
- run: corepack enable
- name: Setup Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v4.0.2
+ uses: actions/setup-node@v4.0.3
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
diff --git a/.github/workflows/test-production.yml b/.github/workflows/test-production.yml
index 7f8db65293..8ad8a64766 100644
--- a/.github/workflows/test-production.yml
+++ b/.github/workflows/test-production.yml
@@ -16,7 +16,7 @@ jobs:
strategy:
matrix:
- node-version: [20.12.2]
+ node-version: [20.16.0]
steps:
- uses: actions/checkout@v4.1.1
@@ -25,7 +25,7 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v4.0.2
+ uses: actions/setup-node@v4.0.3
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
diff --git a/.github/workflows/validate-api-json.yml b/.github/workflows/validate-api-json.yml
index 24340e7d81..06e987f27e 100644
--- a/.github/workflows/validate-api-json.yml
+++ b/.github/workflows/validate-api-json.yml
@@ -7,17 +7,18 @@ on:
- develop
paths:
- packages/backend/**
+ - .github/workflows/validate-api-json.yml
pull_request:
paths:
- packages/backend/**
-
+ - .github/workflows/validate-api-json.yml
jobs:
validate-api-json:
runs-on: ubuntu-latest
strategy:
matrix:
- node-version: [20.12.2]
+ node-version: [20.16.0]
steps:
- uses: actions/checkout@v4.1.1
@@ -26,7 +27,7 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v4.0.2
+ uses: actions/setup-node@v4.0.3
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
diff --git a/.gitignore b/.gitignore
index bdc14fea0a..45170902b1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,8 +35,8 @@ coverage
!/.config/example.yml
!/.config/docker_example.yml
!/.config/docker_example.env
-docker-compose.yml
-!/.devcontainer/docker-compose.yml
+.devcontainer/compose.yml
+!/.devcontainer/compose.yml
# misskey
/build
@@ -59,6 +59,7 @@ ormconfig.json
temp
/packages/frontend/src/**/*.stories.ts
tsdoc-metadata.json
+misskey-assets
# blender backups
*.blend1
diff --git a/.gitmodules b/.gitmodules
index 225a69a652..3218575273 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,3 @@
-[submodule "misskey-assets"]
- path = misskey-assets
- url = https://github.com/misskey-dev/assets.git
[submodule "fluent-emojis"]
path = fluent-emojis
url = https://github.com/misskey-dev/emojis.git
diff --git a/.node-version b/.node-version
index 87834047a6..8ce7030825 100644
--- a/.node-version
+++ b/.node-version
@@ -1 +1 @@
-20.12.2
+20.16.0
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9f78ba677d..b996216ac1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,128 @@
+## 2024.7.0
+
+### Note
+- デッキUIã®æ–°ç€ãƒŽãƒ¼ãƒˆã‚’サウンドã§é€šçŸ¥ã™ã‚‹æ©Ÿèƒ½ã®è¿½åŠ ï¼ˆv2024.5.0)ã«ä¼´ã„ã€ä»¥å‰ã‹ã‚‰å‹•作ã—ãªããªã£ã¦ã„ãŸã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆè¨­å®šå†…ã®ã€Œã‚¢ãƒ³ãƒ†ãƒŠå—ä¿¡ã€ã€Œãƒãƒ£ãƒ³ãƒãƒ«é€šçŸ¥ã€ã‚µã‚¦ãƒ³ãƒ‰ã‚’削除ã—ã¾ã—ãŸã€‚
+- Streaming APIã«ã¦å…¥åŠ›ãŒä¸æ­£ãªå ´åˆã«ã¯ãã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’無視ã™ã‚‹ã‚ˆã†ã«ãªã‚Šã¾ã—ãŸã€‚ #14251
+
+### General
+- Feat: 通報をå—ã‘ãŸéš›ã€ã¾ãŸã¯è§£æ±ºã—ãŸéš›ã«ã€äºˆã‚登録ã—ãŸå®›å…ˆã«é€šçŸ¥ã‚’飛ã°ã›ã‚‹ã‚ˆã†ã«(mail or webhook) #13705
+- Feat: ユーザーã®ã‚¢ã‚¤ã‚³ãƒ³/ãƒãƒŠãƒ¼ã®å¤‰æ›´å¯å¦ã‚’ロールã§è¨­å®šå¯èƒ½ã«
+ - 変更ä¸å¯ã¨ãªã£ã¦ã„ã¦ã‚‚ã€è¨­å®šæ¸ˆã¿ã®ã‚‚ã®ã‚’解除ã—ã¦ãƒ‡ãƒ•ォルト画åƒã«æˆ»ã™ã“ã¨ã¯å‡ºæ¥ã¾ã™
+- Feat: ãƒ¦ãƒ¼ã‚¶ä½œæˆæ™‚ã«SystemWebhookã‚’é€ä¿¡å¯èƒ½ã« #14281
+- Feat: メディアサイレンスを実装 #13842
+ - メディアサイレンスã•れãŸã‚µãƒ¼ãƒãƒ¼ã«æ‰€å±žã™ã‚‹ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã«ã‚ˆã‚‹ãƒ•ァイルã¯ã™ã¹ã¦ã‚»ãƒ³ã‚·ãƒ†ã‚£ãƒ–ã¨ã—ã¦æ‰±ã‚れã€ã‚«ã‚¹ã‚¿ãƒ çµµæ–‡å­—ãŒä½¿ç”¨ã§ããªã„よã†ã«ãªã‚Šã¾ã™ã€‚
+- Enhance: 管ç†ç”»é¢ã§ã‚¢ãƒ¼ã‚«ã‚¤ãƒ–ã«ã—ãŸãŠçŸ¥ã‚‰ã›ã‚’表示・編集ã§ãるよã†ã«
+- Fix: é…ä¿¡åœæ­¢ã—ãŸã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ä¸€è¦§ãŒè¦‹ã‚Œãªããªã‚‹å•題を修正
+- Fix: Dockerコンテナã®ç«‹ã¡ä¸Šã’時ã«`pnpm`ã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã§å›ºã¾ã‚‹ã“ã¨ãŒã‚ã‚‹å•題
+- Fix: デフォルトテーマã«ç„¡åйãªãƒ†ãƒ¼ãƒžã‚³ãƒ¼ãƒ‰ã‚’入力ã™ã‚‹ã¨UIãŒä½¿ç”¨ã§ããªããªã‚‹å•題を修正
+- ç¿»è¨³ã®æ›´æ–°
+- ä¾å­˜é–¢ä¿‚ã®æ›´æ–°
+
+### Client
+- Feat: ユーザーページã‹ã‚‰ã€Œã“ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ãƒŽãƒ¼ãƒˆã‚’検索ã€ã§ãるよã†ã« (#14128)
+- Feat: 検索ページã¯ã‚¯ã‚¨ãƒªã‚’å—ã‘付ã‘るよã†ã«ãªã‚Šã¾ã—㟠(#14128)
+- Enhance: 検索ページã®UI改善 (#14128)
+- Enhance: 内蔵APIドキュメントã®ãƒ‡ã‚¶ã‚¤ãƒ³ãƒ»ãƒ‘フォーマンスを改善
+- Enhance: éžãƒ­ã‚°ã‚¤ãƒ³æ™‚ã«ä»–サーãƒãƒ¼ã«é·ç§»ã™ã‚‹ã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã‚’追加
+- Enhance: éžãƒ­ã‚°ã‚¤ãƒ³æ™‚ã®ãƒã‚¤ãƒ©ã‚¤ãƒˆTLã®ãƒ‡ã‚¶ã‚¤ãƒ³ã‚’改善
+- Enhance: フロントエンドã®ã‚¢ã‚¯ã‚»ã‚·ãƒ“リティ改善
+ (Based on https://github.com/taiyme/misskey/pull/226)
+- Enhance: サーãƒãƒ¼æƒ…報ページ・ãŠå•ã„åˆã‚ã›ãƒšãƒ¼ã‚¸ã‚’改善
+ (Cherry-picked from https://github.com/taiyme/misskey/pull/238)
+- Enhance: AiScriptã‚’0.19.0ã«ã‚¢ãƒƒãƒ—デート
+- Enhance: Allow negative delay for MFM animation elements (`tada`, `jelly`, `twitch`, `shake`, `spin`, `jump`, `bounce`, `rainbow`)
+- Enhance: センシティブãªãƒ¡ãƒ‡ã‚£ã‚¢ã‚’é–‹ãéš›ã«ç¢ºèªãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‚’出ã›ã‚‹ã‚ˆã†ã«
+- Enhance: 検索(ノート/ユーザー)ã§ `#` ã‹ã‚‰å§‹ã¾ã‚‹æ–‡å­—列を入力ã™ã‚‹ã¨ã€ãã®ãƒãƒƒã‚·ãƒ¥ã‚¿ã‚°ã®ãƒŽãƒ¼ãƒˆ/ユーザー一覧ページãŒè¡¨ç¤ºã§ãるよã†ã«
+- Enhance: 検索(ノート/ユーザー)ã«ãŠã„ã¦ã€å…¥åŠ›ã«ç©ºç™½ãŒå«ã¾ã‚Œã¦ã„ã‚‹å ´åˆã¯ç…§ä¼šã‚’行ã‚ãªã„よã†ã«
+- Enhance: 検索(ノート/ユーザー)ã«ãŠã„ã¦ã€ç…§ä¼šã‚’行ã†ã‹ã©ã†ã‹ã€ãƒãƒƒã‚·ãƒ¥ã‚¿ã‚°ã®ãƒŽãƒ¼ãƒˆ/ユーザー一覧ページを表示ã™ã‚‹ã‹ã©ã†ã‹ã®ç¢ºèªãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‚’出ã™ã‚ˆã†ã«
+- Enhance: 検索(ノート/ユーザー)ã§ `@` ã‹ã‚‰å§‹ã¾ã‚‹æ–‡å­—列(`@user@host`ãªã©)を入力ã™ã‚‹ã¨ã€ãã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚’照会ã§ãるよã†ã«
+- Enhance: ドライブã®ãƒ•ァイル・フォルダをドラッグã—ãªãã¦ã‚‚移動ã§ãるよã†ã«
+ (Cherry-picked from https://github.com/nafu-at/misskey/commit/b89c2af6945c6a9f9f10e83f54d2bcf0f240b0b4, https://github.com/nafu-at/misskey/commit/8a7d710c6acb83f50c83f050bd1423c764d60a99)
+- Enhance: デッキã®ã‚¢ãƒ³ãƒ†ãƒŠãƒ»ãƒªã‚¹ãƒˆé¸æŠžç”»é¢ã‹ã‚‰ãれãžã‚Œã‚’æ–°è¦ä½œæˆã§ãるよã†ã«
+- Enhance: ブラウザã®ã‚³ãƒ³ãƒ†ã‚­ã‚¹ãƒˆãƒ¡ãƒ‹ãƒ¥ãƒ¼ã‚’使用ã§ãるよã†ã«
+- Enhance: 連åˆã®ã€Œé€£åˆä¸­ã€,「購読中ã€,「é…信中ã€ã«å¯¾ã—ã¦ãƒ–ロックã—ã¦ã„るサーãƒãƒ¼ã€é…ä¿¡åœæ­¢ã—ã¦ã„るサーãƒãƒ¼ã‚’å«ã‚ãªã„よã†ã«
+- Fix: `/about#federation` ページãªã©ã§å„インスタンスã®ãƒãƒ£ãƒ¼ãƒˆãŒè¡¨ç¤ºã•れãªããªã£ã¦ã„ãŸå•題を修正
+- Fix: ユーザーページã®è¿½åŠ æƒ…å ±ã®ãƒ©ãƒ™ãƒ«ã‚’投稿者ã®ã‚µãƒ¼ãƒãƒ¼ã®çµµæ–‡å­—ã§è¡¨ç¤ºã™ã‚‹ (#13968)
+- Fix: リãƒãƒ¼ã‚·ã®å¯¾å±€ã‚’æ­£ã—ã共有ã§ããªã„ã“ã¨ãŒã‚ã‚‹å•題を修正
+- Fix: コントロールパãƒãƒ«ã§ãƒ™ãƒ¼ã‚¹ãƒ­ãƒ¼ãƒ«ã®ãƒãƒªã‚·ãƒ¼ã‚’編集ã—ã¦ã‚‚UI上ã§ã¯å¤‰æ›´ãŒå映ã•れãªã„å•題を修正
+- Fix: アンテナã®ç·¨é›†ç”»é¢ã®ãƒœã‚¿ãƒ³ã«éš™é–“を追加
+- Fix: テーマプレビューãŒè¦‹ã‚Œãªã„å•題を修正
+- Fix: ショートカットキーãŒé€£æ‰“ã§ãã‚‹å•題を修正
+ (Cherry-picked from https://github.com/taiyme/misskey/pull/234)
+- Fix: MkSignin.vueã®credentialRequestã‹ã‚‰Reactivityを削除(ProxyãŒPasskeyèªè¨¼å‡¦ç†ã«æ¸¡ã‚‹ã“ã¨ã‚’é¿ã‘ã‚‹ãŸã‚)
+- Fix: 「アニメーション画åƒã‚’å†ç”Ÿã—ãªã„ã€ãŒã‚ªãƒ³ã®ã¨ãã§ã‚‚サーãƒãƒ¼ã®ãƒãƒŠãƒ¼ç”»åƒãƒ»èƒŒæ™¯ç”»åƒãŒã‚¢ãƒ‹ãƒ¡ãƒ¼ã‚·ãƒ§ãƒ³ã—ã¦ã—ã¾ã†å•題を修正
+ (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/574)
+- Fix: Twitchã®åŸ‹ã‚è¾¼ã¿ãŒé–‹ã‘ãªã„å•題を修正
+- Fix: å­ãƒ¡ãƒ‹ãƒ¥ãƒ¼ã®é«˜ã•ãŒã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‹ã‚‰ã¯ã¿å‡ºã‚‹ã“ã¨ãŒã‚ã‚‹å•題を修正
+- Fix: 個人宛ã¦ã®ãƒ€ã‚¤ã‚¢ãƒ­ã‚°å½¢å¼ã®ãŠçŸ¥ã‚‰ã›ãŒå³æ™‚表示ã•れãªã„å•題を修正
+- Fix: 一部ã®ç”»åƒãŒã‚»ãƒ³ã‚·ãƒ†ã‚£ãƒ–指定ã•れã¦ã„ã‚‹ã¨ãã«ç”»é¢ã«ä½•も表示ã•れãªã„ã“ã¨ãŒã‚ã‚‹ã®ã‚’修正
+- Fix: リアクションã—ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ä¸€è¦§ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼åãŒã¯ã¿å‡ºã‚‹å•題を修正
+ (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/672)
+- Fix: `/share`ページã«ãŠã„ã¦çµµæ–‡å­—ピッカーを開ãã“ã¨ãŒã§ããªã„å•題を修正
+- Fix: deck uiã®é€šçŸ¥éŸ³ãŒé‡ãªã‚‹å•題 (#14029)
+- Fix: ダイレクト投稿ã®"削除ã—ã¦ç·¨é›†"ã«ãŠã„ã¦ã€å®›å…ˆãŒä¿æŒã•れã¦ã„ãªã‹ã£ãŸå•題を修正
+- Fix: 投稿フォームã¸ã®URL貼り付ã‘ã«ã‚ˆã‚‹å¼•用ãŒä¸‹æ›¸ãã«ä¿å­˜ã•れã¦ã„ãªã‹ã£ãŸå•題を修正
+- Fix: "削除ã—ã¦ç·¨é›†"や下書ãã«ãŠã„ã¦ã€ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã®å—ã‘入れ設定ãŒä¿æŒ/ä¿å­˜ã•れã¦ã„ãªã‹ã£ãŸå•題を修正
+- Fix: 照会㫠`#` ã‹ã‚‰å§‹ã¾ã‚‹æ–‡å­—列を入力ã—ã¦ãã®ãƒãƒƒã‚·ãƒ¥ã‚¿ã‚°ã®ãƒšãƒ¼ã‚¸ã‚’表示ã™ã‚‹éš›ã€å…¥åŠ›ãŒ `#` ã®ã¿ã®å ´åˆã«ã€ŒæŒ‡å®šã•れãŸURLã«è©²å½“ã™ã‚‹ãƒšãƒ¼ã‚¸ã¯ã‚りã¾ã›ã‚“ã§ã—ãŸã€‚ã€ãŒè¡¨ç¤ºã•れã¦ã—ã¾ã†å•題を修正
+- Fix: 照会㫠`@` ã‹ã‚‰å§‹ã¾ã‚‹æ–‡å­—列を入力ã—ã¦ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚’照会ã™ã‚‹éš›ã€å…¥åŠ›ãŒ `@` ã®ã¿ã®å ´åˆã«ã€Œå•題ãŒç™ºç”Ÿã—ã¾ã—ãŸã€ãŒè¡¨ç¤ºã•れã¦ã—ã¾ã†å•題を修正
+- Fix: 投稿フォームã«ãƒŽãƒ¼ãƒˆã®URLを貼り付ã‘ã¦"引用ã¨ã—ã¦æ·»ä»˜"ã—ãŸå ´åˆã€æŠ•稿文を空ã«ã™ã‚‹ã“ã¨ã«ã‚ˆã‚‹Renote化ãŒå‡ºæ¥ãªã‹ã£ãŸå•題を修正
+- Fix: フォロー中ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«é–¢ã™ã‚‹"TLã«ä»–ã®äººã¸ã®è¿”ä¿¡ã‚’å«ã‚ã‚‹"ã®è¨­å®šãŒåˆ†ã‹ã‚Šã¥ã‚‰ã„å•題を修正
+- Fix: タイムラインページを開ã„ãŸæ™‚ã€`TLã«ä»–ã®äººã¸ã®è¿”ä¿¡ã‚’å«ã‚ã‚‹`ãŒã‚ªãƒ•ã®ã¨ãã«`ファイル付ãã®ã¿`をオンã«ã§ããªã„å•題を修正
+- Fix: deck uiã§ã‚¿ã‚¤ãƒ ãƒ©ã‚¤ãƒ³ã‚’切り替ãˆãŸéš›ã«TLã®è¨­å®šé …ç›®ãŒæ›´æ–°ã•れãšã€`TLã«ä»–ã®äººã¸ã®è¿”ä¿¡ã‚’å«ã‚ã‚‹`ã®ãƒˆã‚°ãƒ«ãŒè¡¨ç¤ºã•れãªã„å•題を修正
+- Fix: ウィジェットã®ã‚¿ã‚¤ãƒ ãƒ©ã‚¤ãƒ³é¸æŠžæ¬„ã«ç„¡åŠ¹åŒ–ã•れãŸã‚¿ã‚¤ãƒ ãƒ©ã‚¤ãƒ³ãŒè¡¨ç¤ºã•れるå•題を修正
+- Fix: サウンドã«ãƒ‰ãƒ©ã‚¤ãƒ–ã®éŸ³å£°ã‚’使用ã—ã¦ã„ã‚‹éš›ã«ãƒ‰ãƒ©ã‚¤ãƒ–ã®éŸ³å£°ãŒå†ç”Ÿã§ããªããªã‚‹ã¨è¨­å®šãŒå¤‰æ›´ã§ããªããªã‚‹å•題を修正
+
+### Server
+- Feat: レートリミット制é™ã«å¼•ã£ã‹ã‹ã£ãŸã¨ãã«`Retry-After`ヘッダーを返ã™ã‚ˆã†ã« (#13949)
+- Enhance: エンドãƒã‚¤ãƒ³ãƒˆ`clips/update`ã®å¿…須項目を`clipId`ã®ã¿ã«
+- Enhance: エンドãƒã‚¤ãƒ³ãƒˆ`admin/roles/update`ã®å¿…須項目を`roleId`ã®ã¿ã«
+- Enhance: エンドãƒã‚¤ãƒ³ãƒˆ`pages/update`ã®å¿…須項目を`pageId`ã®ã¿ã«
+- Enhance: エンドãƒã‚¤ãƒ³ãƒˆ`gallery/posts/update`ã®å¿…須項目を`postId`ã®ã¿ã«
+- Enhance: エンドãƒã‚¤ãƒ³ãƒˆ`i/webhook/update`ã®å¿…須項目を`webhookId`ã®ã¿ã«
+- Enhance: エンドãƒã‚¤ãƒ³ãƒˆ`admin/ad/update`ã®å¿…須項目を`id`ã®ã¿ã«
+- Enhance: `default.yml`内ã®`url`, `db.db`, `db.user`, `db.pass`を環境変数ã‹ã‚‰èª­ã¿è¾¼ã‚るよã†ã«
+- Enhance: エンドãƒã‚¤ãƒ³ãƒˆ`api/meta`ã«ãƒ—ロパティ`noteSearchableScope`ãŒå¢—ãˆã€`string`値`local`ã¾ãŸã¯`global`ã‚’è¿”å´ã—ã¾ã™
+- Fix: ãƒãƒ£ãƒ¼ãƒˆç”Ÿæˆæ™‚ã«instance.suspensionStateã«ç½®ãæ›ãˆã‚‰ã‚ŒãŸinstance.isSuspendedãŒå‚ç…§ã•れã¦ã—ã¾ã†å•題を修正
+- Fix: ユーザーã®ãƒ•ィードページã®MFMã‚’HTMLã«å±•é–‹ã™ã‚‹ã‚ˆã†ã« (#14006)
+- Fix: アンテナ・クリップ・リスト・ウェブフックãŒãƒ­ãƒ¼ãƒ«ãƒãƒªã‚·ãƒ¼ã®ä¸Šé™ã‚ˆã‚Šä¸€ã¤å¤šã作れã¦ã—ã¾ã†ã®ã‚’修正 (#14036)
+- Fix: notRespondingSinceãŒå®Ÿè£…ã•れるå‰ã«ä¸é€šã«ãªã£ãŸã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒè‡ªå‹•çš„ã«é…ä¿¡åœæ­¢ã«ãªã‚‰ãªã„ (#14059)
+- Fix: FTT有効時ã€ã‚¿ã‚¤ãƒ ãƒ©ã‚¤ãƒ³ç”¨ã‚¨ãƒ³ãƒ‰ãƒã‚¤ãƒ³ãƒˆã§`sinceId`ã«ã‚­ãƒ£ãƒƒã‚·ãƒ¥å†…最å¤ã®ã‚‚ã®ã‚ˆã‚Šå¤ã„ã‚‚ã®ã‚’指定ã—ãŸå ´åˆã«æ­£ã—ãçµæžœãŒè¿”ã£ã¦ã“ãªã„å•題を修正
+- Fix: 自分以外ã®ã‚¯ãƒªãƒƒãƒ—内ã®ãƒŽãƒ¼ãƒˆå€‹æ•°ãŒè¦‹ãˆã‚‹ã“ã¨ãŒã‚ã‚‹ã®ã‚’修正
+- Fix: 空文字列ã®ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã¯ãƒ•ォールãƒãƒƒã‚¯ã•れるよã†ã«
+- Fix: リノートã«ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã§ããªã„よã†ã«
+- Fix: ユーザーåã®å‰å¾Œã«ç©ºç™½æ–‡å­—列ãŒã‚ã‚‹å ´åˆã¯çœç•¥ã™ã‚‹ã‚ˆã†ã«
+- Fix: プロフィール編集時ã«åå‰ã‚’空白文字列ã®ã¿ã«ã§ãã‚‹å•題を修正
+- Fix: ユーザåã®ã‚µã‚¸ã‚§ã‚¹ãƒˆæ™‚ã«è¡¨ç¤ºã•れる内容ã¨é †ç•ªã‚’調整(以下ã®é †ç•ªã«ãªã‚Šã¾ã™) #14149
+ 1. フォロー中ã‹ã¤ã‚¢ã‚¯ãƒ†ã‚£ãƒ–ãªãƒ¦ãƒ¼ã‚¶
+ 2. フォロー中ã‹ã¤éžã‚¢ã‚¯ãƒ†ã‚£ãƒ–ãªãƒ¦ãƒ¼ã‚¶
+ 3. フォローã—ã¦ã„ãªã„アクティブãªãƒ¦ãƒ¼ã‚¶
+ 4. フォローã—ã¦ã„ãªã„éžã‚¢ã‚¯ãƒ†ã‚£ãƒ–ãªãƒ¦ãƒ¼ã‚¶
+
+ ã¾ãŸã€è‡ªåˆ†è‡ªèº«ã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‚‚サジェストã•れるよã†ã«ãªã‚Šã¾ã—ãŸã€‚
+- Fix: 一般ユーザーã‹ã‚‰è¦‹ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ãƒãƒƒã‚¸ã®ä¸€è¦§ã«å…¬é–‹ã•れã¦ã„ãªã„ã‚‚ã®ãŒå«ã¾ã‚Œã‚‹ã“ã¨ãŒã‚ã‚‹å•題を修正
+ (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/652)
+- Fix: ユーザーã®ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ä¸€è¦§ã§ãƒŸãƒ¥ãƒ¼ãƒˆ/ãƒ–ãƒ­ãƒƒã‚¯ãŒæ©Ÿèƒ½ã—ã¦ã„ãªã‹ã£ãŸå•題を修正
+- Fix: FTT有効時ã«ãƒªãƒ¢ãƒ¼ãƒˆãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ãƒŽãƒ¼ãƒˆãŒHTLã«ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã•れるå•題を修正
+- Fix: 一部ã®é€šçŸ¥ãŒãƒ­ãƒ¼ã‚«ãƒ«ä¸Šã®ãƒªãƒ¢ãƒ¼ãƒˆãƒ¦ãƒ¼ã‚¶ãƒ¼ã«å¯¾ã—ã¦è¡Œã‚れã¦ã„ãŸå•題を修正
+- Fix: エラーメッセージã®èª¤å­—を修正 (#14213)
+- Fix: ソーシャルタイムラインã«ãƒ­ãƒ¼ã‚«ãƒ«ã‚¿ã‚¤ãƒ ãƒ©ã‚¤ãƒ³ã«è¡¨ç¤ºã•れる自分ã¸ã®ãƒªãƒ—ライãŒè¡¨ç¤ºã•れãªã„å•題を修正
+- Fix: リノートã®ãƒŸãƒ¥ãƒ¼ãƒˆãŒé©ç”¨ã•れるã¾ã§ã«æ™‚é–“ãŒã‹ã‹ã‚‹ã“ã¨ãŒã‚ã‚‹å•題を修正
+ (Cherry-picked from https://github.com/Type4ny-Project/Type4ny/commit/e9601029b52e0ad43d9131b555b614e56c84ebc1)
+- Fix: Steaming APIãŒä¸æ­£ãªãƒ‡ãƒ¼ã‚¿ã‚’å—ã‘ãŸå ´åˆã®å‹•作ãŒä¸å®‰å®šã§ã‚ã‚‹å•題 #14251
+- Fix: `users/search`ã«ãŠã„㦠`@` ã‹ã‚‰å§‹ã¾ã‚‹æ–‡å­—列ãŒä¸Žãˆã‚‰ã‚ŒãŸéš›ã®å‡¦ç†ãŒæ­£ã—ããªã‹ã£ãŸå•題を修正
+ - åå‰ã‚„自己紹介㫠`@` ã‹ã‚‰å§‹ã¾ã‚‹æ–‡è¨€ãŒå«ã¾ã‚Œã‚‹ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚‚検索ã§ãるよã†ã«ãªã‚Šã¾ã™
+- Fix: 一部ã®Misskey以外ã®ã‚½ãƒ•トウェアã‹ã‚‰ãƒ•ァイルをå—ã‘å–れãªã„å•題
+ (Cherry-picked from https://github.com/Secineralyr/misskey.dream/pull/73/commits/652eaff1e8aa00b890d71d2e1e52c263c1e67c76)
+ - NOTE: `drive_file`ã®`url`, `uri`, `src`ã®ä¸Šé™ãŒ512ã‹ã‚‰1024ã«å¤‰æ›´ã•れã¾ã™
+ Migrationã§ã¯ã‚«ãƒ©ãƒ å®šç¾©ã®å¤‰æ›´ã®ã¿ãŒè¡Œã‚れã¾ã™ã€‚
+ サーãƒãƒ¼ç®¡ç†è€…ã¯å„サーãƒãƒ¼ã®å¿…è¦ã«å¿œã˜`drive_file` `("uri")`ã«å¯¾ã™ã‚‹ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ã‚’張りãªãŠã™ã“ã¨ã§ã‚ˆã‚Šå®‰å®šã—DBã®æŽ¢ç´¢ãŒè¡Œã‚れるå¯èƒ½æ€§ãŒã‚りã¾ã™ã€‚詳細 㯠[GitHub](https://github.com/misskey-dev/misskey/pull/14323#issuecomment-2257562228)ã§ç¢ºèªå¯èƒ½ã§ã™
+- Fix: 自分ã®ãƒ•ォロワーé™å®šæŠ•稿ã«å¯¾ã™ã‚‹ãƒªãƒ—ライãŒãƒ›ãƒ¼ãƒ ã‚¿ã‚¤ãƒ ãƒ©ã‚¤ãƒ³ã§è¦‹ãˆãªã„ã“ã¨ãŒæœ‰ã‚‹å•題を修正
+- Fix: フォローã—ã¦ã„ãªã„ユーザã«ã‚ˆã‚‹ãƒ•ォロワーé™å®šæŠ•稿ã«å¯¾ã™ã‚‹ãƒªãƒ—ライãŒã‚½ãƒ¼ã‚·ãƒ£ãƒ«ã‚¿ã‚¤ãƒ ãƒ©ã‚¤ãƒ³ã§è¡¨ç¤ºã•れるã“ã¨ãŒã‚ã‚‹å•題を修正
+
+### Misskey.js
+- Feat: `/drive/files/create` ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã«å¯¾å¿œï¼ˆ`multipart/form-data`ã«å¯¾å¿œï¼‰
+- Feat: `/admin/role/create` ã®ãƒ­ãƒ¼ãƒ«ãƒãƒªã‚·ãƒ¼ã®åž‹ã‚’修正
+
## 2024.5.0
### Note
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index dcb625626d..72c84c2f18 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,7 +1,7 @@
# Contribution guide
We're glad you're interested in contributing Misskey! In this document you will find the information you need to contribute to the project.
-> **Note**
+> [!NOTE]
> This project uses Japanese as its major language, **but you do not need to translate and write the Issues/PRs in Japanese.**
> Also, you might receive comments on your Issue/PR in Japanese, but you do not need to reply to them in Japanese as well.\
> The accuracy of machine translation into Japanese is not high, so it will be easier for us to understand if you write it in the original language.
@@ -17,16 +17,31 @@ Before creating an issue, please check the following:
- Issues should only be used to feature requests, suggestions, and bug tracking.
- Please ask questions or troubleshooting in [GitHub Discussions](https://github.com/misskey-dev/misskey/discussions) or [Discord](https://discord.gg/Wp8gVStHW3).
-> **Warning**
+> [!WARNING]
> Do not close issues that are about to be resolved. It should remain open until a commit that actually resolves it is merged.
-## Before implementation
+### Recommended discussing before implementation
+We welcome your proposal.
+
When you want to add a feature or fix a bug, **first have the design and policy reviewed in an Issue** (if it is not there, please make one). Without this step, there is a high possibility that the PR will not be merged even if it is implemented.
At this point, you also need to clarify the goals of the PR you will create, and make sure that the other members of the team are aware of them.
PRs that do not have a clear set of do's and don'ts tend to be bloated and difficult to review.
-Also, when you start implementation, assign yourself to the Issue (if you cannot do it yourself, ask another member to assign you). By expressing your intention to work the Issue, you can prevent conflicts in the work.
+Also, when you start implementation, assign yourself to the Issue (if you cannot do it yourself, ask Committer to assign you).
+By expressing your intention to work on the Issue, you can prevent conflicts in the work.
+
+To the Committers: you should not assign someone on it before the Final Decision.
+
+### How issues are triaged
+
+The Committers may:
+* close an issue that is not reproducible on latest stable release,
+* merge an issue into another issue,
+* split an issue into multiple issues,
+* or re-open that has been closed for some reason which is not applicable anymore.
+
+@syuilo reserves the Final Decision rights including whether the project will implement feature and how to implement, these rights are not always exercised.
## Well-known branches
- **`master`** branch is tracking the latest release and used for production purposes.
@@ -37,14 +52,14 @@ Also, when you start implementation, assign yourself to the Issue (if you cannot
## Creating a PR
Thank you for your PR! Before creating a PR, please check the following:
- If possible, prefix the title with a keyword that identifies the type of this PR, as shown below.
- - `fix` / `refactor` / `feat` / `enhance` / `perf` / `chore` etc
- - Also, make sure that the granularity of this PR is appropriate. Please do not include more than one type of change or interest in a single PR.
+ - `fix` / `refactor` / `feat` / `enhance` / `perf` / `chore` etc
+ - Also, make sure that the granularity of this PR is appropriate. Please do not include more than one type of change or interest in a single PR.
- If there is an Issue which will be resolved by this PR, please include a reference to the Issue in the text.
- Please add the summary of the changes to [`CHANGELOG.md`](/CHANGELOG.md). However, this is not necessary for changes that do not affect the users, such as refactoring.
- Check if there are any documents that need to be created or updated due to this change.
- If you have added a feature or fixed a bug, please add a test case if possible.
- Please make sure that tests and Lint are passed in advance.
- - You can run it with `pnpm test` and `pnpm lint`. [See more info](#testing)
+ - You can run it with `pnpm test` and `pnpm lint`. [See more info](#testing)
- If this PR includes UI changes, please attach a screenshot in the text.
Thanks for your cooperation 🤗
@@ -54,8 +69,8 @@ Be willing to comment on the good points and not just the things you want fixed
### Review perspective
- Scope
- - Are the goals of the PR clear?
- - Is the granularity of the PR appropriate?
+ - Are the goals of the PR clear?
+ - Is the granularity of the PR appropriate?
- Security
- Does merging this PR create a vulnerability?
- Performance
@@ -77,7 +92,7 @@ An actual domain will be assigned so you can test the federation.
## Release
### Release Instructions
-1. Commit version changes in the `develop` branch ([package.json](https://github.com/misskey-dev/misskey/blob/develop/package.json))
+1. Commit version changes in the `develop` branch ([package.json](package.json))
2. Create a release PR.
- Into `master` from `develop` branch.
- The title must be in the format `Release: x.y.z`.
@@ -88,7 +103,7 @@ An actual domain will be assigned so you can test the federation.
- The target branch must be `master`
- The tag name must be the version
-> **Note**
+> [!NOTE]
> Why this instruction is necessary:
> - To perform final QA checks
> - To distribute responsibility
@@ -106,12 +121,42 @@ If your language is not listed in Crowdin, please open an issue.
![Crowdin](https://d322cqt584bo4o.cloudfront.net/misskey/localized.svg)
## Development
-During development, it is useful to use the
+### Setup
+Before developing, you have to set up environment. Misskey requires Redis, PostgreSQL, and FFmpeg.
+
+You would want to install Meilisearch to experiment related features. Technically, meilisearch is not strict requirement, but some features and tests require it.
+
+There are a few ways to proceed.
+
+#### Use system-wide software
+You could install them in system-wide (such as from package manager).
+
+#### Use `docker compose`
+You could obtain middleware container by typing `docker compose -f $PROJECT_ROOT/compose.local-db.yml up -d`.
+
+#### Use Devcontainer
+Devcontainer also has necessary setting. This method can be done by connecting from VSCode.
+
+Instead of running `pnpm` locally, you can use Dev Container to set up your development environment.
+To use Dev Container, open the project directory on VSCode with Dev Containers installed.
+**Note:** If you are using Windows, please clone the repository with WSL. Using Git for Windows will result in broken files due to the difference in how newlines are handled.
+
+It will run the following command automatically inside the container.
+``` bash
+git submodule update --init
+pnpm install --frozen-lockfile
+cp .devcontainer/devcontainer.yml .config/default.yml
+pnpm build
+pnpm migrate
+```
+
+After finishing the migration, you can proceed.
+### Start developing
+During development, it is useful to use the
```
pnpm dev
```
-
command.
- Server-side source files and automatically builds them if they are modified. Automatically start the server process(es).
@@ -135,26 +180,6 @@ MK_DEV_PREFER=backend pnpm dev
- To change the port of Vite, specify with `VITE_PORT` environment variable.
- HMR may not work in some environments such as Windows.
-### Dev Container
-Instead of running `pnpm` locally, you can use Dev Container to set up your development environment.
-To use Dev Container, open the project directory on VSCode with Dev Containers installed.
-**Note:** If you are using Windows, please clone the repository with WSL. Using Git for Windows will result in broken files due to the difference in how newlines are handled.
-
-It will run the following command automatically inside the container.
-``` bash
-git submodule update --init
-pnpm install --frozen-lockfile
-cp .devcontainer/devcontainer.yml .config/default.yml
-pnpm build
-pnpm migrate
-```
-
-After finishing the migration, run the `pnpm dev` command to start the development server.
-
-``` bash
-pnpm dev
-```
-
## Testing
- Test codes are located in [`/packages/backend/test`](/packages/backend/test).
@@ -165,7 +190,7 @@ cp .github/misskey/test.yml .config/
```
Prepare DB/Redis for testing.
```
-docker compose -f packages/backend/test/docker-compose.yml up
+docker compose -f packages/backend/test/compose.yml up
```
Alternatively, prepare an empty (data can be erased) DB and edit `.config/test.yml`.
@@ -204,7 +229,7 @@ niraxã¯ã€Misskeyã§ä½¿ç”¨ã—ã¦ã„るオリジナルã®ãƒ•ロントエンドãƒ
### ルート定義
ルート定義ã¯ã€ä»¥ä¸‹ã®å½¢å¼ã®ã‚ªãƒ–ジェクトã®é…列ã§ã™ã€‚
-``` ts
+```ts
{
name?: string;
path: string;
@@ -217,7 +242,7 @@ niraxã¯ã€Misskeyã§ä½¿ç”¨ã—ã¦ã„るオリジナルã®ãƒ•ロントエンドãƒ
}
```
-> **Warning**
+> [!WARNING]
> ç¾çжã€ãƒ«ãƒ¼ãƒˆã¯å®šç¾©ã•れãŸé †ã«è©•価ã•れã¾ã™ã€‚
> ãŸã¨ãˆã°ã€`/foo/:id`ãƒ«ãƒ¼ãƒˆå®šç¾©ã®æ¬¡ã«`/foo/bar`ルート定義ãŒã•れã¦ã„ãŸå ´åˆã€å¾Œè€…ãŒãƒžãƒƒãƒã™ã‚‹ã“ã¨ã¯ã‚りã¾ã›ã‚“。
@@ -279,7 +304,7 @@ export const Default = {
parameters: {
layout: 'centered',
},
-} satisfies StoryObj<typeof MkAvatar>;
+} satisfies StoryObj<typeof MyComponent>;
```
If you want to opt-out from the automatic generation, create a `MyComponent.stories.impl.ts` file and add the following line to the file.
@@ -390,7 +415,7 @@ describe('test', () => {
})
.useMocker(...
.compile();
-
+
fooService = app.get<FooService>(FooService);
barService = app.get<BarService>(BarService) as jest.Mocked<BarService>;
@@ -511,13 +536,13 @@ pnpm dlx typeorm migration:generate -d ormconfig.js -o <migration name>
- 作æˆã•れãŸã‚¹ã‚¯ãƒªãƒ—トã¯ä¸å¿…è¦ãªå¤‰æ›´ã‚’å«ã‚€ãŸã‚除去ã—ã¦ãã ã•ã„
### JSON Schemaã®objectã§anyOfを使ã†ã¨ã
-JSON Schemaã§ã€objectã«å¯¾ã—ã¦anyOfを使ã†å ´åˆã€anyOfã®ä¸­ã§propertiesを定義ã—ãªã„ã“ã¨ã€‚
-ãƒãƒªãƒ‡ãƒ¼ã‚·ãƒ§ãƒ³ãŒåйã‹ãªã„ãŸã‚。(SchemaTypeã‚‚ãã®ã‚ˆã†ã«ä½œã‚‰ã‚Œã¦ãŠã‚Šã€objectã®anyOf内ã®propertiesã¯æ¨ã¦ã‚‰ã‚Œã¾ã™ï¼‰
+JSON Schemaã§ã€objectã«å¯¾ã—ã¦anyOfを使ã†å ´åˆã€anyOfã®ä¸­ã§propertiesを定義ã—ãªã„ã“ã¨ã€‚
+ãƒãƒªãƒ‡ãƒ¼ã‚·ãƒ§ãƒ³ãŒåйã‹ãªã„ãŸã‚。(SchemaTypeã‚‚ãã®ã‚ˆã†ã«ä½œã‚‰ã‚Œã¦ãŠã‚Šã€objectã®anyOf内ã®propertiesã¯æ¨ã¦ã‚‰ã‚Œã¾ã™ï¼‰
https://github.com/misskey-dev/misskey/pull/10082
テキストhogeãŠã‚ˆã³fugaã«ã¤ã„ã¦ã€ç‰‡æ–¹ã‚’å¿…é ˆã¨ã—ã¤ã¤ä¸¡æ–¹ã®æŒ‡å®šã‚‚ã‚りã†ã‚‹å ´åˆ:
-```
+```ts
export const paramDef = {
type: 'object',
properties: {
diff --git a/Dockerfile b/Dockerfile
index 9fc2d611cd..e247bbcd77 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,6 +1,6 @@
# syntax = docker/dockerfile:1.4
-ARG NODE_VERSION=20.12.2-bullseye
+ARG NODE_VERSION=20.16.0-bullseye
# build assets & compile TypeScript
@@ -82,6 +82,10 @@ RUN apt-get update \
USER misskey
WORKDIR /misskey
+# add package.json to add pnpm
+COPY --chown=misskey:misskey ./package.json ./package.json
+RUN corepack install
+
COPY --chown=misskey:misskey --from=target-builder /misskey/node_modules ./node_modules
COPY --chown=misskey:misskey --from=target-builder /misskey/packages/backend/node_modules ./packages/backend/node_modules
COPY --chown=misskey:misskey --from=target-builder /misskey/packages/misskey-js/node_modules ./packages/misskey-js/node_modules
diff --git a/docker-compose.local-db.yml b/compose.local-db.yml
index 16ba4b49e1..3835cb23db 100644
--- a/docker-compose.local-db.yml
+++ b/compose.local-db.yml
@@ -1,5 +1,3 @@
-version: "3"
-
# ã“ã®configã¯ã€ dockerã§Misskey本体を起動ã›ãšã€ redisã¨postgresql ãªã©ã ã‘ã‚’èµ·å‹•ã—ã¾ã™
services:
diff --git a/docker-compose_example.yml b/compose_example.yml
index 5cebbe4164..336bd814a7 100644
--- a/docker-compose_example.yml
+++ b/compose_example.yml
@@ -1,5 +1,3 @@
-version: "3"
-
services:
web:
build: .
@@ -19,6 +17,8 @@ services:
networks:
- internal_network
- external_network
+ # env_file:
+ # - .config/docker.env
volumes:
- ./files:/misskey/files
- ./.config:/misskey/.config:ro
diff --git a/locales/ar-SA.yml b/locales/ar-SA.yml
index 955d672c1d..b6bfbfa682 100644
--- a/locales/ar-SA.yml
+++ b/locales/ar-SA.yml
@@ -1262,8 +1262,6 @@ _sfx:
note: "الملاحظات"
noteMy: "ملاحظتي"
notification: "الإشعارات"
- antenna: "الهوائيات"
- channel: "إشعارات القنات"
_ago:
future: "المستقبَل"
justNow: "اللحظة"
@@ -1566,6 +1564,10 @@ _webhookSettings:
active: "Ù…ÙÙØ¹Ù‘Ù„"
_events:
reaction: "عند Ø§Ù„ØªÙØ§Ø¹Ù„"
+_abuseReport:
+ _notificationRecipient:
+ _recipientType:
+ mail: "البريد الإلكتروني "
_moderationLogTypes:
suspend: "علÙÙ‚"
deleteDriveFile: "Ø­ÙØ°Ù الملÙ"
diff --git a/locales/bn-BD.yml b/locales/bn-BD.yml
index abcf07da83..6fb51ea5d8 100644
--- a/locales/bn-BD.yml
+++ b/locales/bn-BD.yml
@@ -1033,8 +1033,6 @@ _sfx:
note: "নোটগà§à¦²à¦¿"
noteMy: "নোট (আপনার)"
notification: "বিজà§à¦žà¦ªà§à¦¤à¦¿"
- antenna: "অà§à¦¯à¦¾à¦¨à§à¦Ÿà§‡à¦¨à¦¾à¦—à§à¦²à¦¿"
- channel: "চà§à¦¯à¦¾à¦¨à§‡à¦²à§‡à¦° বিজà§à¦žà¦ªà§à¦¤à¦¿"
_ago:
future: "ভবিষà§à¦¯à§Ž"
justNow: "à¦à¦‡à¦®à¦¾à¦¤à§à¦°"
@@ -1346,6 +1344,10 @@ _deck:
_webhookSettings:
name: "নাম"
active: "চালà§"
+_abuseReport:
+ _notificationRecipient:
+ _recipientType:
+ mail: "ইমেইল"
_moderationLogTypes:
suspend: "সà§à¦¥à¦—িত করা"
resetPassword: "পাসওয়ারà§à¦¡ রিসেট করà§à¦¨"
diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml
index 0345ee0326..7bd9a1bb32 100644
--- a/locales/ca-ES.yml
+++ b/locales/ca-ES.yml
@@ -1893,8 +1893,6 @@ _sfx:
note: "Notes"
noteMy: "Nota (per mi)"
notification: "Notificacions"
- antenna: "Antenes"
- channel: "Notificacions dels canals"
reaction: "Quan se selecciona una reacció "
_soundSettings:
driveFile: "Fer servir un fitxer d'àudio del disc"
@@ -2225,6 +2223,10 @@ _deck:
_webhookSettings:
name: "Nom"
active: "Activat"
+_abuseReport:
+ _notificationRecipient:
+ _recipientType:
+ mail: "Correu electrònic"
_moderationLogTypes:
suspend: "Suspèn"
resetPassword: "Restableix la contrasenya"
diff --git a/locales/cs-CZ.yml b/locales/cs-CZ.yml
index c8a0b0cb28..7db7424762 100644
--- a/locales/cs-CZ.yml
+++ b/locales/cs-CZ.yml
@@ -1645,8 +1645,6 @@ _sfx:
note: "Poznámky"
noteMy: "Moje poznámka"
notification: "Oznámení"
- antenna: "Antény"
- channel: "Oznámení kanálu"
_ago:
future: "Budoucí"
justNow: "TeÄ"
@@ -2012,7 +2010,6 @@ _webhookSettings:
createWebhook: "Vytvořit Webhook"
name: "Jméno"
secret: "Tajné"
- events: "Události Webhook"
active: "Zapnuto"
_events:
follow: "Při sledování uživatele"
@@ -2022,6 +2019,10 @@ _webhookSettings:
renote: "Při renotaci poznámky"
reaction: "Při obdržení reakce"
mention: "Při zmínce"
+_abuseReport:
+ _notificationRecipient:
+ _recipientType:
+ mail: "Email"
_moderationLogTypes:
suspend: "Zmrazit"
resetPassword: "Resetovat heslo"
diff --git a/locales/de-DE.yml b/locales/de-DE.yml
index 9e42e01252..8e44a3bbd4 100644
--- a/locales/de-DE.yml
+++ b/locales/de-DE.yml
@@ -1800,8 +1800,6 @@ _sfx:
note: "Notizen"
noteMy: "Meine Notizen"
notification: "Benachrichtigungen"
- antenna: "Antennen"
- channel: "Kanalbenachrichtigung"
_ago:
future: "Zukunft"
justNow: "Gerade eben"
@@ -2193,7 +2191,6 @@ _webhookSettings:
createWebhook: "Webhook erstellen"
name: "Name"
secret: "Secret"
- events: "Webhook-Ereignisse"
active: "Aktiviert"
_events:
follow: "Wenn du jemandem folgst"
@@ -2203,6 +2200,10 @@ _webhookSettings:
renote: "Wenn du ein Renote erhältst"
reaction: "Wenn du eine Reaktion erhältst"
mention: "Wenn du erwähnt wirst"
+_abuseReport:
+ _notificationRecipient:
+ _recipientType:
+ mail: "Email"
_moderationLogTypes:
createRole: "Rolle erstellt"
deleteRole: "Rolle gelöscht"
diff --git a/locales/el-GR.yml b/locales/el-GR.yml
index 2098c7ef50..5eca348e18 100644
--- a/locales/el-GR.yml
+++ b/locales/el-GR.yml
@@ -301,8 +301,6 @@ _theme:
_sfx:
note: "Σημειώματα"
notification: "Ειδοποιήσεις"
- antenna: "Αντένες"
- channel: "Ειδοποιήσεις καναλιών"
_ago:
future: "Μελλοντικό"
justNow: "Μόλις τώÏα"
diff --git a/locales/en-US.yml b/locales/en-US.yml
index c20a1ac7d8..2cb76fa746 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -60,6 +60,7 @@ copyFileId: "Copy file ID"
copyFolderId: "Copy folder ID"
copyProfileUrl: "Copy profile URL"
searchUser: "Search for a user"
+searchThisUsersNotes: "Search this user’s notes"
reply: "Reply"
loadMore: "Load more"
showMore: "Show more"
@@ -108,7 +109,7 @@ enterEmoji: "Enter an emoji"
renote: "Renote"
unrenote: "Remove renote"
renoted: "Renoted."
-renotedToX: "Renote from {name} users。"
+renotedToX: "Renote to {name}."
cantRenote: "This post can't be renoted."
cantReRenote: "A renote can't be renoted."
quote: "Quote"
@@ -125,8 +126,8 @@ add: "Add"
reaction: "Reactions"
reactions: "Reactions"
emojiPicker: "Emoji picker"
-pinnedEmojisForReactionSettingDescription: "Set the emojis which should be pinned and displayed immediately when reacting."
-pinnedEmojisSettingDescription: "Set the emojis to be pinned and displayed when viewing emoji picker"
+pinnedEmojisForReactionSettingDescription: "Set the emojis to be pinned and displayed when reacting."
+pinnedEmojisSettingDescription: "Set the emojis to be pinned and displayed when viewing emoji picker."
emojiPickerDisplay: "Emoji picker display"
overwriteFromPinnedEmojisForReaction: "Override from reaction settings"
overwriteFromPinnedEmojis: "Override from general settings"
@@ -154,6 +155,7 @@ editList: "Edit list"
selectChannel: "Select a channel"
selectAntenna: "Select an antenna"
editAntenna: "Edit antenna"
+createAntenna: "Create an antenna"
selectWidget: "Select a widget"
editWidgets: "Edit widgets"
editWidgetsExit: "Done"
@@ -165,7 +167,7 @@ emojiUrl: "Emoji URL"
addEmoji: "Add an emoji"
settingGuide: "Recommended settings"
cacheRemoteFiles: "Cache remote files"
-cacheRemoteFilesDescription: "When this setting is disabled, remote files are loaded directly from the remote instance. Disabling this will decrease storage usage, but increase traffic, as thumbnails will not be generated."
+cacheRemoteFilesDescription: "When this setting is disabled, remote files are loaded directly from the remote servers. Disabling this will decrease storage usage, but increase traffic, as thumbnails will not be generated."
youCanCleanRemoteFilesCache: "You can clear the cache by clicking the ðŸ—‘ï¸ button in the file management view."
cacheRemoteSensitiveFiles: "Cache sensitive remote files"
cacheRemoteSensitiveFilesDescription: "When this setting is disabled, sensitive remote files are loaded directly from the remote instance without caching."
@@ -180,6 +182,10 @@ addAccount: "Add account"
reloadAccountsList: "Reload account list"
loginFailed: "Failed to sign in"
showOnRemote: "View on remote instance"
+continueOnRemote: "リモートã§ç¶šè¡Œ"
+chooseServerOnMisskeyHub: "Choose a server from the Misskey Hub"
+specifyServerHost: "Specify a server host directly"
+inputHostName: "Enter the domain"
general: "General"
wallpaper: "Wallpaper"
setWallpaper: "Set wallpaper"
@@ -190,6 +196,7 @@ followConfirm: "Are you sure that you want to follow {name}?"
proxyAccount: "Proxy account"
proxyAccountDescription: "A proxy account is an account that acts as a remote follower for users under certain conditions. For example, when a user adds a remote user to the list, the remote user's activity will not be delivered to the instance if no local user is following that user, so the proxy account will follow instead."
host: "Host"
+selectSelf: "Select myself"
selectUser: "Select a user"
recipient: "Recipient"
annotation: "Comments"
@@ -205,6 +212,7 @@ perDay: "Per Day"
stopActivityDelivery: "Stop sending activities"
blockThisInstance: "Block this instance"
silenceThisInstance: "Silence this instance"
+mediaSilenceThisInstance: "Media-silence this server"
operations: "Operations"
software: "Software"
version: "Version"
@@ -225,7 +233,9 @@ clearCachedFilesConfirm: "Are you sure that you want to delete all cached remote
blockedInstances: "Blocked Instances"
blockedInstancesDescription: "List the hostnames of the instances you want to block separated by linebreaks. Listed instances will no longer be able to communicate with this instance."
silencedInstances: "Silenced instances"
-silencedInstancesDescription: "List the hostnames of the instances that you want to silence. All accounts of the listed instances will be treated as silenced, can only make follow requests, and cannot mention local accounts if not followed. This will not affect blocked instances."
+silencedInstancesDescription: "List the host names of the servers that you want to silence, separated by a new line. All accounts belonging to the listed servers will be treated as silenced, and can only make follow requests, and cannot mention local accounts if not followed. This will not affect the blocked servers."
+mediaSilencedInstances: "Media-silenced servers"
+mediaSilencedInstancesDescription: "List the host names of the servers that you want to media-silence, separated by a new line. All accounts belonging to the listed servers will be treated as sensitive, and can't use custom emojis. This will not affect the blocked servers."
muteAndBlock: "Mutes and Blocks"
mutedUsers: "Muted users"
blockedUsers: "Blocked users"
@@ -316,6 +326,7 @@ selectFile: "Select a file"
selectFiles: "Select files"
selectFolder: "Select a folder"
selectFolders: "Select folders"
+fileNotSelected: ""
renameFile: "Rename file"
folderName: "Folder name"
createFolder: "Create a folder"
@@ -387,7 +398,7 @@ mcaptcha: "mCaptcha"
enableMcaptcha: "Enable mCaptcha"
mcaptchaSiteKey: "Site key"
mcaptchaSecretKey: "Secret key"
-mcaptchaInstanceUrl: "mCaptcha instance URL"
+mcaptchaInstanceUrl: "mCaptcha server URL"
recaptcha: "reCAPTCHA"
enableRecaptcha: "Enable reCAPTCHA"
recaptchaSiteKey: "Site key"
@@ -476,6 +487,7 @@ noMessagesYet: "No messages yet"
newMessageExists: "There are new messages"
onlyOneFileCanBeAttached: "You can only attach one file to a message"
signinRequired: "Please register or sign in before continuing"
+signinOrContinueOnRemote: "To continue, you need to move your server or sign up / log in to this server."
invitations: "Invites"
invitationCode: "Invitation code"
checking: "Checking..."
@@ -836,6 +848,7 @@ administration: "Management"
accounts: "Accounts"
switch: "Switch"
noMaintainerInformationWarning: "Maintainer information is not configured."
+noInquiryUrlWarning: "Inquiry URL isn’t set"
noBotProtectionWarning: "Bot protection is not configured."
configure: "Configure"
postToGallery: "Create new gallery post"
@@ -1025,6 +1038,7 @@ thisPostMayBeAnnoyingHome: "Post to home timeline"
thisPostMayBeAnnoyingCancel: "Cancel"
thisPostMayBeAnnoyingIgnore: "Post anyway"
collapseRenotes: "Collapse renotes you've already seen"
+collapseRenotesDescription: "Collapse notes that you've reacted to or renoted before."
internalServerError: "Internal Server Error"
internalServerErrorDescription: "The server has run into an unexpected error."
copyErrorInfo: "Copy error details"
@@ -1098,6 +1112,8 @@ preservedUsernames: "Reserved usernames"
preservedUsernamesDescription: "List usernames to reserve separated by linebreaks. These will become unable during normal account creation, but can be used by administrators to manually create accounts. Already existing accounts using these usernames will not be affected."
createNoteFromTheFile: "Compose note from this file"
archive: "Archive"
+archived: "Archived"
+unarchive: "Unarchive"
channelArchiveConfirmTitle: "Really archive {name}?"
channelArchiveConfirmDescription: "An archived channel won't appear in the channel list or search results anymore. New posts can also not be added to it anymore."
thisChannelArchived: "This channel has been archived."
@@ -1108,6 +1124,9 @@ preventAiLearning: "Reject usage in Machine Learning (Generative AI)"
preventAiLearningDescription: "Requests crawlers to not use posted text or image material etc. in machine learning (Predictive / Generative AI) data sets. This is achieved by adding a \"noai\" HTML-Response flag to the respective content. A complete prevention can however not be achieved through this flag, as it may simply be ignored."
options: "Options"
specifyUser: "Specific user"
+lookupConfirm: "Do you want to look up?"
+openTagPageConfirm: "Do you want to open a hashtag page?"
+specifyHost: "Specify a host"
failedToPreviewUrl: "Could not preview"
update: "Update"
rolesThatCanBeUsedThisEmojiAsReaction: "Roles that can use this emoji as reaction"
@@ -1239,6 +1258,11 @@ keepOriginalFilenameDescription: "If you turn off this setting, files names will
noDescription: "There is not the explanation"
alwaysConfirmFollow: "Always confirm when following"
inquiry: "Contact"
+tryAgain: "Please try again later"
+confirmWhenRevealingSensitiveMedia: "Confirm when revealing sensitive media"
+sensitiveMediaRevealConfirm: "This might be a sensitive media. Are you sure to reveal?"
+createdLists: "Created lists"
+createdAntennas: "Created antennas"
_delivery:
status: "Delivery status"
stop: "Suspended"
@@ -1373,6 +1397,8 @@ _serverSettings:
fanoutTimelineDescription: "Greatly increases performance of timeline retrieval and reduces load on the database when enabled. In exchange, memory usage of Redis will increase. Consider disabling this in case of low server memory or server instability."
fanoutTimelineDbFallback: "Fallback to database"
fanoutTimelineDbFallbackDescription: "When enabled, the timeline will fall back to the database for additional queries if the timeline is not cached. Disabling it further reduces the server load by eliminating the fallback process, but limits the range of timelines that can be retrieved."
+ inquiryUrl: "Inquiry URL"
+ inquiryUrlDescription: "Specify a URL for the inquiry form to the server maintainer or a web page for the contact information."
_accountMigration:
moveFrom: "Migrate another account to this one"
moveFromSub: "Create alias to another account"
@@ -1689,6 +1715,7 @@ _role:
canManageAvatarDecorations: "Manage avatar decorations"
driveCapacity: "Drive capacity"
alwaysMarkNsfw: "Always mark files as NSFW"
+ canUpdateBioMedia: "Allow to edit an icon or a banner image"
pinMax: "Maximum number of pinned notes"
antennaMax: "Maximum number of antennas"
wordMuteMax: "Maximum number of characters allowed in word mutes"
@@ -1932,8 +1959,6 @@ _sfx:
note: "New note"
noteMy: "Own note"
notification: "Notifications"
- antenna: "Antennas"
- channel: "Channel notifications"
reaction: "On choosing a reaction"
_soundSettings:
driveFile: "Use an audio file in Drive."
@@ -1942,6 +1967,7 @@ _soundSettings:
driveFileTypeWarnDescription: "Select an audio file"
driveFileDurationWarn: "The audio is too long."
driveFileDurationWarnDescription: "Long audio may disrupt using Misskey. Still continue?"
+ driveFileError: "It couldn't load the sound. Please change the setting."
_ago:
future: "Future"
justNow: "Just now"
@@ -2059,7 +2085,7 @@ _permissions:
"read:admin:invite-codes": "View invite codes"
"write:admin:announcements": "Manage announcements"
"read:admin:announcements": "View announcements"
- "write:admin:avatar-decorations": "Manage avatar decorations"
+ "write:admin:avatar-decorations": "Can manage avatar decorations"
"read:admin:avatar-decorations": "View avatar decorations"
"write:admin:federation": "Manage federation data"
"write:admin:account": "Manage user account"
@@ -2358,6 +2384,7 @@ _deck:
alwaysShowMainColumn: "Always show main column"
columnAlign: "Align columns"
addColumn: "Add column"
+ newNoteNotificationSettings: "Notification setting for new notes"
configureColumn: "Column settings"
swapLeft: "Swap with the left column"
swapRight: "Swap with the right column"
@@ -2396,9 +2423,10 @@ _drivecleaner:
orderByCreatedAtAsc: "Ascending Dates"
_webhookSettings:
createWebhook: "Create Webhook"
+ modifyWebhook: "Modify Webhook"
name: "Name"
secret: "Secret"
- events: "Webhook Events"
+ trigger: "Trigger"
active: "Enabled"
_events:
follow: "When following a user"
@@ -2408,6 +2436,26 @@ _webhookSettings:
renote: "When renoted"
reaction: "When receiving a reaction"
mention: "When being mentioned"
+ _systemEvents:
+ abuseReport: "When received a new abuse report"
+ abuseReportResolved: "When resolved abuse reports"
+ userCreated: "When user is created"
+ deleteConfirm: "Are you sure you want to delete the Webhook?"
+_abuseReport:
+ _notificationRecipient:
+ createRecipient: "Add a recipient for abuse reports"
+ modifyRecipient: "Edit a recipient for abuse reports"
+ recipientType: "Notification type"
+ _recipientType:
+ mail: "Email"
+ webhook: "Webhook"
+ _captions:
+ mail: "Send the email to moderators' email addresses when you receive abuse."
+ webhook: "Send a notification to SystemWebhook when you receive or resolve abuse."
+ keywords: "Keywords"
+ notifiedUser: "Users to notify"
+ notifiedWebhook: "Webhook to use"
+ deleteConfirm: "Are you sure that you want to delete the notification recipient?"
_moderationLogTypes:
createRole: "Role created"
deleteRole: "Role deleted"
@@ -2445,6 +2493,12 @@ _moderationLogTypes:
deleteAvatarDecoration: "Avatar decoration deleted"
unsetUserAvatar: "Unset this user's avatar"
unsetUserBanner: "Unset this user's banner"
+ createSystemWebhook: "Create SystemWebhook"
+ updateSystemWebhook: "Update SystemWebHook"
+ deleteSystemWebhook: "Delete SystemWebhook"
+ createAbuseReportNotificationRecipient: "Create a recipient for abuse reports"
+ updateAbuseReportNotificationRecipient: "Update recipients for abuse reports"
+ deleteAbuseReportNotificationRecipient: "Delete a recipient for abuse reports"
_fileViewer:
title: "File details"
type: "File type"
@@ -2576,3 +2630,8 @@ _mediaControls:
pip: "Picture in Picture"
playbackRate: "Playback Speed"
loop: "Loop playback"
+_contextMenu:
+ title: "Context menu"
+ app: "Application"
+ appWithShift: "Application with shift key"
+ native: "Native"
diff --git a/locales/es-ES.yml b/locales/es-ES.yml
index 5c8249ded5..ef066a37ed 100644
--- a/locales/es-ES.yml
+++ b/locales/es-ES.yml
@@ -302,7 +302,7 @@ location: "Lugar"
theme: "Tema"
themeForLightMode: "Tema para usar en Modo Linterna"
themeForDarkMode: "Tema para usar en Modo Oscuro"
-light: "Linterna"
+light: "Claro"
dark: "Oscuro"
lightThemes: "Tema claro"
darkThemes: "Tema oscuro"
@@ -1920,8 +1920,6 @@ _sfx:
note: "Notas"
noteMy: "Nota (a mí mismo)"
notification: "Notificaciones"
- antenna: "Antena receptora"
- channel: "Notificaciones del canal"
reaction: "Al seleccionar una reacción"
_soundSettings:
driveFile: "Usar un archivo de audio en Drive"
@@ -2384,7 +2382,6 @@ _webhookSettings:
createWebhook: "Crear Webhook"
name: "Nombre"
secret: "Secreto"
- events: "Eventos de webhook"
active: "Activado"
_events:
follow: "Cuando se sigue a alguien"
@@ -2394,6 +2391,10 @@ _webhookSettings:
renote: "Cuando reciba un \"re-note\""
reaction: "Cuando se recibe una reacción"
mention: "Cuando hay una mención"
+_abuseReport:
+ _notificationRecipient:
+ _recipientType:
+ mail: "Correo"
_moderationLogTypes:
createRole: "Rol creado"
deleteRole: "Rol eliminado"
diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml
index 8d66c3d375..ee08dfddf1 100644
--- a/locales/fr-FR.yml
+++ b/locales/fr-FR.yml
@@ -1712,8 +1712,6 @@ _sfx:
note: "Nouvelle note"
noteMy: "Ma note"
notification: "Notifications"
- antenna: "Réception de l’antenne"
- channel: "Notifications de canal"
reaction: "Lors de la sélection de la réaction"
_soundSettings:
driveFile: "Utiliser un effet sonore sur le Disque"
@@ -2073,6 +2071,10 @@ _drivecleaner:
_webhookSettings:
name: "Nom"
active: "Activé"
+_abuseReport:
+ _notificationRecipient:
+ _recipientType:
+ mail: "E-mail "
_moderationLogTypes:
createRole: "Rôle créé"
deleteRole: "Rôle supprimé"
diff --git a/locales/id-ID.yml b/locales/id-ID.yml
index 7f509afa50..24f7482fca 100644
--- a/locales/id-ID.yml
+++ b/locales/id-ID.yml
@@ -180,6 +180,10 @@ addAccount: "Tambahkan akun"
reloadAccountsList: "Muat ulang daftar akun"
loginFailed: "Gagal untuk masuk"
showOnRemote: "Lihat profil asli"
+continueOnRemote: "Lihat di peladen asal"
+chooseServerOnMisskeyHub: "Pilih peladen dari Misskey Hub"
+specifyServerHost: "Tentukan domain peladen"
+inputHostName: "Masukkan nama domain"
general: "Umum"
wallpaper: "Wallpaper"
setWallpaper: "Atur wallpaper"
@@ -316,6 +320,7 @@ selectFile: "Pilih berkas"
selectFiles: "Pilih berkas"
selectFolder: "Pilih folder"
selectFolders: "Pilih folder"
+fileNotSelected: "Tidak ada file yang dipilih"
renameFile: "Ubah nama berkas"
folderName: "Nama folder"
createFolder: "Buat folder"
@@ -1239,6 +1244,7 @@ keepOriginalFilenameDescription: "Apabila pengaturan ini dimatikan, nama berkas
noDescription: "Tidak ada deskripsi"
alwaysConfirmFollow: "Selalu konfirmasi ketika mengikuti"
inquiry: "Hubungi kami"
+tryAgain: "Silahkan coba lagi."
_delivery:
status: "Status pengiriman"
stop: "Ditangguhkan"
@@ -1739,7 +1745,7 @@ _emailUnavailable:
smtp: "Peladen alamat surel ini tidak merespon"
banned: "Kamu tidak dapat mendaftar dengan alamat surel ini"
_ffVisibility:
- public: "Terbitkan"
+ public: "Publik"
followers: "Tampil untuk pengikut saja"
private: "Tersembunyi"
_signup:
@@ -1932,8 +1938,6 @@ _sfx:
note: "Catatan"
noteMy: "Catatan (Saya)"
notification: "Notifikasi"
- antenna: "Penerimaan Antenna"
- channel: "Notifikasi Kanal"
reaction: "Ketika memilih reaksi"
_soundSettings:
driveFile: "Menggunakan berkas audio dalam Drive"
@@ -2396,9 +2400,9 @@ _drivecleaner:
orderByCreatedAtAsc: "Tanggal (Naik)"
_webhookSettings:
createWebhook: "Buat Webhook"
+ modifyWebhook: "Sunting Webhook"
name: "Nama"
secret: "Secret"
- events: "Webhook Events"
active: "Aktif"
_events:
follow: "Ketika mengikuti pengguna"
@@ -2408,6 +2412,11 @@ _webhookSettings:
renote: "Ketika direnote"
reaction: "Ketika menerima reaksi"
mention: "Ketika sedang disebut"
+ deleteConfirm: "Apakah kamu yakin ingin menghapus Webhook?"
+_abuseReport:
+ _notificationRecipient:
+ _recipientType:
+ mail: "Surel"
_moderationLogTypes:
createRole: "Peran telah dibuat"
deleteRole: "Peran telah dihapus"
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 0b1b86d373..91d36a14a6 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -257,6 +257,10 @@ export interface Locale extends ILocale {
*/
"searchUser": string;
/**
+ * ユーザーã®ãƒŽãƒ¼ãƒˆã‚’検索
+ */
+ "searchThisUsersNotes": string;
+ /**
* 返信
*/
"reply": string;
@@ -633,6 +637,10 @@ export interface Locale extends ILocale {
*/
"editAntenna": string;
/**
+ * アンテナを作æˆ
+ */
+ "createAntenna": string;
+ /**
* ã‚¦ã‚£ã‚¸ã‚§ãƒƒãƒˆã‚’é¸æŠž
*/
"selectWidget": string;
@@ -737,6 +745,22 @@ export interface Locale extends ILocale {
*/
"showOnRemote": string;
/**
+ * リモートã§ç¶šè¡Œ
+ */
+ "continueOnRemote": string;
+ /**
+ * Misskey Hubã‹ã‚‰ã‚µãƒ¼ãƒãƒ¼ã‚’é¸æŠž
+ */
+ "chooseServerOnMisskeyHub": string;
+ /**
+ * サーãƒãƒ¼ã®ãƒ‰ãƒ¡ã‚¤ãƒ³ã‚’直接指定
+ */
+ "specifyServerHost": string;
+ /**
+ * ドメインを入力ã—ã¦ãã ã•ã„
+ */
+ "inputHostName": string;
+ /**
* 全般
*/
"general": string;
@@ -777,6 +801,10 @@ export interface Locale extends ILocale {
*/
"host": string;
/**
+ * è‡ªåˆ†ã‚’é¸æŠž
+ */
+ "selectSelf": string;
+ /**
* ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚’é¸æŠž
*/
"selectUser": string;
@@ -837,6 +865,10 @@ export interface Locale extends ILocale {
*/
"silenceThisInstance": string;
/**
+ * サーãƒãƒ¼ã‚’メディアサイレンス
+ */
+ "mediaSilenceThisInstance": string;
+ /**
* æ“作
*/
"operations": string;
@@ -921,6 +953,14 @@ export interface Locale extends ILocale {
*/
"silencedInstancesDescription": string;
/**
+ * メディアサイレンスã—ãŸã‚µãƒ¼ãƒãƒ¼
+ */
+ "mediaSilencedInstances": string;
+ /**
+ * メディアサイレンスã—ãŸã„サーãƒãƒ¼ã®ãƒ›ã‚¹ãƒˆã‚’改行ã§åŒºåˆ‡ã£ã¦è¨­å®šã—ã¾ã™ã€‚メディアサイレンスã•れãŸã‚µãƒ¼ãƒãƒ¼ã«æ‰€å±žã™ã‚‹ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã«ã‚ˆã‚‹ãƒ•ァイルã¯ã™ã¹ã¦ã‚»ãƒ³ã‚·ãƒ†ã‚£ãƒ–ã¨ã—ã¦æ‰±ã‚れã€ã‚«ã‚¹ã‚¿ãƒ çµµæ–‡å­—ãŒä½¿ç”¨ã§ããªã„よã†ã«ãªã‚Šã¾ã™ã€‚ブロックã—ãŸã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã«ã¯å½±éŸ¿ã—ã¾ã›ã‚“。
+ */
+ "mediaSilencedInstancesDescription": string;
+ /**
* ミュートã¨ãƒ–ロック
*/
"muteAndBlock": string;
@@ -1921,10 +1961,14 @@ export interface Locale extends ILocale {
*/
"onlyOneFileCanBeAttached": string;
/**
- * 続行ã™ã‚‹å‰ã«ã€ã‚µã‚¤ãƒ³ã‚¢ãƒƒãƒ—ã¾ãŸã¯ã‚µã‚¤ãƒ³ã‚¤ãƒ³ãŒå¿…è¦ã§ã™
+ * 続行ã™ã‚‹å‰ã«ã€ç™»éŒ²ã¾ãŸã¯ãƒ­ã‚°ã‚¤ãƒ³ãŒå¿…è¦ã§ã™
*/
"signinRequired": string;
/**
+ * 続行ã™ã‚‹ã«ã¯ã€ãŠä½¿ã„ã®ã‚µãƒ¼ãƒãƒ¼ã«ç§»å‹•ã™ã‚‹ã‹ã€ã“ã®ã‚µãƒ¼ãƒãƒ¼ã«ç™»éŒ²ãƒ»ãƒ­ã‚°ã‚¤ãƒ³ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™
+ */
+ "signinOrContinueOnRemote": string;
+ /**
* 招待
*/
"invitations": string;
@@ -4421,6 +4465,14 @@ export interface Locale extends ILocale {
*/
"archive": string;
/**
+ * アーカイブ済ã¿
+ */
+ "archived": string;
+ /**
+ * アーカイブ解除
+ */
+ "unarchive": string;
+ /**
* {name}をアーカイブã—ã¾ã™ã‹ï¼Ÿ
*/
"channelArchiveConfirmTitle": ParameterizedString<"name">;
@@ -4461,6 +4513,18 @@ export interface Locale extends ILocale {
*/
"specifyUser": string;
/**
+ * 照会ã—ã¾ã™ã‹ï¼Ÿ
+ */
+ "lookupConfirm": string;
+ /**
+ * ãƒãƒƒã‚·ãƒ¥ã‚¿ã‚°ã®ãƒšãƒ¼ã‚¸ã‚’é–‹ãã¾ã™ã‹ï¼Ÿ
+ */
+ "openTagPageConfirm": string;
+ /**
+ * ホスト指定
+ */
+ "specifyHost": string;
+ /**
* プレビューã§ãã¾ã›ã‚“
*/
"failedToPreviewUrl": string;
@@ -4984,6 +5048,26 @@ export interface Locale extends ILocale {
* ãŠå•ã„åˆã‚ã›
*/
"inquiry": string;
+ /**
+ * ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„。
+ */
+ "tryAgain": string;
+ /**
+ * センシティブãªãƒ¡ãƒ‡ã‚£ã‚¢ã‚’表示ã™ã‚‹ã¨ã確èªã™ã‚‹
+ */
+ "confirmWhenRevealingSensitiveMedia": string;
+ /**
+ * センシティブãªãƒ¡ãƒ‡ã‚£ã‚¢ã§ã™ã€‚表示ã—ã¾ã™ã‹ï¼Ÿ
+ */
+ "sensitiveMediaRevealConfirm": string;
+ /**
+ * 作æˆã—ãŸãƒªã‚¹ãƒˆ
+ */
+ "createdLists": string;
+ /**
+ * 作æˆã—ãŸã‚¢ãƒ³ãƒ†ãƒŠ
+ */
+ "createdAntennas": string;
"_delivery": {
/**
* é…信状態
@@ -6595,6 +6679,10 @@ export interface Locale extends ILocale {
*/
"alwaysMarkNsfw": string;
/**
+ * アイコンã¨ãƒãƒŠãƒ¼ã®æ›´æ–°ã‚’許å¯
+ */
+ "canUpdateBioMedia": string;
+ /**
* ノートã®ãƒ”ン留ã‚ã®æœ€å¤§æ•°
*/
"pinMax": string;
@@ -7516,14 +7604,6 @@ export interface Locale extends ILocale {
*/
"notification": string;
/**
- * アンテナå—ä¿¡
- */
- "antenna": string;
- /**
- * ãƒãƒ£ãƒ³ãƒãƒ«é€šçŸ¥
- */
- "channel": string;
- /**
* ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³é¸æŠžæ™‚
*/
"reaction": string;
@@ -7553,6 +7633,10 @@ export interface Locale extends ILocale {
* é•·ã„音声を使用ã™ã‚‹ã¨Misskeyã®ä½¿ç”¨ã«æ”¯éšœã‚’ããŸã™å¯èƒ½æ€§ãŒã‚りã¾ã™ã€‚ãれã§ã‚‚続行ã—ã¾ã™ã‹ï¼Ÿ
*/
"driveFileDurationWarnDescription": string;
+ /**
+ * 音声ãŒèª­ã¿è¾¼ã‚ã¾ã›ã‚“ã§ã—ãŸã€‚設定を変更ã—ã¦ãã ã•ã„
+ */
+ "driveFileError": string;
};
"_ago": {
/**
@@ -9306,6 +9390,10 @@ export interface Locale extends ILocale {
*/
"createWebhook": string;
/**
+ * Webhookを編集
+ */
+ "modifyWebhook": string;
+ /**
* åå‰
*/
"name": string;
@@ -9314,9 +9402,9 @@ export interface Locale extends ILocale {
*/
"secret": string;
/**
- * Webhookを実行ã™ã‚‹ã‚¿ã‚¤ãƒŸãƒ³ã‚°
+ * トリガー
*/
- "events": string;
+ "trigger": string;
/**
* 有効
*/
@@ -9351,6 +9439,76 @@ export interface Locale extends ILocale {
*/
"mention": string;
};
+ "_systemEvents": {
+ /**
+ * ユーザーã‹ã‚‰é€šå ±ãŒã‚ã£ãŸã¨ã
+ */
+ "abuseReport": string;
+ /**
+ * ユーザーã‹ã‚‰ã®é€šå ±ã‚’処ç†ã—ãŸã¨ã
+ */
+ "abuseReportResolved": string;
+ /**
+ * ユーザーãŒä½œæˆã•れãŸã¨ã
+ */
+ "userCreated": string;
+ };
+ /**
+ * Webhookを削除ã—ã¾ã™ã‹ï¼Ÿ
+ */
+ "deleteConfirm": string;
+ };
+ "_abuseReport": {
+ "_notificationRecipient": {
+ /**
+ * 通報ã®é€šçŸ¥å…ˆã‚’追加
+ */
+ "createRecipient": string;
+ /**
+ * 通報ã®é€šçŸ¥å…ˆã‚’編集
+ */
+ "modifyRecipient": string;
+ /**
+ * 通知先ã®ç¨®é¡ž
+ */
+ "recipientType": string;
+ "_recipientType": {
+ /**
+ * メール
+ */
+ "mail": string;
+ /**
+ * Webhook
+ */
+ "webhook": string;
+ "_captions": {
+ /**
+ * モデレーター権é™ã‚’æŒã¤ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã«é€šçŸ¥ã‚’é€ã‚Šã¾ã™(通報をå—ã‘ãŸæ™‚ã®ã¿)
+ */
+ "mail": string;
+ /**
+ * 指定ã—ãŸSystemWebhookã«é€šçŸ¥ã‚’é€ã‚Šã¾ã™(通報をå—ã‘ãŸæ™‚ã¨é€šå ±ã‚’解決ã—ãŸæ™‚ã«ãれãžã‚Œç™ºä¿¡)
+ */
+ "webhook": string;
+ };
+ };
+ /**
+ * キーワード
+ */
+ "keywords": string;
+ /**
+ * 通知先ユーザー
+ */
+ "notifiedUser": string;
+ /**
+ * 使用ã™ã‚‹Webhook
+ */
+ "notifiedWebhook": string;
+ /**
+ * 通知先を削除ã—ã¾ã™ã‹ï¼Ÿ
+ */
+ "deleteConfirm": string;
+ };
};
"_moderationLogTypes": {
/**
@@ -9497,6 +9655,30 @@ export interface Locale extends ILocale {
* ユーザーã®ãƒãƒŠãƒ¼ã‚’解除
*/
"unsetUserBanner": string;
+ /**
+ * SystemWebhookを作æˆ
+ */
+ "createSystemWebhook": string;
+ /**
+ * SystemWebhookã‚’æ›´æ–°
+ */
+ "updateSystemWebhook": string;
+ /**
+ * SystemWebhookを削除
+ */
+ "deleteSystemWebhook": string;
+ /**
+ * 通報ã®é€šçŸ¥å…ˆã‚’作æˆ
+ */
+ "createAbuseReportNotificationRecipient": string;
+ /**
+ * 通報ã®é€šçŸ¥å…ˆã‚’æ›´æ–°
+ */
+ "updateAbuseReportNotificationRecipient": string;
+ /**
+ * 通報ã®é€šçŸ¥å…ˆã‚’削除
+ */
+ "deleteAbuseReportNotificationRecipient": string;
};
"_fileViewer": {
/**
@@ -9667,7 +9849,7 @@ export interface Locale extends ILocale {
"_dataSaver": {
"_media": {
/**
- * メディアã®èª­ã¿è¾¼ã¿
+ * メディアã®èª­ã¿è¾¼ã¿ã‚’無効化
*/
"title": string;
/**
@@ -9677,7 +9859,7 @@ export interface Locale extends ILocale {
};
"_avatar": {
/**
- * アイコン画åƒ
+ * アイコン画åƒã®ã‚¢ãƒ‹ãƒ¡ãƒ¼ã‚·ãƒ§ãƒ³ã‚’無効化
*/
"title": string;
/**
@@ -9687,7 +9869,7 @@ export interface Locale extends ILocale {
};
"_urlPreview": {
/**
- * URLプレビューã®ã‚µãƒ ãƒã‚¤ãƒ«
+ * URLプレビューã®ã‚µãƒ ãƒã‚¤ãƒ«ã‚’éžè¡¨ç¤º
*/
"title": string;
/**
@@ -9697,7 +9879,7 @@ export interface Locale extends ILocale {
};
"_code": {
/**
- * コードãƒã‚¤ãƒ©ã‚¤ãƒˆ
+ * コードãƒã‚¤ãƒ©ã‚¤ãƒˆã‚’éžè¡¨ç¤º
*/
"title": string;
/**
@@ -9972,6 +10154,24 @@ export interface Locale extends ILocale {
*/
"loop": string;
};
+ "_contextMenu": {
+ /**
+ * コンテキストメニュー
+ */
+ "title": string;
+ /**
+ * アプリケーション
+ */
+ "app": string;
+ /**
+ * Shiftキーã§ã‚¢ãƒ—リケーション
+ */
+ "appWithShift": string;
+ /**
+ * ブラウザã®UI
+ */
+ "native": string;
+ };
}
declare const locales: {
[lang: string]: Locale;
diff --git a/locales/index.js b/locales/index.js
index 650e552337..c2738884eb 100644
--- a/locales/index.js
+++ b/locales/index.js
@@ -52,7 +52,11 @@ const primaries = {
const clean = (text) => text.replace(new RegExp(String.fromCodePoint(0x08), 'g'), '');
export function build() {
- const locales = languages.reduce((a, c) => (a[c] = yaml.load(clean(fs.readFileSync(new URL(`${c}.yml`, import.meta.url), 'utf-8'))) || {}, a), {});
+ // vitestã®æŒ™å‹•を調整ã™ã‚‹ãŸã‚ã€ä¸€åº¦ãƒ­ãƒ¼ã‚«ãƒ«å¤‰æ•°åŒ–ã™ã‚‹å¿…è¦ãŒã‚ã‚‹
+ // https://github.com/vitest-dev/vitest/issues/3988#issuecomment-1686599577
+ // https://github.com/misskey-dev/misskey/pull/14057#issuecomment-2192833785
+ const metaUrl = import.meta.url;
+ const locales = languages.reduce((a, c) => (a[c] = yaml.load(clean(fs.readFileSync(new URL(`${c}.yml`, metaUrl), 'utf-8'))) || {}, a), {});
// 空文字列ãŒå…¥ã‚‹ã“ã¨ãŒã‚りã€ãƒ•ォールãƒãƒƒã‚¯ãŒå‹•作ã—ãªããªã‚‹ã®ã§ãƒ—ロパティã”ã¨æ¶ˆã™
const removeEmpty = (obj) => {
diff --git a/locales/it-IT.yml b/locales/it-IT.yml
index 1d12a62cca..2b4b1e425e 100644
--- a/locales/it-IT.yml
+++ b/locales/it-IT.yml
@@ -108,11 +108,14 @@ enterEmoji: "Inserisci emoji"
renote: "Rinota"
unrenote: "Elimina la Rinota"
renoted: "Rinotata!"
+renotedToX: "Rinota da {name}."
cantRenote: "È impossibile rinotare questa nota."
cantReRenote: "È impossibile rinotare una Rinota."
quote: "Citazione"
inChannelRenote: "Rinota nel canale"
inChannelQuote: "Cita nel canale"
+renoteToChannel: "Rinota al canale"
+renoteToOtherChannel: "Rinota a un altro canale"
pinnedNote: "Nota in primo piano"
pinned: "Fissa sul profilo"
you: "Tu"
@@ -177,6 +180,10 @@ addAccount: "Aggiungi profilo"
reloadAccountsList: "Ricarica l'elenco dei profili"
loginFailed: "Accesso non riuscito"
showOnRemote: "Leggi sull'istanza remota"
+continueOnRemote: "Continua da remoto"
+chooseServerOnMisskeyHub: "Scegli l'istanza sul sito Misskey Hub"
+specifyServerHost: "Indica l'indirizzo dell'istanza"
+inputHostName: "Digita il nome del dominio "
general: "Generali"
wallpaper: "Sfondo"
setWallpaper: "Imposta sfondo"
@@ -313,6 +320,7 @@ selectFile: "Scelta allegato"
selectFiles: "Scelta allegato"
selectFolder: "Seleziona cartella"
selectFolders: "Seleziona cartella"
+fileNotSelected: "Nessun file selezionato"
renameFile: "Rinomina file"
folderName: "Nome della cartella"
createFolder: "Nuova cartella"
@@ -468,10 +476,12 @@ retype: "Conferma"
noteOf: "Note di {user}"
quoteAttached: "Citazione allegata"
quoteQuestion: "Vuoi aggiungere una citazione?"
+attachAsFileQuestion: "Il testo copiato eccede le dimensioni, vuoi allegarlo?"
noMessagesYet: "Ancora nessuna chat"
newMessageExists: "Hai ricevuto un nuovo messaggio"
onlyOneFileCanBeAttached: "È possibile allegare al messaggio soltanto uno file"
signinRequired: "Occorre avere un profilo registrato su questa istanza"
+signinOrContinueOnRemote: "Per continuare, devi accedere alla tua istanza o registrarti su questa e poi accedere"
invitations: "Invita"
invitationCode: "Codice di invito"
checking: "Confermando"
@@ -695,7 +705,7 @@ reporterOrigin: "Segnalazione da"
forwardReport: "Inoltro di un report a un'istanza remota."
forwardReportIsAnonymous: "L'istanza remota non vedrà le tue informazioni, apparirai come profilo di sistema, anonimo."
send: "Inviare"
-abuseMarkAsResolved: "Contrassegna la segnalazione come risolta"
+abuseMarkAsResolved: "Risolvi segnalazione"
openInNewTab: "Apri in una nuova scheda"
openInSideView: "Apri in vista laterale"
defaultNavigationBehaviour: "Navigazione preimpostata"
@@ -832,6 +842,7 @@ administration: "Gestione"
accounts: "Profilo"
switch: "Cambia"
noMaintainerInformationWarning: "Mancano le informazioni sull'amministratore."
+noInquiryUrlWarning: "Non è stata impostata la URL di contatto"
noBotProtectionWarning: "Non è stata impostata alcuna protezione dai Bot"
configure: "Imposta"
postToGallery: "Pubblicare nella galleria"
@@ -1021,6 +1032,7 @@ thisPostMayBeAnnoyingHome: "Pubblica sulla timeline principale"
thisPostMayBeAnnoyingCancel: "Annulla"
thisPostMayBeAnnoyingIgnore: "Pubblica lo stesso"
collapseRenotes: "Comprimi le Rinota già viste"
+collapseRenotesDescription: "Comprimi le Note con cui hai già interagito."
internalServerError: "Errore interno del server"
internalServerErrorDescription: "Si è verificato un errore imprevisto all'interno del server"
copyErrorInfo: "Copia le informazioni sull'errore"
@@ -1233,10 +1245,20 @@ useNativeUIForVideoAudioPlayer: "Riprodurre audio/video usando le funzionalità
keepOriginalFilename: "Mantieni il nome file originale"
keepOriginalFilenameDescription: "Disattivandola, i file verranno caricati usando nomi casuali."
noDescription: "Manca la descrizione"
+alwaysConfirmFollow: "Richiedi conferma per i Follow"
+inquiry: "Contattaci"
+tryAgain: "Per favore riprova"
+confirmWhenRevealingSensitiveMedia: "Richiedi conferma prima di mostrare gli allegati espliciti"
+sensitiveMediaRevealConfirm: "Questo allegato è esplicito, vuoi vederlo?"
_delivery:
+ status: "Stato della consegna"
stop: "Sospensione"
+ resume: "Riprendi la consegna"
_type:
none: "Pubblicazione"
+ manuallySuspended: "Sospesa manualmente"
+ goneSuspended: "Sospensione server a causa dell'eliminazione"
+ autoSuspendedForNotResponding: "Sospensione del server a causa di mancata risposta"
_bubbleGame:
howToPlay: "Come giocare"
hold: "Tieni"
@@ -1362,6 +1384,8 @@ _serverSettings:
fanoutTimelineDescription: "Attivando questa funzionalità migliori notevolmente la capacità delle Timeline di collezionare Note, riducendo il carico sul database. Tuttavia, aumenterà l'impiego di memoria RAM per Redis. Disattiva se il tuo server ha poca RAM o la funzionalità è irregolare."
fanoutTimelineDbFallback: "Elaborazione dati alternativa"
fanoutTimelineDbFallbackDescription: "Attivando l'elaborazione alternativa, verrà interrogato ulteriormente il database se la timeline non è nella cache. \nDisattivando, si può ridurre ulteriormente il carico del server, evitando l'elaborazione alternativa, ma limitando l'intervallo recuperabile delle timeline."
+ inquiryUrl: "URL di contatto"
+ inquiryUrlDescription: "Specificare l'URL al modulo di contatto, oppure le informazioni con i dati di contatto dell'amministrazione."
_accountMigration:
moveFrom: "Migra un altro profilo dentro a questo"
moveFromSub: "Crea un alias verso un altro profilo remoto"
@@ -1678,6 +1702,7 @@ _role:
canManageAvatarDecorations: "Gestisce le decorazioni di immagini del profilo"
driveCapacity: "Capienza del Drive"
alwaysMarkNsfw: "Impostare sempre come esplicito (NSFW)"
+ canUpdateBioMedia: "Può aggiornare foto profilo e di testata"
pinMax: "Quantità massima di Note in primo piano"
antennaMax: "Quantità massima di Antenne"
wordMuteMax: "Lunghezza massima del filtro parole"
@@ -1696,6 +1721,11 @@ _role:
roleAssignedTo: "Assegnato a ruoli manualmente"
isLocal: "Profilo locale"
isRemote: "Profilo remoto"
+ isCat: "È un gattino"
+ isBot: "È un bot"
+ isSuspended: "È sospeso"
+ isLocked: "È in stato privato"
+ isExplorable: "Autorizza la pubblicazione nei cataloghi"
createdLessThan: "Profilo creato da meno di N"
createdMoreThan: "Profilo creato da più di N"
followersLessThanOrEq: "Profilo con N follower o meno"
@@ -1916,8 +1946,6 @@ _sfx:
note: "Nota"
noteMy: "Mia nota"
notification: "Notifiche"
- antenna: "Ricezione dell'antenna"
- channel: "Notifiche di canale"
reaction: "Quando seleziono una reazione"
_soundSettings:
driveFile: "Suoni del Drive"
@@ -2342,6 +2370,7 @@ _deck:
alwaysShowMainColumn: "Mostra sempre la colonna principale"
columnAlign: "Allineare colonne"
addColumn: "Aggiungi colonna"
+ newNoteNotificationSettings: "Preferenze per le notifiche di nuove Note"
configureColumn: "Impostazioni colonna"
swapLeft: "Sposta a sinistra"
swapRight: "Sposta a destra"
@@ -2380,9 +2409,9 @@ _drivecleaner:
orderByCreatedAtAsc: "Dal più vecchio al più recente"
_webhookSettings:
createWebhook: "Creazione Webhook"
+ modifyWebhook: "Modifica Webhook"
name: "Nome"
secret: "Segreto"
- events: "Quando eseguire il Webhook"
active: "Attivo"
_events:
follow: "Quando segui un profilo"
@@ -2392,6 +2421,25 @@ _webhookSettings:
renote: "Quando la Nota è Rinotata"
reaction: "Quando ricevo una reazione"
mention: "Quando mi menzionano"
+ _systemEvents:
+ abuseReport: "Quando arriva una segnalazione"
+ abuseReportResolved: "Quando una segnalazione è risolta"
+ deleteConfirm: "Vuoi davvero eliminare il Webhook?"
+_abuseReport:
+ _notificationRecipient:
+ createRecipient: "Aggiungi destinatario della segnalazione"
+ modifyRecipient: "Modifica destinatario della segnalazione"
+ recipientType: "Tipo di notifica"
+ _recipientType:
+ mail: "Email"
+ webhook: "Webhook"
+ _captions:
+ mail: "Quando ricevi un abuso, notifica l'amministrazione via email"
+ webhook: "Spedire una notifica al SystemWebhook specificato (sia quando si riceve una segnalazione, che quando viene risolta)"
+ keywords: "Parole chiave"
+ notifiedUser: "Profili da notificare"
+ notifiedWebhook: "Webhook da usare"
+ deleteConfirm: "Vuoi davvero rimuovere il destinatario della notifica?"
_moderationLogTypes:
createRole: "Ruolo creato"
deleteRole: "Ruolo eliminato"
@@ -2429,6 +2477,12 @@ _moderationLogTypes:
deleteAvatarDecoration: "Eliminazione decorazione della foto profilo"
unsetUserAvatar: "Rimossa foto profilo"
unsetUserBanner: "Rimossa intestazione profilo"
+ createSystemWebhook: "Crea un SystemWebhook"
+ updateSystemWebhook: "Modifica SystemWebhook"
+ deleteSystemWebhook: "Elimina SystemWebhook"
+ createAbuseReportNotificationRecipient: "Crea destinatario per le notifiche di segnalazioni"
+ updateAbuseReportNotificationRecipient: "Aggiorna destinatario notifiche di segnalazioni"
+ deleteAbuseReportNotificationRecipient: "Elimina destinatario notifiche di segnalazioni"
_fileViewer:
title: "Dettagli del file"
type: "Tipo di file"
@@ -2554,6 +2608,8 @@ _urlPreviewSetting:
userAgent: "User-Agent"
userAgentDescription: "Definire con quale User-Agent si intende identificarsi durante l'acquisizione di un'anteprima. Se è vuoto, useremo il valore predefinito."
summaryProxy: "Endpoint proxy che genera l'anteprima"
+ summaryProxyDescription: "Genera anteprime utilizzando un proxy Summaly anziché Misskey."
+ summaryProxyDescription2: "I parametri sono collegano al proxy come stringa query. Se il proxy non li supporta, verranno ignorati."
_mediaControls:
pip: "Sovraimpressione"
playbackRate: "Velocità di riproduzione"
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index a89cfbd843..b493183974 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -60,6 +60,7 @@ copyFileId: "ファイルIDをコピー"
copyFolderId: "フォルダーIDをコピー"
copyProfileUrl: "プロフィールURLをコピー"
searchUser: "ユーザーを検索"
+searchThisUsersNotes: "ユーザーã®ãƒŽãƒ¼ãƒˆã‚’検索"
reply: "返信"
loadMore: "ã‚‚ã£ã¨è¦‹ã‚‹"
showMore: "ã‚‚ã£ã¨è¦‹ã‚‹"
@@ -154,6 +155,7 @@ editList: "リストを編集"
selectChannel: "ãƒãƒ£ãƒ³ãƒãƒ«ã‚’é¸æŠž"
selectAntenna: "ã‚¢ãƒ³ãƒ†ãƒŠã‚’é¸æŠž"
editAntenna: "アンテナを編集"
+createAntenna: "アンテナを作æˆ"
selectWidget: "ã‚¦ã‚£ã‚¸ã‚§ãƒƒãƒˆã‚’é¸æŠž"
editWidgets: "ウィジェットを編集"
editWidgetsExit: "編集を終了"
@@ -180,6 +182,10 @@ addAccount: "アカウントを追加"
reloadAccountsList: "ã‚¢ã‚«ã‚¦ãƒ³ãƒˆãƒªã‚¹ãƒˆã®æƒ…報を更新"
loginFailed: "ログインã«å¤±æ•—ã—ã¾ã—ãŸ"
showOnRemote: "リモートã§è¡¨ç¤º"
+continueOnRemote: "リモートã§ç¶šè¡Œ"
+chooseServerOnMisskeyHub: "Misskey Hubã‹ã‚‰ã‚µãƒ¼ãƒãƒ¼ã‚’é¸æŠž"
+specifyServerHost: "サーãƒãƒ¼ã®ãƒ‰ãƒ¡ã‚¤ãƒ³ã‚’直接指定"
+inputHostName: "ドメインを入力ã—ã¦ãã ã•ã„"
general: "全般"
wallpaper: "å£ç´™"
setWallpaper: "å£ç´™ã‚’設定"
@@ -190,6 +196,7 @@ followConfirm: "{name}をフォローã—ã¾ã™ã‹ï¼Ÿ"
proxyAccount: "プロキシアカウント"
proxyAccountDescription: "プロキシアカウントã¯ã€ç‰¹å®šã®æ¡ä»¶ä¸‹ã§ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ãƒªãƒ¢ãƒ¼ãƒˆãƒ•ォローを代行ã™ã‚‹ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã§ã™ã€‚例ãˆã°ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒãƒªãƒ¢ãƒ¼ãƒˆãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚’リストã«å…¥ã‚ŒãŸã¨ãã€ãƒªã‚¹ãƒˆã«å…¥ã‚Œã‚‰ã‚ŒãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚’誰もフォローã—ã¦ã„ãªã„ã¨ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティãŒã‚µãƒ¼ãƒãƒ¼ã«é…é”ã•れãªã„ãŸã‚ã€ä»£ã‚りã«ãƒ—ロキシアカウントãŒãƒ•ォローã™ã‚‹ã‚ˆã†ã«ã—ã¾ã™ã€‚"
host: "ホスト"
+selectSelf: "è‡ªåˆ†ã‚’é¸æŠž"
selectUser: "ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚’é¸æŠž"
recipient: "宛先"
annotation: "注釈"
@@ -205,6 +212,7 @@ perDay: "1æ—¥ã”ã¨"
stopActivityDelivery: "アクティビティã®é…é€ã‚’åœæ­¢"
blockThisInstance: "ã“ã®ã‚µãƒ¼ãƒãƒ¼ã‚’ブロック"
silenceThisInstance: "サーãƒãƒ¼ã‚’サイレンス"
+mediaSilenceThisInstance: "サーãƒãƒ¼ã‚’メディアサイレンス"
operations: "æ“作"
software: "ソフトウェア"
version: "ãƒãƒ¼ã‚¸ãƒ§ãƒ³"
@@ -226,6 +234,8 @@ blockedInstances: "ブロックã—ãŸã‚µãƒ¼ãƒãƒ¼"
blockedInstancesDescription: "ブロックã—ãŸã„サーãƒãƒ¼ã®ãƒ›ã‚¹ãƒˆã‚’改行ã§åŒºåˆ‡ã£ã¦è¨­å®šã—ã¾ã™ã€‚ブロックã•れãŸã‚µãƒ¼ãƒãƒ¼ã¯ã€ã“ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã¨ã‚„りå–りã§ããªããªã‚Šã¾ã™ã€‚"
silencedInstances: "サイレンスã—ãŸã‚µãƒ¼ãƒãƒ¼"
silencedInstancesDescription: "サイレンスã—ãŸã„サーãƒãƒ¼ã®ãƒ›ã‚¹ãƒˆã‚’改行ã§åŒºåˆ‡ã£ã¦è¨­å®šã—ã¾ã™ã€‚サイレンスã•れãŸã‚µãƒ¼ãƒãƒ¼ã«æ‰€å±žã™ã‚‹ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã¯ã™ã¹ã¦ã€Œã‚µã‚¤ãƒ¬ãƒ³ã‚¹ã€ã¨ã—ã¦æ‰±ã‚れã€ãƒ•ォローãŒã™ã¹ã¦ãƒªã‚¯ã‚¨ã‚¹ãƒˆã«ãªã‚Šã¾ã™ã€‚ブロックã—ãŸã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã«ã¯å½±éŸ¿ã—ã¾ã›ã‚“。"
+mediaSilencedInstances: "メディアサイレンスã—ãŸã‚µãƒ¼ãƒãƒ¼"
+mediaSilencedInstancesDescription: "メディアサイレンスã—ãŸã„サーãƒãƒ¼ã®ãƒ›ã‚¹ãƒˆã‚’改行ã§åŒºåˆ‡ã£ã¦è¨­å®šã—ã¾ã™ã€‚メディアサイレンスã•れãŸã‚µãƒ¼ãƒãƒ¼ã«æ‰€å±žã™ã‚‹ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã«ã‚ˆã‚‹ãƒ•ァイルã¯ã™ã¹ã¦ã‚»ãƒ³ã‚·ãƒ†ã‚£ãƒ–ã¨ã—ã¦æ‰±ã‚れã€ã‚«ã‚¹ã‚¿ãƒ çµµæ–‡å­—ãŒä½¿ç”¨ã§ããªã„よã†ã«ãªã‚Šã¾ã™ã€‚ブロックã—ãŸã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã«ã¯å½±éŸ¿ã—ã¾ã›ã‚“。"
muteAndBlock: "ミュートã¨ãƒ–ロック"
mutedUsers: "ミュートã—ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼"
blockedUsers: "ブロックã—ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼"
@@ -476,7 +486,8 @@ attachAsFileQuestion: "クリップボードã®ãƒ†ã‚­ã‚¹ãƒˆãŒé•·ã„ã§ã™ã€‚テ
noMessagesYet: "ã¾ã ãƒãƒ£ãƒƒãƒˆã¯ã‚りã¾ã›ã‚“"
newMessageExists: "æ–°ã—ã„メッセージãŒã‚りã¾ã™"
onlyOneFileCanBeAttached: "ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã«æ·»ä»˜ã§ãるファイルã¯ã²ã¨ã¤ã§ã™"
-signinRequired: "続行ã™ã‚‹å‰ã«ã€ã‚µã‚¤ãƒ³ã‚¢ãƒƒãƒ—ã¾ãŸã¯ã‚µã‚¤ãƒ³ã‚¤ãƒ³ãŒå¿…è¦ã§ã™"
+signinRequired: "続行ã™ã‚‹å‰ã«ã€ç™»éŒ²ã¾ãŸã¯ãƒ­ã‚°ã‚¤ãƒ³ãŒå¿…è¦ã§ã™"
+signinOrContinueOnRemote: "続行ã™ã‚‹ã«ã¯ã€ãŠä½¿ã„ã®ã‚µãƒ¼ãƒãƒ¼ã«ç§»å‹•ã™ã‚‹ã‹ã€ã“ã®ã‚µãƒ¼ãƒãƒ¼ã«ç™»éŒ²ãƒ»ãƒ­ã‚°ã‚¤ãƒ³ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™"
invitations: "招待"
invitationCode: "招待コード"
checking: "確èªã—ã¦ã„ã¾ã™"
@@ -1101,6 +1112,8 @@ preservedUsernames: "予約ユーザーå"
preservedUsernamesDescription: "予約ã™ã‚‹ãƒ¦ãƒ¼ã‚¶ãƒ¼åを改行ã§åˆ—挙ã—ã¾ã™ã€‚ã“ã“ã§æŒ‡å®šã•れãŸãƒ¦ãƒ¼ã‚¶ãƒ¼åã¯ã‚¢ã‚«ã‚¦ãƒ³ãƒˆä½œæˆæ™‚ã«ä½¿ãˆãªããªã‚Šã¾ã™ãŒã€ç®¡ç†è€…ã«ã‚ˆã‚‹ã‚¢ã‚«ã‚¦ãƒ³ãƒˆä½œæˆæ™‚ã¯ã“ã®åˆ¶é™ã‚’å—ã‘ã¾ã›ã‚“。ã¾ãŸã€æ—¢ã«å­˜åœ¨ã™ã‚‹ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‚‚影響をå—ã‘ã¾ã›ã‚“。"
createNoteFromTheFile: "ã“ã®ãƒ•ァイルã‹ã‚‰ãƒŽãƒ¼ãƒˆã‚’作æˆ"
archive: "アーカイブ"
+archived: "アーカイブ済ã¿"
+unarchive: "アーカイブ解除"
channelArchiveConfirmTitle: "{name}をアーカイブã—ã¾ã™ã‹ï¼Ÿ"
channelArchiveConfirmDescription: "アーカイブã™ã‚‹ã¨ã€ãƒãƒ£ãƒ³ãƒãƒ«ä¸€è¦§ã‚„æ¤œç´¢çµæžœã«è¡¨ç¤ºã•れãªããªã‚Šã€æ–°ãŸãªæ›¸ãè¾¼ã¿ã‚‚ã§ããªããªã‚Šã¾ã™ã€‚"
thisChannelArchived: "ã“ã®ãƒãƒ£ãƒ³ãƒãƒ«ã¯ã‚¢ãƒ¼ã‚«ã‚¤ãƒ–ã•れã¦ã„ã¾ã™ã€‚"
@@ -1111,6 +1124,9 @@ preventAiLearning: "生æˆAIã«ã‚ˆã‚‹å­¦ç¿’ã‚’æ‹’å¦"
preventAiLearningDescription: "å¤–éƒ¨ã®æ–‡ç« ç”ŸæˆAIã‚„ç”»åƒç”ŸæˆAIã«å¯¾ã—ã¦ã€æŠ•稿ã—ãŸãƒŽãƒ¼ãƒˆã‚„ç”»åƒãªã©ã®ã‚³ãƒ³ãƒ†ãƒ³ãƒ„を学習ã®å¯¾è±¡ã«ã—ãªã„よã†ã«è¦æ±‚ã—ã¾ã™ã€‚ã“れã¯noaiフラグをHTMLレスãƒãƒ³ã‚¹ã«å«ã‚ã‚‹ã“ã¨ã«ã‚ˆã£ã¦å®Ÿç¾ã•れã¾ã™ãŒã€ã“ã®è¦æ±‚ã«å¾“ã†ã‹ã¯ãã®AI次第ã§ã‚ã‚‹ãŸã‚ã€å­¦ç¿’を完全ã«é˜²æ­¢ã™ã‚‹ã‚‚ã®ã§ã¯ã‚りã¾ã›ã‚“。"
options: "オプション"
specifyUser: "ユーザー指定"
+lookupConfirm: "照会ã—ã¾ã™ã‹ï¼Ÿ"
+openTagPageConfirm: "ãƒãƒƒã‚·ãƒ¥ã‚¿ã‚°ã®ãƒšãƒ¼ã‚¸ã‚’é–‹ãã¾ã™ã‹ï¼Ÿ"
+specifyHost: "ホスト指定"
failedToPreviewUrl: "プレビューã§ãã¾ã›ã‚“"
update: "æ›´æ–°"
rolesThatCanBeUsedThisEmojiAsReaction: "リアクションã¨ã—ã¦ä½¿ãˆã‚‹ãƒ­ãƒ¼ãƒ«"
@@ -1242,6 +1258,11 @@ keepOriginalFilenameDescription: "ã“ã®è¨­å®šã‚’オフã«ã™ã‚‹ã¨ã€ã‚¢ãƒƒãƒ—ã
noDescription: "説明文ã¯ã‚りã¾ã›ã‚“"
alwaysConfirmFollow: "フォローã®éš›å¸¸ã«ç¢ºèªã™ã‚‹"
inquiry: "ãŠå•ã„åˆã‚ã›"
+tryAgain: "ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„。"
+confirmWhenRevealingSensitiveMedia: "センシティブãªãƒ¡ãƒ‡ã‚£ã‚¢ã‚’表示ã™ã‚‹ã¨ã確èªã™ã‚‹"
+sensitiveMediaRevealConfirm: "センシティブãªãƒ¡ãƒ‡ã‚£ã‚¢ã§ã™ã€‚表示ã—ã¾ã™ã‹ï¼Ÿ"
+createdLists: "作æˆã—ãŸãƒªã‚¹ãƒˆ"
+createdAntennas: "作æˆã—ãŸã‚¢ãƒ³ãƒ†ãƒŠ"
_delivery:
status: "é…信状態"
@@ -1705,6 +1726,7 @@ _role:
canManageAvatarDecorations: "ã‚¢ãƒã‚¿ãƒ¼ãƒ‡ã‚³ãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³ã®ç®¡ç†"
driveCapacity: "ドライブ容é‡"
alwaysMarkNsfw: "ファイルã«NSFWを常ã«ä»˜ä¸Ž"
+ canUpdateBioMedia: "アイコンã¨ãƒãƒŠãƒ¼ã®æ›´æ–°ã‚’許å¯"
pinMax: "ノートã®ãƒ”ン留ã‚ã®æœ€å¤§æ•°"
antennaMax: "アンテナã®ä½œæˆå¯èƒ½æ•°"
wordMuteMax: "ãƒ¯ãƒ¼ãƒ‰ãƒŸãƒ¥ãƒ¼ãƒˆã®æœ€å¤§æ–‡å­—æ•°"
@@ -1971,8 +1993,6 @@ _sfx:
note: "ノート"
noteMy: "ノート(自分)"
notification: "通知"
- antenna: "アンテナå—ä¿¡"
- channel: "ãƒãƒ£ãƒ³ãƒãƒ«é€šçŸ¥"
reaction: "ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³é¸æŠžæ™‚"
_soundSettings:
@@ -1982,6 +2002,7 @@ _soundSettings:
driveFileTypeWarnDescription: "éŸ³å£°ãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠžã—ã¦ãã ã•ã„"
driveFileDurationWarn: "音声ãŒé•·ã™ãŽã¾ã™"
driveFileDurationWarnDescription: "é•·ã„音声を使用ã™ã‚‹ã¨Misskeyã®ä½¿ç”¨ã«æ”¯éšœã‚’ããŸã™å¯èƒ½æ€§ãŒã‚りã¾ã™ã€‚ãれã§ã‚‚続行ã—ã¾ã™ã‹ï¼Ÿ"
+ driveFileError: "音声ãŒèª­ã¿è¾¼ã‚ã¾ã›ã‚“ã§ã—ãŸã€‚設定を変更ã—ã¦ãã ã•ã„"
_ago:
future: "未æ¥"
@@ -2468,9 +2489,10 @@ _drivecleaner:
_webhookSettings:
createWebhook: "Webhookを作æˆ"
+ modifyWebhook: "Webhookを編集"
name: "åå‰"
secret: "シークレット"
- events: "Webhookを実行ã™ã‚‹ã‚¿ã‚¤ãƒŸãƒ³ã‚°"
+ trigger: "トリガー"
active: "有効"
_events:
follow: "フォローã—ãŸã¨ã"
@@ -2480,6 +2502,27 @@ _webhookSettings:
renote: "Renoteã•れãŸã¨ã"
reaction: "リアクションãŒã‚ã£ãŸã¨ã"
mention: "メンションã•れãŸã¨ã"
+ _systemEvents:
+ abuseReport: "ユーザーã‹ã‚‰é€šå ±ãŒã‚ã£ãŸã¨ã"
+ abuseReportResolved: "ユーザーã‹ã‚‰ã®é€šå ±ã‚’処ç†ã—ãŸã¨ã"
+ userCreated: "ユーザーãŒä½œæˆã•れãŸã¨ã"
+ deleteConfirm: "Webhookを削除ã—ã¾ã™ã‹ï¼Ÿ"
+
+_abuseReport:
+ _notificationRecipient:
+ createRecipient: "通報ã®é€šçŸ¥å…ˆã‚’追加"
+ modifyRecipient: "通報ã®é€šçŸ¥å…ˆã‚’編集"
+ recipientType: "通知先ã®ç¨®é¡ž"
+ _recipientType:
+ mail: "メール"
+ webhook: "Webhook"
+ _captions:
+ mail: "モデレーター権é™ã‚’æŒã¤ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã«é€šçŸ¥ã‚’é€ã‚Šã¾ã™(通報をå—ã‘ãŸæ™‚ã®ã¿)"
+ webhook: "指定ã—ãŸSystemWebhookã«é€šçŸ¥ã‚’é€ã‚Šã¾ã™(通報をå—ã‘ãŸæ™‚ã¨é€šå ±ã‚’解決ã—ãŸæ™‚ã«ãれãžã‚Œç™ºä¿¡)"
+ keywords: "キーワード"
+ notifiedUser: "通知先ユーザー"
+ notifiedWebhook: "使用ã™ã‚‹Webhook"
+ deleteConfirm: "通知先を削除ã—ã¾ã™ã‹ï¼Ÿ"
_moderationLogTypes:
createRole: "ロールを作æˆ"
@@ -2518,6 +2561,12 @@ _moderationLogTypes:
deleteAvatarDecoration: "アイコンデコレーションを削除"
unsetUserAvatar: "ユーザーã®ã‚¢ã‚¤ã‚³ãƒ³ã‚’解除"
unsetUserBanner: "ユーザーã®ãƒãƒŠãƒ¼ã‚’解除"
+ createSystemWebhook: "SystemWebhookを作æˆ"
+ updateSystemWebhook: "SystemWebhookã‚’æ›´æ–°"
+ deleteSystemWebhook: "SystemWebhookを削除"
+ createAbuseReportNotificationRecipient: "通報ã®é€šçŸ¥å…ˆã‚’作æˆ"
+ updateAbuseReportNotificationRecipient: "通報ã®é€šçŸ¥å…ˆã‚’æ›´æ–°"
+ deleteAbuseReportNotificationRecipient: "通報ã®é€šçŸ¥å…ˆã‚’削除"
_fileViewer:
title: "ファイルã®è©³ç´°"
@@ -2572,16 +2621,16 @@ _externalResourceInstaller:
_dataSaver:
_media:
- title: "メディアã®èª­ã¿è¾¼ã¿"
+ title: "メディアã®èª­ã¿è¾¼ã¿ã‚’無効化"
description: "ç”»åƒãƒ»å‹•ç”»ãŒè‡ªå‹•ã§èª­ã¿è¾¼ã¾ã‚Œã‚‹ã®ã‚’防止ã—ã¾ã™ã€‚隠れã¦ã„ã‚‹ç”»åƒãƒ»å‹•ç”»ã¯ã‚¿ãƒƒãƒ—ã™ã‚‹ã¨èª­ã¿è¾¼ã¾ã‚Œã¾ã™ã€‚"
_avatar:
- title: "アイコン画åƒ"
+ title: "アイコン画åƒã®ã‚¢ãƒ‹ãƒ¡ãƒ¼ã‚·ãƒ§ãƒ³ã‚’無効化"
description: "アイコン画åƒã®ã‚¢ãƒ‹ãƒ¡ãƒ¼ã‚·ãƒ§ãƒ³ãŒåœæ­¢ã—ã¾ã™ã€‚アニメーション画åƒã¯é€šå¸¸ã®ç”»åƒã‚ˆã‚Šãƒ•ァイルサイズãŒå¤§ãã„ã“ã¨ãŒã‚ã‚‹ã®ã§ã€ãƒ‡ãƒ¼ã‚¿é€šä¿¡é‡ã‚’ã•らã«å‰Šæ¸›ã§ãã¾ã™ã€‚"
_urlPreview:
- title: "URLプレビューã®ã‚µãƒ ãƒã‚¤ãƒ«"
+ title: "URLプレビューã®ã‚µãƒ ãƒã‚¤ãƒ«ã‚’éžè¡¨ç¤º"
description: "URLプレビューã®ã‚µãƒ ãƒã‚¤ãƒ«ç”»åƒãŒèª­ã¿è¾¼ã¾ã‚Œãªããªã‚Šã¾ã™ã€‚"
_code:
- title: "コードãƒã‚¤ãƒ©ã‚¤ãƒˆ"
+ title: "コードãƒã‚¤ãƒ©ã‚¤ãƒˆã‚’éžè¡¨ç¤º"
description: "MFMãªã©ã§ã‚³ãƒ¼ãƒ‰ãƒã‚¤ãƒ©ã‚¤ãƒˆè¨˜æ³•ãŒä½¿ã‚れã¦ã„ã‚‹å ´åˆã€ã‚¿ãƒƒãƒ—ã™ã‚‹ã¾ã§èª­ã¿è¾¼ã¾ã‚Œãªããªã‚Šã¾ã™ã€‚コードãƒã‚¤ãƒ©ã‚¤ãƒˆã§ã¯ãƒã‚¤ãƒ©ã‚¤ãƒˆã™ã‚‹è¨€èªžã”ã¨ã«ãã®å®šç¾©ãƒ•ァイルを読ã¿è¾¼ã‚€å¿…è¦ãŒã‚りã¾ã™ãŒã€ãれらãŒè‡ªå‹•ã§èª­ã¿è¾¼ã¾ã‚Œãªããªã‚‹ãŸã‚ã€é€šä¿¡é‡ã®å‰Šæ¸›ãŒè¦‹è¾¼ã‚ã¾ã™ã€‚"
_hemisphere:
@@ -2657,3 +2706,9 @@ _mediaControls:
pip: "ピクãƒãƒ£ã‚¤ãƒ³ãƒ”クãƒãƒ£"
playbackRate: "å†ç”Ÿé€Ÿåº¦"
loop: "ループå†ç”Ÿ"
+
+_contextMenu:
+ title: "コンテキストメニュー"
+ app: "アプリケーション"
+ appWithShift: "Shiftキーã§ã‚¢ãƒ—リケーション"
+ native: "ブラウザã®UI"
diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml
index 7a33968e9e..5969082cf2 100644
--- a/locales/ja-KS.yml
+++ b/locales/ja-KS.yml
@@ -108,6 +108,7 @@ enterEmoji: "絵文字を入れã¦ã‚„"
renote: "リノート"
unrenote: "リノートやã‚ã‚‹"
renoted: "リノートã—ãŸã§ã€‚"
+renotedToX: "{name}ã«ãƒªãƒŽãƒ¼ãƒˆã—ãŸã§"
cantRenote: "ã“ã®æŠ•ç¨¿ã¯ãƒªãƒŽãƒ¼ãƒˆã§ãã¸ã‚“ã£ã½ã„。"
cantReRenote: "リノート自体ã¯ãƒªãƒŽãƒ¼ãƒˆã§ãã¸ã‚“ã§ã€‚"
quote: "引用"
@@ -313,6 +314,7 @@ selectFile: "ファイルé¸ã‚“ã§ã‚„"
selectFiles: "ファイルé¸ã‚“ã§ã‚„"
selectFolder: "フォルダé¸ã‚“ã§ã‚„"
selectFolders: "フォルダé¸ã‚“ã§ã‚„"
+fileNotSelected: "ファイルãŒé¸æŠžã•れã¦ã¸ã‚“ã§"
renameFile: "ファイルåã‚’ã„らã†"
folderName: "フォルダーå"
createFolder: "フォルダー作る"
@@ -468,6 +470,7 @@ retype: "ã‚‚ã£ã‹ã„入力"
noteOf: "{user}ã¯ã‚“ã®ãƒŽãƒ¼ãƒˆ"
quoteAttached: "引用付ã„ã¨ã‚‹ã§"
quoteQuestion: "引用ã¨ã—ã¦æ·»ä»˜ã—ã¦ã‚‚ãˆãˆã‹ï¼Ÿ"
+attachAsFileQuestion: "クリップボードã®ãƒ†ã‚­ã‚¹ãƒˆãŒé•·ã™ãŽã‚‹ã‹ã‚‰ãƒ†ã‚­ã‚¹ãƒˆãƒ•ァイルã¨ã—ã¦æ·»ä»˜ã—ã¦ã‚‚ãˆãˆã‹ï¼Ÿ"
noMessagesYet: "ã¾ã ãƒãƒ£ãƒƒãƒˆã¯ã‚らã¸ã‚“ã§"
newMessageExists: "æ–°ã—ã„メッセージãŒããŸã§"
onlyOneFileCanBeAttached: "ã”ã‚ã‚“ãªã€ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã«æ·»ä»˜ã§ãるファイルã¯ã²ã¨ã¤ã ã‘ãªã‚“よ。"
@@ -832,6 +835,7 @@ administration: "管ç†"
accounts: "アカウント"
switch: "切り替ãˆ"
noMaintainerInformationWarning: "管ç†è€…情報ãŒè¨­å®šã•れã¦ã¸ã‚“ã§"
+noInquiryUrlWarning: "å•ã„åˆã‚ã›å…ˆURLãŒè¨­å®šã•れã¦ã¸ã‚“ã§ã€‚"
noBotProtectionWarning: "BotプロテクションãŒè¨­å®šã•れã¦ã¸ã‚“ã§ã€‚"
configure: "設定ã™ã‚‹"
postToGallery: "ã‚®ãƒ£ãƒ©ãƒªãƒ¼ã¸æŠ•ç¨¿"
@@ -1923,8 +1927,6 @@ _sfx:
note: "ノート"
noteMy: "ノート(自分)"
notification: "通知"
- antenna: "アンテナå—ä¿¡"
- channel: "ãƒãƒ£ãƒ³ãƒãƒ«é€šçŸ¥"
reaction: "ツッコミé¸ã‚“ã©ã‚‹ã¨ã"
_soundSettings:
driveFile: "ドライブん中ã®éŸ³ä½¿ã†"
@@ -2389,7 +2391,6 @@ _webhookSettings:
createWebhook: "Webhookã‚’ã¤ãã‚‹"
name: "åå‰"
secret: "シークレット"
- events: "Webhookを投ã’るタイミング"
active: "有効"
_events:
follow: "フォローã—ãŸã¨ã~ï¼"
@@ -2399,6 +2400,12 @@ _webhookSettings:
renote: "リノートã•れるã¨ã~ï¼"
reaction: "ツッコã¾ã‚ŒãŸã¨ã~ï¼"
mention: "メンションãŒã‚ã‚‹ã¨ã~ï¼"
+ deleteConfirm: "ã»ã‚“ã¾ã«Webhookã‚’ã»ã‹ã—ã¦ã‚‚ãˆãˆã‚“ã‹ï¼Ÿ"
+_abuseReport:
+ _notificationRecipient:
+ _recipientType:
+ mail: "メール"
+ deleteConfirm: "通知先を削除ã—ã¦ã‚‚ãˆãˆã‹ï¼Ÿ"
_moderationLogTypes:
createRole: "ロールを追加ã™ã‚“ã§"
deleteRole: "ロールã»ã‹ã™"
diff --git a/locales/kab-KAB.yml b/locales/kab-KAB.yml
index 22e24d3baa..d4aa36fa70 100644
--- a/locales/kab-KAB.yml
+++ b/locales/kab-KAB.yml
@@ -104,3 +104,7 @@ _deck:
_columns:
notifications: "Ilɣuyen"
list: "Tibdarin"
+_abuseReport:
+ _notificationRecipient:
+ _recipientType:
+ mail: "Imayl"
diff --git a/locales/ko-GS.yml b/locales/ko-GS.yml
index 9466aff01f..9323ed2a26 100644
--- a/locales/ko-GS.yml
+++ b/locales/ko-GS.yml
@@ -805,6 +805,10 @@ _deck:
mentions: "받언 멘션"
_webhookSettings:
name: "ì´ëŸ¼"
+_abuseReport:
+ _notificationRecipient:
+ _recipientType:
+ mail: "ì „ìžìš°íŽœ"
_moderationLogTypes:
suspend: "얼우기"
deleteNote: "노트 ë­‰ìºê¸°"
diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml
index 294a5a1520..34c1cc3ebf 100644
--- a/locales/ko-KR.yml
+++ b/locales/ko-KR.yml
@@ -52,14 +52,14 @@ deleteAndEditConfirm: "ì´ ë…¸íŠ¸ë¥¼ 삭제한 ë’¤ 다시 편집하시겠습니ê
addToList: "ë¦¬ìŠ¤íŠ¸ì— ì¶”ê°€"
addToAntenna: "ì•ˆí…Œë‚˜ì— ì¶”ê°€"
sendMessage: "메시지 보내기"
-copyRSS: "RSS 복사"
-copyUsername: "ì‚¬ìš©ìž ì´ë¦„ 복사"
-copyUserId: "ì‚¬ìš©ìž ID 복사"
+copyRSS: "RSS 주소 복사"
+copyUsername: "유저명 복사"
+copyUserId: "유저 ID 복사"
copyNoteId: "노트 ID 복사"
copyFileId: "íŒŒì¼ ID 복사"
copyFolderId: "í´ë” ID 복사"
copyProfileUrl: "프로필 URL 복사"
-searchUser: "ì‚¬ìš©ìž ê²€ìƒ‰"
+searchUser: "유저 검색"
reply: "답글"
loadMore: "ë” ë³´ê¸°"
showMore: "ë” ë³´ê¸°"
@@ -108,22 +108,25 @@ enterEmoji: "ì´ëª¨ì§€ ìž…ë ¥"
renote: "리노트"
unrenote: "리노트 취소"
renoted: "리노트했습니다"
+renotedToX: "{name}ëª…ì´ ë¦¬ë…¸íŠ¸í–ˆìŠµë‹ˆë‹¤."
cantRenote: "ì´ ê²Œì‹œë¬¼ì€ ë¦¬ë…¸íŠ¸ í•  수 없습니다."
-cantReRenote: "리노트를 리노트할 수 없습니다."
+cantReRenote: "리노트를 리노트 할 수 없습니다."
quote: "ì¸ìš©"
inChannelRenote: "ì±„ë„ ë‚´ 리노트"
inChannelQuote: "ì±„ë„ ë‚´ ì¸ìš©"
+renoteToChannel: "채ë„ì— ë¦¬ë…¸íŠ¸"
+renoteToOtherChannel: "다른 채ë„ì— ë¦¬ë…¸íŠ¸"
pinnedNote: "ê³ ì •ëœ ë…¸íŠ¸"
pinned: "고정하기"
you: "나"
clickToShow: "í´ë¦­í•˜ì—¬ 보기"
sensitive: "열람 주ì˜"
add: "추가"
-reaction: "ë°˜ì‘"
-reactions: "ë°˜ì‘"
+reaction: "리액션"
+reactions: "리액션"
emojiPicker: "ì´ëª¨ì§€ ì„ íƒê¸°"
-pinnedEmojisForReactionSettingDescription: "ë¦¬ì•¡ì…˜ì„ í•  때 í”„ë¡œí•„ì— ê³ ì •í•˜ì—¬ 표시할 ì´ëª¨ì§€ë¥¼ 설정할 수 있습니다"
-pinnedEmojisSettingDescription: "ì´ëª¨ì§€ë¥¼ 입력할 때 í”„ë¡œí•„ì— ê³ ì •í•˜ì—¬ 표시할 ì´ëª¨ì§€ë¥¼ 설정할 수 있습니다"
+pinnedEmojisForReactionSettingDescription: "ë¦¬ì•¡ì…˜ì„ í•  때 ì´ëª¨ì§€ ì„ íƒê¸° ìƒë‹¨ì— 표시할 ì´ëª¨ì§€ë¥¼ 설정할 수 있습니다."
+pinnedEmojisSettingDescription: "ì´ëª¨ì§€ë¥¼ 입력할 때 ì´ëª¨ì§€ ì„ íƒê¸° ìƒë‹¨ì— 표시할 ì´ëª¨ì§€ë¥¼ 설정할 수 있습니다."
emojiPickerDisplay: "ì„ íƒê¸° 표시"
overwriteFromPinnedEmojisForReaction: "리액션 ì„¤ì •ì„ ë®ì–´ì“°ê¸°"
overwriteFromPinnedEmojis: "ì¼ë°˜ ì„¤ì •ì„ ë®ì–´ì“°ê¸°"
@@ -136,7 +139,7 @@ unmarkAsSensitive: "ì—´ëžŒì£¼ì˜ í•´ì œ"
enterFileName: "파ì¼ëª…ì„ ìž…ë ¥"
mute: "뮤트"
unmute: "뮤트 해제"
-renoteMute: "리노트 뮤트하기"
+renoteMute: "리노트 뮤트"
renoteUnmute: "리노트 뮤트 해제"
block: "차단"
unblock: "차단 해제"
@@ -174,12 +177,16 @@ flagShowTimelineReplies: "타임ë¼ì¸ì— ë…¸íŠ¸ì˜ ë‹µê¸€ì„ í‘œì‹œí•˜ê¸°"
flagShowTimelineRepliesDescription: "ì´ ì„¤ì •ì„ í™œì„±í™”í•˜ë©´ 타임ë¼ì¸ì— 다른 유저 ê°„ì˜ ë‹µê¸€ì„ í‘œì‹œí•©ë‹ˆë‹¤."
autoAcceptFollowed: "팔로우 ì¤‘ì¸ ìœ ì €ë¡œë¶€í„°ì˜ íŒ”ë¡œìš° ìš”ì²­ì„ ìžë™ 수ë½"
addAccount: "계정 추가"
-reloadAccountsList: "계정 리스트 정보 갱신"
+reloadAccountsList: "계정 ëª©ë¡ ìƒˆë¡œê³ ì¹¨"
loginFailed: "로그ì¸ì— 실패했습니다"
showOnRemote: "리모트ì—서 보기"
+continueOnRemote: "리모트ì—서 계ì†"
+chooseServerOnMisskeyHub: "Misskey Hubì—서 서버 찾아보기"
+specifyServerHost: "서버 ë„ë©”ì¸ ì§ì ‘ 지정"
+inputHostName: "ë„ë©”ì¸ì„ 입력하세요"
general: "ì¼ë°˜"
wallpaper: "ë°°ê²½"
-setWallpaper: "배경화면 설정"
+setWallpaper: "배경 설정"
removeWallpaper: "배경 제거"
searchWith: "검색: {q}"
youHaveNoLists: "리스트가 없습니다"
@@ -187,7 +194,7 @@ followConfirm: "{name}ë‹˜ì„ íŒ”ë¡œìš° 하시겠습니까?"
proxyAccount: "프ë¡ì‹œ 계정"
proxyAccountDescription: "프ë¡ì‹œ ê³„ì •ì€ íŠ¹ì • ì¡°ê±´ 하ì—서 ìœ ì €ì˜ ë¦¬ëª¨íŠ¸ 팔로우를 대행하는 계정입니다. 예를 들면, 유저가 리모트 유저를 ë¦¬ìŠ¤íŠ¸ì— ë„£ì—ˆì„ ë•Œ, ë¦¬ìŠ¤íŠ¸ì— ë“¤ì–´ê°„ 유저를 ì•„ë¬´ë„ íŒ”ë¡œìš°í•œ ì ì´ 없다면 액티비티가 서버로 배달ë˜ì§€ 않기 때문ì—, 대신 프ë¡ì‹œ ê³„ì •ì´ í•´ë‹¹ 유저를 팔로우하ë„ë¡ í•©ë‹ˆë‹¤."
host: "호스트"
-selectUser: "ì‚¬ìš©ìž ì„ íƒ"
+selectUser: "유저 ì„ íƒ"
recipient: "수신ì¸"
annotation: "ë‚´ìš©ì— ëŒ€í•œ 주ì„"
federation: "ì—°í•©"
@@ -230,7 +237,7 @@ noUsers: "ì•„ë¬´ë„ ì—†ìŠµë‹ˆë‹¤"
editProfile: "프로필 수정"
noteDeleteConfirm: "ì´ ë…¸íŠ¸ë¥¼ 삭제하시겠습니까?"
pinLimitExceeded: "ë” ì´ìƒ ê³ ì •í•  수 없습니다."
-intro: "Misskeyì˜ ì„¤ì¹˜ë¥¼ 완료했습니다! ê´€ë¦¬ìž ê³„ì •ì„ ë§Œë“¤ì–´ 주세요."
+intro: "Misskeyì˜ ì„¤ì¹˜ê°€ 완료ë˜ì—ˆìŠµë‹ˆë‹¤! ê´€ë¦¬ìž ê³„ì •ì„ ìƒì„±í•´ì£¼ì„¸ìš”."
done: "완료"
processing: "처리중"
preview: "미리보기"
@@ -247,7 +254,7 @@ publishing: "ë°°í¬ ì¤‘"
notResponding: "ì‘답 ì—†ìŒ"
instanceFollowing: "ì„œë²„ì˜ íŒ”ë¡œìž‰"
instanceFollowers: "ì„œë²„ì˜ íŒ”ë¡œì›Œ"
-instanceUsers: "ì„œë²„ì˜ ìœ ì €"
+instanceUsers: "ì„œë²„ì˜ ì‚¬ìš©ìž"
changePassword: "비밀번호 변경"
security: "보안"
retypedNotMatch: "ìž…ë ¥ì´ ì¼ì¹˜í•˜ì§€ 않습니다."
@@ -263,12 +270,12 @@ lookup: "찾아보기"
announcements: "공지사항"
imageUrl: "ì´ë¯¸ì§€ URL"
remove: "삭제"
-removed: "삭제하였습니다"
+removed: "삭제했습니다"
removeAreYouSure: "\"{x}\" ì„(를) 삭제하시겠습니까?"
deleteAreYouSure: "\"{x}\" ì„(를) 삭제하시겠습니까?"
resetAreYouSure: "초기화 하시겠습니까?"
areYouSure: "ê³„ì† ì§„í–‰í•˜ì‹œê² ìŠµë‹ˆê¹Œ?"
-saved: "저장하였습니다"
+saved: "저장했습니다"
messaging: "대화"
upload: "업로드"
keepOriginalUploading: "ì›ë³¸ ì´ë¯¸ì§€ë¥¼ 유지"
@@ -296,7 +303,7 @@ activity: "활ë™"
images: "ì´ë¯¸ì§€"
image: "ì´ë¯¸ì§€"
birthday: "ìƒì¼"
-yearsOld: "만 {age} 세"
+yearsOld: "{age}세"
registeredDate: "등ë¡ì¼"
location: "장소"
theme: "테마"
@@ -313,6 +320,7 @@ selectFile: "íŒŒì¼ ì„ íƒ"
selectFiles: "íŒŒì¼ ì„ íƒ"
selectFolder: "í´ë” ì„ íƒ"
selectFolders: "í´ë” ì„ íƒ"
+fileNotSelected: "파ì¼ì„ ì„ íƒí•˜ì§€ 않았습니다"
renameFile: "íŒŒì¼ ì´ë¦„ 변경"
folderName: "í´ë” ì´ë¦„"
createFolder: "í´ë” 만들기"
@@ -370,7 +378,7 @@ inMb: "메가바ì´íЏ 단위"
bannerUrl: "배너 ì´ë¯¸ì§€ URL"
backgroundImageUrl: "ë°°ê²½ ì´ë¯¸ì§€ URL"
basicInfo: "기본 정보"
-pinnedUsers: "ê³ ì •ëœ ìœ ì €"
+pinnedUsers: "고정한 사용ìž"
pinnedUsersDescription: "\"발견하기\" 페ì´ì§€ ë“±ì— ê³ ì •í•˜ê³  ì‹¶ì€ ìœ ì €ë¥¼ 한 ì¤„ì— í•œ 명씩 ì ìŠµë‹ˆë‹¤."
pinnedPages: "고정한 페ì´ì§€"
pinnedPagesDescription: "ì„œë²„ì˜ ëŒ€ë¬¸ì— ê³ ì •í•˜ê³  ì‹¶ì€ íŽ˜ì´ì§€ì˜ 경로를 한 ì¤„ì— í•˜ë‚˜ì”© ì ìŠµë‹ˆë‹¤."
@@ -437,13 +445,13 @@ moderationNote: "ì¡°ì • 기ë¡"
addModerationNote: "ì¡°ì • ê¸°ë¡ ì¶”ê°€í•˜ê¸°"
moderationLogs: "모ë”ë ˆì´ì…˜ 로그"
nUsersMentioned: "{n}ëª…ì´ ì–¸ê¸‰í•¨"
-securityKeyAndPasskey: "보안 키 ë˜ëŠ” 패스 키"
+securityKeyAndPasskey: "보안 키 ë˜ëŠ” 패스키"
securityKey: "보안 키"
lastUsed: "마지막 사용"
lastUsedAt: "마지막 사용: {t}"
unregister: "ë“±ë¡ í•´ì œ"
passwordLessLogin: "비밀번호 ì—†ì´ ë¡œê·¸ì¸"
-passwordLessLoginDescription: "비밀번호를 사용하지 않고 보안 키 ë˜ëŠ” 패스 키 등으로만 로그ì¸í•©ë‹ˆë‹¤."
+passwordLessLoginDescription: "비밀번호 ì—†ì´ ë³´ì•ˆ 키 ë˜ëŠ” 패스키만 사용해서 로그ì¸í•©ë‹ˆë‹¤."
resetPassword: "비밀번호 재설정"
newPasswordIs: "새로운 비밀번호는 \"{password}\" 입니다"
reduceUiAnimation: "UIì˜ ì• ë‹ˆë©”ì´ì…˜ì„ 줄ì´ê¸°"
@@ -468,10 +476,12 @@ retype: "다시 입력"
noteOf: "{user}ì˜ ë…¸íŠ¸"
quoteAttached: "ì¸ìš©í•¨"
quoteQuestion: "ì¸ìš©í•´ì„œ 작성하시겠습니까?"
+attachAsFileQuestion: "붙여넣으려는 ê¸€ì´ ë„ˆë¬´ ê¹ë‹ˆë‹¤. í…스트 파ì¼ë¡œ 첨부하시겠습니까?"
noMessagesYet: "ì•„ì§ ëŒ€í™”ê°€ 없습니다"
newMessageExists: "새 메시지가 있습니다"
onlyOneFileCanBeAttached: "ë©”ì‹œì§€ì— ì²¨ë¶€í•  수 있는 파ì¼ì€ 하나까지입니다"
signinRequired: "진행하기 ì „ì— ë¡œê·¸ì¸ì„ í•´ 주세요"
+signinOrContinueOnRemote: "계ì†í•˜ë ¤ë©´ 사용하는 서버로 ì´ë™í•˜ê±°ë‚˜ ì´ ì„œë²„ì— ë¡œê·¸ì¸í•´ì•¼ 합니다."
invitations: "초대"
invitationCode: "초대 코드"
checking: "확ì¸í•˜ëŠ” 중입니다"
@@ -486,7 +496,7 @@ strongPassword: "강한 비밀번호"
passwordMatched: "ì¼ì¹˜í•©ë‹ˆë‹¤"
passwordNotMatched: "ì¼ì¹˜í•˜ì§€ 않습니다"
signinWith: "{x}로 로그ì¸"
-signinFailed: "로그ì¸í•  수 없습니다. 사용ìžëª…ê³¼ 비밀번호를 확ì¸í•˜ì—¬ 주십시오."
+signinFailed: "로그ì¸í•  수 없습니다. ì‚¬ìš©ìž ì´ë¦„ê³¼ 비밀번호를 확ì¸í•´ 주십시오."
or: "혹ì€"
language: "언어"
uiLanguage: "UI 표시 언어"
@@ -494,7 +504,7 @@ aboutX: "{x}ì— ëŒ€í•˜ì—¬"
emojiStyle: "ì´ëª¨ì§€ 스타ì¼"
native: "기본"
disableDrawer: "드로어 메뉴를 사용하지 않기"
-showNoteActionsOnlyHover: "노트 ì•¡ì…˜ ë²„íŠ¼ì„ ë§ˆìš°ìŠ¤ë¥¼ ì˜¬ë ¸ì„ ë•Œì—ë§Œ 표시"
+showNoteActionsOnlyHover: "마우스가 올ë¼ê°„ 때ì—ë§Œ 노트 ë™ìž‘ ë²„íŠ¼ì„ í‘œì‹œí•˜ê¸°"
showReactionsCount: "ë…¸íŠ¸ì˜ ë°˜ì‘ ìˆ˜ë¥¼ 표시하기"
noHistory: "기ë¡ì´ 없습니다"
signinHistory: "ë¡œê·¸ì¸ ê¸°ë¡"
@@ -559,7 +569,7 @@ popout: "새 창으로 열기"
volume: "ìŒëŸ‰"
masterVolume: "마스터 볼륨"
notUseSound: "ìŒì†Œê±° 하기"
-useSoundOnlyWhenActive: "Misskeyê°€ 활성화 ë˜ì–´ì ¸ ìžˆì„ ë•Œë§Œ 소리 출력하기"
+useSoundOnlyWhenActive: "Misskey를 활성화한 때ì—ë§Œ 소리를 출력하기"
details: "ìžì„¸ížˆ"
chooseEmoji: "ì´ëª¨ì§€ ì„ íƒ"
unableToProcess: "ìž‘ì—…ì„ ì™„ë£Œí•  수 없습니다"
@@ -588,7 +598,7 @@ deleteAllFiles: "모든 íŒŒì¼ ì‚­ì œ"
deleteAllFilesConfirm: "모든 파ì¼ì„ 삭제하시겠습니까?"
removeAllFollowing: "모든 팔로잉 해제"
removeAllFollowingDescription: "{host} ì„œë²„ì˜ ëª¨ë“  íŒ”ë¡œìž‰ì„ í•´ì œí•©ë‹ˆë‹¤. 해당 서버가 ë” ì´ìƒ 존재하지 않는 경우 ë“±ì— ì‹¤í–‰í•´ 주세요."
-userSuspended: "ì´ ê³„ì •ì€ ì •ì§€ëœ ìƒíƒœìž…니다."
+userSuspended: "ì´ ì‚¬ìš©ìžëŠ” ì •ì§€ë˜ì—ˆìŠµë‹ˆë‹¤."
userSilenced: "ì´ ê³„ì •ì€ ì‚¬ì¼ëŸ°ìŠ¤ëœ ìƒíƒœìž…니다."
yourAccountSuspendedTitle: "ê³„ì •ì´ ì •ì§€ë˜ì—ˆìŠµë‹ˆë‹¤"
yourAccountSuspendedDescription: "ì´ ê³„ì •ì€ ì„œë²„ì˜ ì´ìš© ì•½ê´€ì„ ìœ„ë°˜í•˜ê±°ë‚˜, 기타 다른 ì´ìœ ë¡œ ì¸í•´ ì •ì§€ë˜ì—ˆìŠµë‹ˆë‹¤. ìžì„¸í•œ ì‚¬í•­ì€ ê´€ë¦¬ìžì—게 문ì˜í•´ 주십시오. ê³„ì •ì„ ìƒˆë¡œ ìƒì„±í•˜ì§€ 마십시오."
@@ -752,7 +762,7 @@ experimentalFeatures: "실험실"
experimental: "실험실"
thisIsExperimentalFeature: "ì´ ê¸°ëŠ¥ì€ ì‹¤í—˜ì ì¸ 기능입니다. ì‚¬ì–‘ì´ ë³€ê²½ë˜ê±°ë‚˜ ì •ìƒì ìœ¼ë¡œ ë™ìž‘하지 ì•Šì„ ê°€ëŠ¥ì„±ì´ ìžˆìŠµë‹ˆë‹¤."
developer: "개발ìž"
-makeExplorable: "\"발견하기\"ì— ë‚´ 계정 ë³´ì´ê¸°"
+makeExplorable: "ê³„ì •ì„ ì‰½ê²Œ 발견하ë„ë¡ í•˜ê¸°"
makeExplorableDescription: "비활성화하면 \"발견하기\"ì— ë‚˜ì˜ ê³„ì •ì„ í‘œì‹œí•˜ì§€ 않습니다."
showGapBetweenNotesInTimeline: "타임ë¼ì¸ì˜ 노트 사ì´ë¥¼ ë„워서 표시"
duplicate: "복제"
@@ -798,7 +808,7 @@ emailNotification: "ë©”ì¼ ì•Œë¦¼"
publish: "게시"
inChannelSearch: "채ë„ì—서 검색"
useReactionPickerForContextMenu: "ìš°í´ë¦­í•˜ì—¬ 리액션 ì„ íƒê¸° 열기"
-typingUsers: "{users} ë‹˜ì´ ìž…ë ¥í•˜ê³  있어요.."
+typingUsers: "{users}ë‹˜ì´ ìž…ë ¥ 중"
jumpToSpecifiedDate: "특정 날짜로 ì´ë™"
showingPastTimeline: "ê³¼ê±°ì˜ íƒ€ìž„ë¼ì¸ì„ 표시하고 있어요"
clear: "지우기"
@@ -832,6 +842,7 @@ administration: "관리"
accounts: "계정"
switch: "전환"
noMaintainerInformationWarning: "ê´€ë¦¬ìž ì •ë³´ê°€ 설정ë˜ì–´ 있지 않습니다."
+noInquiryUrlWarning: "문ì˜ì²˜ 주소를 설정하지 않았습니다."
noBotProtectionWarning: "Bot ë°©ì–´ê°€ 설정ë˜ì–´ 있지 않습니다."
configure: "설정하기"
postToGallery: "ê°¤ëŸ¬ë¦¬ì— ì—…ë¡œë“œ"
@@ -1021,6 +1032,7 @@ thisPostMayBeAnnoyingHome: "í™ˆì— ê²Œì‹œ"
thisPostMayBeAnnoyingCancel: "그만ë‘기"
thisPostMayBeAnnoyingIgnore: "ì´ëŒ€ë¡œ 게시"
collapseRenotes: "ì´ë¯¸ 본 리노트를 간략화하기"
+collapseRenotesDescription: "ë°˜ì‘ì´ë‚˜ 리노트를 한 노트를 접어서 표시합니다."
internalServerError: "내부 서버 오류"
internalServerErrorDescription: "ë‚´ë¶€ 서버ì—서 예기치 ì•Šì€ ì˜¤ë¥˜ê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤."
copyErrorInfo: "오류 정보 복사"
@@ -1090,7 +1102,7 @@ serverRules: "서버 규칙"
pleaseConfirmBelowBeforeSignup: "ì´ ì„œë²„ì— ê°€ìž…í•˜ê¸° ì „ì— ì•„ëž˜ ì‚¬í•­ì„ í™•ì¸í•˜ì—¬ 주십시오."
pleaseAgreeAllToContinue: "계ì†í•˜ì‹œë ¤ë©´ 모든 í•­ëª©ì— ë™ì˜í•˜ì‹­ì‹œì˜¤."
continue: "계ì†"
-preservedUsernames: "ì˜ˆì•½ëœ ì‚¬ìš©ìžëª…"
+preservedUsernames: "예약한 ì‚¬ìš©ìž ì´ë¦„"
preservedUsernamesDescription: "예약할 사용ìžëª…ì„ í•œ ì¤„ì— í•˜ë‚˜ì”© 입력합니다. 여기ì—서 지정한 사용ìžëª…으로는 ê³„ì •ì„ ìƒì„±í•  수 없게 ë©ë‹ˆë‹¤. 단, ê´€ë¦¬ìž ê¶Œí•œìœ¼ë¡œ ê³„ì •ì„ ìƒì„±í•  때ì—는 해당ë˜ì§€ 않으며, ì´ë¯¸ 존재하는 ê³„ì •ë„ ì˜í–¥ì„ 받지 않습니다."
createNoteFromTheFile: "ì´ íŒŒì¼ë¡œ 노트를 작성"
archive: "ì•„ì¹´ì´ë¸Œ"
@@ -1230,10 +1242,22 @@ useTotp: "ì¼íšŒìš© 비밀번호 사용"
useBackupCode: "백업 코드 사용"
launchApp: "앱 실행"
useNativeUIForVideoAudioPlayer: "브ë¼ìš°ì € UIì—서 미디어 재ìƒ"
+keepOriginalFilename: "ì›ë³¸ íŒŒì¼ ì´ë¦„ì„ ìœ ì§€"
+keepOriginalFilenameDescription: "ì´ ì„¤ì •ì„ ë„ë©´ 업로드를 í•  때 íŒŒì¼ ì´ë¦„ì´ ìžë™ìœ¼ë¡œ 무작위 문ìžì—´ë¡œ ë°”ë€ë‹ˆë‹¤."
+noDescription: "ì„¤ëª…ë¬¸ì´ ì—†ìŠµë‹ˆë‹¤"
+alwaysConfirmFollow: "íŒ”ë¡œìš°ì¼ ë•Œ í•­ìƒ í™•ì¸í•˜ê¸°"
+inquiry: "문ì˜í•˜ê¸°"
+tryAgain: "다시 시ë„í•´ 주세요."
+confirmWhenRevealingSensitiveMedia: "민ê°í•œ 미디어를 ì—´ 때 ë‘ ë²ˆ 확ì¸"
_delivery:
+ status: "전송 ìƒíƒœ"
stop: "ì •ì§€ë¨"
+ resume: "전송 다시 시작"
_type:
none: "ë°°í¬ ì¤‘"
+ manuallySuspended: "ìˆ˜ë™ ì •ì§€ 중"
+ goneSuspended: "서버 삭제를 ì´ìœ ë¡œ ì •ì§€ 중"
+ autoSuspendedForNotResponding: "서버 ì‘답 ì—†ìŒì„ ì´ìœ ë¡œ ì •ì§€ 중"
_bubbleGame:
howToPlay: "설명"
hold: "홀드"
@@ -1359,6 +1383,8 @@ _serverSettings:
fanoutTimelineDescription: "활성화하면 ê°ì¢… 타임ë¼ì¸ì„ 가져올 ë•Œì˜ ì„±ëŠ¥ì„ ëŒ€í­ í–¥ìƒí•˜ë©°, ë°ì´í„°ë² ì´ìŠ¤ì˜ ë¶€í•˜ë¥¼ ì¤„ì¼ ìˆ˜ 있습니다. 단, Redisì˜ ë©”ëª¨ë¦¬ ì‚¬ìš©ëŸ‰ì´ ì¦ê°€í•©ë‹ˆë‹¤. ì„œë²„ì˜ ë©”ëª¨ë¦¬ ìš©ëŸ‰ì´ ìž‘ê±°ë‚˜, 서비스가 불안정해지는 경우 비활성화할 수 있습니다."
fanoutTimelineDbFallback: "ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 예비로 사용하기"
fanoutTimelineDbFallbackDescription: "활성화하면 타임ë¼ì¸ì˜ ìºì‹œë˜ì–´ 있지 ì•Šì€ ë¶€ë¶„ì— ëŒ€í•´ DBì— ì§ˆì˜í•˜ì—¬ 정보를 가져옵니다. 비활성화하면 ì´ë¥¼ 실행하지 않ìŒìœ¼ë¡œì¨ ì„œë²„ì˜ ë¶€í•˜ë¥¼ ì¤„ì¼ ìˆ˜ 있지만, 타임ë¼ì¸ì—서 가져올 수 있는 게시물 범위가 한정ë©ë‹ˆë‹¤."
+ inquiryUrl: "문ì˜ì²˜ URL"
+ inquiryUrlDescription: "서버 ìš´ì˜ìžì—게 보내는 ë¬¸ì˜ ì–‘ì‹ì˜ URLì´ë‚˜ ìš´ì˜ìžì˜ ì—°ë½ì²˜ ë“±ì´ ì ížŒ 웹 페ì´ì§€ì˜ URLì„ ì„¤ì •í•©ë‹ˆë‹¤."
_accountMigration:
moveFrom: "다른 계정ì—서 ì´ ê³„ì •ìœ¼ë¡œ ì´ì‚¬"
moveFromSub: "다른 ê³„ì •ì— ëŒ€í•œ ë³„ì¹­ì„ ìƒì„±"
@@ -1675,10 +1701,11 @@ _role:
canManageAvatarDecorations: "아바타 꾸미기 관리"
driveCapacity: "드ë¼ì´ë¸Œ 용량"
alwaysMarkNsfw: "파ì¼ì„ í•­ìƒ NSFW로 지정"
+ canUpdateBioMedia: "아바타 ë° ë°°ë„ˆ ì´ë¯¸ì§€ 변경 허용"
pinMax: "고정할 수 있는 노트 수"
antennaMax: "만들 수 있는 안테나 수"
wordMuteMax: "단어 뮤트할 수 있는 ë¬¸ìž ìˆ˜"
- webhookMax: "만들 수 있는 ì›¹í›„í¬ ìˆ˜"
+ webhookMax: "만들 수 있는 Webhook 수"
clipMax: "만들 수 있는 í´ë¦½ 수"
noteEachClipsMax: "í´ë¦½ì— ë„£ì„ ìˆ˜ 있는 노트 수"
userListMax: "만들 수 있는 ì‚¬ìš©ìž ë¦¬ìŠ¤íŠ¸ 수"
@@ -1693,6 +1720,11 @@ _role:
roleAssignedTo: "ìˆ˜ë™ ì—­í• ì— ì´ë¯¸ 할당ë¨"
isLocal: "로컬 사용ìž"
isRemote: "리모트 사용ìž"
+ isCat: "ê³ ì–‘ì´ ì‚¬ìš©ìž"
+ isBot: "ë´‡ 사용ìž"
+ isSuspended: "ì •ì§€ëœ ì‚¬ìš©ìž"
+ isLocked: "잠금 계정 사용ìž"
+ isExplorable: "â€˜ê³„ì •ì„ ì‰½ê²Œ 발견하ë„ë¡ í•˜ê¸°â€™ë¥¼ 활성화한 사용ìž"
createdLessThan: "가입한 ì§€ ë‹¤ìŒ ì¼ìˆ˜ ì´ë‚´ì¸ 유저"
createdMoreThan: "가입한 ì§€ ë‹¤ìŒ ì¼ìˆ˜ ì´ìƒì¸ 유저"
followersLessThanOrEq: "팔로워 수가 ë‹¤ìŒ ì´í•˜ì¸ 유저"
@@ -1913,8 +1945,6 @@ _sfx:
note: "새 노트"
noteMy: "내 노트"
notification: "알림"
- antenna: "안테나 수신"
- channel: "ì±„ë„ ì•Œë¦¼"
reaction: "리액션 ì„ íƒ"
_soundSettings:
driveFile: "드ë¼ì´ë¸Œì— 있는 오디오를 사용"
@@ -1975,6 +2005,7 @@ _2fa:
backupCodesDescription: "ì¸ì¦ ì•±ì„ ì‚¬ìš©í•  수 없게 ëœ ê²½ìš° 아래 백업 코드를 사용하여 ê³„ì •ì— ì•¡ì„¸ìŠ¤ í•  수 있습니다.ì´ ì½”ë“œë“¤ì€ ë°˜ë“œì‹œ 안전한 ìž¥ì†Œì— ë³´ê´€í•˜ì‹­ì‹œì˜¤.ê° ì½”ë“œëŠ” 한 번만 사용할 수 있습니다."
backupCodeUsedWarning: "백업 코드가 사용ë˜ì—ˆìŠµë‹ˆë‹¤.ì¸ì¦ ì•±ì„ ì‚¬ìš©í•  수 없게 ëœ ê²½ìš°, ì¡°ì†ížˆ ì¸ì¦ ì•±ì„ ë‹¤ì‹œ 설정해 주십시오."
backupCodesExhaustedWarning: "백업 코드가 ëª¨ë‘ ì‚¬ìš©ë˜ì—ˆìŠµë‹ˆë‹¤.ì¸ì¦ ì•±ì„ ì‚¬ìš©í•  수 없는 경우 ë” ì´ìƒ ê³„ì •ì— ì•¡ì„¸ìŠ¤í•˜ëŠ” ê²ƒì´ ë¶ˆê°€ëŠ¥í•©ë‹ˆë‹¤.ì¸ì¦ ì•±ì„ ë‹¤ì‹œ 등ë¡í•´ 주세요."
+ moreDetailedGuideHere: "ì—¬ê¸°ì— ìžì„¸í•œ ì„¤ëª…ì´ ìžˆìŠµë‹ˆë‹¤"
_permissions:
"read:account": "ê³„ì •ì˜ ì •ë³´ë¥¼ 봅니다"
"write:account": "ê³„ì •ì˜ ì •ë³´ë¥¼ 변경합니다"
@@ -2163,7 +2194,7 @@ _postForm:
c: "ë¬´ì—‡ì„ ìƒê°í•˜ê³  있나요?"
d: "ë§í•˜ê³  ì‹¶ì€ ê²Œ 있나요?"
e: "ì—¬ê¸°ì— ì ì–´ 주세요"
- f: "글 쓰기를 기다려요…"
+ f: "작성해주시길 기다리고 있어요..."
_profile:
name: "ì´ë¦„"
username: "ì‚¬ìš©ìž ì´ë¦„"
@@ -2338,6 +2369,7 @@ _deck:
alwaysShowMainColumn: "ë©”ì¸ ì¹¼ëŸ¼ í•­ìƒ í‘œì‹œ"
columnAlign: "칼럼 정렬"
addColumn: "칼럼 추가"
+ newNoteNotificationSettings: "새 노트 알림 설정"
configureColumn: "칼럼 설정"
swapLeft: "왼쪽으로 ì´ë™"
swapRight: "오른쪽으로 ì´ë™"
@@ -2376,9 +2408,9 @@ _drivecleaner:
orderByCreatedAtAsc: "등ë¡ì¼ì´ ì˜¤ëž˜ëœ ìˆœ"
_webhookSettings:
createWebhook: "Webhook ìƒì„±"
+ modifyWebhook: "Webhook 수정"
name: "ì´ë¦„"
secret: "시í¬ë¦¿"
- events: "Webhookì„ ì‹¤í–‰í•  타ì´ë°"
active: "활성화"
_events:
follow: "누군가를 íŒ”ë¡œìš°í–ˆì„ ë•Œ"
@@ -2388,6 +2420,26 @@ _webhookSettings:
renote: "누군가 ë‚´ ê¸€ì„ ë¦¬ë…¸íŠ¸í–ˆì„ ë•Œ"
reaction: "누군가 ë‚´ ë…¸íŠ¸ì— ë¦¬ì•¡ì…˜í–ˆì„ ë•Œ"
mention: "누군가 나를 ë©˜ì…˜í–ˆì„ ë•Œ"
+ _systemEvents:
+ abuseReport: "유저로부터 신고를 ë°›ì•˜ì„ ë•Œ"
+ abuseReportResolved: "ë°›ì€ ì‹ ê³ ë¥¼ ì²˜ë¦¬í–ˆì„ ë•Œ"
+ userCreated: "유저가 ìƒì„±ë˜ì—ˆì„ 때"
+ deleteConfirm: "Webhookì„ ì‚­ì œí• ê¹Œìš”?"
+_abuseReport:
+ _notificationRecipient:
+ createRecipient: "ì‹ ê³  ìˆ˜ì‹ ìž ì¶”ê°€"
+ modifyRecipient: "ì‹ ê³  ìˆ˜ì‹ ìž íŽ¸ì§‘"
+ recipientType: "알림 수신 유형"
+ _recipientType:
+ mail: "ì´ë©”ì¼"
+ webhook: "Webhook"
+ _captions:
+ mail: "모ë”ë ˆì´í„° ê¶Œí•œì„ ê°€ì§„ 사용ìžì˜ ì´ë©”ì¼ ì£¼ì†Œì— ì•Œë¦¼ì„ ë³´ëƒ…ë‹ˆë‹¤ (신고를 ë°›ì€ ë•Œì—ë§Œ)"
+ webhook: "지정한 SystemWebhookì— ì•Œë¦¼ì„ ë³´ëƒ…ë‹ˆë‹¤ (신고를 ë°›ì€ ë•Œì™€ í•´ê²°í–ˆì„ ë•Œì— ì†¡ì‹ )"
+ keywords: "키워드"
+ notifiedUser: "ì‹ ê³  ì•Œë¦¼ì„ ë³´ë‚¼ 유저"
+ notifiedWebhook: "사용할 Webhook"
+ deleteConfirm: "수신ìžë¥¼ 삭제하시겠습니까?"
_moderationLogTypes:
createRole: "ì—­í•  ìƒì„±"
deleteRole: "역할 삭제"
@@ -2403,7 +2455,7 @@ _moderationLogTypes:
updateUserNote: "ì¡°ì • ê¸°ë¡ ê°±ì‹ "
deleteDriveFile: "íŒŒì¼ ì‚­ì œ"
deleteNote: "노트 삭제"
- createGlobalAnnouncement: "모든 공지사항 만들기"
+ createGlobalAnnouncement: "ì „ì—­ 공지사항 ìƒì„±"
createUserAnnouncement: "ì‚¬ìš©ìž ê³µì§€ì‚¬í•­ 만들기"
updateGlobalAnnouncement: "모든 공지사항 수정"
updateUserAnnouncement: "ì‚¬ìš©ìž ê³µì§€ì‚¬í•­ 수정"
@@ -2425,6 +2477,12 @@ _moderationLogTypes:
deleteAvatarDecoration: "아바타 ìž¥ì‹ ì‚­ì œ"
unsetUserAvatar: "유저 아바타 제거"
unsetUserBanner: "유저 배너 제거"
+ createSystemWebhook: "SystemWebhookì„ ìƒì„±"
+ updateSystemWebhook: "SystemWebhookì„ ìˆ˜ì •"
+ deleteSystemWebhook: "SystemWebhookì„ ì‚­ì œ"
+ createAbuseReportNotificationRecipient: "ì‹ ê³  알림 ìˆ˜ì‹ ìž ìƒì„±"
+ updateAbuseReportNotificationRecipient: "ì‹ ê³  알림 ìˆ˜ì‹ ìž íŽ¸ì§‘"
+ deleteAbuseReportNotificationRecipient: "ì‹ ê³  알림 ìˆ˜ì‹ ìž ì‚­ì œ"
_fileViewer:
title: "íŒŒì¼ ìƒì„¸"
type: "íŒŒì¼ ìœ í˜•"
diff --git a/locales/lo-LA.yml b/locales/lo-LA.yml
index 087bac3745..1bead5635d 100644
--- a/locales/lo-LA.yml
+++ b/locales/lo-LA.yml
@@ -18,15 +18,15 @@ enterUsername: "ປ້ອນຊື່ຜູ້ໃຊ້"
renotedBy: "Renoted ໂດຠ{user}"
noNotes: "ບà»à»ˆàº¡àºµ note"
noNotifications: "ບà»à»ˆàº¡àºµàºàº²àº™à»àºˆà»‰àº‡à»€àº•ືອນ"
-instance: "ອີນສະà»àº•ນ"
-settings: "àºàº³àº™àº»àº”ຄ່າ"
+instance: "ເຊີຟເວີຣ໌"
+settings: "ຕັ້ງຄ່າ"
notificationSettings: "ຕັ້ງຄ່າàºàº²àº™à»àºˆà»‰àº‡à»€àº•ືອນ"
basicSettings: "àºàº²àº™àº•ັ້ງຄ່າພື້ນຖານ"
otherSettings: "àºàº²àº™àº•ັ້ງຄ່າອື່ນໆ"
-openInWindow: "ເປີດໃນປ່ອງຢ້ຽມ"
-profile: "ໂພຼຟາàº"
+openInWindow: "ເປີດໃນ window"
+profile: "ໂປຣໄຟລ໌"
timeline: "ໄທມ໌ໄລນ໌"
-noAccountDescription: "ຜູ້ໃຊ້ນີ້àºàº±àº‡àºšà»à»ˆà»„ດ້ຂຽນໃນຊີວະປະຫວັດຂອງເຂົາເຈົ້າເທື່ອ"
+noAccountDescription: "ຜູ້ໃຊ້ຄົນນີ້àºàº±àº‡àºšà»à»ˆà»„ດ້ຂຽນຄຳà»àº™àº°àº™àº³à»‚ຕ"
login: "ເຂົ້າ​ສູ່​ລະ​ບົບ"
loggingIn: "àºàº³àº¥àº±àº‡à»€àº‚ົ້າສູ່ລະບົບ..."
logout: "ອອàºâ€‹àºˆàº²àºâ€‹àº¥àº°â€‹àºšàº»àºš"
@@ -37,7 +37,7 @@ users: "ຜູ້ໃຊ້"
addUser: "ເພີ່ມຜູ້ໃຊ້"
favorite: "ເພີ່ມໃສ່ລາàºàºàº²àº™àº—ີ່ມັàº"
favorites: "ລາàºàºàº²àº™àº—ີ່ມັàº"
-unfavorite: "ລຶບອອàºàºˆàº²àºàº¥àº²àºàºàº²àº™àº—ີ່ມັàº"
+unfavorite: "ເອົາອອàºàºˆàº²àºàº¥àº²àºàºàº²àº™àº—ີ່ມັàº"
favorited: "ເພີ່ມໃສ່ລາàºàºàº²àº™àº—ີ່ມັàºà»àº¥à»‰àº§"
alreadyFavorited: "ເພີ່ມເຂົ້າໃນລາàºàºàº²àº™àº—ີ່ມັàºà»àº¥à»‰àº§."
cantFavorite: "ບà»à»ˆàºªàº²àº¡àº²àº”ເພີ່ມໃສ່ລາàºàºàº²àº™àº—ີ່ມັàºà»„ດ້."
@@ -48,41 +48,41 @@ copyLink: "ຄັດລອàºàº¥àº´à»‰àº‡"
copyLinkRenote: "ຄັດລອàºàº¥àº´à»‰àº‡àº‚ອງ renote"
delete: "ລຶບ"
deleteAndEdit: "ລຶບ​à»àº¥àº°â€‹à»àºà»‰â€‹à»„ຂ​"
-deleteAndEditConfirm: "ເຈົ້າ​à»àº™à»ˆâ€‹à»ƒàºˆâ€‹àºšà»à»ˆ? ທີ່ທ່ານຕ້ອງàºàº²àº™àº—ີ່ຈະລຶບ note ນີ້ à»àº¥àº°à»àºà»‰à»„ຂມັນ ທ່ານອາດຈະສູນເສຠreaction, renote, à»àº¥àº°àºàº²àº™àº•ອບàºàº±àºšàº—ັງà»àº»àº”"
+deleteAndEditConfirm: "ຕ້ອງàºàº²àº™àº¥àº¶àºš note ນີ້à»àº¥àº°à»àºà»‰à»„ຂໃà»à»ˆà»àº¡à»ˆàº™àºšà»à»ˆ? reaction, renote à»àº¥àº°àºàº²àº™àº•ອບàºàº±àºšàº•à»à»ˆ note ນີ້ ທັງເບິດຈະຖືàºàº¥àº¶àºšàº­àº­àº"
addToList: "ເພີ່ມໃສ່ລາàºàºŠàº·à»ˆ"
addToAntenna: "ເພີ່ມໃສ່ເສົາອາàºàº²àº”"
sendMessage: "ສົ່ງຂà»à»‰àº„ວາມ"
-copyRSS: "ສຳເນົາ RSS"
-copyUsername: "ສຳເນົາຊື່ຜູ້ໃຊ້"
-copyUserId: "ສຳເນົາ ID ຜູ້ໃຊ້"
-copyNoteId: "ສຳເນົາ ID ບັນທຶàº"
-copyFileId: "ສຳເນົາ ID ໄຟລ໌"
-copyFolderId: "ສຳເນົາ ID ໂຟນເດີ"
-copyProfileUrl: "ສຳເນົາ URL ໂປຣໄຟລ໌"
+copyRSS: "ຄັດລອຠRSS"
+copyUsername: "ຄັດລອàºàºŠàº·à»ˆàºœàº¹à»‰à»ƒàºŠà»‰"
+copyUserId: "ຄັດລອຠID ຜູ້ໃຊ້"
+copyNoteId: "ຄັດລອຠID ຂອງ note"
+copyFileId: "ຄັດລອຠID ໄຟລ໌"
+copyFolderId: "ຄັດລອຠID ໂຟລ໌ເດີຣ໌"
+copyProfileUrl: "ຄັດລອຠURL ໂປຣໄຟລ໌"
searchUser: "ຄົ້ນຫາຜູ້ໃຊ້"
-reply: "ຕອບ​ໄປ​ທີ"
+reply: "ຕອບ​àºàº±àºš"
loadMore: "ໂຫຼດເພີ່ມເຕີມ"
showMore: "ໂຫຼດເພີ່ມເຕີມ"
showLess: "ປິດ"
-youGotNewFollower: "ໄດ້ຕິດຕາມທ່ານ"
-receiveFollowRequest: "ປະຕິບັດຕາມຄà»àº²àº®à»‰àº­àº‡àº‚à»àº—ີ່ໄດ້ຮັບ"
-followRequestAccepted: "ຜູ້ຕິດຕາມໄດ້àºàº­àº¡àº®àº±àºšàº„à»àº²àº®à»‰àº­àº‡àº‚à»àº‚ອງທ່ານ"
-mention: "àºà»ˆàº²àº§àº–ືງ"
-mentions: "àºà»ˆàº²àº§à»€àº–ິງ"
+youGotNewFollower: "ໄດ້ຕິດຕາມເຈົ້າ"
+receiveFollowRequest: "ມີຄຳຂà»àº•ິດຕາມສົ່ງມາ"
+followRequestAccepted: "àºàº²àº™àº•ິດຕາມໄດ້ຮັບອນຸàºàº²àº”à»àº¥à»‰àº§"
+mention: "ເວົ້າເຖີງ"
+mentions: "ເວົ້າເຖີງເຈົ້າ"
directNotes: "ໂພສ Direct note"
importAndExport: "ນà»àº²à»€àº‚ົ້າ / ສົ່ງອອàº"
import: "ນຳເຂົ້າ"
export: "ສົ່ງອອàº"
files: "ໄຟລ໌"
download: "ດາວໂຫລດ"
-driveFileDeleteConfirm: "ທ່ານà»àº™à»ˆà»ƒàºˆàºšà»à»ˆàº§à»ˆàº²àº•້ອງàºàº²àº™àº¥àº¶àºšà»„ຟລ໌ \"{name}\"? note ທີ່ມີໄຟລ໌à»àº™àºšàº™àºµà»‰àºˆàº°àº–ືàºàº¥àº¶àºšàº–ິ້ມ"
-unfollowConfirm: "ທ່ານà»àº™à»ˆà»ƒàºˆàºšà»à»ˆàº§à»ˆàº²àº•້ອງàºàº²àº™à»€àºŠàº»àº²àº•ິດຕາມ {name}?"
-exportRequested: "ໃນເວລາທີ່ທ່ານໄດ້ຮ້ອງຂà»àºàº²àº™àºªàº»à»ˆàº‡àº­àº­àº ມັນອາດຈະໃຊ້ເວລາບາງເວລາ à»àº¥àº°àº¡àº±àº™àºˆàº°àº–ືàºà»€àºžàºµà»ˆàº¡à»ƒàºªà»ˆ drive ຂອງທ່ານເມື່ອມັນສຳເລັດà»àº¥à»‰àº§"
-importRequested: "ໃນເວລາທີ່ທ່ານໄດ້ຮ້ອງຂà»àºàº²àº™àº™à»àº²à»€àº‚ົ້າ ມັນອາດຈະໃຊ້ເວລາບາງເວລາ"
+driveFileDeleteConfirm: "ຕ້ອງàºàº²àº™àº¥àº¶àºšà»„ຟລ໌ “{name}†à»àº¡à»ˆàº™àºšà»à»ˆ? Note ທີ່à»àº™àºšàº¡àº²àºàº±àºšà»„ຟລ໌ນີ້ຈະຖືàºàº¥àº¶àºšàº­àº­àº"
+unfollowConfirm: "ຕ້ອງàºàº²àº™à»€àº¥àºµàºàº•ິດຕາມ {name} à»àº¡à»ˆàº™àºšà»à»ˆ?"
+exportRequested: "ເຈົ້າໄດ້ຮ້ອງຂà»àºàº²àº™àºªàº»à»ˆàº‡àº­àº­àº ອາດໃຊ້ເວລາຈັàºà»œà»ˆàº­àº ເມື່ອà»àº¥à»‰àº§àºˆàº°àº–ືàºà»€àºžàºµà»ˆàº¡à»ƒàºªà»ˆ drive"
+importRequested: "ເຈົ້າໄດ້ຮ້ອງຂà»àºàº²àº™àº™àº³à»€àº‚ົ້າ àºàº²àº™àº”ຳເນິນàºàº²àº™àº™àºµà»‰àº­àº²àº”ໃຊ້ເວລາຈັàºà»œà»ˆàº­àº"
lists: "ລາàºàºàº²àº™"
-noLists: "ທ່ານ​ບà»à»ˆâ€‹àº¡àºµâ€‹àº¥àº²àºâ€‹àºàº²àº™â€‹à»ƒàº”ໆ​"
-note: "ບັນທຶàº"
-notes: "ບັນທຶàº"
+noLists: "ບà»à»ˆâ€‹àº¡àºµâ€‹àº¥àº²àºâ€‹àºàº²àº™â€‹à»ƒàº”ໆ​"
+note: "Note"
+notes: "Note"
following: "àºàº³àº¥àº±àº‡àº•ິດຕາມ"
followers: "ຜູ້ຕິດຕາມ"
followsYou: "ຕິດ​ຕາມ​ເຈົ້າ"
@@ -124,11 +124,11 @@ reactions: "reaction"
attachCancel: "ເອົາໄຟລ໌à»àº™àºš"
mute: "ປີດສຽງ"
unmute: "ເປີດສຽງ"
-block: "ບ໋ອàº"
-unblock: "àºàº»àºà»€àº¥àºµàºàºàº²àº®àº»àºšàº¥àº±àº­àº"
+block: "ບລັອàº"
+unblock: "ເລີàºàºšàº¥àº±àº­àº"
suspend: "ລະງັບ"
unsuspend: "ເຊົາ​ລະ​ງັບ"
-selectList: "ເລືອàºàºšàº±àº™àºŠàºµàº¥àº²àºàºàº²àº™"
+selectList: "ເລືອàºàº¥àº²àºàºŠàº·à»ˆ"
editList: "à»àºà»‰à»„ຂລາàºàºŠàº·à»ˆ"
selectChannel: "ເລືອàºàºŠà»ˆàº­àº‡"
selectAntenna: "ເລືອàºà»€àºªàº»àº²àº­àº²àºàº²àº”"
@@ -151,30 +151,30 @@ flagShowTimelineRepliesDescription: "ສະà»àº”ງàºàº²àº™àº•ອບàºàº±àºšà
autoAcceptFollowed: "ອະນຸມັດອັດຕະໂນມັດຕາມຄຳຮ້ອງຂà»àºˆàº²àºàºœàº¹à»‰à»ƒàºŠà»‰àº—ີ່ທ່ານàºàº³àº¥àº±àº‡àº•ິດຕາມຢູ່"
addAccount: "ເພີ່ມບັນຊີ"
loginFailed: "àºàº²àº™à»€àº‚ົ້າສູ່ລະບົບບà»à»ˆàºªàº³à»€àº¥àº±àº”"
-showOnRemote: "ເບິ່ງຢູ່ໃນຕົວຢ່າງໄລàºàº°à»„àº"
+showOnRemote: "ເບິ່ງໃນເຊີຟເວີຣ໌ໄລàºàº°à»„àº"
general: "ທົ່ວໄປ"
wallpaper: "ພາບພື້ນຫລັງ"
setWallpaper: "ຕັ້ງເປັນພາບພື້ນຫຼັງ"
removeWallpaper: "ລຶບຮູບວà»à»€àº›à»€àº›àºµàº­àº­àº"
searchWith: "ຊອàºàº«àº²: {q}"
-youHaveNoLists: "ທ່ານ​ບà»à»ˆâ€‹àº¡àºµâ€‹àº¥àº²àºâ€‹àºàº²àº™â€‹à»ƒàº”ໆ​"
+youHaveNoLists: "ເຈົ້າບà»à»ˆàº¡àºµàº¥àº²àºàºŠàº·à»ˆà»ƒàº”ໆ"
proxyAccount: "ບັນຊີພຣັອàºàºŠàºµ"
-host: "ໂຮດສ"
+host: "ໂຮສຕ໌"
selectUser: "ເລືອàºàºœàº¹à»‰à»ƒàºŠà»‰"
recipient: "ເຖິງ"
annotation: "ຄຳເຫັນ"
federation: "ສະຫະພັນ"
-instances: "ອີນສະà»àº•ນ"
+instances: "ເຊີຟເວີຣ໌"
registeredAt: "ລົງທະບຽນຢູ່"
storageUsage: "ບ່ອນ​ຈັດ​ເàºàº±àºšâ€‹àº‚à»à»‰â€‹àº¡àº¹àº™àº—ີ່ໃຊ້"
-charts: "ອັນດັບເພງ"
+charts: "à»àºœàº™àºžàº¹àº¡"
perHour: "ຕà»à»ˆàºŠàº»à»ˆàº§à»‚ມງ"
perDay: "ຕà»à»ˆâ€‹àº¡àº·à»‰"
stopActivityDelivery: "ຢຸດເຊົາàºàº²àº™àºªàº»à»ˆàº‡àºàº´àº”ຈະàºà»àº²"
blockThisInstance: "ຂັດຂວາງຕົວຢ່າງນີ້"
operations: "àºàº²àº™àº”ຳເນີນງານ"
software: "ຊອບà»àº§"
-version: "ສະບັບ"
+version: "ເວີຣ໌ຊັນ"
metadata: "Metadata"
withNFiles: "{n} ໄຟລ໌(s)"
monitor: "ຈà»àºžàº²àºš"
@@ -199,15 +199,15 @@ federating: "ສະຫະພັນ"
blocked: "ບລັອàºà»àº¥à»‰àº§ "
suspended: "ໂຈະ"
all: "ທັງà»àº»àº”"
-subscribing: "ສະà»àº±àºàºªàº°àº¡àº²àºŠàº´àºà»àº¥àº±àº§"
-publishing: "àºàº²àº™â€‹àºžàº´àº¡â€‹à»€àºœàºµàºâ€‹à»àºœà»ˆ"
+subscribing: "àºàº³àº¥àº±àº‡àºªàº°àº¡àº±àºàºªàº°àº¡àº²àºŠàº´àº"
+publishing: "àºàº³àº¥àº±àº‡â€‹à»€àºœàºµàºâ€‹à»àºžà»ˆ"
notResponding: "ບà»à»ˆàº•ອບສະໜອງ"
-instanceFollowing: "àºàº³àº¥àº±àº‡àº•ິດຕາມສຸດຕົວຢ່າງ"
-instanceFollowers: "ຜູ້ຕິດຕາມຕົວຢ່າງ"
-instanceUsers: "ຜູ້​ຊົມ​ໃຊ້​ຂອງ​ຕົວ​ຢ່າງ​ນີ້​"
+instanceFollowing: "àºàº³àº¥àº±àº‡àº•ິດຕາມບົນເຊີຟເວີຣ໌"
+instanceFollowers: "ຜູ້ຕິດຕາມຂອງເຊີຟເວີຣ໌"
+instanceUsers: "ຜູ້​ໃຊ້​ຂອງ​ເຊີຟເວີຣ໌ນີ້"
changePassword: "ປ່ຽນ​ລະ​ຫັດ​ຜ່ານ"
security: "ຄວາມປອດໄພ"
-retypedNotMatch: "ວັດສະດຸປ້ອນບà»à»ˆàºàº»àº‡àºàº±àº™"
+retypedNotMatch: "ປ້ອນຂà»à»‰àº¡àº¹àº™àºšà»à»ˆàºàº»àº‡àºàº±àº™"
currentPassword: "ລະຫັດຜ່ານປະຈຸບັນ"
newPassword: "ລະຫັດຜ່ານໃà»à»ˆ"
newPasswordRetype: "ໃສ່ລະຫັດຜ່ານໃà»à»ˆàº­àºµàºà»€àº—ື່ອໜຶ່ງ"
@@ -223,14 +223,14 @@ remove: "ລຶບ"
removed: "ລຶບà»àº¥à»‰àº§"
resetAreYouSure: "ຣີ​ເຊັດບ�"
saved: "ບັນທຶàºà»àº¥à»‰àº§"
-messaging: "à»àºŠà»‹àº”"
+messaging: "à»àºŠàº±àº•"
upload: "ອັບໂຫຼດ"
keepOriginalUploading: "ຮັàºàºªàº²àº®àº¹àºšàºžàº²àºšàº•ົ້ນສະບັບ"
fromDrive: "ຈາຠDrive"
fromUrl: "ຈາຠURL"
uploadFromUrl: "ອັບໂຫຼດຈາຠURL"
uploadFromUrlDescription: "URL ຂອງໄຟລ໌ທີ່ທ່ານຕ້ອງàºàº²àº™àº­àº±àºšà»‚ຫລດ"
-uploadFromUrlRequested: "ຮ້ອງຂà»àºàº²àº™àº­àº±àºšà»‚ຫລດ"
+uploadFromUrlRequested: "ຮ້ອງຂà»àºàº²àº™àº­àº±àºšà»‚ຫລດà»àº¥à»‰àº§"
explore: "ສຳຫຼວດ"
messageRead: "ອ່ານà»àº¥à»‰àº§"
startMessaging: "ເລີ່ມàºàº²àº™àºªàº»àº™àº—ະນາໃà»à»ˆ"
@@ -244,47 +244,47 @@ images: "ຮູບພາບ"
image: "ຮູບພາບ"
birthday: "ວັນເàºàºµàº”"
yearsOld: "{age} ປີ"
-registeredDate: "ວັນທີ່ເປັນສະມາຊິàº"
+registeredDate: "ວັນທີ່ລົງທະບຽນ"
location: "ທີ່ຕັ້ງ"
-theme: "à»àº—໋ມ"
-themeForLightMode: "ຮູບà»àºšàºšàºªàºµàºªàº±àº™à»€àºžàº·à»ˆàº­à»ƒàºŠà»‰à»ƒàº™à»‚à»àº”à»àºªàº‡"
-themeForDarkMode: "ຮູບà»àºšàºšàºªàºµàºªàº±àº™àº—ີ່ຈະໃຊ້ຢູ່ໃນໂà»àº”ມືດ"
+theme: "Theme"
+themeForLightMode: "Theme ໃຊ້ໃນໂà»àº”ສະຫວ່າງ"
+themeForDarkMode: "Theme ໃຊ້ໃນໂà»àº”ມືດ"
light: "ສະຫວ່າງ"
dark: "ມືດ"
lightThemes: "ຊຸດຮູບà»àºšàºšàºªàº°àº«àº§à»ˆàº²àº‡"
darkThemes: "ຮູບà»àºšàºšàºªàºµàºªàº±àº™àº¡àº·àº”"
syncDeviceDarkMode: "ຊິງຄ໌ໂà»àº”ມືດàºàº±àºšàºàº²àº™àº•ັ້ງຄ່າທົ່ວອຸປະàºàº­àº™"
-drive: "ຂັບ"
+drive: "Drive"
fileName: "ຊື່ໄຟລ໌"
selectFile: "ເລືອàºà»„ຟລ໌"
selectFiles: "ເລືອàºà»„ຟລ໌"
selectFolder: "ເລືອàºà»‚ຟລເດີ"
selectFolders: "ເລືອàºà»‚ຟລເດີ"
renameFile: "ປ່ຽນຊື່ໄຟລ໌"
-folderName: "ຊື່ໂຟນເດີ"
+folderName: "ຊື່ໂຟລເດີຣ໌"
createFolder: "​ສ້າງ​ໂຟ​ລ​ເດີ"
renameFolder: "ປ່ຽນຊື່ໂຟນເດີນີ້"
deleteFolder: "ລົບໂຟ​ລ​ເດີ​"
addFile: "ເພີ່ມໄຟລ໌"
emptyDrive: "Drive ຂອງທ່ານຫວ່າງເປົ່າ"
-emptyFolder: "ໂຟນເດີນີ້ເປົ່າຫວ່າງ"
+emptyFolder: "ໂຟລເດີຣ໌ນີ້ວ່າງເປົ່າ"
unableToDelete: "ບà»à»ˆâ€‹àºªàº²â€‹àº¡àº²àº”ລົບໄດ້"
inputNewFileName: "ໃສ່ຊື່ໄຟລ໌ໃà»à»ˆ"
inputNewDescription: "ໃສ່ຄຳບັນàºàº²àºà»ƒà»à»ˆ"
inputNewFolderName: "ໃສ່ຊື່ໂຟນເດີໃà»à»ˆ"
circularReferenceFolder: "ໂຟນເດີປາàºàº—າງà»àº¡à»ˆàº™à»‚ຟນເດີàºà»ˆàº­àºàº‚ອງໂຟນເດີທີ່ທ່ານຕ້ອງàºàº²àº™àºà»‰àº²àº"
rename: "ປ່ຽນຊື່"
-doNothing: "ບà»à»ˆàºªàº»àº™à»ƒàºˆ"
-watch: "ເບິ່ງ"
-unwatch: "ຢຸດເບິ່ງ"
+doNothing: "ຢ່າມັນ"
+watch: "ເພັ່ງເລັງ"
+unwatch: "ຢຸດເພັ່ງເລັງ"
accept: "ອະນຸàºàº²àº”"
reject: "ປະຕິເສດ"
normal: "ປົàºàºàº°àº•ິ"
instanceName: "ຊື່ເຊີເວີ້"
-instanceDescription: "ຄà»àº²àº­àº°àº—ິບາàºàº•ົວຢ່າງ"
+instanceDescription: "ຄຳອະທິບາàºà»àº™àº°àº™àº³à»€àºŠàºµàºŸà»€àº§àºµàº£à»Œ"
maintainerName: "ຜູ້ດູà»àº¥"
-maintainerEmail: "ອີເມວ admin"
-tosUrl: "ເງື່ອນໄຂàºàº²àº™à»ƒàº«à»‰àºšà»àº¥àº´àºàº²àº™ URL"
+maintainerEmail: "ອີເມລຜູ້ດູà»àº¥"
+tosUrl: " URL ເງື່ອນໄຂàºàº²àº™à»ƒàº«à»‰àºšà»àº¥àº´àºàº²àº™"
thisYear: "ປີນີ້"
thisMonth: "ເດືອນນີ້"
today: "ມື້ນີ້"
@@ -292,34 +292,34 @@ dayX: "ວັນ {day}"
monthX: "ເດືອນ {month}"
yearX: "ປີ {year}"
pages: "ໜ້າ"
-integration: "ຄວາມສຳພັນຂອງ"
+integration: "ເຊື່ອມໂàºàº‡"
connectService: "ເຊື່ອມຕà»à»ˆ"
disconnectService: "ຕັດàºàº²àº™à»€àºŠàº·à»ˆàº­àº¡àº•à»à»ˆ"
enableLocalTimeline: "ເປີດໃຊ້ທາມລາàºàº—້ອງຖິ່ນ"
enableGlobalTimeline: "ເປີດໃຊ້ທາມລາàºàº—ົ່ວໂລàº"
-disablingTimelinesInfo: "ຜູ້ເບິ່ງà»àºàº‡àº¥àº°àºšàº»àºš à»àº¥àº°àºœàº¹à»‰àº„ວບຄຸມຈະມີàºàº²àº™à»€àº‚ົ້າເຖິງທຸàºàºàº³àº™àº»àº”ເວລາ, ເຖິງà»àº¡à»ˆàº™àº§à»ˆàº²àºˆàº°àºšà»à»ˆà»„ດ້ເປີດໃຊ້ງານàºà»àº•າມ"
+disablingTimelinesInfo: "ຜູ້ດູà»àº¥àº¥àº°àºšàºšà»àº¥àº°àºœàº¹à»‰àº„ວບຄຸມຈະສາມາດເຂົ້າເຖີງໄທມ໌ໄລນ໌ທັ້ງເບີດ ເຖີງວ່າຈະບà»à»ˆà»„ດ້ເປີດໃຊ້ງານàºà»à»ˆàº•າມ"
registration: "ລົງທະບຽນ"
enableRegistration: "ເປີດໃຊ້àºàº²àº™àº¥àº»àº‡àº—ະບຽນຜູ້ໃຊ້ໃà»à»ˆ"
invite: "ເຊີນ"
-driveCapacityPerLocalAccount: "ຄວາມອາດສາມາດຂັບຕà»à»ˆàºœàº¹à»‰à»ƒàºŠà»‰àº—້ອງຖິ່ນ"
-driveCapacityPerRemoteAccount: "ໄດຣຟ໌ຄວາມອາດສາມາດຕà»à»ˆàºœàº¹à»‰à»ƒàºŠà»‰àº—າງໄàº"
+driveCapacityPerLocalAccount: "ຄວາມຈຸຂອງ drive ຕà»à»ˆàºœàº¹à»‰à»ƒàºŠà»‰àº—້ອງຖິ່ນ"
+driveCapacityPerRemoteAccount: "ຄວາມຈຸຂອງ drive ຕà»à»ˆàºœàº¹à»‰à»ƒàºŠà»‰à»„ລàºàº°à»„àº"
basicInfo: "ຂà»à»‰àº¡àº¸àº™à»€àºšàº·à»‰àº­àº‡àº•ົ້ນ"
-pinnedNotes: "ບັນທຶàºàº—ີ່ປັàºà»àº¸àº”ໄວ້"
-hcaptchaSiteKey: "àºàº°à»àºˆà»„ຊທ໌"
-hcaptchaSecretKey: "àºàº°à»àºˆàº¥àº±àºš"
-mcaptchaSiteKey: "àºàº°à»àºˆà»„ຊທ໌"
-mcaptchaSecretKey: "àºàº°à»àºˆàº¥àº±àºš"
+pinnedNotes: "Note ທີ່ປັàºà»àº¸àº”ໄວ້"
+hcaptchaSiteKey: "Site key"
+hcaptchaSecretKey: "Secret key"
+mcaptchaSiteKey: "Site key"
+mcaptchaSecretKey: "Secret Key"
recaptcha: "reCAPTCHA"
-enableRecaptcha: "ເປີດໃຊ້ງານລີà»àº„໋ບຈາ"
-recaptchaSiteKey: "àºàº°à»àºˆà»„ຊທ໌"
-recaptchaSecretKey: "àºàº°à»àºˆàº¥àº±àºš"
-turnstileSiteKey: "àºàº°à»àºˆà»„ຊທ໌"
-turnstileSecretKey: "àºàº°à»àºˆàº¥àº±àºš"
+enableRecaptcha: "ເປີດໃຊ້ງານ reCAPTCHA"
+recaptchaSiteKey: "Site key"
+recaptchaSecretKey: "Secret key"
+turnstileSiteKey: "Site key"
+turnstileSecretKey: "Secret key"
name: "ຊື່"
userList: "ລາàºàºàº²àº™"
about: "àºà»ˆàº½àº§àºàº±àºš"
aboutMisskey: "àºà»ˆàº½àº§àºàº±àºš Misskey"
-administrator: "ຜູ້ບà»àº¥àº´àº«àº²àº™"
+administrator: "ຜູ້ດູà»àº¥"
token: "ໂທເຄັນ"
share: "à»àºšà»ˆàº‡àº›àº±àº™"
notFound: "ບà»à»ˆàºžàº»àºš"
@@ -332,27 +332,27 @@ title: "ຫົວຂà»à»‰"
text: "ຂà»à»‰àº„ວາມ"
enable: "ເປີດໃຊ້"
next: "ຕà»à»ˆà»„ປ"
-retype: "ເຂົ້າໄປອີàºàº„ັ້ງ"
-quoteAttached: "ວົງຢືມ"
+retype: "ລອງພິມລະຫັດອີàºà»€àº—ື່ອໜຶ່ງ"
+quoteAttached: "ອ້າງອິງ"
invitations: "ເຊີນ"
unavailable: "ບà»à»ˆâ€‹àºªàº²â€‹àº¡àº²àº”​ໃຊ້​ໄດ້"
language: "ພາສາ"
aboutX: "àºà»ˆàº½àº§àºàº±àºš {x}"
emojiStyle: "ຮູບà»àºšàºšàº­àºµà»‚ມຈິ"
native: "ພາ​ສາ​à»àº¡à»ˆ"
-noHistory: "​ບà»à»ˆâ€‹àº¡àºµâ€‹àº¥àº²àºâ€‹àºàº²àº™â€‹àº¢àº¹à»ˆâ€‹àºšà»ˆàº­àº™â€‹àº™àºµà»‰"
+noHistory: "​ບà»à»ˆâ€‹àº¡àºµàº›àº°àº«àº§àº±àº”"
doing: "àºàº³àº¥àº±àº‡àº›àº°àº¡àº§àº™àºœàº»àº™..."
category: "ຫມວດຫມູ່"
-tags: "à»àº—໋àº"
+tags: "Aliases"
createAccount: "ສ້າງບັນຊີ"
-existingAccount: "ທີ່ມີຢູ່"
-dashboard: "ໜ້າປັດ"
+existingAccount: "ບັນຊີທີ່ມີຢູ່à»àº¥à»‰àº§"
+dashboard: "Dashboard"
local: "ທ້ອງຖິ່ນ"
numberOfDays: "ຈຳນວນມື້"
objectStorageBucket: "Bucket"
objectStoragePrefix: "Prefix"
objectStorageEndpoint: "Endpoint"
-objectStorageRegion: "ພາàºâ€‹àºžàº·à»‰àº™"
+objectStorageRegion: "ພູມິພາàº"
deleteAll: "ລຶບທັງà»àº»àº”"
sounds: "ສຽງ"
sound: "ສຽງ"
@@ -365,11 +365,11 @@ state: "ສະຖານະ"
sort: "ຈັດຮຽງໂດàº"
ascendingOrder: "ນ້ອàºà»„ປຫາໃຫàºà»ˆ"
descendingOrder: "ໃຫàºà»ˆàº«àº²àº™à»‰àº­àº"
-output: "ຜົນຜະລິດ"
-script: "ບົດ​ຄວາມ"
+output: "Output"
+script: "Script"
menu: "ເມນູ"
-rearrange: "ຈັດລຽງຄືນ"
-poll: "àºàº²àº™àºžàº¹àº™"
+rearrange: "ຈັດລຽງໃà»à»ˆ"
+poll: "Poll"
description: "ລາàºàº¥àº°àº­àº½àº”"
author: "ຜູ້ຂຽນ"
manage: "àºàº²àº™àºˆàº±àº”àºàº²àº™"
@@ -383,7 +383,7 @@ permission: "àºàº²àº™àº­àº°àº™àº¸àºàº²àº”"
notificationType: "​ປະເພດàºàº²àº™â€‹à»àºˆà»‰àº‡â€‹à»€àº•ືອນ"
edit: "à»àºà»‰à»„ຂ"
email: "ອີເມວ"
-smtpHost: "ໂຮດສ"
+smtpHost: "ໂຮສຕ໌"
smtpUser: "ຊື່ຜູ້ໃຊ້"
smtpPass: "ລະຫັດຜ່ານ"
clearCache: "ລຶບລ້າງà»àº„ສ"
@@ -393,12 +393,12 @@ administration: "àºàº²àº™àºˆàº±àº”àºàº²àº™"
middle: "ປານàºàº²àº‡"
searchByGoogle: "ຄົ້ນຫາ"
file: "ໄຟລ໌"
-replies: "ຕອບ​ໄປ​ທີ"
+replies: "ຕອບ​àºàº±àºš"
renotes: "Renote"
_delivery:
stop: "ໂຈະ"
_type:
- none: "àºàº²àº™â€‹àºžàº´àº¡â€‹à»€àºœàºµàºâ€‹à»àºœà»ˆ"
+ none: "àºàº³àº¥àº±àº‡â€‹à»€àºœàºµàºâ€‹à»àºžà»ˆ"
_role:
_priority:
middle: "ປານàºàº²àº‡"
@@ -416,8 +416,8 @@ _sfx:
_2fa:
renewTOTPCancel: "ບà»à»ˆâ€‹à»àº¡à»ˆàº™â€‹àº•ອນ​ນີ້"
_widgets:
- profile: "ໂພຼຟາàº"
- instanceInfo: "ອີນສະà»àº•ນ"
+ profile: "ໂປຣໄຟລ໌"
+ instanceInfo: "ຂà»à»‰àº¡àº¹àº¥à»€àºŠàºµàºŸà»€àº§àºµàº£à»Œ"
notifications: "àºàº²àº™à»àºˆà»‰àº‡à»€àº•ືອນ"
timeline: "​ເສັ້ນàºàº³â€‹àº™àº»àº”​ເວ​ລາ​"
activity: "àºàº´àº”ຈະàºàº³"
@@ -436,28 +436,28 @@ _profile:
_exportOrImport:
followingList: "àºàº³àº¥àº±àº‡àº•ິດຕາມ"
muteList: "ປີດສຽງ"
- blockingList: "ບ໋ອàº"
+ blockingList: "ບລັອàº"
userLists: "ລາàºàºàº²àº™"
_charts:
federation: "ສະຫະພັນ"
_timelines:
home: "ໜ້າຫຼັàº"
_play:
- script: "ບົດ​ຄວາມ"
+ script: "Script"
summary: "ລາàºàº¥àº°àº­àº½àº”"
_pages:
blocks:
image: "ຮູບພາບ"
_notification:
- youWereFollowed: "ໄດ້ຕິດຕາມທ່ານ"
+ youWereFollowed: "ໄດ້ຕິດຕາມເຈົ້າ"
_types:
follow: "àºàº³àº¥àº±àº‡àº•ິດຕາມ"
- mention: "ໄດ້àºà»ˆàº²àº§àº¡àº²"
+ mention: "ໄດ້àºà»ˆàº²àº§à»€àº–ິງ"
renote: "Renote"
- quote: "ລວມຂà»à»‰àº„ວາມອ້າງອີງ"
- reaction: "ປະຕິàºàº´àº¥àº´àºàº²"
+ quote: "ອ້າງອີງ"
+ reaction: "Reaction"
_actions:
- reply: "ຕອບ​ໄປ​ທີ"
+ reply: "ຕອບ​àºàº±àºš"
renote: "Renote"
_deck:
_columns:
@@ -465,8 +465,12 @@ _deck:
tl: "​ເສັ້ນàºàº³â€‹àº™àº»àº”​ເວ​ລາ​"
list: "ລາàºàºàº²àº™"
channel: "ຊ່ອງ"
- mentions: "àºà»ˆàº²àº§à»€àº–ິງ"
+ mentions: "àºà»ˆàº²àº§à»€àº–ິງເຈົ້າ"
_webhookSettings:
name: "ຊື່"
+_abuseReport:
+ _notificationRecipient:
+ _recipientType:
+ mail: "ອີເມວ"
_moderationLogTypes:
suspend: "ລະງັບ"
diff --git a/locales/no-NO.yml b/locales/no-NO.yml
index 2b4c9b7776..cd00ecf9ab 100644
--- a/locales/no-NO.yml
+++ b/locales/no-NO.yml
@@ -721,5 +721,9 @@ _deck:
direct: "Direkte"
_webhookSettings:
name: "Navn"
+_abuseReport:
+ _notificationRecipient:
+ _recipientType:
+ mail: "E-post"
_moderationLogTypes:
suspend: "Suspender"
diff --git a/locales/pl-PL.yml b/locales/pl-PL.yml
index 9d75f7a9d7..73eff0941a 100644
--- a/locales/pl-PL.yml
+++ b/locales/pl-PL.yml
@@ -1221,8 +1221,6 @@ _sfx:
note: "Wpisy"
noteMy: "Mój wpis"
notification: "Powiadomienia"
- antenna: "Anteny"
- channel: "Powiadomienia kanału"
_ago:
future: "W przyszłości"
justNow: "Przed chwilÄ…"
@@ -1546,7 +1544,6 @@ _webhookSettings:
createWebhook: "Stwórz Webhook"
name: "Nazwa"
secret: "Sekret"
- events: "Uruchomienie Webhooka"
active: "Właczono"
_events:
follow: "Po zaobserwowaniu użytkownika"
@@ -1556,6 +1553,10 @@ _webhookSettings:
renote: "Po udostępnieniu wpisu"
reaction: "Po otrzymaniu reakcji"
mention: "Po zostaniu wspomnianym"
+_abuseReport:
+ _notificationRecipient:
+ _recipientType:
+ mail: "Adres e-mail"
_moderationLogTypes:
suspend: "ZawieÅ›"
resetPassword: "Zresetuj hasło"
diff --git a/locales/pt-PT.yml b/locales/pt-PT.yml
index cfc576b6e1..2e26f6d12a 100644
--- a/locales/pt-PT.yml
+++ b/locales/pt-PT.yml
@@ -1500,6 +1500,10 @@ _webhookSettings:
follow: "Quando seguindo um usuário"
followed: "Quando sendo seguido"
renote: "Quando repostado"
+_abuseReport:
+ _notificationRecipient:
+ _recipientType:
+ mail: "E-mail"
_moderationLogTypes:
suspend: "Suspender"
resetPassword: "Redefinir senha"
diff --git a/locales/ro-RO.yml b/locales/ro-RO.yml
index 328d34405e..b4c9b90de9 100644
--- a/locales/ro-RO.yml
+++ b/locales/ro-RO.yml
@@ -728,6 +728,10 @@ _deck:
mentions: "Mențiuni"
_webhookSettings:
name: "Nume"
+_abuseReport:
+ _notificationRecipient:
+ _recipientType:
+ mail: "Email"
_moderationLogTypes:
suspend: "Suspendă"
resetPassword: "Resetează parola"
diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml
index 71f5cad601..88f59155d6 100644
--- a/locales/ru-RU.yml
+++ b/locales/ru-RU.yml
@@ -1612,8 +1612,6 @@ _sfx:
note: "Заметки"
noteMy: "СобÑтвенные заметки"
notification: "УведомлениÑ"
- antenna: "Ðнтенна"
- channel: "Канал"
_ago:
future: "Из будущего"
justNow: "Только что"
@@ -1983,6 +1981,10 @@ _webhookSettings:
createWebhook: "Создать вебхук"
name: "Ðазвание"
active: "Вкл."
+_abuseReport:
+ _notificationRecipient:
+ _recipientType:
+ mail: "Ð­Ð»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ð¿Ð¾Ñ‡Ñ‚Ð°"
_moderationLogTypes:
suspend: "Заморозить"
addCustomEmoji: "Добавлено Ñмодзи"
diff --git a/locales/sk-SK.yml b/locales/sk-SK.yml
index 52f6bf142c..41f8949196 100644
--- a/locales/sk-SK.yml
+++ b/locales/sk-SK.yml
@@ -1124,8 +1124,6 @@ _sfx:
note: "Poznámky"
noteMy: "Vlastná poznámka"
notification: "Oznámenia"
- antenna: "Antény"
- channel: "Upozornenia kanála"
_ago:
future: "Budúcnosť"
justNow: "Teraz"
@@ -1447,6 +1445,10 @@ _deck:
_webhookSettings:
name: "Názov"
active: "Zapnuté"
+_abuseReport:
+ _notificationRecipient:
+ _recipientType:
+ mail: "Email"
_moderationLogTypes:
suspend: "Zmraziť"
resetPassword: "Resetovať heslo"
diff --git a/locales/sv-SE.yml b/locales/sv-SE.yml
index 089dc3949f..c1a998b8fb 100644
--- a/locales/sv-SE.yml
+++ b/locales/sv-SE.yml
@@ -512,7 +512,6 @@ _theme:
_sfx:
note: "Noter"
notification: "Notifikationer"
- antenna: "Antenner"
_2fa:
renewTOTPCancel: "Nej tack"
_antennaSources:
@@ -577,6 +576,10 @@ _deck:
_webhookSettings:
name: "Namn"
active: "Aktiverad"
+_abuseReport:
+ _notificationRecipient:
+ _recipientType:
+ mail: "E-post"
_moderationLogTypes:
suspend: "Suspendera"
resetPassword: "Återställ Lösenord"
diff --git a/locales/th-TH.yml b/locales/th-TH.yml
index ab09ac4d5a..63f2793428 100644
--- a/locales/th-TH.yml
+++ b/locales/th-TH.yml
@@ -2,10 +2,10 @@
_lang_: "ภาษาไทย"
headlineMisskey: "เชื่อมต่อเครือข่ายโดยโน้ต"
introMisskey: "ยินดีต้อนรับทุà¸à¸„นจ้า! Misskey คือ ซอฟต์à¹à¸§à¸£à¹Œà¹‚อเพนซอร์สสำหรับบริà¸à¸²à¸£à¹„มโครบล็อà¸à¸à¸´à¹‰à¸‡ (MicroBlogging) à¹à¸šà¸šà¸à¸£à¸°à¸ˆà¸²à¸¢à¸¨à¸¹à¸™à¸¢à¹Œà¸­à¸³à¸™à¸²à¸ˆ (Decentralized) \n\nเขียน “โน้ต (Note)†เพื่อส่งต่อเรื่องราวของคุณให้ทั้งโลà¸à¹„ด้รับรู้📡\nà¹à¸¥à¸°à¸­à¸¢à¹ˆà¸²à¸¥à¸·à¸¡à¸—ี่จะ “รีà¹à¸­à¸„ชั่น†à¸à¸±à¸šà¹€à¸£à¸·à¹ˆà¸­à¸‡à¸£à¸²à¸§à¸‚องคนอื่น ๆ ด้วยนะ! ðŸ‘\n\nท่องสำรวจโลà¸à¹ƒà¸šà¹ƒà¸«à¸¡à¹ˆà¸à¸±à¸™à¹€à¸–อะ🚀"
-poweredByMisskeyDescription: "{name} เป็นส่วนหนึ่งในบริà¸à¸²à¸£à¸—ี่ถูà¸à¸‚ับเคลื่อนโดยà¹à¸žà¸¥à¸•ฟอร์มโอเพ่นซอร์ส <b>Misskey</b> (เรียà¸à¸§à¹ˆà¸² \"อินสà¹à¸•นซ์ Misskey\")"
+poweredByMisskeyDescription: "{name} เป็นหนึ่งในเซิร์ฟเวอร์ของà¹à¸žà¸¥à¸•ฟอร์มโอเพ่นซอร์ส <b>Misskey</b>"
monthAndDay: "{month}/{day}"
search: "ค้นหา"
-notifications: "à¸à¸²à¸£à¹€à¹€à¸ˆà¹‰à¸‡à¹€à¸•ือน"
+notifications: "เเจ้งเตือน"
username: "ชื่อผู้ใช้"
password: "รหัสผ่าน"
forgotPassword: "ลืมรหัสผ่าน"
@@ -18,7 +18,7 @@ enterUsername: "à¸à¸£à¸­à¸à¸Šà¸·à¹ˆà¸­à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰"
renotedBy: "รีโน้ตโดย {user}"
noNotes: "ไม่มีโน้ต"
noNotifications: "ไม่มีà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือน"
-instance: "อินสà¹à¸•นซ์"
+instance: "เซิร์ฟเวอร์"
settings: "à¸à¸²à¸£à¸•ั้งค่า"
notificationSettings: "ตั้งค่าà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือน"
basicSettings: "à¸à¸²à¸£à¸•ั้งค่าพื้นà¸à¸²à¸™"
@@ -48,7 +48,7 @@ copyLink: "คัดลอà¸à¸¥à¸´à¸‡à¸à¹Œ"
copyLinkRenote: "คัดลอà¸à¸¥à¸´à¸‡à¸à¹Œà¸£à¸µà¹‚น้ต"
delete: "ลบ"
deleteAndEdit: "ลบà¹à¸¥à¸°à¹à¸à¹‰à¹„ข"
-deleteAndEditConfirm: "คุณต้องà¸à¸²à¸£à¸¥à¸šà¹‚น้ตนี้à¹à¸¥à¸°à¹à¸à¹‰à¹„ขใหม่ใช่ไหม? รีà¹à¸­à¸„ชั่น รีโน้ต à¹à¸¥à¸°à¸à¸²à¸£à¸•อบà¸à¸¥à¸±à¸šà¸•่อโน้ตนี้ทั้งหมดจะถูà¸à¸¥à¸šà¸­à¸­à¸à¸”้วย"
+deleteAndEditConfirm: "ต้องà¸à¸²à¸£à¸¥à¸šà¹‚น้ตนี้à¹à¸¥à¸°à¹à¸à¹‰à¹„ขใหม่ใช่ไหม? รีà¹à¸­à¸„ชั่น รีโน้ต à¹à¸¥à¸°à¸à¸²à¸£à¸•อบà¸à¸¥à¸±à¸šà¸•่อโน้ตนี้ทั้งหมดจะถูà¸à¸¥à¸šà¸­à¸­à¸à¸”้วย"
addToList: "เพิ่มลงรายชื่อ"
addToAntenna: "เพิ่มไปยังเสาอาà¸à¸²à¸¨"
sendMessage: "ส่งข้อความ"
@@ -60,6 +60,7 @@ copyFileId: "คัดลอà¸à¹„ฟล์ ID"
copyFolderId: "คัดลอà¸à¹‚ฟลเดอร์ ID"
copyProfileUrl: "คัดลอà¸à¹‚ปรไฟล์ URL"
searchUser: "ค้นหาผู้ใช้"
+searchThisUsersNotes: "ค้นหาโน้ตของผู้ใช้"
reply: "ตอบà¸à¸¥à¸±à¸š"
loadMore: "à¹à¸ªà¸”งเพิ่มเติม"
showMore: "à¹à¸ªà¸”งเพิ่มเติม"
@@ -68,7 +69,7 @@ youGotNewFollower: "ได้ติดตามคุณ"
receiveFollowRequest: "มีคำขอติดตามส่งมาหา"
followRequestAccepted: "à¸à¸²à¸£à¸•ิดตามได้รับà¸à¸²à¸£à¸­à¸™à¸¸à¸¡à¸±à¸•ิà¹à¸¥à¹‰à¸§"
mention: "à¸à¸¥à¹ˆà¸²à¸§à¸–ึง"
-mentions: "พูดถึง"
+mentions: "à¸à¸¥à¹ˆà¸²à¸§à¸–ึงคุณ"
directNotes: "โพสต์à¹à¸šà¸šà¹„ดเร็à¸à¸•์"
importAndExport: "นำเข้า / ส่งออà¸"
import: "นำเข้า"
@@ -92,7 +93,7 @@ error: "ผิดพลาด!"
somethingHappened: "อุ๊ย ! มีอะไรบางอย่างผิดพลาด"
retry: "ลองใหม่อีà¸à¸„รั้ง"
pageLoadError: "เà¸à¸´à¸”ข้อผิดพลาดในà¸à¸²à¸£à¹‚หลดหน้านี้"
-pageLoadErrorDescription: "โดยปà¸à¸•ิà¹à¸¥à¹‰à¸§à¸¡à¸±à¸à¸ˆà¸°à¹€à¸à¸´à¸”จาà¸à¸‚้อผิดพลาดของเครือข่ายหรือà¹à¸„ชของเบราว์เซอร์ ลองล้างà¹à¸„ชà¹à¸¥à¹‰à¸§à¸¥à¸­à¸‡à¹ƒà¸«à¸¡à¹ˆà¸­à¸µà¸à¸„รั้งหลังจาà¸à¸£à¸­à¸ªà¸±à¸à¸„รู่ "
+pageLoadErrorDescription: "ปัà¸à¸«à¸²à¸™à¸µà¹‰à¸¡à¸±à¸à¹€à¸à¸´à¸”จาà¸à¹à¸„ชของเครือข่ายหรือเบราว์เซอร์ ควรล้างà¹à¸„ช, รอสัà¸à¸„รู่ à¹à¸¥à¹‰à¸§à¸¥à¸­à¸‡à¹ƒà¸«à¸¡à¹ˆà¸­à¸µà¸à¸„รั้ง"
serverIsDead: "เซิร์ฟเวอร์นี้ไม่มีà¸à¸²à¸£à¸•อบสนอง โปรดà¸à¸£à¸¸à¸“ารอสัà¸à¸„รู่à¹à¸¥à¹‰à¸§à¸¥à¸­à¸‡à¹ƒà¸«à¸¡à¹ˆà¸­à¸µà¸à¸„รั้ง"
youShouldUpgradeClient: "หาà¸à¸•้องà¸à¸²à¸£à¸”ูหน้านี้ à¸à¸£à¸¸à¸“าโหลดหน้าใหม่เพื่ออัปเดตไคลเอ็นต์ของคุณ"
enterListName: "ป้อนนามเรียà¸à¸‚องรายชื่อชุดนี้"
@@ -108,11 +109,14 @@ enterEmoji: "พิมพ์เอโมจิ"
renote: "รีโน้ต"
unrenote: "เลิà¸à¸£à¸µà¹‚น้ต"
renoted: "รีโน้ตà¹à¸¥à¹‰à¸§"
+renotedToX: "รีโน้ตให้ {name} à¹à¸¥à¹‰à¸§"
cantRenote: "โพสต์นี้ไม่สามารถรีโน้ตใหม่ได้"
cantReRenote: "รีโน้ตไม่สามารถรีโน้ตซ้ำได้"
quote: "อ้างอิง"
inChannelRenote: "รีโน้ตในช่องเท่านั้น"
inChannelQuote: "อ้างอิงในช่องเท่านั้น"
+renoteToChannel: "รีโน้ตไปที่ช่อง"
+renoteToOtherChannel: "รีโน้ตไปยังช่องอื่น"
pinnedNote: "โน้ตที่ปัà¸à¸«à¸¡à¸¸à¸”ไว้"
pinned: "ปัà¸à¸«à¸¡à¸¸à¸”"
you: "คุณ"
@@ -151,6 +155,7 @@ editList: "à¹à¸à¹‰à¹„ขรายชื่อ"
selectChannel: "เลือà¸à¸Šà¹ˆà¸­à¸‡"
selectAntenna: "เลือà¸à¹€à¸ªà¸²à¸­à¸²à¸à¸²à¸¨"
editAntenna: "à¹à¸à¹‰à¹„ขเสาอาà¸à¸²à¸¨"
+createAntenna: "สร้างเสาอาà¸à¸²à¸¨"
selectWidget: "เลือà¸à¸§à¸´à¸”เจ็ต"
editWidgets: "à¹à¸à¹‰à¹„ขวิดเจ็ต"
editWidgetsExit: "เรียบร้อย"
@@ -163,20 +168,24 @@ addEmoji: "à¹à¸—รà¸à¹€à¸­à¹‚มจิ"
settingGuide: "à¸à¸²à¸£à¸•ั้งค่าที่à¹à¸™à¸°à¸™à¸³"
cacheRemoteFiles: "à¹à¸„ชไฟล์ระยะไà¸à¸¥"
cacheRemoteFilesDescription: "หาà¸à¹€à¸›à¸´à¸”ใช้งาน ไฟล์ระยะไà¸à¸¥à¸ˆà¸°à¸–ูà¸à¹à¸„ชไว้ ทำให้à¹à¸ªà¸”งภาพเร็วขึ้น à¹à¸•่à¸à¹‡à¹ƒà¸Šà¹‰à¸žà¸·à¹‰à¸™à¸—ี่เà¸à¹‡à¸šà¸‚้อมูลของเซิร์ฟเวอร์มาà¸à¸‚ึ้นเช่นà¸à¸±à¸™ สำหรับขีดจำà¸à¸±à¸”ที่ผู้ใช้ระยะไà¸à¸¥à¸–ูà¸à¹à¸„ชไว้จะขึ้นอยู่à¸à¸±à¸šà¸„วามจุไดรฟ์ตามบทบาทของเขา เมื่อเà¸à¸´à¸™à¹à¸¥à¹‰à¸§à¹„ฟล์เà¸à¹ˆà¸²à¸ˆà¸°à¸–ูà¸à¸¥à¸šà¸­à¸­à¸à¹à¸¥à¸°à¹€à¸à¹‡à¸šà¹€à¸›à¹‡à¸™à¸¥à¸´à¸‡à¸à¹Œà¹à¸—น หาà¸à¸›à¸´à¸”ใช้งาน ไฟล์ระยะไà¸à¸¥à¸ˆà¸°à¸–ูà¸à¹€à¸à¹‡à¸šà¹€à¸›à¹‡à¸™à¸¥à¸´à¸‡à¸à¹Œà¸•ั้งà¹à¸•่ต้น เราà¹à¸™à¸°à¸™à¸³à¹ƒà¸«à¹‰à¸•ั้งค่า proxyRemoteFiles ใน default.yml เป็น true เพื่อสร้างธัมบ์เนลà¹à¸¥à¸°à¸›à¸à¸›à¹‰à¸­à¸‡à¸„วามเป็นส่วนตัวของผู้ใช้"
-youCanCleanRemoteFilesCache: "คุณสามารถล้างà¹à¸„ชได้โดยคลิà¸à¸—ี่ปุ่ม ðŸ—‘ï¸ à¹ƒà¸™à¸¡à¸¸à¸¡à¸¡à¸­à¸‡à¸à¸²à¸£à¸ˆà¸±à¸”à¸à¸²à¸£à¹„ฟล์"
+youCanCleanRemoteFilesCache: "สามารถลบà¹à¸„ชทั้งหมดได้โดยใช้ปุ่ม ðŸ—‘ï¸ à¹ƒà¸™à¸«à¸™à¹‰à¸²à¸à¸²à¸£à¸ˆà¸±à¸”à¸à¸²à¸£à¹„ฟล์"
cacheRemoteSensitiveFiles: "à¹à¸„ชไฟล์ระยะไà¸à¸¥à¸—ี่มีเนื้อหาละเอียดอ่อน"
-cacheRemoteSensitiveFilesDescription: "เมื่อปิดà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¸à¸²à¸£à¸•ั้งค่านี้ ไฟล์ระยะไà¸à¸¥à¸—ี่มีเครื่องหมายว่ามีเนื้อหาละเอียดอ่อนนั้นจะถูà¸à¹‚หลดโดยตรงจาà¸à¸­à¸´à¸™à¸ªà¹à¸•นซ์ระยะไà¸à¸¥à¹‚ดยที่ไม่มีà¸à¸²à¸£à¹à¸„ช"
+cacheRemoteSensitiveFilesDescription: "เมื่อปิดà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¸à¸²à¸£à¸•ั้งค่านี้ ไฟล์ระยะไà¸à¸¥à¸—ี่มีเนื้อหาละเอียดอ่อนจะถูà¸à¹‚หลดโดยตรงจาà¸à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸£à¸°à¸¢à¸°à¹„à¸à¸¥à¹‚ดยไม่มีà¸à¸²à¸£à¹à¸„ช"
flagAsBot: "ทำเครื่องหมายบอà¸à¸§à¹ˆà¸²à¸šà¸±à¸à¸Šà¸µà¸™à¸µà¹‰à¹€à¸›à¹‡à¸™à¸šà¸­à¸•"
-flagAsBotDescription: "à¸à¸²à¸£à¹€à¸›à¸´à¸”ใช้งานตัวเลือà¸à¸™à¸µà¹‰à¸«à¸²à¸à¸šà¸±à¸à¸Šà¸µà¸™à¸µà¹‰à¸–ูà¸à¸„วบคุมโดยนัà¸à¹€à¸‚ียนโปรà¹à¸à¸£à¸¡ หรือ ถ้าหาà¸à¹€à¸›à¸´à¸”ใช้งาน มันจะทำหน้าที่เป็นà¹à¸Ÿà¸¥à¹‡à¸à¸ªà¸³à¸«à¸£à¸±à¸šà¸™à¸±à¸à¸žà¸±à¸’นารายอื่นๆ à¹à¸¥à¸°à¹€à¸žà¸·à¹ˆà¸­à¸›à¹‰à¸­à¸‡à¸à¸±à¸™à¸à¸²à¸£à¹‚ต้ตอบà¹à¸šà¸šà¹„ม่มีที่สิ้นสุดà¸à¸±à¸šà¸šà¸­à¸—ตัวอื่นๆ à¹à¸¥à¸°à¸¢à¸±à¸‡à¸ªà¸²à¸¡à¸²à¸£à¸–ปรับเปลี่ยนระบบภายในของ Misskey เพื่อปà¸à¸´à¸šà¸±à¸•ิต่อบัà¸à¸Šà¸µà¸™à¸µà¹‰à¹€à¸›à¹‡à¸™à¸šà¸­à¸—"
+flagAsBotDescription: "เปิดใช้งานตัวเลือà¸à¸™à¸µà¹‰à¸«à¸²à¸à¸šà¸±à¸à¸Šà¸µà¸™à¸µà¹‰à¸–ูà¸à¸„วบคุมโดยโปรà¹à¸à¸£à¸¡ เมื่อเปิดใช้งาน มันจะทำหน้าที่เป็นà¹à¸Ÿà¸¥à¹‡à¸à¸ªà¸³à¸«à¸£à¸±à¸šà¸™à¸±à¸à¸žà¸±à¸’นารายอื่นในà¸à¸²à¸£à¸›à¹‰à¸­à¸‡à¸à¸±à¸™à¸à¸²à¸£à¸ªà¸£à¹‰à¸²à¸‡à¸«à¹ˆà¸§à¸‡à¹‚ซ่à¸à¸²à¸£à¹‚ต้ตอบà¹à¸šà¸šà¸­à¸™à¸±à¸™à¸•์à¸à¸±à¸šà¸šà¸­à¸•ตัวอื่น à¹à¸¥à¸°à¸›à¸£à¸±à¸šà¸£à¸°à¸šà¸šà¸ à¸²à¸¢à¹ƒà¸™à¸‚อง Misskey เพื่อจัดà¸à¸²à¸£à¸šà¸±à¸à¸Šà¸µà¸™à¸µà¹‰à¹ƒà¸™à¸à¸²à¸™à¸°à¸šà¸­à¸•"
flagAsCat: "เมี้ยววววววววววววววว!!!!!!!!!!!"
flagAsCatDescription: "เหมียวเหมียวเมี้ยว??"
-flagShowTimelineReplies: "à¹à¸ªà¸”งตอบà¸à¸¥à¸±à¸š ในไทม์ไลน์"
-flagShowTimelineRepliesDescription: "à¹à¸ªà¸”งà¸à¸²à¸£à¸•อบà¸à¸¥à¸±à¸šà¸‚องผู้ใช้งานไปยังโน้ตของผู้ใช้งานรายอื่นๆในไทม์ไลน์หาà¸à¹„ด้เปิดเอาไว้"
-autoAcceptFollowed: "อนุมัติคำขอติดตามโดยอัตโนมัติทันที จาà¸à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¸—ี่คุณà¸à¸³à¸¥à¸±à¸‡à¸•ิดตาม"
+flagShowTimelineReplies: "à¹à¸ªà¸”งตอบà¸à¸¥à¸±à¸šà¹‚น้ตลงไทม์ไลน์"
+flagShowTimelineRepliesDescription: "เมื่อเปิดใช้งาน จะà¹à¸ªà¸”งà¸à¸²à¸£à¸•อบà¸à¸¥à¸±à¸šà¸‚องผู้ใช้คนนั้นต่อโน้ตอื่นๆ ในไทม์ไลน์ด้วย"
+autoAcceptFollowed: "อนุมัติคำขอติดตามจาà¸à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸—ี่คุณติดตามอยู่โดยอัตโนมัติ"
addAccount: "เพิ่มบัà¸à¸Šà¸µ"
reloadAccountsList: "รีโหลดรายà¸à¸²à¸£à¸šà¸±à¸à¸Šà¸µà¹ƒà¸«à¸¡à¹ˆ"
loginFailed: "à¸à¸²à¸£à¹€à¸‚้าสู่ระบบไม่สำเร็จ"
-showOnRemote: "ดูบนอินสà¹à¸•นซ์ระยะไà¸à¸¥"
+showOnRemote: "ดูบนเซิร์ฟเวอร์à¸à¸±à¹ˆà¸‡à¸£à¸°à¸¢à¸°à¹„à¸à¸¥"
+continueOnRemote: "ดำเนินà¸à¸²à¸£à¸•่อบนเซิร์ฟเวอร์à¸à¸±à¹ˆà¸‡à¸£à¸°à¸¢à¸°à¹„à¸à¸¥"
+chooseServerOnMisskeyHub: "เลือà¸à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸ˆà¸²à¸ Misskey Hub"
+specifyServerHost: "ระบุโดเมนของเซิร์ฟเวอร์โดยตรง"
+inputHostName: "โปรดป้อนโดเมน"
general: "ทั่วไป"
wallpaper: "ภาพพื้นหลัง"
setWallpaper: "ตั้งค่าภาพพื้นหลัง"
@@ -185,23 +194,25 @@ searchWith: "ค้นหา: {q}"
youHaveNoLists: "คุณไม่มีรายชื่อใดๆ "
followConfirm: "ต้องà¸à¸²à¸£à¸•ิดตาม {name} ใช่ไหม?"
proxyAccount: "บัà¸à¸Šà¸µà¸žà¸£à¹‡à¸­à¸à¸‹à¸µà¹ˆ"
-proxyAccountDescription: "บัà¸à¸Šà¸µà¸žà¸£à¹‡à¸­à¸à¸‹à¸µà¹ˆ คือ บัà¸à¸Šà¸µà¸—ี่จะทำหน้าที่เป็นผู้ติดตามระยะไà¸à¸¥à¸ªà¸³à¸«à¸£à¸±à¸šà¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¸—ี่อยู่ภายใต้ด้วยเงื่อนไขบางอย่าง ยà¸à¸•ัวอย่าง เช่น เมื่อมีผู้ใช้งานนั้นได้เพิ่มผู้ใช้งานจาà¸à¸£à¸°à¸¢à¸°à¹„à¸à¸¥à¸¥à¸‡à¹ƒà¸™à¸£à¸²à¸¢à¸à¸²à¸£ à¹à¸•่à¸à¸´à¸ˆà¸à¸£à¸£à¸¡à¸‚องผู้ใช้ในระยะไà¸à¸¥à¸™à¸±à¹‰à¸™à¸ˆà¸°à¹„ม่ถูà¸à¸ªà¹ˆà¸‡à¹„ปยังอินสà¹à¸•นซ์หาà¸à¹„ม่มีผู้ใช้งานในพื้นที่ติดตามผู้ใช้รายนั้น ดังนั้นบัà¸à¸Šà¸µà¸žà¸£à¹‡à¸­à¸à¸‹à¸µà¸™à¸µà¹‰à¸ˆà¸°à¸•ิดตามà¹à¸—น"
+proxyAccountDescription: "บัà¸à¸Šà¸µà¸žà¸£à¹‡à¸­à¸à¸‹à¸µ คือ บัà¸à¸Šà¸µà¸—ี่ทำหน้าที่ติดตาม(ผู้ใช้)ระยะไà¸à¸¥à¸ à¸²à¸¢à¹ƒà¸•้เงื่อนไขบางประà¸à¸²à¸£ ตัวอย่างเช่น เมื่อผู้ใช้ท้องถิ่นเพิ่มผู้ใช้ระยะไà¸à¸¥à¸¥à¸‡à¸£à¸²à¸¢à¸Šà¸·à¹ˆà¸­ หาà¸à¹„ม่มีใครติดตามผู้ใช้ระยะไà¸à¸¥à¹ƒà¸™à¸£à¸²à¸¢à¸Šà¸·à¹ˆà¸­à¸™à¸±à¹‰à¸™ à¸à¸´à¸ˆà¸à¸£à¸£à¸¡à¸à¹‡à¸ˆà¸°à¹„ม่ถูà¸à¸ªà¹ˆà¸‡à¸¡à¸²à¸¢à¸±à¸‡à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œ ดังนั้นจึงมีบัà¸à¸Šà¸µà¸žà¸£à¹‡à¸­à¸à¸‹à¸µà¹„ว้ติดตามผู้ใช้ระยะไà¸à¸¥à¹€à¸«à¸¥à¹ˆà¸²à¸™à¸±à¹‰à¸™"
host: "โฮสต์"
+selectSelf: "เลือà¸à¸•ัวเอง"
selectUser: "เลือà¸à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸‡à¸²à¸™"
recipient: "ผู้รับ"
annotation: "หมายเหตุประà¸à¸­à¸š"
federation: "สหพันธ์"
-instances: "อินสà¹à¸•นซ์"
+instances: "เซิร์ฟเวอร์"
registeredAt: "วันที่ลงทะเบียน"
latestRequestReceivedAt: "คำขอล่าสุดที่ได้รับ"
latestStatus: "สถานะล่าสุด"
storageUsage: "พื้นที่จัดเà¸à¹‡à¸šà¸‚้อมูลที่ใช้ไป"
-charts: "โดดเด่น"
-perHour: "ทุà¸à¸Šà¸±à¹ˆà¸§à¹‚มง"
+charts: "à¹à¸œà¸™à¸ à¸¹à¸¡à¸´"
+perHour: "ต่อชั่วโมง"
perDay: "ต่อวัน"
stopActivityDelivery: "หยุดส่งà¸à¸´à¸ˆà¸à¸£à¸£à¸¡"
-blockThisInstance: "บล็อà¸à¸­à¸´à¸™à¸ªà¹à¸•นซ์นี้"
-silenceThisInstance: "ปิดปาà¸à¸­à¸´à¸™à¸ªà¹à¸•นซ์นี้"
+blockThisInstance: "บล็อà¸à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸™à¸µà¹‰"
+silenceThisInstance: "ปิดปาà¸à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸™à¸µà¹‰"
+mediaSilenceThisInstance: "ปิดปาà¸à¸ªà¸·à¹ˆà¸­à¸‚องเซิร์ฟเวอร์นี้"
operations: "ดำเนินà¸à¸²à¸£"
software: "ซอฟต์à¹à¸§à¸£à¹Œ"
version: "เวอร์ชั่น"
@@ -212,17 +223,19 @@ jobQueue: "คิวงาน"
cpuAndMemory: "ซีพียู à¹à¸¥à¸° หน่วยความจำ"
network: "เครือข่าย"
disk: "ดิสà¸à¹Œ"
-instanceInfo: "ข้อมูลอินสà¹à¸•นซ์"
+instanceInfo: "ข้อมูลเซิร์ฟเวอร์"
statistics: "สถิติà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™"
clearQueue: "ล้างคิว"
clearQueueConfirmTitle: "ต้องà¸à¸²à¸£à¸¥à¹‰à¸²à¸‡à¸„ิวใช่ไหม?"
clearQueueConfirmText: "โพสต์ที่ยังค้างในคิวจะไม่ถูà¸à¸ˆà¸±à¸”ส่งอีà¸à¸•่อไป โดยปà¸à¸•ิà¹à¸¥à¹‰à¸§à¸à¸²à¸£à¸”ำเนินà¸à¸²à¸£à¸™à¸µà¹‰à¹„ม่จำเป็น"
clearCachedFiles: "ล้างà¹à¸„ช"
clearCachedFilesConfirm: "ต้องà¸à¸²à¸£à¸¥à¸šà¹„ฟล์ระยะไà¸à¸¥à¸—ี่à¹à¸„ชไว้ทั้งหมดใช่ไหม?"
-blockedInstances: "อินสà¹à¸•นซ์ที่ถูà¸à¸šà¸¥à¹‡à¸­à¸"
-blockedInstancesDescription: "ระบุชื่อโฮสต์ของอินสà¹à¸•นซ์ที่คุณต้องà¸à¸²à¸£à¸šà¸¥à¹‡à¸­à¸ อินสà¹à¸•นซ์ที่อยู่ในรายà¸à¸²à¸£à¸™à¸±à¹‰à¸™à¸ˆà¸°à¹„ม่สามารถพูดคุยà¸à¸±à¸šà¸­à¸´à¸™à¸ªà¹à¸•นซ์นี้ได้อีà¸à¸•่อไป"
-silencedInstances: "ปิดปาà¸à¸­à¸´à¸™à¸ªà¹à¸•นซ์นี้à¹à¸¥à¹‰à¸§"
-silencedInstancesDescription: "ตั้งค่ารายชื่อโฮสต์ของอินสà¹à¸•นซ์ที่คุณต้องà¸à¸²à¸£à¸›à¸´à¸”ปาภบัà¸à¸Šà¸µà¸—ั้งหมดของอินสà¹à¸•นซ์ที่อยู่ในรายชื่อนั้นๆ จะถือว่าถูà¸à¸›à¸´à¸”ปาà¸à¹€à¸Šà¹ˆà¸™à¸à¸±à¸™ ทำได้เฉพาะคำขอติดตามเท่านั้น à¹à¸¥à¸°à¹„ม่สามารถà¸à¸¥à¹ˆà¸²à¸§à¸–ึงบัà¸à¸Šà¸µà¹ƒà¸™à¸žà¸·à¹‰à¸™à¸—ี่ได้หาà¸à¹„ม่ได้ติดตาม | สิ่งนี้ไม่มีผลต่ออินสà¹à¸•นซ์ที่ถูà¸à¸šà¸¥à¹‡à¸­à¸"
+blockedInstances: "เซิร์ฟเวอร์ที่ถูà¸à¸šà¸¥à¹‡à¸­à¸"
+blockedInstancesDescription: "ระบุโฮสต์ของเซิร์ฟเวอร์ที่ต้องà¸à¸²à¸£à¸šà¸¥à¹‡à¸­à¸ คั่นด้วยà¸à¸²à¸£à¸‚ึ้นบรรทัดใหม่ เซิร์ฟเวอร์ที่ถูà¸à¸šà¸¥à¹‡à¸­à¸à¸ˆà¸°à¹„ม่สามารถติดต่อà¸à¸±à¸šà¸­à¸´à¸™à¸ªà¹à¸•นซ์นี้ได้"
+silencedInstances: "ปิดปาà¸à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸™à¸µà¹‰à¹à¸¥à¹‰à¸§"
+silencedInstancesDescription: "ระบุโฮสต์ของเซิร์ฟเวอร์ที่ต้องà¸à¸²à¸£à¸›à¸´à¸”ปาภคั่นด้วยà¸à¸²à¸£à¸‚ึ้นบรรทัดใหม่, บัà¸à¸Šà¸µà¸—ั้งหมดของเซิร์ฟเวอร์ดังà¸à¸¥à¹ˆà¸²à¸§à¸ˆà¸°à¸–ือว่าถูà¸à¸›à¸´à¸”ปาà¸à¹€à¸Šà¹ˆà¸™à¸à¸±à¸™ ทำได้เฉพาะคำขอติดตามเท่านั้น à¹à¸¥à¸°à¹„ม่สามารถà¸à¸¥à¹ˆà¸²à¸§à¸–ึงบัà¸à¸Šà¸µà¹ƒà¸™à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸™à¸µà¹‰à¹„ด้หาà¸à¹„ม่ได้ถูà¸à¸•ิดตามà¸à¸¥à¸±à¸š | สิ่งนี้ไม่มีผลต่ออินสà¹à¸•นซ์ที่ถูà¸à¸šà¸¥à¹‡à¸­à¸"
+mediaSilencedInstances: "เซิร์ฟเวอร์ที่ถูà¸à¸›à¸´à¸”ปาà¸à¸ªà¸·à¹ˆà¸­"
+mediaSilencedInstancesDescription: "ระบุโฮสต์ของเซิร์ฟเวอร์ที่ต้องà¸à¸²à¸£à¸›à¸´à¸”ปาà¸à¸ªà¸·à¹ˆà¸­ คั่นด้วยà¸à¸²à¸£à¸‚ึ้นบรรทัดใหม่, ไฟล์ที่ถูà¸à¸ªà¹ˆà¸‡à¸ˆà¸²à¸à¸šà¸±à¸à¸Šà¸µà¸‚องเซิร์ฟเวอร์ดังà¸à¸¥à¹ˆà¸²à¸§à¸ˆà¸°à¸–ือว่าถูà¸à¸›à¸´à¸”ปาภà¹à¸¥à¹‰à¸§à¸ˆà¸°à¸–ูà¸à¸•ิดเครื่องหมายว่ามีเนื้อหาละเอียดอ่อน à¹à¸¥à¸°à¹€à¸­à¹‚มจิà¹à¸šà¸šà¸à¸³à¸«à¸™à¸”เองà¸à¹‡à¸ˆà¸°à¹ƒà¸Šà¹‰à¹„ม่ได้ด้วย | สิ่งนี้ไม่มีผลต่ออินสà¹à¸•นซ์ที่ถูà¸à¸šà¸¥à¹‡à¸­à¸"
muteAndBlock: "ปิดเสียงà¹à¸¥à¸°à¸šà¸¥à¹‡à¸­à¸"
mutedUsers: "ผู้ใช้ที่ถูà¸à¸›à¸´à¸”เสียง"
blockedUsers: "ผู้ใช้ที่ถูà¸à¸šà¸¥à¹‡à¸­à¸"
@@ -240,14 +253,14 @@ noCustomEmojis: "ไม่มีเอโมจิ"
noJobs: "ไม่มีงาน"
federating: "สหพันธ์"
blocked: "ถูà¸à¸šà¸¥à¹‡à¸­à¸"
-suspended: "ถูà¸à¸£à¸°à¸‡à¸±à¸š"
+suspended: "ระงับà¸à¸²à¸£à¸ªà¹ˆà¸‡"
all: "ทั้งหมด"
-subscribing: "สมัครà¹à¸¥à¹‰à¸§"
+subscribing: "à¸à¸³à¸¥à¸±à¸‡à¸ªà¸¡à¸±à¸„รสมาชิà¸"
publishing: "à¸à¸³à¸¥à¸±à¸‡à¹€à¸œà¸¢à¹à¸žà¸£à¹ˆ"
notResponding: "ไม่มีà¸à¸²à¸£à¸•อบสนอง"
-instanceFollowing: "à¸à¸³à¸¥à¸±à¸‡à¸•ิดตามบนอินสà¹à¸•นซ์"
-instanceFollowers: "ผู้ติดตามของอินสà¹à¸•นซ์"
-instanceUsers: "ผู้ใช้งานของอินสà¹à¸•นซ์นี้"
+instanceFollowing: "à¸à¸³à¸¥à¸±à¸‡à¸•ิดตามบนเซิร์ฟเวอร์"
+instanceFollowers: "ผู้ติดตามของเซิร์ฟเวอร์"
+instanceUsers: "ผู้ใช้ของเซิร์ฟเวอร์นี้"
changePassword: "เปลี่ยนรหัสผ่าน"
security: "ความปลอดภัย"
retypedNotMatch: "ทั้งสองป้อนข้อมูลไม่สอดคล้องà¸à¸±à¸™"
@@ -284,20 +297,20 @@ messageRead: "อ่านà¹à¸¥à¹‰à¸§"
noMoreHistory: "ไม่มีประวัติเพิ่มเติม"
startMessaging: "เริ่มà¸à¸²à¸£à¸ªà¸™à¸—นา"
nUsersRead: "อ่านโดย {n}"
-agreeTo: "ฉันยอมรับที่จะ {0}"
+agreeTo: "ฉันยอมรับ {0}"
agree: "ยอมรับ"
-agreeBelow: "ฉันยอมรับถึงด้านล่าง"
+agreeBelow: "ยอมรับตามที่ระบุด้านล่าง"
basicNotesBeforeCreateAccount: "หมายเหตุสำคัà¸"
termsOfService: "เงื่อนไขà¸à¸²à¸£à¹ƒà¸«à¹‰à¸šà¸£à¸´à¸à¸²à¸£"
start: "เริ่ม"
-home: "หน้าà¹à¸£à¸"
-remoteUserCaution: "ข้อมูลอาจไม่สมบูรณ์เนื่องจาà¸à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸£à¸²à¸¢à¸™à¸µà¹‰à¸¡à¸²à¸ˆà¸²à¸à¸­à¸´à¸™à¸ªà¹à¸•นซ์ระยะไà¸à¸¥"
+home: "หน้าหลัà¸"
+remoteUserCaution: "ข้อมูลอาจไม่สมบูรณ์เนื่องจาà¸à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸£à¸²à¸¢à¸™à¸µà¹‰à¸¡à¸²à¸ˆà¸²à¸à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸£à¸°à¸¢à¸°à¹„à¸à¸¥"
activity: "à¸à¸´à¸ˆà¸à¸£à¸£à¸¡"
images: "รูปภาพ"
image: "รูปภาพ"
birthday: "วันเà¸à¸´à¸”"
yearsOld: "{age} ปี"
-registeredDate: "วันที่สมัครสมาชิà¸"
+registeredDate: "วันที่ลงทะเบียน"
location: "ตำà¹à¸«à¸™à¹ˆà¸‡à¸—ี่ตั้ง"
theme: "ธีม"
themeForLightMode: "ธีมที่จะใช้ในโหมดสว่าง"
@@ -313,6 +326,7 @@ selectFile: "เลือà¸à¹„ฟล์"
selectFiles: "เลือà¸à¹„ฟล์"
selectFolder: "เลือà¸à¹‚ฟลเดอร์"
selectFolders: "เลือà¸à¹‚ฟลเดอร์"
+fileNotSelected: "ยังไม่ได้เลือà¸à¹„ฟล์"
renameFile: "เปลี่ยนชื่อไฟล์"
folderName: "ชื่อโฟลเดอร์"
createFolder: "สร้างโฟลเดอร์"
@@ -336,15 +350,15 @@ displayOfSensitiveMedia: "à¹à¸ªà¸”งสื่อที่มีเนื้อ
whenServerDisconnected: "เมื่อสูà¸à¹€à¸ªà¸µà¸¢à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•่อà¸à¸±à¸šà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œ"
disconnectedFromServer: "à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•่อเซิร์ฟเวอร์ถูà¸à¸•ัด"
reload: "รีโหลด"
-doNothing: "เมิน"
+doNothing: "ช่างมัน"
reloadConfirm: "รีโหลดเลยไหม?"
-watch: "ดู"
-unwatch: "หยุดดู"
+watch: "เพ่งเล็ง"
+unwatch: "เลิà¸à¹€à¸žà¹ˆà¸‡à¹€à¸¥à¹‡à¸‡"
accept: "ยอมรับ"
reject: "ปà¸à¸´à¹€à¸ªà¸˜"
normal: "ปà¸à¸•ิ"
-instanceName: "ชื่ออินสà¹à¸•นซ์"
-instanceDescription: "คำอธิบายอินสà¹à¸•นซ์"
+instanceName: "ชื่อเซิร์ฟเวอร์"
+instanceDescription: "คำอธิบายà¹à¸™à¸°à¸™à¸³à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œ"
maintainerName: "ผู้ดูà¹à¸¥"
maintainerEmail: "อีเมลผู้ดูà¹à¸¥à¸£à¸°à¸šà¸š"
tosUrl: "URL เงื่อนไขà¸à¸²à¸£à¹ƒà¸«à¹‰à¸šà¸£à¸´à¸à¸²à¸£"
@@ -355,16 +369,16 @@ dayX: "{day}"
monthX: "เดือน {month}"
yearX: "{year}"
pages: "หน้าเพจ"
-integration: "รวบรวม"
+integration: "เชื่อมโยง"
connectService: "เชื่อมต่อ"
disconnectService: "ตัดà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•่อ"
-enableLocalTimeline: "เปิดใช้งานไทม์ไลน์ในพื้นที่"
+enableLocalTimeline: "เปิดใช้งานไทม์ไลน์ท้องถิ่น"
enableGlobalTimeline: "เปิดใช้งานไทม์ไลน์ทั่วโลà¸"
disablingTimelinesInfo: "ผู้ดูà¹à¸¥à¸£à¸°à¸šà¸šà¹à¸¥à¸°à¸œà¸¹à¹‰à¸„วบคุมจะสามารถเข้าถึงไทม์ไลน์ทั้งหมด ถึงà¹à¸¡à¹‰à¸§à¹ˆà¸²à¸ˆà¸°à¹„ม่ได้เปิดใช้งานà¸à¹‡à¸•าม"
registration: "ลงทะเบียน"
enableRegistration: "เปิดใช้งานà¸à¸²à¸£à¸¥à¸‡à¸—ะเบียนผู้ใช้ใหม่"
invite: "คำเชิà¸"
-driveCapacityPerLocalAccount: "ความจุของไดรฟ์ต่อผู้ใช้ภายในเครื่อง"
+driveCapacityPerLocalAccount: "ความจุของไดรฟ์ต่อผู้ใช้ท้องถิ่น"
driveCapacityPerRemoteAccount: "ความจุของไดรฟ์ต่อผู้ใช้ระยะไà¸à¸¥"
inMb: "เป็นเมà¸à¸°à¹„บต์"
bannerUrl: "URL รูปภาพà¹à¸šà¸™à¹€à¸™à¸­à¸£à¹Œ"
@@ -373,7 +387,7 @@ basicInfo: "ข้อมูลเบื้องต้น"
pinnedUsers: "ผู้ใช้ที่ถูà¸à¸›à¸±à¸à¸«à¸¡à¸¸à¸”"
pinnedUsersDescription: "ป้อนชื่อผู้ใช้ที่คุณต้องà¸à¸²à¸£à¸›à¸±à¸à¸«à¸¡à¸¸à¸”ในหน้า “ค้นพบ†ฯลฯ คั่นด้วยà¸à¸²à¸£à¸‚ึ้นบรรทัดใหม่"
pinnedPages: "หน้าเพจที่ปัà¸à¸«à¸¡à¸¸à¸”"
-pinnedPagesDescription: "ป้อนเส้นทางของหน้าเพจที่คุณต้องà¸à¸²à¸£à¸›à¸±à¸à¸«à¸¡à¸¸à¸”ไว้ที่หน้าà¹à¸£à¸à¸‚องอินสà¹à¸•นซ์นี้ คั่นด้วยขึ้นบรรทัดใหม่"
+pinnedPagesDescription: "ป้อนเส้นทางของหน้าเพจที่คุณต้องà¸à¸²à¸£à¸›à¸±à¸à¸«à¸¡à¸¸à¸”ไว้ที่หน้าà¹à¸£à¸à¸‚องเซิร์ฟเวอร์นี้ คั่นด้วยà¸à¸²à¸£à¸‚ึ้นบรรทัดใหม่"
pinnedClipId: "ID ของคลิปที่จะปัà¸à¸«à¸¡à¸¸à¸”"
pinnedNotes: "โน้ตที่ปัà¸à¸«à¸¡à¸¸à¸”ไว้"
hcaptcha: "hCaptcha"
@@ -389,11 +403,11 @@ recaptcha: "reCAPTCHA"
enableRecaptcha: "เปิดใช้ reCAPTCHA"
recaptchaSiteKey: "คีย์ไซต์"
recaptchaSecretKey: "คีย์ลับ"
-turnstile: "เทิร์น'สไทล"
-enableTurnstile: "เปิดใช้งาน เทิร์น'สไทล"
+turnstile: "Turnstile"
+enableTurnstile: "เปิดใช้งาน Turnstile"
turnstileSiteKey: "คีย์ไซต์"
turnstileSecretKey: "คีย์ลับ"
-avoidMultiCaptchaConfirm: "à¸à¸²à¸£à¹ƒà¸Šà¹‰à¸£à¸°à¸šà¸š Captcha หลายระบบอาจทำให้เà¸à¸´à¸”à¸à¸²à¸£à¸£à¸šà¸à¸§à¸™à¸«à¸£à¸·à¸­à¸­à¸²à¸ˆà¸ˆà¸°à¹€à¸à¸´à¸”ข้อผิดพลาดได้ หาà¸à¸•้องà¸à¸²à¸£à¸—ี่จะปิดà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¸£à¸°à¸šà¸š Captcha อื่น ๆ à¹à¸™à¸°à¸™à¸³à¹ƒà¸«à¹‰à¸›à¸´à¸”ตัวอื่นๆà¸à¹ˆà¸­à¸™ ถ้าหาà¸à¸„ุณต้องà¸à¸²à¸£à¹ƒà¸«à¹‰à¹€à¸›à¸´à¸”ใช้งานต่อไป ให้ à¸à¸” ยà¸à¹€à¸¥à¸´à¸"
+avoidMultiCaptchaConfirm: "à¸à¸²à¸£à¹ƒà¸Šà¹‰ Captcha หลายตัวอาจทำให้เà¸à¸´à¸”à¸à¸²à¸£à¸£à¸šà¸à¸§à¸™à¸«à¸£à¸·à¸­à¸‚้อผิดพลาดได้ ต้องà¸à¸²à¸£à¸—ี่จะปิดà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™ Captcha ตัวอื่นเลยไหม? หาà¸à¸•้องà¸à¸²à¸£à¹ƒà¸«à¹‰à¹€à¸›à¸´à¸”ใช้งานต่อไป ให้à¸à¸”ยà¸à¹€à¸¥à¸´à¸"
antennas: "เสาอาà¸à¸²à¸¨"
manageAntennas: "จัดà¸à¸²à¸£à¹€à¸ªà¸²à¸­à¸²à¸à¸²à¸¨"
name: "ชื่อ"
@@ -401,7 +415,7 @@ antennaSource: "à¹à¸«à¸¥à¹ˆà¸‡à¹€à¸ªà¸²à¸­à¸²à¸à¸²à¸¨"
antennaKeywords: "คีย์เวิร์ดที่ควรฟัง"
antennaExcludeKeywords: "คีย์เวิร์ดที่จะยà¸à¹€à¸§à¹‰à¸™"
antennaExcludeBots: "ยà¸à¹€à¸§à¹‰à¸™à¸šà¸±à¸à¸Šà¸µà¸šà¸­à¸•"
-antennaKeywordsDescription: "คั่นด้วยช่องว่างสำหรับเงื่อนไข AND หรือด้วยà¸à¸²à¸£à¸‚ึ้นบรรทัดใหม่สำหรับเงื่อนไข OR"
+antennaKeywordsDescription: "คั่นด้วยเว้นวรรคสำหรับเงื่อนไข AND, หรือขึ้นบรรทัดใหม่สำหรับเงื่อนไข OR"
notifyAntenna: "à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนเà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¹‚น้ตใหม่"
withFileAntenna: "เฉพาะโน้ตที่มีไฟล์"
enableServiceworker: "เปิดใช้งานà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนà¹à¸šà¸šà¸žà¸¸à¸Šà¹„ปยังเบราว์เซอร์ของคุณ"
@@ -418,7 +432,7 @@ unsilenceConfirm: "ต้องà¸à¸²à¸£à¹€à¸¥à¸´à¸à¸›à¸´à¸”ปาà¸à¸œà¸¹à¹‰à
popularUsers: "ผู้ใช้ที่เป็นที่นิยม"
recentlyUpdatedUsers: "ผู้ใช้ที่เพิ่งใช้งานล่าสุด"
recentlyRegisteredUsers: "ผู้ใช้ที่เข้าร่วมใหม่"
-recentlyDiscoveredUsers: "ผู้ใช้ที่เพิ่งค้นพบใหม่"
+recentlyDiscoveredUsers: "ผู้ใช้ที่เพิ่งค้นพบล่าสุด"
exploreUsersCount: "มีผู้ใช้ {count} ราย"
exploreFediverse: "สำรวจสหพันธ์"
popularTags: "à¹à¸—็à¸à¸¢à¸­à¸”นิยม"
@@ -435,7 +449,7 @@ moderator: "ผู้ควบคุม"
moderation: "à¸à¸²à¸£à¸à¸¥à¸±à¹ˆà¸™à¸à¸£à¸­à¸‡"
moderationNote: "โน้ตà¸à¸²à¸£à¸à¸¥à¸±à¹ˆà¸™à¸à¸£à¸­à¸‡"
addModerationNote: "เพิ่มโน้ตà¸à¸²à¸£à¸à¸¥à¸±à¹ˆà¸™à¸à¸£à¸­à¸‡"
-moderationLogs: "ปูมà¸à¸²à¸£à¹à¸à¹‰à¹„ข"
+moderationLogs: "ปูมà¸à¸²à¸£à¸„วบคุมดูà¹à¸¥"
nUsersMentioned: "à¸à¸¥à¹ˆà¸²à¸§à¸–ึงโดยผู้ใช้ {n} ราย"
securityKeyAndPasskey: "ความปลอดภัยà¹à¸¥à¸°à¸£à¸«à¸±à¸ªà¸œà¹ˆà¸²à¸™"
securityKey: "à¸à¸¸à¸à¹à¸ˆà¸„วามปลอดภัย"
@@ -468,44 +482,46 @@ retype: "พิมพ์รหัสอีà¸à¸„รั้ง"
noteOf: "โน้ตของ {user}"
quoteAttached: "อ้างอิง"
quoteQuestion: "ต้องà¸à¸²à¸£à¸—ี่จะà¹à¸™à¸šà¸¡à¸±à¸™à¹€à¸žà¸·à¹ˆà¸­à¸­à¹‰à¸²à¸‡à¸­à¸´à¸‡à¹ƒà¸Šà¹ˆà¹„หม?"
+attachAsFileQuestion: "ข้อความในคลิปบอร์ดยาวเà¸à¸´à¸™à¹„ป คุณต้องà¸à¸²à¸£à¹à¸™à¸šà¹€à¸›à¹‡à¸™à¹„ฟล์ข้อความหรือไม่?"
noMessagesYet: "ยังไม่มีข้อความ"
newMessageExists: "คุณมีข้อความใหม่"
onlyOneFileCanBeAttached: "สามารถà¹à¸™à¸šà¹„ฟล์ได้เพียงไฟล์เดียวต่อ 1 ข้อความ"
-signinRequired: "à¸à¸£à¸¸à¸“าลงทะเบียนหรือลงชื่อเข้าใช้à¸à¹ˆà¸­à¸™à¸”ำเนินà¸à¸²à¸£à¸•่อ"
+signinRequired: "à¸à¹ˆà¸­à¸™à¸”ำเนินà¸à¸²à¸£à¸•่อ à¸à¸£à¸¸à¸“าลงทะเบียนหรือเข้าสู่ระบบ"
+signinOrContinueOnRemote: "เพื่อดำเนินà¸à¸²à¸£à¸•่อได้ คุณต้องไปที่เซิร์ฟเวอร์ที่คุณใช้งานอยู่ หรือลงทะเบียน/เข้าสู่ระบบเซิร์ฟเวอร์นี้"
invitations: "คำเชิà¸"
invitationCode: "รหัสเชิà¸"
checking: "Checking"
available: "พร้อมใช้งาน"
unavailable: "ไม่พร้อมใช้"
-usernameInvalidFormat: "คุณสามารถใช้อัà¸à¸©à¸£à¸•ัวพิมพ์ใหà¸à¹ˆà¹à¸¥à¸°à¸•ัวพิมพ์เล็ภตัวเลข à¹à¸¥à¸°à¸‚ีดล่างได้นะ ( a-z , A-Z , 0-9 , รวมไปถึงอัà¸à¸©à¸£à¸žà¸´à¹€à¸¨à¸©à¹€à¸Šà¹ˆà¸™ + * / , . - อื่นๆเป็นต้น )"
+usernameInvalidFormat: "สามารถใช้ a~z A~Z 0~9 à¹à¸¥à¸° _ ได้"
tooShort: "สั้นเà¸à¸´à¸™à¹„ปนะ"
tooLong: "ยาวเà¸à¸´à¸™à¹„ปนะ"
-weakPassword: "รหัสผ่าน à¹à¸¢à¹ˆà¸¡à¸²à¸"
+weakPassword: "รหัสผ่านà¹à¸¢à¹ˆà¸¡à¸²à¸"
normalPassword: "รหัสผ่านปà¸à¸•ิ"
strongPassword: "รหัสผ่านรัดà¸à¸¸à¸¡à¸¡à¸²à¸"
passwordMatched: "ถูà¸à¸•้อง!"
passwordNotMatched: "ไม่ถูà¸à¸•้อง"
-signinWith: "ลงชื่อเข้าใช้ด้วย {x}"
-signinFailed: "ไม่สามารถลงชื่อผู้เข้าใช้ได้ เนื่องจาภชื่อผู้ใช้หรือรหัสผ่านที่คุณป้อนนั้นไม่ถูà¸à¸•้องนะ"
+signinWith: "เข้าสู่ระบบด้วย {x}"
+signinFailed: "ไม่สามารถเข้าสู่ระบบได้ à¸à¸£à¸¸à¸“าตรวจสอบชื่อผู้ใช้à¹à¸¥à¸°à¸£à¸«à¸±à¸ªà¸œà¹ˆà¸²à¸™"
or: "หรือ"
language: "ภาษา"
uiLanguage: "ภาษาอินเทอร์เฟซผู้ใช้งาน"
aboutX: "เà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸š {x}"
-emojiStyle: "สไตล์เอโมจิ"
+emojiStyle: "สไตล์ของเอโมจิ"
native: "ภาษาà¹à¸¡à¹ˆ"
-disableDrawer: "อย่าใช้ลิ้นชัà¸à¸ªà¹„ตล์เมนู"
-showNoteActionsOnlyHover: "à¹à¸ªà¸”งà¸à¸²à¸£à¸”ำเนินà¸à¸²à¸£à¹€à¸‰à¸žà¸²à¸°à¹‚น้ตเมื่อโฮเวอร์"
+disableDrawer: "ไม่à¹à¸ªà¸”งเมนูในรูปà¹à¸šà¸šà¸¥à¸´à¹‰à¸™à¸Šà¸±à¸"
+showNoteActionsOnlyHover: "à¹à¸ªà¸”งà¸à¸²à¸£à¸”ำเนินà¸à¸²à¸£à¹‚น้ตเมื่อโฮเวอร์(วางเมาส์เหนือ)เท่านั้น"
showReactionsCount: "à¹à¸ªà¸”งจำนวนรีà¹à¸­à¸à¸Šà¸±à¹ˆà¸™à¹ƒà¸™à¹‚น้ต"
noHistory: "ไม่มีประวัติ"
signinHistory: "ประวัติà¸à¸²à¸£à¹€à¸‚้าสู่ระบบ"
enableAdvancedMfm: "เปิดใช้งาน MFM ขั้นสูง"
-enableAnimatedMfm: "เปิดà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™ MFM ด้วยà¹à¸­à¸™à¸´à¹€à¸¡à¸Šà¸±à¹ˆà¸™"
+enableAnimatedMfm: "เปิดà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™ MFM à¹à¸šà¸šà¹€à¸„ลื่อนไหว"
doing: "à¸à¸³à¸¥à¸±à¸‡à¸›à¸£à¸°à¸¡à¸§à¸¥à¸œà¸¥......"
category: "หมวดหมู่"
tags: "นามà¹à¸à¸‡"
docSource: "ที่มาของเอà¸à¸ªà¸²à¸£à¸™à¸µà¹‰"
createAccount: "สร้างบัà¸à¸Šà¸µ"
-existingAccount: "บัà¸à¸Šà¸µà¸—ี่มีอยู่"
+existingAccount: "บัà¸à¸Šà¸µà¸—ี่มีอยู่à¹à¸¥à¹‰à¸§"
regenerate: "สร้างอีà¸à¸„รั้ง"
fontSize: "ขนาดตัวอัà¸à¸©à¸£"
mediaListWithOneImageAppearance: "ความสูงของรายà¸à¸²à¸£à¸ªà¸·à¹ˆà¸­à¸—ี่มีเพียงรูปเดียว"
@@ -513,11 +529,11 @@ limitTo: "จำà¸à¸±à¸”ไว้ที่ {x}"
noFollowRequests: "คุณไม่มีคำขอติดตามที่รอดำเนินà¸à¸²à¸£"
openImageInNewTab: "เปิดรูปภาพในà¹à¸—็บใหม่"
dashboard: "หน้าà¸à¸£à¸°à¸”านหลัà¸"
-local: "ในพื้นที่"
+local: "ท้องถิ่น"
remote: "ระยะไà¸à¸¥"
total: "รวมทั้งหมด"
-weekOverWeekChanges: "เปลี่ยนà¹à¸›à¸¥à¸‡à¹„ปเมื่อสัปดาห์ที่à¹à¸¥à¹‰à¸§"
-dayOverDayChanges: "เปลี่ยนà¹à¸›à¸¥à¸‡à¹„ปเมื่อวานนี้"
+weekOverWeekChanges: "เทียบà¸à¸±à¸šà¸ªà¸±à¸›à¸”าห์à¸à¹ˆà¸­à¸™"
+dayOverDayChanges: "เทียบà¸à¸±à¸šà¹€à¸¡à¸·à¹ˆà¸­à¸§à¸²à¸™"
appearance: "ภาพลัà¸à¸©à¸“์"
clientSettings: "à¸à¸²à¸£à¸•ั้งค่าไคลเอนต์"
accountSettings: "ตั้งค่าบัà¸à¸Šà¸µ"
@@ -531,19 +547,19 @@ useObjectStorage: "ใช้à¸à¸²à¸£à¸ˆà¸±à¸”เà¸à¹‡à¸šà¹ƒà¸™à¸£à¸¹à¸›à¹à¸šà
objectStorageBaseUrl: "Base URL"
objectStorageBaseUrlDesc: "URL ที่ใช้เป็นข้อมูลอ้างอิง ระบุ URL ของ CDN หรือ Proxy ถ้าหาà¸à¸„ุณใช้อย่างใดอย่างหนึ่ง\n สำหรับà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™ S3 'https://<bucket>.s3.amazonaws.com' à¹à¸¥à¸°à¸ªà¸³à¸«à¸£à¸±à¸š GCS หรือบริà¸à¸²à¸£à¸—ี่เทียบเท่าใช้ 'https://storage.googleapis.com/<bucket>', เป็นต้น"
objectStorageBucket: "Bucket"
-objectStorageBucketDesc: "โปรดระบุชื่อที่เà¸à¹‡à¸šà¸‚้อมูลที่ใช้à¸à¸±à¸šà¸œà¸¹à¹‰à¹ƒà¸«à¹‰à¸šà¸£à¸´à¸à¸²à¸£à¸‚องคุณ"
+objectStorageBucketDesc: "โปรดระบุชื่อบัคเà¸à¹‡à¸•ของบริà¸à¸²à¸£à¸—ี่ใช้อยู่"
objectStoragePrefix: "คำนำหน้า"
objectStoragePrefixDesc: "ไฟล์ทั้งหมดจะถูà¸à¹€à¸à¹‡à¸šà¹„ว้ภายใต้ไดเร็à¸à¸—อรีที่มีคำนำหน้านี้"
objectStorageEndpoint: "ปลายทาง"
objectStorageEndpointDesc: "เว้นว่างไว้หาà¸à¸„ุณใช้ AWS S3 หรือระบุปลายทางเป็น '<host>' หรือ '<host>:<port>' ทั้งนี้ขึ้นอยู่à¸à¸±à¸šà¸œà¸¹à¹‰à¹ƒà¸«à¹‰à¸šà¸£à¸´à¸à¸²à¸£à¸—ี่คุณใช้อยู่ด้วย"
objectStorageRegion: "ภูมิภาค"
-objectStorageRegionDesc: "ระบุภูมิภาค เช่น 'xx-east-1' ถ้าหาà¸à¸šà¸£à¸´à¸à¸²à¸£à¸‚องคุณไม่ได้à¹à¸¢à¸à¸„วามà¹à¸•à¸à¸•่างระหว่างภูมิภาคà¸à¹‡à¹ƒà¸«à¹‰ เว้นว่างไว้หรือป้อน 'us-east-1'"
+objectStorageRegionDesc: "ระบุภูมิภาค เช่น ‘xx-east-1’ หาà¸à¸šà¸£à¸´à¸à¸²à¸£à¸‚องคุณไม่à¹à¸¢à¸à¸ à¸¹à¸¡à¸´à¸ à¸²à¸„ ให้ระบุเป็น ‘us-east-1’ หรือเว้นวางไว้หาà¸à¹ƒà¸Šà¹‰ AWS configuration files / environment variables"
objectStorageUseSSL: "ใช้ SSL"
objectStorageUseSSLDesc: "ปิดà¸à¸²à¸£à¸—ำงานนี้ไว้ ถ้าหาà¸à¸„ุณจะไม่ใช้ HTTPS สำหรับà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•่อ API"
objectStorageUseProxy: "เชื่อมต่อผ่านพร็อà¸à¸‹à¸µ"
objectStorageUseProxyDesc: "ปิดสิ่งนี้ไว้ถ้าหาà¸à¸„ุณจะไม่ใช้ Proxy สำหรับà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•่อ API"
objectStorageSetPublicRead: "ตั้งค่าเป็น “public-read†เมื่ออัปโหลด"
-s3ForcePathStyleDesc: "ถ้าหาà¸à¹€à¸›à¸´à¸”ใช้งาน s3ForcePathStyle ชื่อบัคเà¸à¹‡à¸•นั้นอาจจะต้องรวมอยู่ในเส้นทางของ URL ซึ่งตรงข้ามà¸à¸±à¸šà¸Šà¸·à¹ˆà¸­à¹‚ฮสต์ของ URL คุณอาจจะต้องเปิดใช้งานà¸à¸²à¸£à¸•ั้งค่านี้เมื่อใช้บริà¸à¸²à¸£à¸•่างๆ เช่น อินสà¹à¸•นซ์ Minio ที่โฮสต์เองนะ"
+s3ForcePathStyleDesc: "เมื่อเปิดใช้งาน s3ForcePathStyle จะบังคับให้ ระบุชื่อบัคเà¸à¹‡à¸•เป็นส่วนหนึ่งของพาธ à¹à¸—นที่จะเป็นชื่อโฮสต์ใน URL, อาจจำเป็นต้องเปิดใช้งานตัวเลือà¸à¸™à¸µà¹‰à¹€à¸¡à¸·à¹ˆà¸­à¹ƒà¸Šà¹‰à¸à¸±à¸š Minio ที่โฮสต์เองหรือบริà¸à¸²à¸£à¸—ี่คล้ายà¸à¸±à¸™"
serverLogs: "ปูมของเซิร์ฟเวอร์"
deleteAll: "ลบทั้งหมด"
showFixedPostForm: "à¹à¸ªà¸”งà¹à¸šà¸šà¸Ÿà¸­à¸£à¹Œà¸¡à¸à¸²à¸£à¹‚พสต์ที่ด้านบนสุดของไทม์ไลน์"
@@ -575,7 +591,7 @@ sort: "เรียงลำดับ"
ascendingOrder: "เรียงลำดับขึ้น"
descendingOrder: "เรียงลำดับลง"
scratchpad: "Scratchpad"
-scratchpadDescription: "Scratchpad เป็นà¸à¸²à¸£à¸ˆà¸±à¸”เตรียมสภาพà¹à¸§à¸”ล้อมสำหรับà¸à¸²à¸£à¸—ดลอง AiScript à¹à¸•่คุณสามารถเขียน ดำเนินà¸à¸²à¸£ à¹à¸¥à¸°à¸•รวจสอบผลลัพธ์ของà¸à¸²à¸£à¹‚ต้ตอบà¸à¸±à¸š Misskey มันได้ด้วยนะ"
+scratchpadDescription: "Scratchpad ให้สภาพà¹à¸§à¸”ล้อมสำหรับà¸à¸²à¸£à¸—ดลอง AiScript คุณสามารถเขียนโค้ด/สั่งดำเนินà¸à¸²à¸£/ตรวจสอบผลลัพธ์ ของà¸à¸²à¸£à¹‚ต้ตอบà¸à¸±à¸š Misskey ได้"
output: "เอาท์พุต"
script: "สคริปต์"
disablePagesScript: "ปิดà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™ AiScript บนเพจ"
@@ -587,15 +603,15 @@ unsetUserBannerConfirm: "ต้องà¸à¸²à¸£à¹€à¸¥à¸´à¸à¸•ั้งà¹à¸šà¸™à
deleteAllFiles: "ลบไฟล์ทั้งหมด"
deleteAllFilesConfirm: "ต้องà¸à¸²à¸£à¸¥à¸šà¹„ฟล์ทั้งหมดใช่ไหม?"
removeAllFollowing: "เลิà¸à¸•ิดตามผู้ใช้ที่ติดตามทั้งหมด"
-removeAllFollowingDescription: "เลิà¸à¸•ิดตามทั้งหมดจาภ{host} โปรดเรียà¸à¹ƒà¸Šà¹‰à¸ªà¸´à¹ˆà¸‡à¸™à¸µà¹‰à¹€à¸¡à¸·à¹ˆà¸­à¸­à¸´à¸™à¸ªà¹à¸•นซ์ดังà¸à¸¥à¹ˆà¸²à¸§à¹„ด้สูà¸à¸«à¸²à¸¢à¸•ายจาà¸à¹„ปà¹à¸¥à¹‰à¸§"
+removeAllFollowingDescription: "จะเลิà¸à¸•ิดตามทั้งหมดจาภ{host} โปรดดำเนินà¸à¸²à¸£à¸ªà¸´à¹ˆà¸‡à¸™à¸µà¹‰à¹€à¸¡à¸·à¹ˆà¸­à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸”ังà¸à¸¥à¹ˆà¸²à¸§à¹„ด้สูà¸à¸«à¸²à¸¢à¸•ายจาà¸à¹„ปà¹à¸¥à¹‰à¸§"
userSuspended: "ผู้ใช้รายนี้ถูà¸à¸£à¸°à¸‡à¸±à¸šà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™"
userSilenced: "ผู้ใช้รายนี้ถูà¸à¸›à¸´à¸”ปาà¸à¸­à¸¢à¸¹à¹ˆ"
yourAccountSuspendedTitle: "บัà¸à¸Šà¸µà¸™à¸µà¹‰à¸™à¸±à¹‰à¸™à¸–ูà¸à¸£à¸°à¸‡à¸±à¸š"
yourAccountSuspendedDescription: "บัà¸à¸Šà¸µà¸™à¸µà¹‰à¸–ูà¸à¸£à¸°à¸‡à¸±à¸š เนื่องจาà¸à¸¥à¸°à¹€à¸¡à¸´à¸”ข้อà¸à¸³à¸«à¸™à¸”ในà¸à¸²à¸£à¹ƒà¸«à¹‰à¸šà¸£à¸´à¸à¸²à¸£à¸‚องเซิร์ฟเวอร์หรืออาจจะละเมิดหลัà¸à¹€à¸à¸“ฑ์ชุมชน หรือ อาจจะโดนร้องเรียนเรื่องà¸à¸²à¸£à¸¥à¸°à¹€à¸¡à¸´à¸”ลิขสิทธิ์à¹à¸¥à¸°à¸­à¸·à¹ˆà¸™à¹†à¸­à¸¢à¹ˆà¸²à¸‡à¸•่อเนื่องซ้ำๆ หาà¸à¸„ุณคิดว่าไม่ได้ทำผิดจริงๆหรือตัดสินผิดพลาด ได้โปรดà¸à¸£à¸¸à¸“าติดต่อผู้ดูà¹à¸¥à¸£à¸°à¸šà¸šà¸«à¸²à¸à¸„ุณต้องà¸à¸²à¸£à¸—ราบเหตุผลโดยละเอียดเพิ่มเติม à¹à¸¥à¸°à¸‚อความà¸à¸£à¸¸à¸“าอย่าสร้างบัà¸à¸Šà¸µà¹ƒà¸«à¸¡à¹ˆ"
tokenRevoked: "โทเค็นไม่ถูà¸à¸•้อง"
-tokenRevokedDescription: "โทเค็นนี้หมดอายุà¹à¸¥à¹‰à¸§à¸™à¸°à¸„่ะà¸à¸£à¸¸à¸“าเข้าสู่ระบบอีà¸à¸„รั้งนะ"
+tokenRevokedDescription: "โทเค็นà¸à¸²à¸£à¹€à¸‚้าสู่ระบบหมดอายุ à¸à¸£à¸¸à¸“าเข้าสู่ระบบใหม่อีà¸à¸„รั้ง"
accountDeleted: "ลบบัà¸à¸Šà¸µà¹à¸¥à¹‰à¸§"
-accountDeletedDescription: "บัà¸à¸Šà¸µà¸™à¸µà¹‰à¸–ูà¸à¸¥à¸šà¹„ปà¹à¸¥à¹‰à¸§à¸™à¸°"
+accountDeletedDescription: "บัà¸à¸Šà¸µà¸™à¸µà¹‰à¸–ูà¸à¸¥à¸šà¹à¸¥à¹‰à¸§"
menu: "เมนู"
divider: "ตัวà¹à¸šà¹ˆà¸‡"
addItem: "เพิ่มรายà¸à¸²à¸£"
@@ -615,14 +631,14 @@ enablePlayer: "เปิดเครื่องเล่นวิดีโอ"
disablePlayer: "ปิดเครื่องเล่นวิดีโอ"
expandTweet: "ขยายทวีต"
themeEditor: "ตัวà¹à¸à¹‰à¹„ขธีม"
-description: "รายละเอียด"
+description: "คำอธิบาย"
describeFile: "เพิ่มà¹à¸„ปชั่น"
enterFileDescription: "ใส่à¹à¸„ปชั่น"
author: "ผู้เขียน"
leaveConfirm: "มีà¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡à¸—ี่ยังไม่ได้บันทึภต้องà¸à¸²à¸£à¸¥à¸°à¸—ิ้งมันใช่ไหม?"
manage: "à¸à¸²à¸£à¸ˆà¸±à¸”à¸à¸²à¸£"
plugins: "ปลั๊à¸à¸­à¸´à¸™"
-preferencesBackups: "ตั้งค่าà¸à¸²à¸£à¸ªà¸³à¸£à¸­à¸‡à¸‚้อมูล"
+preferencesBackups: "สำรองà¸à¸²à¸£à¸•ั้งค่า"
deck: "เด็ค"
undeck: "ออà¸à¸ˆà¸²à¸à¹€à¸”็ค"
useBlurEffectForModal: "ใช้เอฟเฟà¸à¸•์เบลอสำหรับโมดอล"
@@ -632,21 +648,21 @@ height: "ความสูง"
large: "ใหà¸à¹ˆ"
medium: "ปานà¸à¸¥à¸²à¸‡"
small: "เล็à¸"
-generateAccessToken: "สร้างà¸à¸²à¸£à¹€à¸‚้าถึงโทเค็น"
-permission: "à¸à¸²à¸£à¸­à¸™à¸¸à¸à¸²à¸•"
+generateAccessToken: "สร้างโทเค็นà¸à¸²à¸£à¹€à¸‚้าถึง"
+permission: "สิทธิ์"
adminPermission: "สิทธิ์ของผู้ดูà¹à¸¥à¸£à¸°à¸šà¸š"
enableAll: "เปิดใช้งานทั้งหมด"
disableAll: "ปิดà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¸—ั้งหมด"
tokenRequested: "ให้สิทธิ์à¸à¸²à¸£à¹€à¸‚้าถึงบัà¸à¸Šà¸µ"
-pluginTokenRequestedDescription: "ปลั๊à¸à¸­à¸´à¸™à¸™à¸µà¹‰à¸ˆà¸°à¸ªà¸²à¸¡à¸²à¸£à¸–ใช้à¸à¸²à¸£à¸­à¸™à¸¸à¸à¸²à¸•ที่ตั้งค่าไว้ที่นี่นะ"
+pluginTokenRequestedDescription: "ปลั๊à¸à¸­à¸´à¸™à¸™à¸µà¹‰à¸ˆà¸°à¹ƒà¸Šà¹‰à¸ªà¸´à¸—ธิ์ตามที่ตั้งค่าไว้ที่นี่"
notificationType: "ประเภทà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือน"
edit: "à¹à¸à¹‰à¹„ข"
-emailServer: "อีเมลเซิร์ฟเวอร์"
+emailServer: "เซิร์ฟเวอร์ของอีเมล"
enableEmail: "เปิดใช้งานà¸à¸²à¸£à¸à¸£à¸°à¸ˆà¸²à¸¢à¸­à¸µà¹€à¸¡à¸¥"
-emailConfigInfo: "ใช้เพื่อยืนยันอีเมลของคุณระหว่างà¸à¸²à¸£à¸ªà¸¡à¸±à¸„รหรือถ้าหาà¸à¸„ุณลืมรหัสผ่าน"
+emailConfigInfo: "ใช้สำหรับà¸à¸²à¸£à¸¢à¸·à¸™à¸¢à¸±à¸™à¸­à¸µà¹€à¸¡à¸¥à¸«à¸£à¸·à¸­à¸à¸²à¸£à¸£à¸µà¹€à¸‹à¹‡à¸•รหัสผ่าน"
email: "อีเมล"
emailAddress: "ที่อยู่อีเมล"
-smtpConfig: "à¸à¸³à¸«à¸™à¸”ค่าเซิร์ฟเวอร์ SMTP"
+smtpConfig: "ตั้งค่าเซิร์ฟเวอร์ SMTP"
smtpHost: "โฮสต์"
smtpPort: "พอร์ต"
smtpUser: "ชื่อผู้ใช้"
@@ -656,10 +672,10 @@ smtpSecure: "ใช้โดยนัย SSL/TLS สำหรับà¸à¸²à¸£à¹€à
smtpSecureInfo: "ปิดสิ่งนี้เมื่อใช้ STARTTLS"
testEmail: "ทดสอบà¸à¸²à¸£à¸ªà¹ˆà¸‡à¸­à¸µà¹€à¸¡à¸¥"
wordMute: "ปิดเสียงคำ"
-hardWordMute: "ปิดเสียงคำยาà¸"
-regexpError: "ข้อผิดพลาดของนิพจน์ทั่วไป"
-regexpErrorDescription: "เà¸à¸´à¸”ข้อผิดพลาดในนิพจน์ทั่วไปในบรรทัดที่ {line} ของà¸à¸²à¸£à¸›à¸´à¸”เสียงคำ {tab} ของคุณ:"
-instanceMute: "ปิดเสียง อินสà¹à¸•นซ์"
+hardWordMute: "ปิดเสียงคำà¹à¸šà¸šà¹à¸‚็งโป๊à¸"
+regexpError: "เà¸à¸´à¸”ข้อผิดพลาดใน regular expression"
+regexpErrorDescription: "เà¸à¸´à¸”ข้อผิดพลาดใน regular expression บรรทัดที่ {line} ของà¸à¸²à¸£à¸›à¸´à¸”เสียงคำ {tab} :"
+instanceMute: "ปิดเสียงเซิร์ฟเวอร์"
userSaysSomething: "{name} พูดอะไรบางอย่าง"
makeActive: "เปิดใช้งาน"
display: "à¹à¸ªà¸”งผล"
@@ -690,17 +706,17 @@ reportAbuseOf: "รายงาน {name}"
fillAbuseReportDescription: "à¸à¸£à¸¸à¸“าà¸à¸£à¸­à¸à¸£à¸²à¸¢à¸¥à¸°à¹€à¸­à¸µà¸¢à¸”เà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¸£à¸²à¸¢à¸‡à¸²à¸™à¸™à¸µà¹‰ หาà¸à¹€à¸›à¹‡à¸™à¹€à¸£à¸·à¹ˆà¸­à¸‡à¹€à¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¹‚น้ตโดยเฉพาะ ได้โปรดระบุ URL"
abuseReported: "เราได้ส่งรายงานของคุณไปà¹à¸¥à¹‰à¸§ ขอบคุณมาà¸à¹†à¸™à¸°"
reporter: "ผู้รายงาน"
-reporteeOrigin: "รายงานต้นทาง"
+reporteeOrigin: "ปลายทางรายงาน"
reporterOrigin: "à¹à¸«à¸¥à¹ˆà¸‡à¸œà¸¹à¹‰à¸£à¸²à¸¢à¸‡à¸²à¸™"
-forwardReport: "ส่งต่อรายงานไปยังอินสà¹à¸•นซ์ระยะไà¸à¸¥"
-forwardReportIsAnonymous: "ข้อมูลของคุณจะไม่ปราà¸à¸à¸šà¸™à¸­à¸´à¸™à¸ªà¹à¸•นซ์ระยะไà¸à¸¥à¹à¸¥à¸°à¸›à¸£à¸²à¸à¸à¹€à¸›à¹‡à¸™à¸šà¸±à¸à¸Šà¸µà¸£à¸°à¸šà¸šà¸—ี่ไม่ระบุชื่อ"
+forwardReport: "ส่งต่อรายงานไปยังเซิร์ฟเวอร์ระยะไà¸à¸¥"
+forwardReportIsAnonymous: "ข้อมูลของคุณจะไม่ปราà¸à¸à¸šà¸™à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸£à¸°à¸¢à¸°à¹„à¸à¸¥à¹à¸¥à¸°à¸›à¸£à¸²à¸à¸à¹€à¸›à¹‡à¸™à¸šà¸±à¸à¸Šà¸µà¸£à¸°à¸šà¸šà¸—ี่ไม่ระบุชื่อ"
send: "ส่ง"
abuseMarkAsResolved: "ทำเครื่องหมายรายงานว่าà¹à¸à¹‰à¹„ขà¹à¸¥à¹‰à¸§"
openInNewTab: "เปิดในà¹à¸—็บใหม่"
openInSideView: "เปิดในมุมมองด้านข้าง"
defaultNavigationBehaviour: "พฤติà¸à¸£à¸£à¸¡à¸à¸²à¸£à¸™à¸³à¸—างที่เป็นค่าเริ่มต้น"
editTheseSettingsMayBreakAccount: "à¸à¸²à¸£à¹à¸à¹‰à¹„ขà¸à¸²à¸£à¸•ั้งค่าเหล่านี้อาจทำให้บัà¸à¸Šà¸µà¸‚องคุณเสียหายนะ"
-instanceTicker: "ข้อมูลอินสà¹à¸•นซ์ของโน้ต"
+instanceTicker: "ข้อมูลเซิร์ฟเวอร์ของโน้ต"
waitingFor: "à¸à¸³à¸¥à¸±à¸‡à¸£à¸­ {x}"
random: "สุ่มค่า"
system: "ระบบ"
@@ -739,7 +755,7 @@ alwaysMarkSensitive: "ทำเครื่องหมายว่ามีเà
loadRawImages: "โหลดภาพต้นฉบับà¹à¸—นà¸à¸²à¸£à¹à¸ªà¸”งภาพขนาดย่อ"
disableShowingAnimatedImages: "ไม่ต้องเล่นภาพเคลื่อนไหว"
highlightSensitiveMedia: "ไฮไลท์สื่อที่มีเนื้อหาละเอียดอ่อน"
-verificationEmailSent: "ส่งอีเมลยืนยันà¹à¸¥à¹‰à¸§à¸™à¸° ได้โปรดà¸à¸£à¸¸à¸“าไปที่ลิงà¸à¹Œà¸—ี่รวมไว้เพื่อทำà¸à¸²à¸£à¸•รวจสอบให้เสร็จสิ้น"
+verificationEmailSent: "ได้ส่งอีเมลยืนยันà¹à¸¥à¹‰à¸§ à¸à¸£à¸¸à¸“าเข้าลิงà¸à¹Œà¸—ี่ระบุในอีเมลเพื่อทำà¸à¸²à¸£à¸•ั้งค่าให้เสร็จสิ้น"
notSet: "ไม่ได้ตั้งค่า"
emailVerified: "อีเมลได้รับà¸à¸²à¸£à¸¢à¸·à¸™à¸¢à¸±à¸™à¹à¸¥à¹‰à¸§"
noteFavoritesCount: "จำนวนโน้ตที่ชื่นชอบ"
@@ -750,7 +766,7 @@ useSystemFont: "ใช้ฟอนต์เริ่มต้นของระà
clips: "คลิป"
experimentalFeatures: "ฟังà¸à¹Œà¸Šà¸±à¹ˆà¸™à¸—ดสอบ"
experimental: "ทดลอง"
-thisIsExperimentalFeature: "นี่คือฟีเจอร์ทดลองนะค่ะ ฟังà¸à¹Œà¸Šà¸±à¸™à¸à¸²à¸£à¸—ำงานบางอย่างอาจเปลี่ยนà¹à¸›à¸¥à¸‡à¹„ด้ à¹à¸¥à¸°à¸­à¸²à¸ˆà¹„ม่ทำงานหรือไม่เสถียรตามที่ตั้งใจไว้นะ"
+thisIsExperimentalFeature: "นี่เป็นฟีเจอร์ทดลอง ซึ่งอาจมีà¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡à¸à¸²à¸£à¸—ำงาน à¹à¸¥à¸°à¸­à¸²à¸ˆà¹„ม่ทำงานตามที่ตั้งใจไว้"
developer: "สำหรับนัà¸à¸žà¸±à¸’นา"
makeExplorable: "ทำให้บัà¸à¸Šà¸µà¸¡à¸­à¸‡à¹€à¸«à¹‡à¸™à¹ƒà¸™ “สำรวจâ€"
makeExplorableDescription: "ถ้าหาà¸à¸„ุณปิดà¸à¸²à¸£à¸—ำงานนี้ บัà¸à¸Šà¸µà¸‚องคุณนั้นจะไม่à¹à¸ªà¸”งในส่วน “สำรวจâ€"
@@ -761,14 +777,14 @@ center: "à¸à¸¶à¹ˆà¸‡à¸à¸¥à¸²à¸‡"
wide: "à¸à¸§à¹‰à¸²à¸‡"
narrow: "ชิด"
reloadToApplySetting: "à¸à¸²à¸£à¸•ั้งค่านี้จะมีผลหลังจาà¸à¹‚หลดหน้าซ้ำเท่านั้น ต้องà¸à¸²à¸£à¸—ี่จะโหลดใหม่เลยไหม?"
-needReloadToApply: "จำเป็นต้องโหลดซ้ำถึงจะมีผลนะ"
+needReloadToApply: "ต้องรีโหลดเพื่อให้à¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡à¸¡à¸µà¸œà¸¥"
showTitlebar: "à¹à¸ªà¸”งà¹à¸–บชื่อ"
clearCache: "ล้างà¹à¸„ช"
-onlineUsersCount: "{n} ผู้ใช้คนนี้à¸à¸³à¸¥à¸±à¸‡à¸­à¸­à¸™à¹„ลน์"
+onlineUsersCount: "{n} รายà¸à¸³à¸¥à¸±à¸‡à¸­à¸­à¸™à¹„ลน์"
nUsers: "{n} ผู้ใช้งาน"
nNotes: "{n} โน้ต"
-sendErrorReports: "ส่งรายงานว่าข้อผิดพลาด"
-sendErrorReportsDescription: "เมื่อเปิดใช้งาน ข้อมูลข้อผิดพลาดโดยรายละเอียดนั้นจะถูà¸à¹à¸Šà¸£à¹Œà¹ƒà¸«à¹‰à¸à¸±à¸š Misskey เมื่อเà¸à¸´à¸”ปัà¸à¸«à¸² ซึ่งช่วยปรับปรุงคุณภาพของ Misskey\nซึ่งจะรวมถึงข้อมูล เช่น เวอร์ชั่นของระบบปà¸à¸´à¸šà¸±à¸•ิà¸à¸²à¸£ เบราว์เซอร์ที่คุณใช้ à¸à¸´à¸ˆà¸à¸£à¸£à¸¡à¸‚องคุณใน Misskey เป็นต้น"
+sendErrorReports: "ส่งรายงานข้อผิดพลาด"
+sendErrorReportsDescription: "เมื่อเปิดใช้งาน à¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¸‚้อผิดพลาดจะถูà¸à¹à¸Šà¸£à¹Œà¸à¸±à¸š Misskey เมื่อเà¸à¸´à¸”ปัà¸à¸«à¸² ซึ่งช่วยในà¸à¸²à¸£à¸›à¸£à¸±à¸šà¸›à¸£à¸¸à¸‡à¸„ุณภาพของซอฟต์à¹à¸§à¸£à¹Œ ข้อมูลข้อผิดพลาดอาจรวมถึงเวอร์ชันของระบบปà¸à¸´à¸šà¸±à¸•ิà¸à¸²à¸£ ประเภทของเบราว์เซอร์ à¹à¸¥à¸°à¸›à¸£à¸°à¸§à¸±à¸•ิà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™ ฯลฯ"
myTheme: "ธีมของฉัน"
backgroundColor: "สีพื้นหลัง"
accentColor: "สีหลัà¸"
@@ -780,7 +796,7 @@ value: "ค่า"
createdAt: "สร้างเมื่อ"
updatedAt: "อัปเดตล่าสุด"
saveConfirm: "บันทึà¸à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡à¸¡à¸±à¹‰à¸¢?"
-deleteConfirm: "ลบจริงๆเหรอ?"
+deleteConfirm: "ต้องà¸à¸²à¸£à¸¥à¸šà¹ƒà¸Šà¹ˆà¹„หม?"
invalidValue: "ค่านี้ไม่ถูà¸à¸•้อง"
registry: "ทะเบียน"
closeAccount: "ปิด บัà¸à¸Šà¸µ"
@@ -793,7 +809,7 @@ capacity: "ความจุ"
inUse: "ใช้à¹à¸¥à¹‰à¸§"
editCode: "à¹à¸à¹‰à¹„ขโค้ด"
apply: "นำไปใช้"
-receiveAnnouncementFromInstance: "รับà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนจาà¸à¸­à¸´à¸™à¸ªà¹à¸•นซ์นี้"
+receiveAnnouncementFromInstance: "รับà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนจาà¸à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸™à¸µà¹‰"
emailNotification: "à¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนทางอีเมล"
publish: "เผยà¹à¸žà¸£à¹ˆ"
inChannelSearch: "ค้นหาในช่อง"
@@ -821,7 +837,7 @@ active: "ใช้งานอยู่"
offline: "ออฟไลน์"
notRecommended: "ไม่à¹à¸™à¸°à¸™à¸³"
botProtection: "à¸à¸²à¸£à¸›à¹‰à¸­à¸‡à¸à¸±à¸™ Bot"
-instanceBlocking: "อินสà¹à¸•นซ์ที่ถูà¸à¸šà¸¥à¹‡à¸­à¸"
+instanceBlocking: "เซิร์ฟเวอร์ที่ถูà¸à¸šà¸¥à¹‡à¸­à¸/ปิดปาà¸"
selectAccount: "เลือà¸à¸šà¸±à¸à¸Šà¸µ"
switchAccount: "สลับบัà¸à¸Šà¸µà¸œà¸¹à¹‰à¹ƒà¸Šà¹‰"
enabled: "เปิดใช้งาน"
@@ -831,9 +847,10 @@ user: "ผู้ใช้"
administration: "à¸à¸²à¸£à¸ˆà¸±à¸”à¸à¸²à¸£"
accounts: "บัà¸à¸Šà¸µà¸œà¸¹à¹‰à¹ƒà¸Šà¹‰"
switch: "สลับ"
-noMaintainerInformationWarning: "ข้อมูลผู้ดูà¹à¸¥à¹„ม่ได้รับà¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่านะ"
-noBotProtectionWarning: "ไม่ได้à¸à¸³à¸«à¸™à¸”ค่าà¸à¸²à¸£à¸›à¹‰à¸­à¸‡à¸à¸±à¸™à¸šà¸­à¸—นะ"
-configure: "à¸à¸³à¸«à¸™à¸”ค่า"
+noMaintainerInformationWarning: "ยังไม่ได้ตั้งค่าข้อมูลของผู้ดูà¹à¸¥à¸£à¸°à¸šà¸š"
+noInquiryUrlWarning: "ยังไม่ได้ตั้งค่า URL สำหรับà¸à¸²à¸£à¸•ิดต่อสอบถาม"
+noBotProtectionWarning: "ยังไม่ได้ตั้งค่าà¸à¸²à¸£à¸›à¹‰à¸­à¸‡à¸à¸±à¸™à¸šà¸­à¸•"
+configure: "ตั้งค่า"
postToGallery: "สร้างโพสต์à¹à¸à¸¥à¹€à¸¥à¸­à¸£à¸µà¹ˆà¹ƒà¸«à¸¡à¹ˆ"
postToHashtag: "โพสต์ไปที่à¹à¸®à¸Šà¹à¸—็à¸à¸™à¸µà¹‰"
gallery: "à¹à¸à¸¥à¹€à¸¥à¸­à¸£à¸µà¹ˆ"
@@ -909,8 +926,8 @@ themeColor: "สีธีม"
size: "ขนาด"
numberOfColumn: "จำนวนคอลัมน์"
searchByGoogle: "ค้นหา"
-instanceDefaultLightTheme: "ธีมสว่างตามค่าเริ่มต้นของอินสà¹à¸•นซ์"
-instanceDefaultDarkTheme: "ธีมมืดตามค่าเริ่มต้นของอินสà¹à¸•นซ์"
+instanceDefaultLightTheme: "ธีมสว่างตามค่าเริ่มต้นของเซิร์ฟเวอร์"
+instanceDefaultDarkTheme: "ธีมมืดตามค่าเริ่มต้นของเซิร์ฟเวอร์"
instanceDefaultThemeDescription: "ป้อนรหัสธีมในรูปà¹à¸šà¸šà¸­à¸­à¸šà¹€à¸ˆà¹‡à¸à¸•์"
mutePeriod: "ระยะเวลาปิดเสียง"
period: "ระยะเวลา"
@@ -930,7 +947,7 @@ cropNo: "ใช้ตามที่เป็นอยู่"
file: "ไฟล์"
recentNHours: "ล่าสุด {n} ชั่วโมงที่à¹à¸¥à¹‰à¸§"
recentNDays: "ล่าสุด {n} วันที่à¹à¸¥à¹‰à¸§"
-noEmailServerWarning: "ไม่ได้à¸à¸³à¸«à¸™à¸”ค่าเซิร์ฟเวอร์อีเมลนี้"
+noEmailServerWarning: "ยังไม่ได้ตั้งค่าเซิร์ฟเวอร์ของอีเมล"
thereIsUnresolvedAbuseReportWarning: "มีรายงานที่ยังไม่ได้à¹à¸à¹‰à¹„ข"
recommended: "à¹à¸™à¸°à¸™à¸³"
check: "ตรวจสอบ"
@@ -965,7 +982,7 @@ cannotUploadBecauseExceedsFileSizeLimit: "ไม่สามารถอัปà¹
beta: "เบต้า"
enableAutoSensitive: "ทำเครื่องหมายว่ามีเนื้อหาที่ละเอียดอ่อนโดยอัตโนมัติ"
enableAutoSensitiveDescription: "อนุà¸à¸²à¸•ให้ตรวจหาà¹à¸¥à¸°à¸—ำเครื่องหมายสื่อว่ามีเนื้อหาโดยละเอียดอ่อนโดยอัตโนมัติ ผ่าน Machine Learning หาà¸à¹€à¸›à¹‡à¸™à¹„ปได้ à¹à¸¡à¹‰à¸§à¹ˆà¸²à¸„ุณจะปิดคุณสมบัตินี้ à¸à¹‡à¸­à¸²à¸ˆà¸–ูà¸à¸•ั้งค่าโดยอัตโนมัติ ทั้งนี้ขึ้นอยู่à¸à¸±à¸šà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œ"
-activeEmailValidationDescription: "เปิดใช้งานà¸à¸²à¸£à¸•รวจสอบที่อยู่อีเมลให้มีความเข้มงวดยิ่งขึ้น ซึ่งอาจจะรวมไปถึงà¸à¸²à¸£à¸•รวจสอบที่อยู่อีเมล์ที่ใช้à¹à¸¥à¹‰à¸§à¸—ิ้งà¹à¸¥à¸°à¹‚ดยให้พิจารณาว่าสามารถสื่อสารด้วยได้หรือไม่ เมื่อไม่เลือà¸à¸£à¸°à¸šà¸šà¸ˆà¸°à¸•รวจสอบเฉพาะรูปà¹à¸šà¸šà¸‚องอีเมลเท่านั้น"
+activeEmailValidationDescription: "à¸à¸²à¸£à¸•รวจสอบอีเมลของผู้ใช้จะเข้มงวดมาà¸à¸‚ึ้น โดยพิจารณาว่าเป็นอีเมลชั่วคราวหรือไม่ à¹à¸¥à¸°à¸ªà¸²à¸¡à¸²à¸£à¸–ติดต่อได้จริงหรือไม่ หาà¸à¸›à¸´à¸”à¸à¸²à¸£à¸•รวจสอบนี้ จะตรวจสอบเพียงว่ารูปà¹à¸šà¸šà¸­à¸µà¹€à¸¡à¸¥à¸—ี่ถูà¸à¸•้องหรือไม่เท่านั้น"
navbar: "à¹à¸–บนำทาง"
shuffle: "สลับ"
account: "บัà¸à¸Šà¸µà¸œà¸¹à¹‰à¹ƒà¸Šà¹‰"
@@ -974,7 +991,7 @@ pushNotification: "à¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนà¹à¸šà¸šà¸žà¸¸à¸Š"
subscribePushNotification: "เปิดà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนà¹à¸šà¸šà¸žà¸¸à¸Š"
unsubscribePushNotification: "ปิดà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนà¹à¸šà¸šà¸žà¸¸à¸Š"
pushNotificationAlreadySubscribed: "à¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนà¹à¸šà¸šà¸žà¸¸à¸Šà¹„ด้เปิดใช้งานà¹à¸¥à¹‰à¸§"
-pushNotificationNotSupported: "เบราว์เซอร์หรืออินสà¹à¸•นซ์ของคุณนั้นไม่รองรับà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนà¹à¸šà¸šà¸žà¸¸à¸Š"
+pushNotificationNotSupported: "เบราว์เซอร์หรือเซิร์ฟเวอร์ไม่รองรับà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนà¹à¸šà¸šà¸žà¸¸à¸Š"
sendPushNotificationReadMessage: "ลบà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนà¹à¸šà¸šà¸žà¸¸à¸Šà¹€à¸¡à¸·à¹ˆà¸­à¸­à¹ˆà¸²à¸™à¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนหรือข้อความที่เà¸à¸µà¹ˆà¸¢à¸§à¸‚้องà¹à¸¥à¹‰à¸§"
sendPushNotificationReadMessageCaption: "อาจทำให้อุปà¸à¸£à¸“์ของคุณใช้พลังงานมาà¸à¸‚ึ้น"
windowMaximize: "ขยายใหà¸à¹ˆà¸ªà¸¸à¸”"
@@ -1017,36 +1034,37 @@ achievements: "ความสำเร็จ"
gotInvalidResponseError: "à¸à¸²à¸£à¸•อบสนองเซิร์ฟเวอร์ไม่ถูà¸à¸•้อง"
gotInvalidResponseErrorDescription: "เซิร์ฟเวอร์อาจไม่สามารถเข้าถึงได้หรืออาจจะà¸à¸³à¸¥à¸±à¸‡à¸­à¸¢à¸¹à¹ˆà¹ƒà¸™à¸£à¸°à¸«à¸§à¹ˆà¸²à¸‡à¸›à¸£à¸±à¸šà¸›à¸£à¸¸à¸‡ à¸à¸£à¸¸à¸“าลองใหม่อีà¸à¸„รั้งในภายหลังนะคะ"
thisPostMayBeAnnoying: "โน้ตนี้อาจจะเป็นà¸à¸²à¸£à¸£à¸šà¸à¸§à¸™à¸œà¸¹à¹‰à¸­à¸·à¹ˆà¸™à¸™à¸°à¸„ะ"
-thisPostMayBeAnnoyingHome: "โพสต์ไปยังไทม์ไลน์หน้าà¹à¸£à¸"
+thisPostMayBeAnnoyingHome: "โพสต์ไปยังไทม์ไลน์หลัà¸"
thisPostMayBeAnnoyingCancel: "เลิà¸"
thisPostMayBeAnnoyingIgnore: "โพสต์ยังไงà¸à¹‡à¹à¸¥à¹‰à¸§à¹à¸•่"
collapseRenotes: "ยุบรีโน้ตที่คุณเคยเห็นà¹à¸¥à¹‰à¸§"
+collapseRenotesDescription: "พับย่อโน้ตที่เคยตอบสนองหรือรีโน้ตà¹à¸¥à¹‰à¸§"
internalServerError: "เซิร์ฟเวอร์ภายในเà¸à¸´à¸”ข้อผิดพลาด"
-internalServerErrorDescription: "เซิร์ฟเวอร์รันค้นพบข้อผิดพลาดที่ไม่คาดคิด"
+internalServerErrorDescription: "เà¸à¸´à¸”ข้อผิดพลาดที่ไม่คาดคิดภายในเซิร์ฟเวอร์"
copyErrorInfo: "คัดลอà¸à¸£à¸²à¸¢à¸¥à¸°à¹€à¸­à¸µà¸¢à¸”ข้อผิดพลาด"
-joinThisServer: "ลงชื่อสมัครใช้ในอินสà¹à¸•นซ์นี้"
-exploreOtherServers: "มองหาอินสà¹à¸•นซ์อื่น"
+joinThisServer: "ลงทะเบียนบนเซิร์ฟเวอร์นี้"
+exploreOtherServers: "มองหาเซิร์ฟเวอร์อื่น"
letsLookAtTimeline: "มาดูไทม์ไลน์à¸à¸±à¸™"
-disableFederationConfirm: "ปิดใช้งานสหพันธ์จริงๆหรอà¹à¸™à¹ˆà¹ƒà¸ˆà¹à¸¥à¹‰à¸§à¸™à¸°?"
+disableFederationConfirm: "ปิดใช้งานสหพันธ์เลยใช่ไหม?"
disableFederationConfirmWarn: "โพสต์จะยังคงเป็นสาธารณะต่อไป เว้นà¹à¸•่จะตั้งค่าเป็นอย่างอื่น"
disableFederationOk: "ปิดà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™"
-invitationRequiredToRegister: "อินสà¹à¸•นซ์นี้เป็นà¹à¸šà¸šà¸£à¸±à¸šà¹€à¸Šà¸´à¸ เฉพาะผู้ที่มีรหัสเชิà¸à¹€à¸—่านั้นที่สามารถลงทะเบียนได้"
-emailNotSupported: "อินสà¹à¸•นซ์นี้ไม่รองรับà¸à¸²à¸£à¸ªà¹ˆà¸‡à¸­à¸µà¹€à¸¡à¸¥"
+invitationRequiredToRegister: "เซิร์ฟเวอร์นี้เป็นà¹à¸šà¸šà¸£à¸±à¸šà¹€à¸Šà¸´à¸ เฉพาะผู้มีรหัสเชิà¸à¹€à¸—่านั้นถึงสามารถลงทะเบียนได้"
+emailNotSupported: "เซิร์ฟเวอร์นี้ไม่รองรับà¸à¸²à¸£à¸ªà¹ˆà¸‡à¸­à¸µà¹€à¸¡à¸¥"
postToTheChannel: "โพสต์ลงช่อง"
cannotBeChangedLater: "สิ่งนี้ไม่สามารถเปลี่ยนà¹à¸›à¸¥à¸‡à¹„ด้ในภายหลังนะ"
reactionAcceptance: "à¸à¸²à¸£à¸¢à¸­à¸¡à¸£à¸±à¸šà¸£à¸µà¹à¸­à¸„ชั่น"
likeOnly: "ที่ถูà¸à¹ƒà¸ˆà¹€à¸—่านั้น"
-likeOnlyForRemote: "ทั้งหมด (เฉพาะà¸à¸²à¸£à¸–ูà¸à¹ƒà¸ˆà¸ˆà¸²à¸à¸­à¸´à¸™à¸ªà¹à¸•นซ์ระยะไà¸à¸¥)"
+likeOnlyForRemote: "ทั้งหมด (เฉพาะà¸à¸²à¸£à¸–ูà¸à¹ƒà¸ˆà¸ˆà¸²à¸à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸£à¸°à¸¢à¸°à¹„à¸à¸¥)"
nonSensitiveOnly: "เฉพาะไม่มีเนื้อหาละเอียดอ่อน"
nonSensitiveOnlyForLocalLikeOnlyForRemote: "เฉพาะไม่มีเนื้อหาละเอียดอ่อน (เฉพาะà¸à¸²à¸£à¸–ูà¸à¹ƒà¸ˆà¸ˆà¸²à¸à¸£à¸°à¸¢à¸°à¹„à¸à¸¥à¹€à¸—่านั้น)"
rolesAssignedToMe: "บทบาทที่ได้รับมอบหมายให้ฉัน"
-resetPasswordConfirm: "รีเซ็ตรหัสผ่านของคุณจริงๆหรอ?"
+resetPasswordConfirm: "ต้องà¸à¸²à¸£à¸£à¸µà¹€à¸‹à¹‡à¸•รหัสผ่านใช่ไหม?"
sensitiveWords: "คำที่มีเนื้อหาละเอียดอ่อน"
-sensitiveWordsDescription: "à¸à¸²à¸£à¹€à¸›à¸´à¸”เผยโน้ตทั้งหมดที่มีคำที่à¸à¸³à¸«à¸™à¸”ค่าไว้จะถูà¸à¸•ั้งค่าเป็น \"หน้าà¹à¸£à¸\" โดยอัตโนมัติ คุณยังสามารถà¹à¸ªà¸”งหลายรายà¸à¸²à¸£à¹„ด้โดยà¹à¸¢à¸à¸£à¸²à¸¢à¸à¸²à¸£à¹‚ดยใช้ตัวà¹à¸šà¹ˆà¸‡à¸šà¸£à¸£à¸—ัดได้นะ"
-sensitiveWordsDescription2: "à¸à¸²à¸£à¹ƒà¸Šà¹‰à¸Šà¹ˆà¸­à¸‡à¸§à¹ˆà¸²à¸‡à¸™à¸±à¹‰à¸™à¸­à¸²à¸ˆà¸ˆà¸°à¸ªà¸£à¹‰à¸²à¸‡à¸™à¸´à¸žà¸ˆà¸™à¹Œ AND à¹à¸¥à¸°à¸„ำหลัà¸à¸—ี่มีเครื่องหมายทับล้อมรอบจะเปลี่ยนเป็นนิพจน์ทั่วไปนะ"
+sensitiveWordsDescription: "โน้ตที่มีคำที่ระบุไว้จะถูà¸à¸•ั้งค่าà¸à¸²à¸£à¸¡à¸­à¸‡à¹€à¸«à¹‡à¸™à¸‚องให้à¹à¸ªà¸”งเฉพาะในหน้าหลัà¸à¹€à¸—่านั้น คั่นคำด้วยà¸à¸²à¸£à¸‚ึ้นบรรทัดใหม่"
+sensitiveWordsDescription2: "ถ้าà¹à¸¢à¸à¸”้วยเว้นวรรคจะเป็นà¸à¸²à¸£à¸£à¸°à¸šà¸¸ AND à¹à¸¥à¸°à¸–้าล้อมคำด้วยสà¹à¸¥à¸Š (/) จะเป็นà¸à¸²à¸£à¹ƒà¸Šà¹‰ regular expression"
prohibitedWords: "คำต้องห้าม"
prohibitedWordsDescription: "จะà¹à¸ˆà¹‰à¸‡à¹€à¸•ือนว่าเà¸à¸´à¸”ข้อผิดพลาดเมื่อพยายามโพสต์โน้ตที่มีคำที่à¸à¸³à¸«à¸™à¸”ไว้ สามารถตั้งได้หลายคำด้วยà¸à¸²à¸£à¸‚ึ้นบรรทัดใหม่"
-prohibitedWordsDescription2: "à¸à¸²à¸£à¹ƒà¸Šà¹‰à¸Šà¹ˆà¸­à¸‡à¸§à¹ˆà¸²à¸‡à¸™à¸±à¹‰à¸™à¸­à¸²à¸ˆà¸ˆà¸°à¸ªà¸£à¹‰à¸²à¸‡à¸™à¸´à¸žà¸ˆà¸™à¹Œ AND à¹à¸¥à¸°à¸„ำหลัà¸à¸—ี่มีเครื่องหมายทับล้อมรอบจะเปลี่ยนเป็นนิพจน์ทั่วไปนะ"
+prohibitedWordsDescription2: "ถ้าà¹à¸¢à¸à¸”้วยเว้นวรรคจะเป็นà¸à¸²à¸£à¸£à¸°à¸šà¸¸ AND à¹à¸¥à¸°à¸–้าล้อมคำด้วยสà¹à¸¥à¸Š (/) จะเป็นà¸à¸²à¸£à¹ƒà¸Šà¹‰ regular expression"
hiddenTags: "à¹à¸®à¸Šà¹à¸—็à¸à¸—ี่ซ่อนอยู่"
hiddenTagsDescription: "เลือà¸à¹à¸—็à¸à¸—ี่จะไม่à¹à¸ªà¸”งในรายà¸à¸²à¸£à¹€à¸—รนด์ สามารถลงทะเบียนหลายà¹à¸—็à¸à¹„ด้โดยขึ้นบรรทัดใหม่"
notesSearchNotAvailable: "à¸à¸²à¸£à¸„้นหาโน้ตไม่พร้อมใช้งาน"
@@ -1058,7 +1076,7 @@ retryAllQueuesNow: "ลองเรียà¸à¹ƒà¸Šà¹‰à¸„ิวทั้งหม
retryAllQueuesConfirmTitle: "ลองใหม่ทั้งหมดจริงๆหรอà¹à¸™à¹ˆà¹ƒà¸ˆà¸™à¸°?"
retryAllQueuesConfirmText: "สิ่งนี้จะเพิ่มà¸à¸²à¸£à¹‚หลดเซิร์ฟเวอร์ชั่วคราวนะ"
enableChartsForRemoteUser: "สร้างà¹à¸œà¸™à¸ à¸¹à¸¡à¸´à¸‚้อมูลผู้ใช้ระยะไà¸à¸¥"
-enableChartsForFederatedInstances: "สร้างà¹à¸œà¸™à¸ à¸¹à¸¡à¸´à¸‚้อมูลอินสà¹à¸•นซ์ระยะไà¸à¸¥"
+enableChartsForFederatedInstances: "สร้างà¹à¸œà¸™à¸ à¸¹à¸¡à¸´à¸‚องเซิร์ฟเวอร์ระยะไà¸à¸¥"
showClipButtonInNoteFooter: "เพิ่ม “คลิป†ไปยังเมนูสั่งà¸à¸²à¸£à¸‚องโน้ต"
reactionsDisplaySize: "ขนาดของรีà¹à¸­à¸„ชั่น"
limitWidthOfReaction: "จำà¸à¸±à¸”ความà¸à¸§à¹‰à¸²à¸‡à¸ªà¸¹à¸‡à¸ªà¸¸à¸”ของรีà¹à¸­à¸„ชั่นà¹à¸¥à¸°à¹à¸ªà¸”งให้เล็à¸à¸¥à¸‡"
@@ -1077,7 +1095,7 @@ addMemo: "เพิ่มเมโม"
editMemo: "à¹à¸à¹‰à¹„ขเมโม"
reactionsList: "รายà¸à¸²à¸£à¸£à¸µà¹à¸­à¸„ชั่น"
renotesList: "รายà¸à¸²à¸£à¸£à¸µà¹‚น้ต"
-notificationDisplay: "à¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือน"
+notificationDisplay: "à¸à¸²à¸£à¹à¸ªà¸”งà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือน"
leftTop: "บนซ้าย"
rightTop: "บนขวา"
leftBottom: "ล่างซ้าย"
@@ -1087,13 +1105,15 @@ vertical: "à¹à¸™à¸§à¸•ั้ง"
horizontal: "à¹à¸™à¸§à¸™à¸­à¸™"
position: "ตำà¹à¸«à¸™à¹ˆà¸‡"
serverRules: "à¸à¸Žà¸‚องเซิร์ฟเวอร์"
-pleaseConfirmBelowBeforeSignup: "โปรดยืนยันที่ด้านล่างà¸à¹ˆà¸­à¸™à¸ªà¸¡à¸±à¸„รใช้งาน"
+pleaseConfirmBelowBeforeSignup: "หาà¸à¸•้องà¸à¸²à¸£à¸¥à¸‡à¸—ะเบียนบนเซิร์ฟเวอร์นี้ คุณต้องตรวจสอบà¹à¸¥à¸°à¸¢à¸­à¸¡à¸£à¸±à¸šà¸ªà¸´à¹ˆà¸‡à¸•่อไปนี้"
pleaseAgreeAllToContinue: "คุณต้องยอมรับทุà¸à¸Šà¹ˆà¸­à¸‡à¸•รงด้านบนเพื่อดำเนินà¸à¸²à¸£à¸•่อค่ะ"
continue: "ดำเนินà¸à¸²à¸£à¸•่อ"
preservedUsernames: "ชื่อผู้ใช้ที่สงวนไว้"
preservedUsernamesDescription: "ระบุชื่อผู้ใช้ที่จะสงวนชื่อไว้ คั่นด้วยà¸à¸²à¸£à¸‚ึ้นบรรทัดใหม่ ชื่อผู้ใช้ที่ระบุที่นี่จะไม่สามารถใช้งานได้อีà¸à¸•่อไปเมื่อสร้างบัà¸à¸Šà¸µà¹ƒà¸«à¸¡à¹ˆ ยà¸à¹€à¸§à¹‰à¸™à¹€à¸¡à¸·à¹ˆà¸­à¸œà¸¹à¹‰à¸”ูà¹à¸¥à¸£à¸°à¸šà¸šà¸ªà¸£à¹‰à¸²à¸‡à¸šà¸±à¸à¸Šà¸µ นอà¸à¸ˆà¸²à¸à¸™à¸µà¹‰ บัà¸à¸Šà¸µà¸—ี่มีอยู่à¹à¸¥à¹‰à¸§à¸ˆà¸°à¹„ม่ได้รับผลà¸à¸£à¸°à¸—บ"
createNoteFromTheFile: "เรียบเรียงโน้ตจาà¸à¹„ฟล์นี้"
archive: "เà¸à¹‡à¸šà¸–าวร"
+archived: "เà¸à¹‡à¸šà¸–าวรà¹à¸¥à¹‰à¸§"
+unarchive: "เลิà¸à¸à¸²à¸£à¹€à¸à¹‡à¸šà¸–าวร"
channelArchiveConfirmTitle: "ต้องà¸à¸²à¸£à¹€à¸à¹‡à¸šà¸–าวรเจ้า {name} ใช่ไหม?"
channelArchiveConfirmDescription: "เมื่อเà¸à¹‡à¸šà¸–าวรà¹à¸¥à¹‰à¸§ จะไม่ปราà¸à¸à¹ƒà¸™à¸£à¸²à¸¢à¸à¸²à¸£à¸Šà¹ˆà¸­à¸‡à¸«à¸£à¸·à¸­à¸œà¸¥à¸à¸²à¸£à¸„้นหาอีà¸à¸•่อไป à¹à¸¥à¸°à¸ˆà¸°à¹„ม่สามารถโพสต์ใหม่ได้อีà¸à¸•่อไป"
thisChannelArchived: "ช่องนี้ถูà¸à¹€à¸à¹‡à¸šà¸–าวรà¹à¸¥à¹‰à¸§à¸™à¸°"
@@ -1104,6 +1124,9 @@ preventAiLearning: "ปà¸à¸´à¹€à¸ªà¸˜à¸à¸²à¸£à¹€à¸£à¸µà¸¢à¸™à¸£à¸¹à¹‰à¸”้ว
preventAiLearningDescription: "ส่งคำร้องขอไม่ให้ใช้ ข้อความในโน้ตที่โพสต์, หรือเนื้อหารูปภาพ ฯลฯ ในà¸à¸²à¸£à¹€à¸£à¸µà¸¢à¸™à¸£à¸¹à¹‰à¸‚องเครื่อง(machine learning) / Predictive AI / Generative AI โดยà¸à¸²à¸£à¹€à¸žà¸´à¹ˆà¸¡à¹à¸Ÿà¸¥à¹‡à¸ “noai†ลง HTML-Response ให้à¸à¸±à¸šà¹€à¸™à¸·à¹‰à¸­à¸«à¸²à¸—ี่เà¸à¸µà¹ˆà¸¢à¸§à¸‚้อง à¹à¸•่ทั้งนี้ ไม่ได้ป้องà¸à¸±à¸™ AI จาà¸à¸à¸²à¸£à¹€à¸£à¸µà¸¢à¸™à¸£à¸¹à¹‰à¹„ด้อย่างสมบูรณ์ เนื่องจาà¸à¸¡à¸µ AI บางตัวเท่านั้นที่จะเคารพคำขอดังà¸à¸¥à¹ˆà¸²à¸§"
options: "ตัวเลือà¸à¸šà¸—บาท"
specifyUser: "ผู้ใช้เฉพาะ"
+lookupConfirm: "ต้องà¸à¸²à¸£à¹€à¸£à¸µà¸¢à¸à¸”ูข้อมูลใช่ไหม?"
+openTagPageConfirm: "ต้องà¸à¸²à¸£à¹€à¸›à¸´à¸”หน้าà¹à¸®à¸Šà¹à¸—็à¸à¹ƒà¸Šà¹ˆà¹„หม?"
+specifyHost: "ระบุโฮสต์"
failedToPreviewUrl: "ไม่สามารถดูตัวอย่างได้"
update: "อัปเดต"
rolesThatCanBeUsedThisEmojiAsReaction: "บทบาทที่สามารถใช้เอโมจินี้เป็นรีà¹à¸­à¸„ชั่นได้"
@@ -1157,7 +1180,7 @@ notifyNotes: "à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนเà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¹‚พสต
unnotifyNotes: "หยุดà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนเà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¹‚น้ตใหม่"
authentication: "à¸à¸²à¸£à¸•รวจสอบสิทธิ์"
authenticationRequiredToContinue: "à¸à¸£à¸¸à¸“ายืนยันตัวตนทางอิเล็à¸à¸—รอนิà¸à¸ªà¹Œà¹€à¸žà¸·à¹ˆà¸­à¸”ำเนินà¸à¸²à¸£à¸•่อ"
-dateAndTime: "เวลาประทับ"
+dateAndTime: "วันเวลา"
showRenotes: "à¹à¸ªà¸”งรีโน้ต"
edited: "à¹à¸à¹‰à¹„ขà¹à¸¥à¹‰à¸§"
notificationRecieveConfig: "à¸à¸²à¸£à¸•ั้งค่าà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือน"
@@ -1168,11 +1191,11 @@ showRepliesToOthersInTimeline: "à¹à¸ªà¸”งà¸à¸²à¸£à¸•อบà¸à¸¥à¸±à¸šà¸œà¸¹
hideRepliesToOthersInTimeline: "ไม่à¹à¸ªà¸”งà¸à¸²à¸£à¸•อบà¸à¸¥à¸±à¸šà¸œà¸¹à¹‰à¸­à¸·à¹ˆà¸™à¸¥à¸‡à¹ƒà¸™à¹„ทม์ไลน์"
showRepliesToOthersInTimelineAll: "รวมตอบà¸à¸¥à¸±à¸šà¸ˆà¸²à¸à¸—ุà¸à¸„นที่คุณติดตามไว้ในไทม์ไลน์ของคุณ"
hideRepliesToOthersInTimelineAll: "ซ่อนตอบà¸à¸¥à¸±à¸šà¸ˆà¸²à¸à¸—ุà¸à¸„นที่คุณติดตามไปจาà¸à¹„ทม์ไลน์ของคุณ"
-confirmShowRepliesAll: "à¸à¸²à¸£à¸”ำเนินà¸à¸²à¸£à¸™à¸µà¹‰à¹„ม่สามารถย้อนà¸à¸¥à¸±à¸šà¹„ด้ คุณต้องà¸à¸²à¸£à¹à¸ªà¸”งà¸à¸²à¸£à¸•อบà¸à¸¥à¸±à¸šà¸œà¸¹à¹‰à¸­à¸·à¹ˆà¸™à¸ˆà¸²à¸à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸—ุà¸à¸„นที่คุณติดตามอยู่ในไทม์ไลน์ของคุณหรือไม่?"
-confirmHideRepliesAll: "à¸à¸²à¸£à¸”ำเนินà¸à¸²à¸£à¸™à¸µà¹‰à¹„ม่สามารถย้อนà¸à¸¥à¸±à¸šà¹„ด้ คุณต้องà¸à¸²à¸£à¸‹à¹ˆà¸­à¸™à¸à¸²à¸£à¸•อบà¸à¸¥à¸±à¸šà¸œà¸¹à¹‰à¸­à¸·à¹ˆà¸™à¸ˆà¸²à¸à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸—ุà¸à¸„นที่คุณติดตามอยู่ในไทม์ไลน์ของคุณหรือไม่?"
+confirmShowRepliesAll: "à¸à¸²à¸£à¸”ำเนินà¸à¸²à¸£à¸™à¸µà¹‰à¹„ม่สามารถย้อนà¸à¸¥à¸±à¸šà¹„ด้ คุณต้องà¸à¸²à¸£à¹à¸ªà¸”งà¸à¸²à¸£à¸•อบà¸à¸¥à¸±à¸šà¸œà¸¹à¹‰à¸­à¸·à¹ˆà¸™à¸ˆà¸²à¸à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸—ุà¸à¸„นที่คุณติดตามอยู่ ใส่ลงไทม์ไลน์ใช่ไหม?"
+confirmHideRepliesAll: "à¸à¸²à¸£à¸”ำเนินà¸à¸²à¸£à¸™à¸µà¹‰à¹„ม่สามารถย้อนà¸à¸¥à¸±à¸šà¹„ด้ คุณต้องà¸à¸²à¸£à¸‹à¹ˆà¸­à¸™à¸à¸²à¸£à¸•อบà¸à¸¥à¸±à¸šà¸œà¸¹à¹‰à¸­à¸·à¹ˆà¸™à¸ˆà¸²à¸à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸—ุà¸à¸„นที่คุณติดตามอยู่ ไปจาà¸à¹„ทม์ไลน์ใช่ไหม?"
externalServices: "บริà¸à¸²à¸£à¸ à¸²à¸¢à¸™à¸­à¸"
sourceCode: "ซอร์สโค้ด"
-sourceCodeIsNotYetProvided: "ซอร์สโค้ดยังไม่พร้อมใช้งาน โปรดติดต่อผู้ดูà¹à¸¥à¸£à¸°à¸šà¸šà¸‚องคุณเพื่อà¹à¸à¹‰à¹„ขปัà¸à¸«à¸²à¸™à¸µà¹‰"
+sourceCodeIsNotYetProvided: "ซอร์สโค้ดยังไม่พร้อมใช้งาน โปรดติดต่อผู้ดูà¹à¸¥à¸£à¸°à¸šà¸šà¹€à¸žà¸·à¹ˆà¸­à¹à¸à¹‰à¹„ขปัà¸à¸«à¸²à¸™à¸µà¹‰"
repositoryUrl: "URL ของ repository"
repositoryUrlDescription: "หาà¸à¸¡à¸µà¸—ี่เà¸à¹‡à¸šà¸‹à¸­à¸£à¹Œà¸ªà¹‚ค้ดที่เปิดเผยต่อสาธารณะ ให้ป้อน URL ที่เà¸à¹‡à¸šà¸‹à¸­à¸£à¹Œà¸ªà¹‚ค้ดนั้น à¹à¸•่หาà¸à¸„ุณใช้ Misskey ตามต้นฉบับ (ไม่มีà¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡à¸‹à¸­à¸£à¹Œà¸ªà¹‚ค้ด) ให้ป้อน https://github.com/misskey-dev/misskey"
repositoryUrlOrTarballRequired: "หาà¸à¸„ุณไม่มี repository สาธารณะ คุณจะต้องจัดเตรียม tarball à¹à¸—น ดู .config/example.yml สำหรับรายละเอียด"
@@ -1227,7 +1250,7 @@ surrender: "ยอมà¹à¸žà¹‰"
gameRetry: "เริ่มเà¸à¸¡à¹ƒà¸«à¸¡à¹ˆ"
notUsePleaseLeaveBlank: "หาà¸à¹„ม่ได้ใช้à¸à¸£à¸¸à¸“าเว้นว่างไว้"
useTotp: "ใช้รหัสผ่านà¹à¸šà¸šà¹ƒà¸Šà¹‰à¸„รั้งเดียว (TOTP)"
-useBackupCode: "ใช้รหัสสำรอง"
+useBackupCode: "ใช้รหัสà¹à¸šà¹Šà¸à¸­à¸±à¸›"
launchApp: "เริ่มà¹à¸­à¸›"
useNativeUIForVideoAudioPlayer: "ใช้ UI ของเบราว์เซอร์เพื่อเล่นวิดีโอ/เสียง"
keepOriginalFilename: "คงชื่อไฟล์เดิมไว้"
@@ -1235,13 +1258,23 @@ keepOriginalFilenameDescription: "หาà¸à¸›à¸´à¸”à¸à¸²à¸£à¸•ั้งค่à
noDescription: "ไม่มีข้อความอธิบาย"
alwaysConfirmFollow: "à¹à¸ªà¸”งข้อความยืนยันเมื่อà¸à¸”ติดตาม"
inquiry: "ติดต่อเรา"
+tryAgain: "โปรดลองอีà¸à¸„รั้ง"
+confirmWhenRevealingSensitiveMedia: "ตรวจสอบà¸à¹ˆà¸­à¸™à¹à¸ªà¸”งสื่อที่มีเนื้อหาละเอียดอ่อน"
+sensitiveMediaRevealConfirm: "สื่อนี้มีเนื้อหาละเอียดอ่อน, ต้องà¸à¸²à¸£à¹à¸ªà¸”งใช่ไหม?"
+createdLists: "รายชื่อที่ถูà¸à¸ªà¸£à¹‰à¸²à¸‡"
+createdAntennas: "เสาอาà¸à¸²à¸¨à¸—ี่ถูà¸à¸ªà¸£à¹‰à¸²à¸‡"
_delivery:
- stop: "ถูà¸à¸£à¸°à¸‡à¸±à¸š"
+ status: "สถานะà¸à¸²à¸£à¸ˆà¸±à¸”ส่ง"
+ stop: "ระงับà¸à¸²à¸£à¸ªà¹ˆà¸‡"
+ resume: "จัดส่งต่อ"
_type:
none: "à¸à¸³à¸¥à¸±à¸‡à¹€à¸œà¸¢à¹à¸žà¸£à¹ˆ"
+ manuallySuspended: "หยุดชั่วคราวด้วยตนเอง"
+ goneSuspended: "เซิร์ฟเวอร์ถูà¸à¸£à¸°à¸‡à¸±à¸šà¹€à¸™à¸·à¹ˆà¸­à¸‡à¸ˆà¸²à¸à¸¡à¸µà¸à¸²à¸£à¸¥à¸šà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸™à¸µà¹‰"
+ autoSuspendedForNotResponding: "เซิร์ฟเวอร์ถูà¸à¸£à¸°à¸‡à¸±à¸šà¹€à¸™à¸·à¹ˆà¸­à¸‡à¸ˆà¸²à¸à¹„ม่ตอบสนอง"
_bubbleGame:
howToPlay: "วิธีเล่น"
- hold: "หยุดชั่วคราว"
+ hold: "ถือไว้"
_score:
score: "คะà¹à¸™à¸™"
scoreYen: "จำนวนเงินที่ได้รับ"
@@ -1255,27 +1288,27 @@ _bubbleGame:
section2: "เมื่อวัตถุประเภทเดียวà¸à¸±à¸™à¸¡à¸²à¸£à¸§à¸¡à¸à¸±à¸™ พวà¸à¸¡à¸±à¸™à¸ˆà¸°à¸à¸¥à¸²à¸¢à¹€à¸›à¹‡à¸™à¸§à¸±à¸•ถุใหม่à¹à¸¥à¸°à¸„ุณจะได้รับคะà¹à¸™à¸™"
section3: "หาà¸à¸§à¸±à¸•ถุล้นออà¸à¸¡à¸²à¸ˆà¸²à¸à¸à¸¥à¹ˆà¸­à¸‡ เà¸à¸¡à¸à¹‡à¸ˆà¸°à¸ˆà¸šà¸¥à¸‡ ตั้งเป้าทำคะà¹à¸™à¸™à¹ƒà¸«à¹‰à¸ªà¸¹à¸‡à¸”้วยà¸à¸²à¸£à¸«à¸¥à¸­à¸¡à¸§à¸±à¸•ถุต่าง ๆ โดยไม่ทำให้ล้นà¸à¸¥à¹ˆà¸­à¸‡!"
_announcement:
- forExistingUsers: "ผู้ใช้งานที่มีอยู่เท่านั้น"
- forExistingUsersDescription: "à¸à¸²à¸£à¸›à¸£à¸°à¸à¸²à¸¨à¸™à¸µà¹‰à¸ˆà¸°à¹à¸ªà¸”งต่อผู้ใช้ที่มีอยู่ ณ จุดที่เผยà¹à¸žà¸£à¹ˆà¸™à¸±à¹‰à¸™à¹†à¸–้าหาà¸à¹€à¸›à¸´à¸”ใช้งาน ถ้าหาà¸à¸›à¸´à¸”ใช้งานผู้ที่à¸à¸³à¸¥à¸±à¸‡à¸ªà¸¡à¸±à¸„รใหม่หลังจาà¸à¹‚พสต์à¹à¸¥à¹‰à¸§à¸™à¸±à¹‰à¸™à¸à¹‡à¸ˆà¸°à¹€à¸«à¹‡à¸™à¹€à¸Šà¹ˆà¸™à¸à¸±à¸™"
+ forExistingUsers: "ผู้ใช้งานที่มีอยู่ตอนนี้เท่านั้น"
+ forExistingUsersDescription: "หาà¸à¹€à¸›à¸´à¸”ใช้งาน à¸à¸²à¸£à¸›à¸£à¸°à¸à¸²à¸¨à¸™à¸µà¹‰à¸ˆà¸°à¹à¸ªà¸”งเฉพาะà¸à¸±à¸šà¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸—ี่สร้างบัà¸à¸Šà¸µà¸à¹ˆà¸­à¸™/ที่มีอยู่ในขณะที่สร้างประà¸à¸²à¸¨à¸™à¸µà¹‰à¹€à¸—่านั้น หาà¸à¸›à¸´à¸”ใช้งาน à¸à¸²à¸£à¸›à¸£à¸°à¸à¸²à¸¨à¸™à¸µà¹‰à¸ˆà¸°à¹à¸ªà¸”งà¸à¸±à¸šà¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸—ี่สร้างบัà¸à¸Šà¸µà¸«à¸¥à¸±à¸‡à¸ˆà¸²à¸à¸ªà¸£à¹‰à¸²à¸‡à¸›à¸£à¸°à¸à¸²à¸¨à¸™à¸µà¹‰à¸”้วย"
needConfirmationToRead: "จำเป็นต้องยืนยันว่าอ่านà¹à¸¥à¹‰à¸§"
needConfirmationToReadDescription: "à¸à¸¥à¹ˆà¸­à¸‡à¹‚ต้ตอบà¸à¸²à¸£à¸¢à¸·à¸™à¸¢à¸±à¸™à¸ˆà¸°à¸›à¸£à¸²à¸à¸à¸‚ึ้นเมื่อจะทำเครื่องหมายว่าอ่านà¹à¸¥à¹‰à¸§ นอà¸à¸ˆà¸²à¸à¸™à¸µà¹‰à¸¢à¸±à¸‡à¸—ำให้ประà¸à¸²à¸¨à¸™à¸µà¹‰à¸¢à¸±à¸‡à¹„ม่ถูà¸à¸­à¹ˆà¸²à¸™à¹€à¸¡à¸·à¹ˆà¸­à¹ƒà¸Šà¹‰à¸Ÿà¸±à¸‡à¸à¹Œà¸Šà¸±à¹ˆà¸™ “ทำเครื่องหมายฯ ทั้งหมดว่าอ่านà¹à¸¥à¹‰à¸§â€"
end: "เà¸à¹‡à¸šà¸›à¸£à¸°à¸à¸²à¸¨"
- tooManyActiveAnnouncementDescription: "à¸à¸²à¸£à¸¡à¸µà¸›à¸£à¸°à¸à¸²à¸¨à¸—ี่ใช้งานมาà¸à¹€à¸à¸´à¸™à¹„ปนั้นอาจจะทำให้ประสบà¸à¸²à¸£à¸“์ของผู้ใช้งานนั้นดูà¹à¸¢à¹ˆà¸¥à¸‡ โปรดà¸à¸£à¸¸à¸“าพิจารณาà¸à¸²à¸£à¹€à¸à¹‡à¸šà¸›à¸£à¸°à¸à¸²à¸¨à¸—ี่ล้าสมัยด้วยนะค่ะ"
+ tooManyActiveAnnouncementDescription: "เนื่องจาà¸à¸¡à¸µà¸à¸²à¸£à¸›à¸£à¸°à¸à¸²à¸¨à¸—ี่ยังใช้งานอยู่จำนวนมาภอาจทำให้ UX ลดลง à¹à¸™à¸°à¸™à¸³à¹ƒà¸«à¹‰à¸žà¸´à¸ˆà¸²à¸£à¸“าà¸à¸²à¸£à¹€à¸à¹‡à¸šà¸›à¸£à¸°à¸à¸²à¸¨à¸—ี่สิ้นสุดไปà¹à¸¥à¹‰à¸§"
readConfirmTitle: "ทำเครื่องหมายว่าอ่านà¹à¸¥à¹‰à¸§à¹€à¸¥à¸¢à¹„หม?"
readConfirmText: "จะทำเครื่องหมายใส่ “{title}†ว่าอ่านà¹à¸¥à¹‰à¸§"
- shouldNotBeUsedToPresentPermanentInfo: "เราขอà¹à¸™à¸°à¸™à¸³à¹ƒà¸«à¹‰à¹ƒà¸Šà¹‰à¸›à¸£à¸°à¸à¸²à¸¨à¹€à¸žà¸·à¹ˆà¸­à¹‚พสต์ข้อมูลà¹à¸šà¸š flow มาà¸à¸à¸§à¹ˆà¸²à¸‚้อมูลà¹à¸šà¸š stock เนื่องจาà¸à¸¡à¸µà¹à¸™à¸§à¹‚น้มที่จะส่งผลเสียต่อ UX โดยเฉพาะสำหรับผู้ใช้ใหม่"
+ shouldNotBeUsedToPresentPermanentInfo: "เนื่องจาà¸à¸¡à¸µà¸„วามเป็นไปได้สูงที่จะส่งผลเสียต่อง UX ของผู้ใช้ใหม่ จึงขอà¹à¸™à¸°à¸™à¸³à¹ƒà¸«à¹‰à¹ƒà¸Šà¹‰à¸›à¸£à¸°à¸à¸²à¸¨à¸ªà¸³à¸«à¸£à¸±à¸šà¸‚้อมูลที่ต้องà¸à¸²à¸£à¸à¸²à¸£à¸•อบสนองในทันที ไม่ใช่ข้อมูลที่ต้องà¸à¸²à¸£à¹à¸ªà¸”งตลอดเวลา"
dialogAnnouncementUxWarn: "เราขอà¹à¸™à¸°à¸™à¸³à¹ƒà¸«à¹‰à¹ƒà¸Šà¹‰à¸”้วยความระมัดระวัง เนื่องจาà¸à¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนà¹à¸šà¸šà¸à¸¥à¹ˆà¸­à¸‡à¹‚ต้ตอบตั้งà¹à¸•่ 2 รายà¸à¸²à¸£à¸‚ึ้นไปพร้อมà¸à¸±à¸™à¸­à¸²à¸ˆà¸ªà¹ˆà¸‡à¸œà¸¥à¹€à¸ªà¸µà¸¢à¸•่อ UX ได้อย่างมาà¸"
silence: "ไม่มีà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือน"
silenceDescription: "หาà¸à¹€à¸›à¸´à¸”ใช้งาน จะไม่มีà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนประà¸à¸²à¸¨à¸™à¸µà¹‰ à¹à¸¥à¸°à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸ˆà¸°à¹„ม่จำเป็นต้องทำเครื่องหมายว่าอ่านà¹à¸¥à¹‰à¸§"
_initialAccountSetting:
- accountCreated: "คุณได้สร้างบัà¸à¸Šà¸µà¸‚องคุณสำเร็จเรียบร้อยà¹à¸¥à¹‰à¸§!"
+ accountCreated: "สร้างบัà¸à¸Šà¸µà¹€à¸ªà¸£à¹‡à¸ˆà¸ªà¸¡à¸šà¸¹à¸£à¸“์!"
letsStartAccountSetup: "สำหรับผู้เริ่มต้นมาตั้งค่าโปรไฟล์ของคุณà¸à¸±à¸™à¹€à¸–อะ"
letsFillYourProfile: "à¸à¹ˆà¸­à¸™à¸­à¸·à¹ˆà¸™à¸¡à¸²à¸•ั้งค่าโปรไฟล์ของคุณ"
profileSetting: "ตั้งค่าโปรไฟล์"
privacySetting: "ตั้งค่าความเป็นส่วนตัว"
theseSettingsCanEditLater: "คุณสามารถเปลี่ยนà¸à¸²à¸£à¸•ั้งค่าเหล่านี้ได้ในภายหลังได้ตลอดเวลานะ"
- youCanEditMoreSettingsInSettingsPageLater: "ยังมีà¸à¸²à¸£à¸•ั้งค่าอื่นๆ อีà¸à¸¡à¸²à¸à¸¡à¸²à¸¢à¸—ี่คุณนั้นสามารถà¸à¸³à¸«à¸™à¸”ค่าได้จาภ\"à¸à¸²à¸£à¸•ั้งค่า\" เพื่อให้à¹à¸™à¹ˆà¹ƒà¸ˆà¸§à¹ˆà¸²à¹„ด้เยี่ยมชมมันได้ภายหลังนะ"
- followUsers: "ลองติดตามผู้ใช้บางคนที่คุณอาจจะสนใจเพื่อสร้างไทม์ไลน์ของคุณสิ !"
+ youCanEditMoreSettingsInSettingsPageLater: "สามารถตั้งค่าเพิ่มเติมได้ที่หน้า “à¸à¸²à¸£à¸•ั้งค่า†อย่าลืมไปเยี่ยมชมภายหลังด้วย"
+ followUsers: "ลองติดตามผู้ใช้ที่สนใจเพื่อสร้างไทม์ไลน์ดูสิ"
pushNotificationDescription: "à¸à¸³à¸¥à¸±à¸‡à¹€à¸›à¸´à¸”ใช้งานà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนà¹à¸šà¸šà¸žà¸¸à¸Šà¸ˆà¸°à¸Šà¹ˆà¸§à¸¢à¹ƒà¸«à¹‰à¸„ุณได้รับà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนจาภ{name} โดยตรงบนอุปà¸à¸£à¸“์ของคุณนะ"
initialAccountSettingCompleted: "ตั้งค่าโปรไฟล์เสร็จสมบูรณ์à¹à¸¥à¹‰à¸§!"
haveFun: "ขอให้สนุà¸à¸à¸±à¸š {name}!"
@@ -1310,7 +1343,7 @@ _initialTutorial:
description1: "Misskey มีหลายไทม์ไลน์ขึ้นอยู่à¸à¸±à¸šà¸§à¸´à¸˜à¸µà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¸‚องคุณ (บางไทม์ไลน์อาจไม่สามารถใช้ได้ขึ้นอยู่à¸à¸±à¸šà¸™à¹‚ยบายของเซิร์ฟเวอร์)"
home: "คุณสามารถดูโพสต์จาà¸à¸šà¸±à¸à¸Šà¸µà¸—ี่คุณติดตามได้"
local: "คุณสามารถดูโพสต์จาà¸à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸—ั้งหมดบนเซิร์ฟเวอร์นี้"
- social: "โพสต์จาà¸à¸—ั้งไทม์ไลน์หน้าà¹à¸£à¸à¹à¸¥à¸°à¹„ทม์ไลน์ในพื้นที่ของคุณจะปราà¸à¸à¸‚ึ้น"
+ social: "จะà¹à¸ªà¸”งโพสต์ทั้งจาà¸à¹„ทม์ไลน์หลัà¸à¹à¸¥à¸°à¹„ทม์ไลน์ท้องถิ่น"
global: "คุณสามารถดูโพสต์จาà¸à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸—ี่เชื่อมต่ออื่นๆ ทั้งหมดได้"
description2: "คุณสามารถสลับระหว่างà¹à¸•่ละไทม์ไลน์ได้ตลอดเวลาได้ที่บริเวณด้านบนของหน้าจอ"
description3: "นอà¸à¸ˆà¸²à¸à¸™à¸µà¹‰à¸¢à¸±à¸‡à¸¡à¸µà¸£à¸²à¸¢à¸à¸²à¸£à¹„ทม์ไลน์ ไทม์ไลน์ของช่อง ฯลฯ โปรดดู {link} สำหรับรายละเอียดเพิ่มเติม"
@@ -1320,7 +1353,7 @@ _initialTutorial:
_visibility:
description: "คุณสามารถจำà¸à¸±à¸”ผู้ที่สามารถดูโน้ตของคุณได้นะ"
public: "โน้ตของคุณนั้นจะปราà¸à¸à¹à¸à¹ˆà¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¸—ุà¸à¸„น"
- home: "เผยà¹à¸žà¸£à¹ˆà¸šà¸™à¹„ทม์ไลน์หน้าà¹à¸£à¸à¹€à¸—่านั้น ผู้คนที่เข้าชมโปรไฟล์ของคุณ ผ่านผู้ติดตาม à¹à¸¥à¸°à¸œà¹ˆà¸²à¸™à¸à¸²à¸£à¸£à¸µà¹‚น้ตสามารถเห็นได้"
+ home: "เผยà¹à¸žà¸£à¹ˆà¸šà¸™à¹„ทม์ไลน์หลัà¸à¹€à¸—่านั้น à¹à¸•่ผู้ติดตาม ผู้ที่เข้ามาดูโปรไฟล์ à¹à¸¥à¸°à¸œà¸¹à¹‰à¸—ี่เห็นจาà¸à¸£à¸µà¹‚น้ตยังสามารถดูโพสต์นี้ได้"
followers: "มองเห็นได้เฉพาะผู้ติดตามเท่านั้น ไม่มีใครอื่นนอà¸à¸ˆà¸²à¸à¸•ัวคุณเองที่สามารถรีโน้ตได้ à¹à¸¥à¸°à¸¡à¸µà¹€à¸žà¸µà¸¢à¸‡à¸œà¸¹à¹‰à¸•ิดตามของคุณเท่านั้นที่สามารถดูได้"
direct: "เปิดให้เห็นเฉพาะผู้ใช้ที่ระบุเท่านั้น à¹à¸¥à¸°à¸žà¸§à¸à¹€à¸‚าจะได้รับà¹à¸ˆà¹‰à¸‡à¹€à¸•ือนด้วย คุณสามารถใช้มันà¹à¸—นข้อความโดยตรง (dm)"
doNotSendConfidencialOnDirect1: "โปรดใช้ความระมัดระวังในà¸à¸²à¸£à¸ªà¹ˆà¸‡à¸‚้อมูลที่ละเอียดอ่อน"
@@ -1346,17 +1379,17 @@ _initialTutorial:
title: "บทเรียนจบลงà¹à¸¥à¹‰à¸§à¸ˆà¹‰à¸² เย่เย่เย่ 🎉"
description: "คุณสมบัติที่à¹à¸™à¸°à¸™à¸³à¹ƒà¸™à¸—ี่นี่เป็นเพียงบางส่วนเท่านั้น หาà¸à¸•้องà¸à¸²à¸£à¹€à¸£à¸µà¸¢à¸™à¸£à¸¹à¹‰à¹€à¸žà¸´à¹ˆà¸¡à¹€à¸•ิมเà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¸§à¸´à¸˜à¸µà¹ƒà¸Šà¹‰ Misskey โปรดไปที่ {link}"
_timelineDescription:
- home: "บนไทม์ไลน์หน้าà¹à¸£à¸ คุณสามารถดูโพสต์จาà¸à¸šà¸±à¸à¸Šà¸µà¸—ี่คุณติดตามได้"
- local: "ไทม์ไลน์ในพื้นที่ช่วยให้คุณเห็นโพสต์จาà¸à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸—ั้งหมดบนเซิร์ฟเวอร์นี้"
- social: "ไทม์ไลน์โซเชียลจะà¹à¸ªà¸”งโพสต์จาà¸à¸—ั้งไทม์ไลน์หน้าà¹à¸£à¸à¹à¸¥à¸°à¹„ทม์ไลน์ในพื้นที่"
+ home: "บนไทม์ไลน์หลัภคุณสามารถดูโพสต์จาà¸à¸šà¸±à¸à¸Šà¸µà¸—ี่ติดตามอยู่ได้"
+ local: "ไทม์ไลน์ท้องถิ่นช่วยให้เห็นโพสต์จาà¸à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸—ั้งหมดบนเซิร์ฟเวอร์นี้"
+ social: "ไทม์ไลน์โซเชียลจะà¹à¸ªà¸”งโพสต์จาà¸à¸—ั้งไทม์ไลน์หลัà¸à¹à¸¥à¸°à¹„ทม์ไลน์ท้องถิ่น"
global: "ในไทม์ไลน์ทั่วโลภคุณสามารถดูโน้ตจาà¸à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸—ี่เชื่อมต่อทั้งหมดได้"
_serverRules:
description: "ชุดของà¸à¸Žà¸—ี่จะà¹à¸ªà¸”งà¸à¹ˆà¸­à¸™à¸à¸²à¸£à¸¥à¸‡à¸—ะเบียนเราขอà¹à¸™à¸°à¸™à¸³à¹ƒà¸«à¹‰à¸•ั้งค่าสรุปข้อà¸à¸³à¸«à¸™à¸”ในà¸à¸²à¸£à¹ƒà¸«à¹‰à¸šà¸£à¸´à¸à¸²à¸£"
_serverSettings:
iconUrl: "URL ไอคอน"
appIconDescription: "ระบุไอคอนที่จะใช้เมื่อ {host} à¹à¸ªà¸”งเป็นà¹à¸­à¸›"
- appIconUsageExample: "E.g. เป็น PWA หรือเมื่อà¹à¸ªà¸”งผลเป็นบุ๊à¸à¸¡à¸²à¸£à¹Œà¸à¸«à¸™à¹‰à¸²à¸ˆà¸­à¸«à¸¥à¸±à¸à¸šà¸™à¹‚ทรศัพท์"
- appIconStyleRecommendation: "เนื่องจาà¸à¹„อคอนอาจถูà¸à¸„รอบตัดเป็นสี่เหลี่ยมจัตุรัสหรือวงà¸à¸¥à¸¡ จึงà¹à¸™à¸°à¸™à¸³à¹ƒà¸«à¹‰à¹ƒà¸Šà¹‰à¹„อคอนที่มีขอบสีรอบๆ เนื้อหา"
+ appIconUsageExample: "ตัวอย่างเช่น เมื่อถูà¸à¹€à¸žà¸´à¹ˆà¸¡à¹€à¸›à¹‡à¸™ PWA หรือบุ๊à¸à¸¡à¸²à¸£à¹Œà¸à¸šà¸™à¸«à¸™à¹‰à¸²à¸ˆà¸­à¸«à¸¥à¸±à¸à¹ƒà¸™à¸ªà¸¡à¸²à¸£à¹Œà¸—โฟน"
+ appIconStyleRecommendation: "เนื่องจาà¸à¸­à¸²à¸ˆà¸–ูà¸à¸„รอบตัดเป็นสี่เหลี่ยมหรือวงà¸à¸¥à¸¡ จึงà¹à¸™à¸°à¸™à¸³à¹ƒà¸«à¹‰à¹ƒà¸Šà¹‰à¸ à¸²à¸žà¸—ี่เผื่อพื้นที่รอบๆ ตัวโลโà¸à¹‰à¹„อคอนไว้"
appIconResolutionMustBe: "ความละเอียดขั้นต่ำไว้คือ {resolution}."
manifestJsonOverride: "เขียนทับ manifest.json"
shortName: "ชื่อย่อ"
@@ -1364,27 +1397,29 @@ _serverSettings:
fanoutTimelineDescription: "เพิ่มประสิทธิภาพà¸à¸²à¸£à¸”ึงข้อมูลไทม์ไลน์อย่างมาภà¹à¸¥à¸°à¸¥à¸”ภาระในà¸à¸²à¸™à¸‚้อมูลเมื่อเปิดใช้งาน ในทางà¸à¸¥à¸±à¸šà¸à¸±à¸™ à¸à¸²à¸£à¹ƒà¸Šà¹‰à¸«à¸™à¹ˆà¸§à¸¢à¸„วามจำของ Redis จะเพิ่มขึ้น ลองปิดà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¸™à¸µà¹‰à¹ƒà¸™à¸à¸£à¸“ีที่หน่วยความจำเซิร์ฟเวอร์เหลือน้อยหรือเซิร์ฟเวอร์ไม่เสถียร"
fanoutTimelineDbFallback: "ฟอลà¹à¸šà¹Šà¸à¸à¸¥à¸±à¸šà¸à¸²à¸™à¸‚้อมูล"
fanoutTimelineDbFallbackDescription: "เมื่อเปิดใช้งาน หาà¸à¹„ม่ได้à¹à¸„ชไทม์ไลน์ ไทม์ไลน์จะฟอลà¹à¸šà¹Šà¸à¹„ปยังà¸à¸²à¸™à¸‚้อมูลสำหรับà¸à¸²à¸£ query เพิ่มเติม à¸à¸²à¸£à¸›à¸´à¸”ใช้งานจะช่วยลดภาระของเซิร์ฟเวอร์ด้วยà¸à¸²à¸£à¸à¸³à¸ˆà¸±à¸”à¸à¸£à¸°à¸šà¸§à¸™à¸Ÿà¸­à¸¥à¹à¸šà¹Šà¸ à¹à¸•่มันà¸à¹‡à¸ˆà¸°à¸ˆà¸³à¸à¸±à¸”ช่วงเวลาไทม์ไลน์ที่สามารถดึงข้อมูลได้"
+ inquiryUrl: "URL สำหรับà¸à¸²à¸£à¸•ิดต่อสอบถาม"
+ inquiryUrlDescription: "ระบุ URL ของหน้าเว็บที่มีà¹à¸šà¸šà¸Ÿà¸­à¸£à¹Œà¸¡à¸ªà¸³à¸«à¸£à¸±à¸šà¸•ิดต่อผู้ดูà¹à¸¥à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œ หรือข้อมูลà¸à¸²à¸£à¸•ิดต่อของผู้ดูà¹à¸¥à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œ"
_accountMigration:
- moveFrom: "ย้ายข้อมูลบัà¸à¸Šà¸µà¸­à¸·à¹ˆà¸™à¹„ปยังอีà¸à¸šà¸±à¸à¸Šà¸µà¸™à¸µà¹‰à¸«à¸™à¸¶à¹ˆà¸‡"
+ moveFrom: "ย้ายจาà¸à¸šà¸±à¸à¸Šà¸µà¸­à¸·à¹ˆà¸™à¸¡à¸²à¸—ี่บัà¸à¸Šà¸µà¸™à¸µà¹‰"
moveFromSub: "สร้างนามà¹à¸à¸‡à¹„ปยังบัà¸à¸Šà¸µà¸­à¸·à¹ˆà¸™"
moveFromLabel: "บัà¸à¸Šà¸µà¸—ี่จะย้ายจาภ#{n}"
- moveFromDescription: "ถ้าหาà¸à¸„ุณต้องà¸à¸²à¸£à¹‚อนข้อมูล คุณจำเป็นต้องสร้างบัà¸à¸Šà¸µà¸ªà¸³à¸£à¸­à¸‡à¸ªà¸³à¸«à¸£à¸±à¸šà¸à¸²à¸£à¸¢à¹‰à¸²à¸¢à¸šà¸±à¸à¸Šà¸µ หลังจาà¸à¸™à¸±à¹‰à¸™à¸›à¹‰à¸­à¸™à¸šà¸±à¸à¸Šà¸µà¸—ี่จะย้ายไปในรูปà¹à¸šà¸šà¸•่อไปนี้: @person@instance.com"
- moveTo: "ย้ายข้อมูลบัà¸à¸Šà¸µà¸™à¸µà¹‰à¹„ปยังบัà¸à¸Šà¸µà¸­à¸µà¸à¸«à¸™à¸¶à¹ˆà¸‡"
+ moveFromDescription: "หาà¸à¸•้องà¸à¸²à¸£à¹‚อนข้อมูลจาà¸à¸šà¸±à¸à¸Šà¸µà¸­à¸·à¹ˆà¸™à¸¡à¸²à¸¢à¸±à¸‡à¸šà¸±à¸à¸Šà¸µà¸™à¸µà¹‰ จำเป็นต้องสร้างบัà¸à¸Šà¸µà¸™à¸²à¸¡à¹à¸à¸‡ (alias) ไว้ที่นี่ด้วย\nà¸à¸£à¸¸à¸“าà¸à¸£à¸­à¸à¸šà¸±à¸à¸Šà¸µà¹€à¸”ิมในรูปà¹à¸šà¸š: @username@server.example.com\nหาà¸à¸•้องà¸à¸²à¸£à¸¥à¸š alias, ให้เว้นว่างไว้à¹à¸¥à¹‰à¸§à¸šà¸±à¸™à¸—ึภ(ไม่à¹à¸™à¸°à¸™à¸³)"
+ moveTo: "ย้ายบัà¸à¸Šà¸µà¸™à¸µà¹‰à¹„ปยังบัà¸à¸Šà¸µà¹ƒà¸«à¸¡à¹ˆ"
moveToLabel: "บัà¸à¸Šà¸µà¸—ี่จะย้ายไปที่:"
moveCannotBeUndone: "ไม่สามารถยà¸à¹€à¸¥à¸´à¸à¸à¸²à¸£à¹‚อนย้ายบัà¸à¸Šà¸µà¹„ด้"
moveAccountDescription: "à¸à¸²à¸£à¸”ำเนินà¸à¸²à¸£à¸™à¸µà¹‰à¸ˆà¸°à¸¢à¹‰à¸²à¸¢à¸šà¸±à¸à¸Šà¸µà¸‚องคุณไปยังบัà¸à¸Šà¸µà¸­à¸·à¹ˆà¸™\n・ผู้ที่à¸à¸³à¸¥à¸±à¸‡à¸•ิดตามคุณจาà¸à¸šà¸±à¸à¸Šà¸µà¸™à¸µà¹‰à¸ˆà¸°à¸–ูà¸à¸¢à¹‰à¸²à¸¢à¹„ปยังบัà¸à¸Šà¸µà¹ƒà¸«à¸¡à¹ˆà¹‚ดยอัตโนมัติ\n・บัà¸à¸Šà¸µà¸™à¸µà¹‰à¸ˆà¸°à¹€à¸¥à¸´à¸à¸•ิดตามผู้ใช้ทั้งหมดที่à¸à¸³à¸¥à¸±à¸‡à¸•ิดตามอยู่\n・คุณจะไม่สามารถสร้างโน้ต ฯลฯ ในบัà¸à¸Šà¸µà¸™à¸µà¹‰à¹„ด้\n\nà¹à¸¡à¹‰à¸§à¹ˆà¸²à¸à¸²à¸£à¸¢à¹‰à¸²à¸¢à¸œà¸¹à¹‰à¸—ี่ติดตามคุณจะเป็นไปโดยอัตโนมัติ à¹à¸•่คุณต้องเตรียมขั้นตอนบางอย่างด้วยตนเอง เพื่อย้ายรายชื่อผู้ใช้ที่คุณà¸à¸³à¸¥à¸±à¸‡à¸•ิดตาม โดยดำเนินà¸à¸²à¸£à¸ªà¹ˆà¸‡à¸­à¸­à¸à¸£à¸²à¸¢à¸Šà¸·à¹ˆà¸­à¹à¸¥à¹‰à¸§à¸„่อยนำเข้ามาภายหลังในเมนูà¸à¸²à¸£à¸•ั้งค่าของบัà¸à¸Šà¸µà¹ƒà¸«à¸¡à¹ˆ ใช้ขั้นตอนเดียวà¸à¸±à¸™à¸™à¸µà¹‰à¹ƒà¸Šà¹‰à¸£à¸²à¸¢à¸Šà¸·à¹ˆà¸­à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸—ี่ถูà¸à¸›à¸´à¸”เสียงà¹à¸¥à¸°à¸–ูà¸à¸šà¸¥à¹‡à¸­à¸\n\n(คำอธิบายนี้ใช้à¸à¸±à¸š Misskey v13.12.0 ขึ้นไป, ซอฟต์à¹à¸§à¸£à¹Œ ActivityPub อื่นๆ เช่น Mastodon อาจทำงานà¹à¸•à¸à¸•่างออà¸à¹„ป)"
- moveAccountHowTo: "หาà¸à¸•้องà¸à¸²à¸£à¸¢à¹‰à¸²à¸¢à¸‚้อมูลà¸à¹ˆà¸­à¸™à¸­à¸·à¹ˆà¸™à¹ƒà¸«à¹‰à¸ªà¸£à¹‰à¸²à¸‡à¸Šà¸·à¹ˆà¸­à¹à¸—นสำหรับบัà¸à¸Šà¸µà¸™à¸µà¹‰ ในบัà¸à¸Šà¸µà¸—ี่จะต้องà¸à¸²à¸£à¸¢à¹‰à¸²à¸¢à¹„ป\nหลังจาà¸à¸—ี่คุณสร้างนามà¹à¸à¸‡à¸™à¸±à¹‰à¸™à¹à¸¥à¹‰à¸§ ให้ป้อนบัà¸à¸Šà¸µà¸—ี่ต้องà¸à¸²à¸£à¸ˆà¸°à¸¢à¹‰à¸²à¸¢à¹„ปในรูปà¹à¸šà¸šà¸”ังต่อไปนี้: @username@server.example.com"
+ moveAccountHowTo: "à¸à¸²à¸£à¸¢à¹‰à¸²à¸¢à¸šà¸±à¸à¸Šà¸µà¸ˆà¸°à¹€à¸£à¸´à¹ˆà¸¡à¸•้นโดยà¸à¸²à¸£à¸ªà¸£à¹‰à¸²à¸‡à¸šà¸±à¸à¸Šà¸µà¸™à¸²à¸¡à¹à¸à¸‡ (alias) ของบัà¸à¸Šà¸µà¸™à¸µà¹‰ ณ บัà¸à¸Šà¸µà¸—ี่เป็นปลายทาง หลังจาà¸à¸ªà¸£à¹‰à¸²à¸‡à¸™à¸²à¸¡à¹à¸à¸‡à¹à¸¥à¹‰à¸§ ให้ป้อนบัà¸à¸Šà¸µà¸›à¸¥à¸²à¸¢à¸—างในรูปà¹à¸šà¸šà¸”ังนี้: @username@server.example.com"
startMigration: "โอนย้าย"
migrationConfirm: "ยืนยันà¸à¸²à¸£à¸¢à¹‰à¸²à¸¢à¸‚้อมูลบัà¸à¸Šà¸µà¸™à¸µà¹‰à¹„ปที่ {account} เมื่อเริ่มà¹à¸¥à¹‰à¸§à¸ˆà¸°à¹„ม่สามารถหยุดหรือนำà¸à¸¥à¸±à¸šà¸„ืนมาได้ à¹à¸¥à¸°à¸„ุณจะไม่สามารถใช้บัà¸à¸Šà¸µà¸™à¸µà¹‰à¹ƒà¸™à¸ªà¸–านะดั้งเดิมได้อีà¸à¸•่อไป\n\nนอà¸à¸ˆà¸²à¸à¸™à¸µà¹‰ คุณจำเป็นต้องสร้างบัà¸à¸Šà¸µà¸ªà¸³à¸£à¸­à¸‡à¸ªà¸³à¸«à¸£à¸±à¸šà¸à¸²à¸£à¸¢à¹‰à¸²à¸¢à¸šà¸±à¸à¸Šà¸µ"
- movedAndCannotBeUndone: "\nบัà¸à¸Šà¸µà¸™à¸µà¹‰à¸–ูà¸à¹‚อนย้ายไปà¹à¸¥à¹‰à¸§\nไม่สามารถย้อนà¸à¸¥à¸±à¸šà¹‚อนย้ายข้อมูลได้"
- postMigrationNote: "บัà¸à¸Šà¸µà¸™à¸µà¹‰à¸ˆà¸°à¸–ูà¸à¹€à¸¥à¸´à¸à¸•ิดตามบัà¸à¸Šà¸µà¸—ั้งหมดที่à¸à¸³à¸¥à¸±à¸‡à¸•ิดตามภายใน 24 ชั่วโมงหลังจาà¸à¸à¸²à¸£à¸¢à¹‰à¸²à¸¢à¸‚้อมูลนั้นเสร็จสิ้น ทั้งจำนวนผู้ติดตามà¹à¸¥à¸°à¸œà¸¹à¹‰à¸•ิดตามนั้นจะà¸à¸¥à¸²à¸¢à¹€à¸›à¹‡à¸™à¸¨à¸¹à¸™à¸¢à¹Œ เพื่อหลีà¸à¹€à¸¥à¸µà¹ˆà¸¢à¸‡à¸›à¹‰à¸­à¸‡à¸à¸±à¸™à¹„ม่ให้ผู้ติดตามของคุณนั้นไม่สามารถเห็นโพสต์เฉพาะผู้ติดตามของบัà¸à¸Šà¸µà¸™à¸µà¹‰à¹„ด้ à¹à¸•่อย่างไรà¸à¹‡à¸•ามà¹à¸¥à¹‰à¸§à¸žà¸§à¸à¹€à¸‚าจะยังคงติดตามบัà¸à¸Šà¸µà¸™à¸µà¹‰à¸•่อไป"
- movedTo: "บัà¸à¸Šà¸µà¸—ี่จะย้ายไปที่:"
+ movedAndCannotBeUndone: "\nบัà¸à¸Šà¸µà¸™à¸µà¹‰à¸–ูà¸à¹‚อนย้ายไปà¹à¸¥à¹‰à¸§\nไม่สามารถยà¸à¹€à¸¥à¸´à¸à¸à¸²à¸£à¹‚อนย้ายได้"
+ postMigrationNote: "บัà¸à¸Šà¸µà¸™à¸µà¹‰à¸ˆà¸°à¸”ำเนินà¸à¸²à¸£à¸¢à¸à¹€à¸¥à¸´à¸à¸à¸²à¸£à¸•ิดตามทั้งหมดหลังจาà¸à¸à¸²à¸£à¸¢à¹‰à¸²à¸¢à¸‚้อมูลไปà¹à¸¥à¹‰à¸§ 24 ชั่วโมง จำนวนà¸à¸³à¸¥à¸±à¸‡à¸•ิดตามà¹à¸¥à¸°à¸ˆà¸³à¸™à¸§à¸™à¸œà¸¹à¹‰à¸•ิดตามของบัà¸à¸Šà¸µà¸™à¸µà¹‰à¸ˆà¸°à¹€à¸›à¹‡à¸™ 0 à¹à¸¥à¸°à¹€à¸žà¸·à¹ˆà¸­à¸«à¸¥à¸µà¸à¹€à¸¥à¸µà¹ˆà¸¢à¸‡à¹„ม่ให้ผู้ติดตามคุณนั้นไม่สามารถเห็นโพสต์เฉพาะผู้ติดตามฯได้ à¸à¸²à¸£à¸¢à¸à¹€à¸¥à¸´à¸à¸à¸²à¸£à¸•ิดตามจะไม่à¸à¸£à¸°à¸—บà¸à¸±à¸šà¸œà¸¹à¹‰à¸•ิดตามคุณ ดังนั้นผู้ติดตามคุณยังคงสามารถดูโพสต์ของบัà¸à¸Šà¸µà¸™à¸µà¹‰à¹„ด้"
+ movedTo: "บัà¸à¸Šà¸µà¸—ี่จะย้ายไป:"
_achievements:
earnedAt: "ได้รับเมื่อ"
_types:
_notes1:
title: "just setting up my msky"
- description: "โพสต์โน้ตà¹à¸£à¸à¸‚องคุณ"
+ description: "โพสต์โน้ตเป็นครั้งà¹à¸£à¸"
flavor: "ขอให้มีช่วงเวลาที่ดีà¸à¸±à¸š Misskey นะคะ!"
_notes10:
title: "โน้ตไม่à¸à¸µà¹ˆà¸Šà¸´à¹‰à¸™"
@@ -1484,19 +1519,19 @@ _achievements:
flavor: "ขอบคุณที่ใช้ Misskey นะ !"
_noteClipped1:
title: "อดไม่ได้ที่จะต้องคลิปมันเอาไว้"
- description: "คลิปโน้ตตัวà¹à¸£à¸à¸‚องคุณ"
+ description: "คลิปโน้ตเป็นครั้งà¹à¸£à¸"
_noteFavorited1:
title: "สตาร์เà¸à¹€à¸‹à¸­à¸£à¹Œ"
- description: "ชื่นชอบโน้ตà¹à¸£à¸à¸‚องคุณ"
+ description: "ใส่โน้ตเป็นรายà¸à¸²à¸£à¹‚ปรดเป็นครั้งà¹à¸£à¸"
_myNoteFavorited1:
title: "à¹à¸ªà¸§à¸‡à¸«à¸²à¸”วงดาว"
- description: "มีคนอื่นๆที่ชื่นชอบหนึ่งในโน้ตของคุณ"
+ description: "โน้ตตัวเองถูà¸à¸„นอื่นเพิ่มลงรายà¸à¸²à¸£à¹‚ปรดของเขา"
_profileFilled:
title: "เตรียมตัวอย่างดี"
- description: "ตั้งค่าโปรไฟล์ของคุณ"
+ description: "ตั้งค่าโปรไฟล์"
_markedAsCat:
title: "ฉันเป็นà¹à¸¡à¸§"
- description: "ทำเครื่องหมายบัà¸à¸Šà¸µà¸‚องคุณว่าเป็นà¹à¸¡à¸§"
+ description: "ตั้งค่าบัà¸à¸Šà¸µà¹€à¸›à¹‡à¸™à¹à¸¡à¸§à¹€à¸¡à¸µà¹‰à¸¢à¸§à¹€à¸¡à¸µà¹‰à¸¢à¸§"
flavor: "à¹à¸¡à¸§à¸™à¹‰à¸­à¸¢à¹„ร้ชื่อ"
_following1:
title: "à¸à¹‰à¸²à¸§à¹à¸£à¸à¸ªà¸¹à¹ˆ...à¸à¸”ติดตาม"
@@ -1539,7 +1574,7 @@ _achievements:
description: "ได้รับความสำเร็จ 30 ครั้ง"
_viewAchievements3min:
title: "ชอบบรรลุความสà¹à¸²à¹€à¸£à¹‡à¸ˆ"
- description: "มองดูรายà¸à¸²à¸£à¸„วามสำเร็จของคุณเป็นเวลาอย่างน้อย 3 นาที"
+ description: "มองดูรายà¸à¸²à¸£à¸„วามสำเร็จเป็นเวลานานà¸à¸§à¹ˆà¸² 3 นาที"
_iLoveMisskey:
title: "ฉันรัภMisskey"
description: "โพสต์ “I ⤠#Misskeyâ€"
@@ -1566,13 +1601,13 @@ _achievements:
flavor: "โป๊ะ โป๊ะ โป๊ะ ปิ้งงงงง"
_selfQuote:
title: "อ้างอิงตนเอง"
- description: "อ้างโน้ตของคุณเอง"
+ description: "อ้างอิงโน้ตตัวเอง"
_htl20npm:
title: "ไทม์ไลน์ไหล"
- description: "มีà¸à¸²à¸£à¸—ำความเร็วของไทม์ไลน์หน้าà¹à¸£à¸à¹€à¸à¸´à¸™ 20 npm (โน้ตต่อนาที)"
+ description: "มีà¸à¸²à¸£à¸—ำความเร็วของไทม์ไลน์หลัà¸à¹€à¸à¸´à¸™ 20 npm (โน้ตต่อนาที)"
_viewInstanceChart:
title: "วิเคราะห์"
- description: "ดูà¹à¸œà¸™à¸ à¸¹à¸¡à¸´à¸­à¸´à¸™à¸ªà¹à¸•นซ์ของคุณ"
+ description: "ดูà¹à¸œà¸™à¸ à¸¹à¸¡à¸´à¸‚องเซิร์ฟเวอร์"
_outputHelloWorldOnScratchpad:
title: "หวัดดีชาวโลà¸!"
description: "เอาพุต \"hello world\" ใน Scratchpad"
@@ -1593,16 +1628,16 @@ _achievements:
description: "มีโอà¸à¸²à¸ªà¸—ี่จะได้รับด้วยความน่าจะเป็นไปได้ 0.005% ทุภๆ 10 วินาที"
_setNameToSyuilo:
title: "คอมเพล็à¸à¸‹à¹Œà¸‚องพระเจ้า"
- description: "ตั้งชื่อของคุณเป็น “syuiloâ€"
+ description: "ตั้งชื่อเป็น “syuiloâ€"
_passedSinceAccountCreated1:
title: "ครบรอบหนึ่งปี"
- description: "ผ่านไปหนึ่งปีà¹à¸¥à¹‰à¸§à¸™à¸°à¸•ั้งà¹à¸•่บัà¸à¸Šà¸µà¸‚องคุณถูà¸à¸ªà¸£à¹‰à¸²à¸‡à¸‚ึ้นมาน่ะ"
+ description: "ผ่านไป 1 ปีนับตั้งà¹à¸•่สร้างบัà¸à¸Šà¸µ"
_passedSinceAccountCreated2:
title: "ครบรอบสองปี"
- description: "ผ่านไปสองปีà¹à¸¥à¹‰à¸§à¸™à¸°à¸•ั้งà¹à¸•่บัà¸à¸Šà¸µà¸‚องคุณถูà¸à¸ªà¸£à¹‰à¸²à¸‡à¸‚ึ้นมาน่ะ"
+ description: "ผ่านไป 2 ปีนับตั้งà¹à¸•่สร้างบัà¸à¸Šà¸µ"
_passedSinceAccountCreated3:
title: "ครบรอบสามปี"
- description: "ผ่านไปสามปีà¹à¸¥à¹‰à¸§à¸™à¸°à¸•ั้งà¹à¸•่บัà¸à¸Šà¸µà¸‚องคุณถูà¸à¸ªà¸£à¹‰à¸²à¸‡à¸‚ึ้นมาน่ะ"
+ description: "ผ่านไป 3 ปีนับตั้งà¹à¸•่สร้างบัà¸à¸Šà¸µ"
_loggedInOnBirthday:
title: "สุขสันต์วันเà¸à¸´à¸”"
description: "เข้าสู่ระบบในวันเà¸à¸´à¸”ของคุณ"
@@ -1637,7 +1672,7 @@ _role:
name: "ชื่อบทบาท"
description: "คำอธิบายบทบาท"
permission: "สิทธิ์ตามบทบาท"
- descriptionOfPermission: "<b>ผู้ควบคุม</b> สามารถดำเนินà¸à¸²à¸£à¸”ูà¹à¸¥à¸‚ั้นพื้นà¸à¸²à¸™à¹„ด้\n<b>ผู้ดูà¹à¸¥à¸£à¸°à¸šà¸š</b> สามารถเปลี่ยนà¸à¸²à¸£à¸•ั้งค่าทั้งหมดของอินสà¹à¸•นซ์ได้"
+ descriptionOfPermission: "<b>ผู้ควบคุม</b> สามารถดำเนินà¸à¸²à¸£à¸”ูà¹à¸¥à¸‚ั้นพื้นà¸à¸²à¸™à¹„ด้\n<b>ผู้ดูà¹à¸¥à¸£à¸°à¸šà¸š</b> สามารถเปลี่ยนà¸à¸²à¸£à¸•ั้งค่าทั้งหมดของเซิร์ฟเวอร์ได้"
assignTarget: "มอบหมาย"
descriptionOfAssignTarget: "à¹à¸šà¸š<b>ปรับเอง</b> เพิ่มถอนบทบาทนี้à¹à¸à¹ˆà¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸”้วยตัวเอง\nà¹à¸šà¸š<b>มีเงื่อนไข</b> เพิ่มถอนบทบาทนี้à¹à¸à¹ˆà¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¹‚ดยอัตโนมัติหาà¸à¹€à¸‚้าเงื่อนไขใดต่อไปนี้"
manual: "ปรับเอง"
@@ -1650,8 +1685,8 @@ _role:
descriptionOfIsPublic: "บทบาทจะปราà¸à¸à¸šà¸™à¹‚ปรไฟล์ของผู้ใช้à¹à¸¥à¸°à¹€à¸›à¸´à¸”เผยต่อสาธารณะ (ทุà¸à¸„นสามารถเห็นได้ว่าผู้ใช้รายนี้มีบทบาทนี้)"
options: "ตัวเลือà¸à¸šà¸—บาท"
policies: "นโยบาย"
- baseRole: "เทมเพลตบทบาท"
- useBaseValue: "ใช้ตามเทมเพลตบทบาท"
+ baseRole: "à¹à¸¡à¹ˆà¹à¸šà¸šà¸šà¸—บาท"
+ useBaseValue: "ใช้ตามà¹à¸¡à¹ˆà¹à¸šà¸šà¸šà¸—บาท"
chooseRoleToAssign: "เลือà¸à¸šà¸—บาทที่ต้องà¸à¸²à¸£à¸à¸³à¸«à¸™à¸”"
iconUrl: "URL ไอคอน"
asBadge: "à¹à¸ªà¸”งเป็นตรา"
@@ -1668,11 +1703,11 @@ _role:
middle: "ปานà¸à¸¥à¸²à¸‡"
high: "สูง"
_options:
- gtlAvailable: "à¸à¸²à¸£à¸”ูไทม์ไลน์ทั่วโลà¸"
- ltlAvailable: "à¸à¸²à¸£à¸”ูไทม์ไลน์ในท้องถิ่น"
+ gtlAvailable: "สามารถดูไทม์ไลน์ทั่วโลà¸à¹„ด้"
+ ltlAvailable: "สามารถดูไทม์ไลน์ท้องถิ่นได้"
canPublicNote: "สามารถโพสต์à¹à¸šà¸šà¸ªà¸²à¸˜à¸²à¸£à¸“ะ"
mentionMax: "จำนวนà¸à¸²à¸£à¸à¸¥à¹ˆà¸²à¸§à¸–ึงสูงสุดต่อโน้ต"
- canInvite: "สร้างรหัสเชิà¸à¸­à¸´à¸™à¸ªà¹à¸•นซ์"
+ canInvite: "สร้างรหัสเชิà¸à¹€à¸‚้าเซิร์ฟเวอร์"
inviteLimit: "จำà¸à¸±à¸”à¸à¸²à¸£à¹€à¸Šà¸´à¸"
inviteLimitCycle: "คูลดาวน์ในà¸à¸²à¸£à¹€à¸Šà¸´à¸"
inviteExpirationTime: "วันหมดอายุของรหัสà¸à¸²à¸£à¹€à¸Šà¸´à¸"
@@ -1680,6 +1715,7 @@ _role:
canManageAvatarDecorations: "จัดà¸à¸²à¸£à¸•à¸à¹à¸•่งอวตาร"
driveCapacity: "ความจุของไดรฟ์"
alwaysMarkNsfw: "ทำเครื่องหมายไฟล์ว่าเป็น NSFW เสมอ"
+ canUpdateBioMedia: "อนุà¸à¸²à¸•ให้ปรับปรุงไอคอนà¹à¸¥à¸°à¹à¸šà¸™à¹€à¸™à¸­à¸£à¹Œ"
pinMax: "จà¹à¸²à¸™à¸§à¸™à¸ªà¸¹à¸‡à¸ªà¸¸à¸”ของโน้ตที่ปัà¸à¸«à¸¡à¸¸à¸”ไว้"
antennaMax: "จำนวนสูงสุดของเสาอาà¸à¸²à¸¨"
wordMuteMax: "จำนวนอัà¸à¸‚ระสูงสุดที่อนุà¸à¸²à¸•ในà¸à¸²à¸£à¸›à¸´à¸”เสียงคำ"
@@ -1696,7 +1732,7 @@ _role:
avatarDecorationLimit: "จำนวนà¸à¸²à¸£à¸•à¸à¹à¸•่งไอคอนสูงสุดที่สามารถติดตั้งได้"
_condition:
roleAssignedTo: "มอบหมายให้มีบทบาทà¹à¸šà¸šà¸—ำมือ"
- isLocal: "ผู้ใช้ในพื้นที่"
+ isLocal: "ผู้ใช้ท้องถิ่น"
isRemote: "ผู้ใช้ระยะไà¸à¸¥"
isCat: "ผู้ใช้ที่เป็นà¹à¸¡à¸§"
isBot: "ผู้ใช้ที่เป็นบอต"
@@ -1755,8 +1791,8 @@ _ad:
adsTooClose: "เนื่องจาà¸à¸Šà¹ˆà¸§à¸‡à¹€à¸§à¸¥à¸²à¸à¸²à¸£à¹à¸ªà¸”งโฆษณาสั้นมาภประสบà¸à¸²à¸£à¸“์ผู้ใช้จึงอาจลดลงอย่างมาà¸"
_forgotPassword:
enterEmail: "ป้อนที่อยู่อีเมลที่คุณเคยใช้ในà¸à¸²à¸£à¸¥à¸‡à¸—ะเบียนไว้ ลิงà¸à¹Œà¸—ี่คุณสามารถรีเซ็ตรหัสผ่านได้นั้นจะถูà¸à¸ªà¹ˆà¸‡à¹„ปนะ"
- ifNoEmail: "ถ้าหาà¸à¸„ุณไม่ได้ใช้อีเมลระหว่างà¸à¸²à¸£à¸¥à¸‡à¸—ะเบียน à¸à¸£à¸¸à¸“าติดต่อผู้ดูà¹à¸¥à¸£à¸°à¸šà¸šà¸­à¸´à¸™à¸ªà¹à¸•นซ์à¹à¸—นนะ"
- contactAdmin: "อินสà¹à¸•นซ์นี้ไม่รองรับà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¸—ี่อยู่อีเมลนี้ à¸à¸£à¸¸à¸“าติดต่อผู้ดูà¹à¸¥à¸£à¸°à¸šà¸šà¸­à¸´à¸™à¸ªà¹à¸•นซ์เพื่อรีเซ็ตรหัสผ่านของคุณà¹à¸—น"
+ ifNoEmail: "หาà¸à¸¥à¸‡à¸—ะเบียนà¹à¸šà¸šà¹„ม่ใช้อีเมล โปรดติดต่อผู้ดูà¹à¸¥à¸£à¸°à¸šà¸š"
+ contactAdmin: "เนื่องจาà¸à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸™à¸µà¹‰à¹„ม่รองรับà¸à¸²à¸£à¸ªà¹ˆà¸‡à¸­à¸µà¹€à¸¡à¸¥ หาà¸à¸•้องà¸à¸²à¸£à¸£à¸µà¹€à¸‹à¹‡à¸•รหัสผ่าน à¸à¸£à¸¸à¸“าติดต่อผู้ดูà¹à¸¥à¸£à¸°à¸šà¸š"
_gallery:
my: "à¹à¸à¸¥à¸¥à¸­à¸£à¸µà¹ˆà¸‚องฉัน"
liked: "โพสต์ที่ถูà¸à¹ƒà¸ˆ"
@@ -1774,23 +1810,23 @@ _plugin:
viewSource: "ดูต้นฉบับ"
viewLog: "à¹à¸ªà¸”งปูม"
_preferencesBackups:
- list: "สร้างà¸à¸²à¸£à¸ªà¸³à¸£à¸­à¸‡à¸‚้อมูล"
- saveNew: "บันทึà¸à¸‚้อมูลสำรองใหม่"
+ list: "à¸à¸²à¸£à¸•ั้งค่าที่สำรองไว้"
+ saveNew: "บันทึà¸à¸à¸²à¸£à¸•ั้งค่าสำรองใหม่"
loadFile: "โหลดจาà¸à¹„ฟล์"
apply: "นำไปใช้à¸à¸±à¸šà¸­à¸¸à¸›à¸à¸£à¸“์นี้"
save: "บันทึà¸"
- inputName: "à¸à¸£à¸¸à¸“าป้อนชื่อสำหรับข้อมูลสำรองนี้"
+ inputName: "à¸à¸£à¸¸à¸“าป้อนชื่อà¸à¸²à¸£à¸•ั้งค่าสำรองนี้"
cannotSave: "à¸à¸²à¸£à¸šà¸±à¸™à¸—ึà¸à¸¥à¹‰à¸¡à¹€à¸«à¸¥à¸§"
- nameAlreadyExists: "มีข้อมูลสำรองชื่อ \"{name}\" นี้อยู่à¹à¸¥à¹‰à¸§ à¸à¸£à¸¸à¸“าป้อนชื่ออื่นนะ"
- applyConfirm: "คุณต้องà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‚้อมูลสำรอง \"{name}\" à¸à¸±à¸šà¸­à¸¸à¸›à¸à¸£à¸“์นี้อย่างงั้นจริงหรอ à¸à¸²à¸£à¸•ั้งค่าที่มีอยู่ของอุปà¸à¸£à¸“์นี้จะถูà¸à¹€à¸‚ียนทับนะ"
- saveConfirm: "บันทึà¸à¸‚้อมูลสำรองเป็น {name} มั้ย?"
- deleteConfirm: "ลบข้อมูลสำรอง {name} มั้ย?"
- renameConfirm: "ต้องà¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¸Šà¸·à¹ˆà¸­à¸‚้อมูลสำรองจาภ“{old}†เป็น “{new}†ใช่ไหม?"
- noBackups: "ไม่มีข้อมูลสำรอง สามารถบันทึà¸à¸à¸²à¸£à¸•ั้งค่าไคลเอนต์ปัจจุบันไปยังเซิร์ฟเวอร์ด้วย “บันทึà¸à¸‚้อมูลสำรองใหม่â€"
+ nameAlreadyExists: "มีà¸à¸²à¸£à¸•ั้งค่าสำรองชื่อ “{name}†อยู่à¹à¸¥à¹‰à¸§ à¸à¸£à¸¸à¸“าป้อนชื่ออื่น"
+ applyConfirm: "ต้องà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸à¸²à¸£à¸•ั้งค่าสำรอง “{name}†à¸à¸±à¸šà¸­à¸¸à¸›à¸à¸£à¸“์นี้ใช่ไหม? à¸à¸²à¸£à¸•ั้งค่าที่มีอยู่บนอุปà¸à¸£à¸“์นี้จะถูà¸à¹€à¸‚ียนทับ"
+ saveConfirm: "บันทึà¸à¸à¸²à¸£à¸•ั้งค่าสำรองเป็น {name} ใช่ไหม?"
+ deleteConfirm: "ต้องà¸à¸²à¸£à¸¥à¸š {name} ใช่ไหม?"
+ renameConfirm: "ต้องà¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¸Šà¸·à¹ˆà¸­à¸ˆà¸²à¸ “{old}†เป็น “{new}†ใช่ไหม?"
+ noBackups: "ไม่มีà¸à¸²à¸£à¸•ั้งค่าสำรอง สามารถบันทึà¸à¸à¸²à¸£à¸•ั้งค่าไคลเอนต์ปัจจุบันไปยังเซิร์ฟเวอร์ด้วย “บันทึà¸à¸à¸²à¸£à¸•ั้งค่าสำรองใหม่â€"
createdAt: "สร้างเมื่อ: {date} {time}"
updatedAt: "อัปเดตเมื่อ: {date} {time}"
cannotLoad: "à¸à¸²à¸£à¹‚หลดล้มเหลว"
- invalidFile: "รูปà¹à¸šà¸šà¹„ฟล์ไม่ถูà¸à¸•้องนะ"
+ invalidFile: "รูปà¹à¸šà¸šà¹„ฟล์ไม่ถูà¸à¸•้อง"
_registry:
scope: "สโคป"
key: "คีย์"
@@ -1841,13 +1877,13 @@ _menuDisplay:
hide: "ซ่อน"
_wordMute:
muteWords: "ปิดเสียงคำ"
- muteWordsDescription: "คั่นด้วยช่องว่างสำหรับเงื่อนไข AND หรือด้วยà¸à¸²à¸£à¸‚ึ้นบรรทัดใหม่สำหรับเงื่อนไข OR นะ"
+ muteWordsDescription: "คั่นด้วยเว้นวรรคสำหรับเงื่อนไข AND, หรือขึ้นบรรทัดใหม่สำหรับเงื่อนไข OR"
muteWordsDescription2: "ล้อมรอบคีย์เวิร์ดด้วยเครื่องหมายทับเพื่อใช้นิพจน์ทั่วไป"
_instanceMute:
- instanceMuteDescription: "à¸à¸²à¸£à¸”ำเนินà¸à¸²à¸£à¸™à¸µà¹‰à¸ˆà¸°à¸›à¸´à¸”เสียง\"โน้ต/รีโน้ต\"จาà¸à¸­à¸´à¸™à¸ªà¹à¸•นซ์ที่อยู่ในรายà¸à¸²à¸£ รวมถึงบันทึà¸à¸‚องผู้ใช้ที่ตอบà¸à¸¥à¸±à¸šà¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸ˆà¸²à¸à¸­à¸´à¸™à¸ªà¹à¸•นซ์ที่ปิดเสียง"
+ instanceMuteDescription: "ปิดเสียง “โน้ต/รีโน้ต†ทั้งหมดจาà¸à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸—ี่ระบุไว้ รวมถึงโน้ตของผู้ใช้ที่ตอบà¸à¸¥à¸±à¸šà¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸ˆà¸²à¸à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸—ี่ถูà¸à¸›à¸´à¸”เสียง"
instanceMuteDescription2: "คั่นด้วยà¸à¸²à¸£à¸‚ึ้นบรรทัดใหม่"
- title: "ซ่อนโน้ตจาà¸à¸­à¸´à¸™à¸ªà¹à¸•นซ์ที่มีอยู่ในรายชื่อ"
- heading: "รายชื่ออินสà¹à¸•นซ์ที่ถูà¸à¸›à¸´à¸”เสียง"
+ title: "ซ่อนโน้ตจาà¸à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸—ี่มีระบุไว้"
+ heading: "เซิร์ฟเวอร์ที่ถูà¸à¸›à¸´à¸”เสียง"
_theme:
explore: "สำรวจธีม"
install: "ติดตั้งธีม"
@@ -1923,8 +1959,6 @@ _sfx:
note: "โน้ต"
noteMy: "โน้ตของตัวเอง"
notification: "à¸à¸²à¸£à¹€à¹€à¸ˆà¹‰à¸‡à¹€à¸•ือน"
- antenna: "เสาอาà¸à¸²à¸¨"
- channel: "à¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนช่อง"
reaction: "เมื่อเลือà¸à¸£à¸µà¹à¸­à¸„ชั่น"
_soundSettings:
driveFile: "ใช้เสียงจาà¸à¹„ดรฟ์"
@@ -1932,7 +1966,8 @@ _soundSettings:
driveFileTypeWarn: "ไม่รองรับไฟล์นี้"
driveFileTypeWarnDescription: "à¸à¸£à¸¸à¸“าเลือà¸à¹„ฟล์เสียง"
driveFileDurationWarn: "เสียงยาวเà¸à¸´à¸™à¹„ป"
- driveFileDurationWarnDescription: "à¸à¸²à¸£à¹ƒà¸Šà¹‰à¹€à¸ªà¸µà¸¢à¸‡à¸—ี่ยาวอาจรบà¸à¸§à¸™à¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™ Misskey, ต้องà¸à¸²à¸£à¸”ำเนินà¸à¸²à¸£à¸•่อหรือไม่?"
+ driveFileDurationWarnDescription: "à¸à¸²à¸£à¹ƒà¸Šà¹‰à¹€à¸ªà¸µà¸¢à¸‡à¸—ี่ยาว อาจรบà¸à¸§à¸™à¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™ Misskey, ต้องà¸à¸²à¸£à¸”ำเนินà¸à¸²à¸£à¸•่อใช่ไหม?"
+ driveFileError: "ไม่สามารถโหลดไฟล์เสียงได้ à¸à¸£à¸¸à¸“าเปลี่ยนà¹à¸›à¸¥à¸‡à¸à¸²à¸£à¸•ั้งค่า"
_ago:
future: "อนาคต"
justNow: "เมื่อà¸à¸µà¹Šà¸™à¸µà¹‰"
@@ -1976,49 +2011,49 @@ _2fa:
removeKey: "ลบคีย์ความปลอดภัยออà¸"
removeKeyConfirm: "ลบข้อมูลสำรอง {name} มั้ย?"
whyTOTPOnlyRenew: "ไม่สามารถลบà¹à¸­à¸›à¸•ัวรับรองความถูà¸à¸•้องได้ตราบใดที่มีà¸à¸²à¸£à¸¥à¸‡à¸—ะเบียนคีย์ความปลอดภัยไว้à¹à¸¥à¹‰à¸§"
- renewTOTP: "à¸à¸³à¸«à¸™à¸”ค่าà¹à¸­à¸žà¸•ัวตรวจสอบสิทธิ์ใหม่"
+ renewTOTP: "ตั้งค่าà¹à¸­à¸›à¸¢à¸·à¸™à¸¢à¸±à¸™à¸•ัวตน"
renewTOTPConfirm: "วิธีà¸à¸²à¸£à¹à¸šà¸šà¸™à¸µà¹‰à¸ˆà¸°à¸—à¹à¸²à¹ƒà¸«à¹‰à¸£à¸«à¸±à¸ªà¸¢à¸·à¸™à¸¢à¸±à¸™à¸ˆà¸²à¸à¹à¸­à¸žà¸à¹ˆà¸­à¸™à¸«à¸™à¹‰à¸²à¸‚องคุณหยุดทà¹à¸²à¸‡à¸²à¸™à¹€à¸¥à¸¢à¸™à¸°"
renewTOTPOk: "ตั้งค่าคอนฟิà¸à¹ƒà¸«à¸¡à¹ˆ"
renewTOTPCancel: "ไม่เป็นไร"
- checkBackupCodesBeforeCloseThisWizard: "โปรดตรวจสอบรหัสสำรองด้านล่างà¸à¹ˆà¸­à¸™à¸—ี่จะปิดวิซาร์ดนี้"
- backupCodes: "รหัสสำรองข้อมูล"
+ checkBackupCodesBeforeCloseThisWizard: "โปรดตรวจสอบรหัสà¹à¸šà¹Šà¸à¸­à¸±à¸›à¸”้านล่างà¸à¹ˆà¸­à¸™à¸—ี่จะปิดวิซาร์ดนี้"
+ backupCodes: "รหัสà¹à¸šà¹Šà¸à¸­à¸±à¸›"
backupCodesDescription: "หาà¸à¹à¸­à¸›à¸¢à¸·à¸™à¸¢à¸±à¸™à¸•ัวตนของคุณไม่พร้อมใช้งาน คุณสามารถใช้รหัสสำรองด้านล่างเพื่อเข้าถึงบัà¸à¸Šà¸µà¸‚องคุณได้ อย่าลืมเà¸à¹‡à¸šà¸£à¸«à¸±à¸ªà¹€à¸«à¸¥à¹ˆà¸²à¸™à¸µà¹‰à¹„ว้ในที่ปลอดภัย à¹à¸•่ละรหัสสามารถใช้ได้เพียงครั้งเดียวเท่านั้น"
- backupCodeUsedWarning: "มีà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸£à¸«à¸±à¸ªà¸ªà¸³à¸£à¸­à¸‡à¹à¸¥à¹‰à¸§ โปรดà¸à¸£à¸¸à¸“าà¸à¸³à¸«à¸™à¸”ค่าà¸à¸²à¸£à¸•รวจสอบสิทธิ์à¹à¸šà¸šà¸ªà¸­à¸‡à¸›à¸±à¸ˆà¸ˆà¸±à¸¢à¹‚ดยเร็วที่สุดถ้าหาà¸à¸„ุณยังไม่สามารถใช้งานได้อีà¸"
- backupCodesExhaustedWarning: "รหัสสำรองทั้งหมดถูà¸à¹ƒà¸Šà¹‰à¹à¸¥à¹‰à¸§ ถ้าหาà¸à¸„ุณยังสูà¸à¹€à¸ªà¸µà¸¢à¸à¸²à¸£à¹€à¸‚้าถึงà¹à¸­à¸›à¸à¸²à¸£à¸•รวจสอบสิทธิ์à¹à¸šà¸šà¸ªà¸­à¸‡à¸›à¸±à¸ˆà¸ˆà¸±à¸¢à¸„ุณจะยังไม่สามารถเข้าถึงบัà¸à¸Šà¸µà¸™à¸µà¹‰à¹„ด้ à¸à¸£à¸¸à¸“าà¸à¸³à¸«à¸™à¸”ค่าà¸à¸²à¸£à¸£à¸±à¸šà¸£à¸­à¸‡à¸„วามถูà¸à¸•้องด้วยà¸à¸²à¸£à¸¢à¸·à¸™à¸¢à¸±à¸™à¸ªà¸­à¸‡à¸Šà¸±à¹‰à¸™"
+ backupCodeUsedWarning: "รหัสà¹à¸šà¹Šà¸à¸­à¸±à¸›à¸–ูà¸à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¹à¸¥à¹‰à¸§ หาà¸à¹à¸­à¸›à¸žà¸¥à¸´à¹€à¸„ชันà¸à¸²à¸£à¸¢à¸·à¸™à¸¢à¸±à¸™à¸•ัวตนไม่สามารถใช้งานได้ ให้รีบทำà¸à¸²à¸£à¸•ั้งค่าà¹à¸­à¸›à¸¯à¹ƒà¸«à¸¡à¹ˆà¹‚ดยเร็วที่สุด"
+ backupCodesExhaustedWarning: "รหัสà¹à¸šà¹Šà¸à¸­à¸±à¸›à¸—ั้งหมดถูà¸à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¹à¸¥à¹‰à¸§ หาà¸à¸¢à¸±à¸‡à¹„ม่สามารถใช้à¹à¸­à¸›à¸žà¸¥à¸´à¹€à¸„ชันà¸à¸²à¸£à¸¢à¸·à¸™à¸¢à¸±à¸™à¸•ัวตนได้à¸à¹‡à¸ˆà¸°à¹„ม่สามารถเข้าถึงบัà¸à¸Šà¸µà¸™à¸µà¹‰à¹„ด้อีà¸à¸•่อไป à¸à¸£à¸¸à¸“าลงทะเบียนà¹à¸­à¸›à¸žà¸¥à¸´à¹€à¸„ชันà¸à¸²à¸£à¸¢à¸·à¸™à¸¢à¸±à¸™à¸•ัวตนใหม่"
moreDetailedGuideHere: "คลิà¸à¸—ี่นี่เพื่อดูคำà¹à¸™à¸°à¸™à¸³à¹‚ดยละเอียด"
_permissions:
- "read:account": "ดูข้อมูลบัà¸à¸Šà¸µà¸‚องคุณ"
- "write:account": "à¹à¸à¹‰à¹„ขข้อมูลบัà¸à¸Šà¸µà¸‚องคุณ"
- "read:blocks": "ดูรายชื่อผู้ใช้ที่ถูà¸à¸šà¸¥à¹‡à¸­à¸à¸‚องคุณ"
- "write:blocks": "à¹à¸à¹‰à¹„ขรายชื่อผู้ใช้ที่ถูà¸à¸šà¸¥à¹‡à¸­à¸à¸‚องคุณ"
- "read:drive": "เข้าถึงไฟล์à¹à¸¥à¸°à¹‚ฟลเดอร์ในไดรฟ์ของคุณ"
- "write:drive": "à¹à¸à¹‰à¹„ขหรือลบไฟล์à¹à¸¥à¸°à¹‚ฟลเดอร์ในไดรฟ์ของคุณ"
+ "read:account": "ดูข้อมูลบัà¸à¸Šà¸µ"
+ "write:account": "à¹à¸à¹‰à¹„ขข้อมูลบัà¸à¸Šà¸µ"
+ "read:blocks": "ดูรายชื่อผู้ใช้ที่ถูà¸à¸šà¸¥à¹‡à¸­à¸"
+ "write:blocks": "à¹à¸à¹‰à¹„ขรายชื่อผู้ใช้ที่ถูà¸à¸šà¸¥à¹‡à¸­à¸"
+ "read:drive": "เข้าถึงไดรฟ์"
+ "write:drive": "จัดà¸à¸²à¸£à¹„ดรฟ์"
"read:favorites": "ดูรายà¸à¸²à¸£à¹‚ปรด"
"write:favorites": "à¹à¸à¹‰à¹„ขรายà¸à¸²à¸£à¹‚ปรด"
"read:following": "ดูข้อมูลว่าใครที่คุณติดตาม"
"write:following": "ติดตามหรือเลิà¸à¸•ิดตามบัà¸à¸Šà¸µà¸­à¸·à¹ˆà¸™"
- "read:messaging": "ดูà¹à¸Šà¸—ของคุณ"
+ "read:messaging": "ดูà¹à¸Šà¸—"
"write:messaging": "เขียนหรือลบข้อความà¹à¸Šà¸—"
- "read:mutes": "ดูรายชื่อผู้ใช้ที่ปิดเสียงของคุณ"
+ "read:mutes": "ดูรายชื่อผู้ใช้ที่ถูà¸à¸›à¸´à¸”เสียง"
"write:mutes": "à¹à¸à¹‰à¹„ขรายชื่อผู้ใช้ที่ถูà¸à¸›à¸´à¸”เสียง"
"write:notes": "เขียนหรือลบโน้ต"
- "read:notifications": "ดูà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนของคุณ"
- "write:notifications": "จัดà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนของคุณ"
- "read:reactions": "ดูรีà¹à¸­à¸„ชั่นของคุณ"
- "write:reactions": "à¹à¸à¹‰à¹„ขรีà¹à¸­à¸„ชั่นของคุณ"
+ "read:notifications": "ดูà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือน"
+ "write:notifications": "จัดà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือน"
+ "read:reactions": "ดูรีà¹à¸­à¸„ชั่น"
+ "write:reactions": "à¹à¸à¹‰à¹„ขรีà¹à¸­à¸„ชั่น"
"write:votes": "โหวตบนสำรวจความคิดเห็น"
"read:pages": "ดูหน้าเพจ"
- "write:pages": "à¹à¸à¹‰à¹„ขหรือลบเพจของคุณ"
+ "write:pages": "à¹à¸à¹‰à¹„ขหรือลบเพจ"
"read:page-likes": "ดูรายà¸à¸²à¸£à¹€à¸žà¸ˆà¸—ี่ถูà¸à¹ƒà¸ˆà¹„ว้"
"write:page-likes": "à¹à¸à¹‰à¹„ขรายà¸à¸²à¸£à¹€à¸žà¸ˆà¸—ี่ถูà¸à¹ƒà¸ˆ"
- "read:user-groups": "ดูà¸à¸¥à¸¸à¹ˆà¸¡à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸‚องคุณ"
- "write:user-groups": "à¹à¸à¹‰à¹„ขหรือลบà¸à¸¥à¸¸à¹ˆà¸¡à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸‚องคุณ"
- "read:channels": "ดูà¹à¸Šà¸™à¹à¸™à¸¥à¸‚องคุณ"
- "write:channels": "à¹à¸à¹‰à¹„ขà¹à¸Šà¸™à¹à¸™à¸¥à¸‚องคุณ"
+ "read:user-groups": "ดูà¸à¸¥à¸¸à¹ˆà¸¡à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰"
+ "write:user-groups": "à¹à¸à¹‰à¹„ขหรือลบà¸à¸¥à¸¸à¹ˆà¸¡à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰"
+ "read:channels": "ดูช่อง"
+ "write:channels": "à¹à¸à¹‰à¹„ขช่อง"
"read:gallery": "ดูà¹à¸à¸¥à¹€à¸¥à¸­à¸£à¸µà¹ˆ"
- "write:gallery": "à¹à¸à¹‰à¹„ขà¹à¸à¸¥à¹€à¸¥à¸­à¸£à¸µà¹ˆà¸‚องคุณ"
- "read:gallery-likes": "ดูรายà¸à¸²à¸£à¹‚พสต์à¹à¸à¸¥à¹€à¸¥à¸­à¸£à¸µà¸—ี่ถูà¸à¹ƒà¸ˆà¹„ว้"
- "write:gallery-likes": "à¹à¸à¹‰à¹„ขรายà¸à¸²à¸£à¹‚พสต์à¹à¸à¸¥à¹€à¸¥à¸­à¸£à¸µà¸—ี่ถูà¸à¹ƒà¸ˆà¹„ว้"
+ "write:gallery": "à¹à¸à¹‰à¹„ขà¹à¸à¸¥à¹€à¸¥à¸­à¸£à¸µ"
+ "read:gallery-likes": "ดูà¹à¸à¸¥à¹€à¸¥à¸­à¸£à¸µà¸—ี่ถูà¸à¹ƒà¸ˆà¹„ว้"
+ "write:gallery-likes": "จัดà¸à¸²à¸£à¹à¸à¸¥à¹€à¸¥à¸­à¸£à¸µà¸—ี่ถูà¸à¹ƒà¸ˆà¹„ว้"
"read:flash": "ดู Play"
"write:flash": "à¹à¸à¹‰à¹„ข Play"
"read:flash-likes": "ดูรายà¸à¸²à¸£ play ที่ถูà¸à¹ƒà¸ˆà¹„ว้"
@@ -2027,20 +2062,20 @@ _permissions:
"write:admin:delete-account": "ลบบัà¸à¸Šà¸µà¸œà¸¹à¹‰à¹ƒà¸Šà¹‰"
"write:admin:delete-all-files-of-a-user": "ลบไฟล์ทั้งหมดของผู้ใช้"
"read:admin:index-stats": "ดูข้อมูลเà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¸”ัชนีà¸à¸²à¸™à¸‚้อมูล"
- "read:admin:table-stats": "ดูข้อมูลเà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¸•ารางà¸à¸²à¸™à¸‚้อมูล"
+ "read:admin:table-stats": "ดูข้อมูลเà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¸•ารางในà¸à¸²à¸™à¸‚้อมูล"
"read:admin:user-ips": "ดูที่อยู่ IP ของผู้ใช้"
- "read:admin:meta": "ดูข้อมูลเมตาของอินสà¹à¸•นซ์"
+ "read:admin:meta": "ดูข้อมูลอภิพันธุ์ของอินสà¹à¸•นซ์"
"write:admin:reset-password": "รีเซ็ตรหัสผ่านของผู้ใช้"
"write:admin:resolve-abuse-user-report": "à¹à¸à¹‰à¹„ขรายงานจาà¸à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰"
"write:admin:send-email": "ส่งอีเมล"
"read:admin:server-info": "ดูข้อมูลเซิร์ฟเวอร์"
- "read:admin:show-moderation-log": "ดูปูมà¸à¸²à¸£à¹à¸à¹‰à¹„ข"
+ "read:admin:show-moderation-log": "ดูปูมà¸à¸²à¸£à¸„วบคุมดูà¹à¸¥"
"read:admin:show-user": "ดูข้อมูลส่วนตัวของผู้ใช้"
"write:admin:suspend-user": "ระงับผู้ใช้"
"write:admin:unset-user-avatar": "ลบอวตารผู้ใช้"
"write:admin:unset-user-banner": "ลบà¹à¸šà¸™à¹€à¸™à¸­à¸£à¹Œà¸œà¸¹à¹‰à¹ƒà¸Šà¹‰"
"write:admin:unsuspend-user": "ยà¸à¹€à¸¥à¸´à¸à¸à¸²à¸£à¸£à¸°à¸‡à¸±à¸šà¸œà¸¹à¹‰à¹ƒà¸Šà¹‰"
- "write:admin:meta": "จัดà¸à¸²à¸£à¸‚้อมูลเมตาของอินสà¹à¸•นซ์"
+ "write:admin:meta": "จัดà¸à¸²à¸£à¸‚้อมูลอภิพันธุ์ของอินสà¹à¸•นซ์"
"write:admin:user-note": "จัดà¸à¸²à¸£à¹‚น้ตà¸à¸²à¸£à¸à¸¥à¸±à¹ˆà¸™à¸à¸£à¸­à¸‡"
"write:admin:roles": "จัดà¸à¸²à¸£à¸šà¸—บาท"
"read:admin:roles": "ดูบทบาท"
@@ -2067,14 +2102,14 @@ _permissions:
"read:admin:ad": "ดูโฆษณา"
"write:invite-codes": "สร้างรหัสเชิà¸"
"read:invite-codes": "รับรหัสเชิà¸"
- "write:clip-favorite": "ควบคุมà¸à¸²à¸£à¸–ูà¸à¹ƒà¸ˆà¸‚องคลิป"
- "read:clip-favorite": "ดูà¸à¸²à¸£à¸–ูà¸à¹ƒà¸ˆà¸‚องคลิป"
+ "write:clip-favorite": "จัดà¸à¸²à¸£à¸„ลิปที่ถูà¸à¹ƒà¸ˆ"
+ "read:clip-favorite": "ดูคลิปที่ถูà¸à¹ƒà¸ˆ"
"read:federation": "รับข้อมูลเà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¸ªà¸«à¸žà¸±à¸™à¸˜à¹Œ"
"write:report-abuse": "รายงานà¸à¸²à¸£à¸¥à¸°à¹€à¸¡à¸´à¸”"
_auth:
shareAccessTitle: "à¸à¸²à¸£à¹ƒà¸«à¹‰à¸ªà¸´à¸—ธิ์à¹à¸­à¸›à¸žà¸¥à¸´à¹€à¸„ชัน"
shareAccess: "คุณต้องà¸à¸²à¸£à¸­à¸™à¸¸à¸à¸²à¸•ให้ \"{name}\" เข้าถึงบัà¸à¸Šà¸µà¸™à¸µà¹‰à¹€à¸¥à¸¢à¸¡à¸±à¹‰à¸¢?"
- shareAccessAsk: "ต้องà¸à¸²à¸£à¸­à¸™à¸¸à¸à¸²à¸•ให้à¹à¸­à¸›à¸žà¸¥à¸´à¹€à¸„ชันนี้เข้าถึงบัà¸à¸Šà¸µà¸‚องคุณหรือไม่?"
+ shareAccessAsk: "ต้องà¸à¸²à¸£à¸­à¸™à¸¸à¸à¸²à¸•ให้à¹à¸­à¸›à¸žà¸¥à¸´à¹€à¸„ชันนี้เข้าถึงบัà¸à¸Šà¸µà¸‚องคุณใช่ไหม?"
permission: "{name} ได้ขอสิทธิ์à¸à¸²à¸£à¹€à¸‚้าถึงดังต่อไปนี้"
permissionAsk: "à¹à¸­à¸›à¸žà¸¥à¸´à¹€à¸„ชันนี้ขอสิทธิ์ดังต่อไปนี้"
pleaseGoBack: "à¸à¸£à¸¸à¸“าà¸à¸¥à¸±à¸šà¹„ปที่à¹à¸­à¸›à¸žà¸¥à¸´à¹€à¸„ชัน"
@@ -2097,7 +2132,7 @@ _weekday:
saturday: "วันเสาร์"
_widgets:
profile: "โปรไฟล์"
- instanceInfo: "ข้อมูล อินสà¹à¸•นซ์"
+ instanceInfo: "ข้อมูลเซิร์ฟเวอร์"
memo: "โน้ตà¹à¸›à¸°"
notifications: "à¸à¸²à¸£à¹€à¹€à¸ˆà¹‰à¸‡à¹€à¸•ือน"
timeline: "ไทม์ไลน์"
@@ -2111,7 +2146,7 @@ _widgets:
digitalClock: "นาฬิà¸à¸²à¸”ิจิตอล"
unixClock: "นาฬิà¸à¸² UNIX"
federation: "สหพันธ์"
- instanceCloud: "อินสà¹à¸•นซ์คลาวด์"
+ instanceCloud: "à¸à¸¥à¸¸à¹ˆà¸¡à¹€à¸¡à¸†à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œ"
postForm: "à¹à¸šà¸šà¸Ÿà¸­à¸£à¹Œà¸¡à¸à¸²à¸£à¹‚พสต์"
slideshow: "à¹à¸ªà¸”งภาพนิ่ง"
button: "ปุ่ม"
@@ -2144,7 +2179,7 @@ _poll:
deadlineTime: "เวลา"
duration: "ระยะเวลา"
votesCount: "{n} คะà¹à¸™à¸™à¹€à¸ªà¸µà¸¢à¸‡"
- totalVotes: "{n} คะà¹à¸™à¸™à¹€à¸ªà¸µà¸¢à¸‡à¸—ั้งหมด"
+ totalVotes: "ทั้งหมด {n} คะà¹à¸™à¸™à¹€à¸ªà¸µà¸¢à¸‡"
vote: "โหวต"
showResult: "ดูผลลัพธ์"
voted: "โหวตà¹à¸¥à¹‰à¸§"
@@ -2156,14 +2191,14 @@ _poll:
_visibility:
public: "สาธารณะ"
publicDescription: "โน้ตของคุณจะปราà¸à¸à¹à¸à¹ˆà¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸—ุà¸à¸„น"
- home: "หน้าà¹à¸£à¸"
- homeDescription: "โพสลงไทม์ไลน์ที่บ้านเท่านั้น"
+ home: "หน้าหลัà¸"
+ homeDescription: "โพสต์ลงไทม์ไลน์หลัà¸à¹€à¸—่านั้น"
followers: "ผู้ติดตาม"
followersDescription: "เฉพาะผู้ติดตามเท่านั้นที่มองเห็นได้"
specified: "ไดเร็ค"
specifiedDescription: "ทำให้มองเห็นได้เฉพาะผู้ใช้ที่ระบุเท่านั้น"
disableFederation: "ไม่มีสหพันธ์"
- disableFederationDescription: "อย่าส่งไปยังอินสà¹à¸•นซ์อื่น"
+ disableFederationDescription: "อย่าส่งข้อมูลไปยังเซิร์ฟเวอร์อื่น"
_postForm:
replyPlaceholder: "ตอบà¸à¸¥à¸±à¸šà¹‚น้ตนี้..."
quotePlaceholder: "อ้างโน้ตนี้..."
@@ -2199,37 +2234,37 @@ _exportOrImport:
userLists: "รายชื่อ"
excludeMutingUsers: "ยà¸à¹€à¸§à¹‰à¸™à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸—ี่ปิดเสียง"
excludeInactiveUsers: "ยà¸à¹€à¸§à¹‰à¸™à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸—ี่ไม่ได้ใช้งาน"
- withReplies: "รวมà¸à¸²à¸£à¸•อบà¸à¸¥à¸±à¸šà¸ˆà¸²à¸à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸—ี่นำเข้าไว้ในไทม์ไลน์"
+ withReplies: "รวมà¸à¸²à¸£à¸•อบà¸à¸¥à¸±à¸šà¸ˆà¸²à¸à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸—ี่ถูà¸à¸™à¸³à¹€à¸‚้า ลงไทม์ไลน์"
_charts:
federation: "สหพันธ์"
apRequest: "คำขอ"
- usersIncDec: "ความà¹à¸•à¸à¸•่างของจำนวนผู้ใช้งาน"
+ usersIncDec: "à¸à¸²à¸£à¹€à¸žà¸´à¹ˆà¸¡à¸¥à¸”ของจำนวนผู้ใช้"
usersTotal: "จำนวนผู้ใช้งานทั้งหมด"
activeUsers: "จำนวนผู้ใช้งานที่ยังมีความเคลื่อนไหวอยู่"
- notesIncDec: "ความà¹à¸•à¸à¸•่างของจำนวนโน้ต"
- localNotesIncDec: "ความà¹à¸•à¸à¸•่างของจำนวนโน้ตท้องถิ่น"
- remoteNotesIncDec: "ความà¹à¸•à¸à¸•่างของจำนวนโน้ตระยะไà¸à¸¥"
+ notesIncDec: "à¸à¸²à¸£à¹€à¸žà¸´à¹ˆà¸¡à¸¥à¸”ของจำนวนโน้ต"
+ localNotesIncDec: "à¸à¸²à¸£à¹€à¸žà¸´à¹ˆà¸¡à¸¥à¸”ของจำนวนโน้ตท้องถิ่น"
+ remoteNotesIncDec: "à¸à¸²à¸£à¹€à¸žà¸´à¹ˆà¸¡à¸¥à¸”ของจำนวนโน้ตระยะไà¸à¸¥"
notesTotal: "จำนวนโน้ตทั้งหมด"
- filesIncDec: "ความà¹à¸•à¸à¸•่างของจำนวนไฟล์"
+ filesIncDec: "à¸à¸²à¸£à¹€à¸žà¸´à¹ˆà¸¡à¸¥à¸”ของจำนวนไฟล์"
filesTotal: "จำนวนไฟล์ทั้งหมด"
- storageUsageIncDec: "ความà¹à¸•à¸à¸•่างในà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸žà¸·à¹‰à¸™à¸—ี่เà¸à¹‡à¸šà¸‚้อมูล"
+ storageUsageIncDec: "à¸à¸²à¸£à¹€à¸žà¸´à¹ˆà¸¡à¸¥à¸”ในà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸žà¸·à¹‰à¸™à¸—ี่เà¸à¹‡à¸šà¸‚้อมูล"
storageUsageTotal: "à¸à¸²à¸£à¹ƒà¸Šà¹‰à¸žà¸·à¹‰à¸™à¸—ี่เà¸à¹‡à¸šà¸‚้อมูลทั้งหมด"
_instanceCharts:
requests: "คำขอ"
- users: "ความà¹à¸•à¸à¸•่างของจำนวนผู้ใช้งาน"
+ users: "à¸à¸²à¸£à¹€à¸žà¸´à¹ˆà¸¡à¸¥à¸”ของจำนวนผู้ใช้งาน"
usersTotal: "จำนวนผู้ใช้งานสะสม"
- notes: "ความà¹à¸•à¸à¸•่างของจำนวนโน้ต"
+ notes: "à¸à¸²à¸£à¹€à¸žà¸´à¹ˆà¸¡à¸¥à¸”ของจำนวนโน้ต"
notesTotal: "จำนวนโน้ตสะสม"
- ff: "ความà¹à¸•à¸à¸•่างของจำนวนผู้ใช้ที่ติดตาม / ผู้ติดตาม"
- ffTotal: "จำนวนผู้ใช้งานที่ติดตามสะสม / ผู้ติดตาม"
- cacheSize: "ความà¹à¸•à¸à¸•่างในขนาดของà¹à¸„ช"
- cacheSizeTotal: "ขนาดà¹à¸„ชรวมที่สะสม"
- files: "ความà¹à¸•à¸à¸•่างของจำนวนไฟล์"
+ ff: "à¸à¸²à¸£à¹€à¸žà¸´à¹ˆà¸¡à¸¥à¸”ของà¸à¸²à¸£à¸•ิดตาม/ผู้ติดตาม"
+ ffTotal: "จำนวนสะสมของà¸à¸²à¸£à¸•ิดตาม/ผู้ติดตาม"
+ cacheSize: "à¸à¸²à¸£à¹€à¸žà¸´à¹ˆà¸¡à¸¥à¸”ขนาดของà¹à¸„ช"
+ cacheSizeTotal: "ขนาดà¹à¸„ชสะสม"
+ files: "à¸à¸²à¸£à¹€à¸žà¸´à¹ˆà¸¡à¸¥à¸”ของจำนวนไฟล์"
filesTotal: "จำนวนไฟล์สะสม"
_timelines:
- home: "หน้าà¹à¸£à¸"
- local: "ในพื้นที่"
- social: "โซเชี่ยล"
+ home: "หน้าหลัà¸"
+ local: "ท้องถิ่น"
+ social: "โซเชียล"
global: "ทั่วโลà¸"
_play:
new: "สร้าง Play"
@@ -2245,7 +2280,7 @@ _play:
featured: "เป็นที่นิยม"
title: "หัวข้อ"
script: "สคริปต์"
- summary: "รายละเอียด"
+ summary: "คำอธิบาย"
visibilityDescription: "หาà¸à¸•ั้งค่าเป็นส่วนตัว มันจะไม่ปราà¸à¸à¹ƒà¸™à¹‚ปรไฟล์อีà¸à¸•่อไป à¹à¸•่ผู้ที่ทราบ URL ของมันจะยังสามารถเข้าถึงได้"
_pages:
newPage: "สร้างหน้าเพจใหม่"
@@ -2333,7 +2368,7 @@ _notification:
mention: "à¸à¸¥à¹ˆà¸²à¸§à¸–ึง"
reply: "ตอบà¸à¸¥à¸±à¸š"
renote: "รีโน้ต"
- quote: "อ้างคำพูด"
+ quote: "อ้างอิง"
reaction: "รีà¹à¸­à¸„ชั่น"
pollEnded: "โพลสิ้นสุดà¹à¸¥à¹‰à¸§"
receiveFollowRequest: "ได้รับคำร้องขอติดตาม"
@@ -2349,6 +2384,7 @@ _deck:
alwaysShowMainColumn: "à¹à¸ªà¸”งคอลัมน์หลัà¸à¹€à¸ªà¸¡à¸­"
columnAlign: "จัดà¹à¸™à¸§à¸„อลัมน์"
addColumn: "เพิ่มคอลัมน์"
+ newNoteNotificationSettings: "ตั้งค่าà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนเมื่อมีโน้ตใหม่"
configureColumn: "ตั้งค่าคอลัมน์"
swapLeft: "ขยับไปทางซ้าย"
swapRight: "ขยับไปทางขวา"
@@ -2373,7 +2409,7 @@ _deck:
antenna: "เสาอาà¸à¸²à¸¨"
list: "รายà¸à¸²à¸£"
channel: "ช่อง"
- mentions: "พูดถึง"
+ mentions: "à¸à¸¥à¹ˆà¸²à¸§à¸–ึงคุณ"
direct: "ไดเร็à¸à¸•์"
roleTimeline: "บทบาทไทม์ไลน์"
_dialog:
@@ -2387,9 +2423,9 @@ _drivecleaner:
orderByCreatedAtAsc: "วันที่จาà¸à¸™à¹‰à¸­à¸¢à¹„ปหามาà¸"
_webhookSettings:
createWebhook: "สร้าง Webhook"
+ modifyWebhook: "à¹à¸à¹‰à¹„ข Webhook"
name: "ชื่อ"
secret: "ความลับ"
- events: "อีเว้นท์ Webhook"
active: "เปิดใช้งาน"
_events:
follow: "เมื่อà¸à¸³à¸¥à¸±à¸‡à¸•ิดตามผู้ใช้"
@@ -2399,6 +2435,26 @@ _webhookSettings:
renote: "รีโน้ตà¹à¸¥à¹‰à¸§à¹€à¸¡à¸·à¹ˆà¸­"
reaction: "เมื่อได้รับรีà¹à¸­à¸„ชั่น"
mention: "เมื่อà¸à¸³à¸¥à¸±à¸‡à¸–ูà¸à¸à¸¥à¹ˆà¸²à¸§à¸–ึง"
+ _systemEvents:
+ abuseReport: "เมื่อมีà¸à¸²à¸£à¸£à¸²à¸¢à¸‡à¸²à¸™à¸ˆà¸²à¸à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰"
+ abuseReportResolved: "เมื่อมีà¸à¸²à¸£à¸ˆà¸±à¸”à¸à¸²à¸£à¸à¸±à¸šà¸à¸²à¸£à¸£à¸²à¸¢à¸‡à¸²à¸™à¸ˆà¸²à¸à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰"
+ userCreated: "เมื่อผู้ใช้ถูà¸à¸ªà¸£à¹‰à¸²à¸‡à¸‚ึ้น"
+ deleteConfirm: "ต้องà¸à¸²à¸£à¸¥à¸š Webhook ใช่ไหม?"
+_abuseReport:
+ _notificationRecipient:
+ createRecipient: "เพิ่มปลายทางà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนà¸à¸²à¸£à¸£à¸²à¸¢à¸‡à¸²à¸™"
+ modifyRecipient: "à¹à¸à¹‰à¹„ขปลายทางà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนà¸à¸²à¸£à¸£à¸²à¸¢à¸‡à¸²à¸™"
+ recipientType: "ประเภทของปลายทางà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือน\n"
+ _recipientType:
+ mail: "อีเมล"
+ webhook: "Webhook"
+ _captions:
+ mail: "ส่งà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนไปยังที่อยู่อีเมลของผู้ควบคุม (เฉพาะเมื่อได้รับà¸à¸²à¸£à¸£à¸²à¸¢à¸‡à¸²à¸™)"
+ webhook: "ส่งà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนไปยัง SystemWebhook ที่à¸à¸³à¸«à¸™à¸” (จะส่งเมื่อได้รับà¸à¸²à¸£à¸£à¸²à¸¢à¸‡à¸²à¸™à¹à¸¥à¸°à¹€à¸¡à¸·à¹ˆà¸­à¸à¸²à¸£à¸£à¸²à¸¢à¸‡à¸²à¸™à¹„ด้รับà¸à¸²à¸£à¹à¸à¹‰à¹„ข)"
+ keywords: "คีย์เวิร์ด"
+ notifiedUser: "ผู้ใช้ที่ได้รับà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือน"
+ notifiedWebhook: "Webhook ที่ใช้"
+ deleteConfirm: "ต้องà¸à¸²à¸£à¸¥à¸šà¸›à¸¥à¸²à¸¢à¸—างà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนใช่ไหม?"
_moderationLogTypes:
createRole: "สร้างบทบาทà¹à¸¥à¹‰à¸§"
deleteRole: "ลบบทบาทà¹à¸¥à¹‰à¸§"
@@ -2421,9 +2477,9 @@ _moderationLogTypes:
deleteGlobalAnnouncement: "ลบประà¸à¸²à¸¨à¸—ั่วโลà¸à¸­à¸­à¸à¹à¸¥à¹‰à¸§"
deleteUserAnnouncement: "ลบประà¸à¸²à¸¨à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸­à¸­à¸à¹à¸¥à¹‰à¸§"
resetPassword: "รีเซ็ตรหัสผ่าน"
- suspendRemoteInstance: "ระงับอินสà¹à¸•นซ์ระยะไà¸à¸¥"
- unsuspendRemoteInstance: "เลิà¸à¸£à¸°à¸‡à¸±à¸šà¸­à¸´à¸™à¸ªà¹à¸•นซ์ระยะไà¸à¸¥"
- updateRemoteInstanceNote: "อัปเดตโน้ตà¸à¸²à¸£à¸à¸¥à¸±à¹ˆà¸™à¸à¸£à¸­à¸‡à¸‚องอินสà¹à¸•นซ์ระยะไà¸à¸¥à¹à¸¥à¹‰à¸§"
+ suspendRemoteInstance: "ระงับเซิร์ฟเวอร์ระยะไà¸à¸¥"
+ unsuspendRemoteInstance: "เลิà¸à¸£à¸°à¸‡à¸±à¸šà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸£à¸°à¸¢à¸°à¹„à¸à¸¥"
+ updateRemoteInstanceNote: "อัปเดตโน้ตà¸à¸²à¸£à¸à¸¥à¸±à¹ˆà¸™à¸à¸£à¸­à¸‡à¸ªà¸³à¸«à¸£à¸±à¸šà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸£à¸°à¸¢à¸°à¹„à¸à¸¥à¹à¸¥à¹‰à¸§"
markSensitiveDriveFile: "ทำเครื่องหมายไฟล์ว่ามีเนื้อหาละเอียดอ่อน"
unmarkSensitiveDriveFile: "ยà¸à¹€à¸¥à¸´à¸à¸—ำเครื่องหมายไฟล์ว่ามีเนื้อหาละเอียดอ่อน"
resolveAbuseReport: "รายงานได้รับà¸à¸²à¸£à¹à¸à¹‰à¹„ขà¹à¸¥à¹‰à¸§"
@@ -2436,6 +2492,12 @@ _moderationLogTypes:
deleteAvatarDecoration: "ลบà¸à¸²à¸£à¸•à¸à¹à¸•่งไอคอนà¹à¸¥à¹‰à¸§"
unsetUserAvatar: "ลบไอคอนผู้ใช้"
unsetUserBanner: "ลบà¹à¸šà¸™à¹€à¸™à¸­à¸£à¹Œà¸œà¸¹à¹‰à¹ƒà¸Šà¹‰"
+ createSystemWebhook: "สร้าง SystemWebhook"
+ updateSystemWebhook: "อัปเดต SystemWebhook"
+ deleteSystemWebhook: "ลบ SystemWebhook"
+ createAbuseReportNotificationRecipient: "สร้างปลายทางà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนà¸à¸²à¸£à¸£à¸²à¸¢à¸‡à¸²à¸™"
+ updateAbuseReportNotificationRecipient: "อัปเดตปลายทางà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนà¸à¸²à¸£à¸£à¸²à¸¢à¸‡à¸²à¸™"
+ deleteAbuseReportNotificationRecipient: "ลบปลายทางà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ือนà¸à¸²à¸£à¸£à¸²à¸¢à¸‡à¸²à¸™"
_fileViewer:
title: "รายละเอียดไฟล์"
type: "ประเภทไฟล์"
@@ -2448,10 +2510,10 @@ _externalResourceInstaller:
title: "ติดตั้งจาà¸à¹„ซต์ภายนอà¸"
checkVendorBeforeInstall: "โปรดตรวจสอบให้à¹à¸™à¹ˆà¹ƒà¸ˆà¸§à¹ˆà¸²à¹à¸«à¸¥à¹ˆà¸‡à¹à¸ˆà¸à¸«à¸™à¹ˆà¸²à¸¢à¸¡à¸µà¸„วามน่าเชื่อถือà¸à¹ˆà¸­à¸™à¸—ำà¸à¸²à¸£à¸•ิดตั้ง"
_plugin:
- title: "ต้องà¸à¸²à¸£à¸•ิดตั้งปลั๊à¸à¸­à¸´à¸™à¸™à¸µà¹‰à¸«à¸£à¸·à¸­à¹„ม่?"
+ title: "ต้องà¸à¸²à¸£à¸•ิดตั้งปลั๊à¸à¸­à¸´à¸™à¸™à¸µà¹‰à¹ƒà¸Šà¹ˆà¹„หม?"
metaTitle: "ข้อมูลส่วนเสริม"
_theme:
- title: "ต้องà¸à¸²à¸£à¸•ิดตั้งธีมนี้หรือไม่?"
+ title: "ต้องà¸à¸²à¸£à¸•ิดตั้งธีมนี้ใช่ไหม?"
metaTitle: "ข้อมูลธีม"
_meta:
base: "โทนสีพื้นà¸à¸²à¸™"
@@ -2487,7 +2549,7 @@ _externalResourceInstaller:
description: "เà¸à¸´à¸”ปัà¸à¸«à¸²à¸£à¸°à¸«à¸§à¹ˆà¸²à¸‡à¸à¸²à¸£à¸•ิดตั้งธีม à¸à¸£à¸¸à¸“าลองอีà¸à¸„รั้ง. รายละเอียดข้อผิดพลาดสามารถดูได้ในคอนโซล Javascript"
_dataSaver:
_media:
- title: "โหลดมีเดีย"
+ title: "โหลดสื่อ"
description: "à¸à¸±à¸™à¹„ม่ให้ภาพà¹à¸¥à¸°à¸§à¸´à¸”ีโอโหลดโดยอัตโนมัติ à¹à¸•ะรูปภาพ/วิดีโอที่ซ่อนอยู่เพื่อโหลด"
_avatar:
title: "รูปไอคอน"
@@ -2567,3 +2629,8 @@ _mediaControls:
pip: "รูปภาพในรูปภาม"
playbackRate: "ความเร็วในà¸à¸²à¸£à¹€à¸¥à¹ˆà¸™"
loop: "เล่นวนซ้ำ"
+_contextMenu:
+ title: "เมนูเนื้อหา"
+ app: "à¹à¸­à¸›à¸žà¸¥à¸´à¹€à¸„ชัน"
+ appWithShift: "à¹à¸­à¸›à¸Ÿà¸¥à¸´à¹€à¸„ชันด้วยปุ่มยà¸à¹à¸„ร่ (Shift)"
+ native: "UI ของเบราว์เซอร์"
diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml
index 661ecf19d7..36d741d30e 100644
--- a/locales/uk-UA.yml
+++ b/locales/uk-UA.yml
@@ -1318,8 +1318,6 @@ _sfx:
note: "Ðотатки"
noteMy: "Мої нотатки"
notification: "СповіщеннÑ"
- antenna: "Прийом антени"
- channel: "ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ ÐºÐ°Ð½Ð°Ð»Ñƒ"
_ago:
future: "Майбутнє"
justNow: "Щойно"
@@ -1622,6 +1620,10 @@ _deck:
_webhookSettings:
name: "Ім'Ñ"
active: "Увімкнено"
+_abuseReport:
+ _notificationRecipient:
+ _recipientType:
+ mail: "E-mail"
_moderationLogTypes:
suspend: "Призупинити"
resetPassword: "Скинути пароль"
diff --git a/locales/uz-UZ.yml b/locales/uz-UZ.yml
index 4a930626f4..ee4ab83ce7 100644
--- a/locales/uz-UZ.yml
+++ b/locales/uz-UZ.yml
@@ -1089,6 +1089,10 @@ _webhookSettings:
_events:
renote: "Qayta qayd qilinganda"
mention: "Eslanganda"
+_abuseReport:
+ _notificationRecipient:
+ _recipientType:
+ mail: "Email"
_moderationLogTypes:
suspend: "To'xtatish"
resetPassword: "Parolni tiklash"
diff --git a/locales/vi-VN.yml b/locales/vi-VN.yml
index acc2e0c6a9..aadbf8b16f 100644
--- a/locales/vi-VN.yml
+++ b/locales/vi-VN.yml
@@ -376,6 +376,7 @@ mcaptcha: "mCaptcha"
enableMcaptcha: "Bật mCaptcha"
mcaptchaSiteKey: "Khóa của trang"
mcaptchaSecretKey: "Khóa bí mật"
+mcaptchaInstanceUrl: "URL mCaptcha máy chủ"
recaptcha: "reCAPTCHA"
enableRecaptcha: "Bật reCAPTCHA"
recaptchaSiteKey: "Khóa của trang"
@@ -426,6 +427,7 @@ moderator: "Kiểm duyệt viên"
moderation: "Kiểm duyệt"
moderationNote: "Ghi chú kiểm duyệt"
addModerationNote: "Thêm ghi chú kiểm duyệt"
+moderationLogs: "Nhật kí quản trị"
nUsersMentioned: "Dùng bởi {n} ngưá»i"
securityKeyAndPasskey: "Mã bảo mật・Passkey"
securityKey: "Khóa bảo mật"
@@ -458,6 +460,7 @@ retype: "Nhập lại"
noteOf: "Tút của {user}"
quoteAttached: "Trích dẫn"
quoteQuestion: "Trích dẫn lại?"
+attachAsFileQuestion: "Văn bản ở trong bộ nhớ tạm rất dài. Bạn có muốn đăng nó dưới dạng một tệp văn bản không?"
noMessagesYet: "Chưa có tin nhắn"
newMessageExists: "Bạn có tin nhắn mới"
onlyOneFileCanBeAttached: "Bạn chỉ có thể đính kèm một tập tin"
@@ -1559,8 +1562,6 @@ _sfx:
note: "Tút"
noteMy: "Tút của tôi"
notification: "Thông báo"
- antenna: "Trạm phát sóng"
- channel: "Kênh"
_ago:
future: "Tương lai"
justNow: "Vừa xong"
@@ -1917,11 +1918,14 @@ _webhookSettings:
createWebhook: "Tạo Webhook"
name: "Tên"
secret: "Mã bí mật"
- events: "Sự kiện Webhook"
active: "Äã bật"
_events:
reaction: "Khi nhận được sự kiện"
mention: "Khi có ngưá»i nhắc tá»›i bạn"
+_abuseReport:
+ _notificationRecipient:
+ _recipientType:
+ mail: "Email"
_moderationLogTypes:
suspend: "Vô hiệu hóa"
resetPassword: "Äặt lại mật khẩu"
diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml
index f92d997b5a..1deb0effc3 100644
--- a/locales/zh-CN.yml
+++ b/locales/zh-CN.yml
@@ -60,6 +60,7 @@ copyFileId: "å¤åˆ¶æ–‡ä»¶ID"
copyFolderId: "å¤åˆ¶æ–‡ä»¶å¤¹ID"
copyProfileUrl: "å¤åˆ¶ä¸ªäººèµ„æ–™URL"
searchUser: "æœç´¢ç”¨æˆ·"
+searchThisUsersNotes: "æœç´¢ç”¨æˆ·å¸–å­"
reply: "回å¤"
loadMore: "查看更多"
showMore: "查看更多"
@@ -154,6 +155,7 @@ editList: "编辑列表"
selectChannel: "选择频é“"
selectAntenna: "选择天线"
editAntenna: "编辑天线"
+createAntenna: "创建天线"
selectWidget: "选择å°å·¥å…·"
editWidgets: "编辑部件"
editWidgetsExit: "完æˆç¼–辑"
@@ -180,6 +182,10 @@ addAccount: "添加账户"
reloadAccountsList: "更新账户列表"
loginFailed: "登录失败"
showOnRemote: "转到所在æœåŠ¡å™¨æ˜¾ç¤º"
+continueOnRemote: "转到所在æœåŠ¡å™¨ç»§ç»­"
+chooseServerOnMisskeyHub: "从 Misskey Hub 选择æœåС噍"
+specifyServerHost: "直接输入æœåŠ¡å™¨åŸŸå"
+inputHostName: "请输入域å"
general: "常规设置"
wallpaper: "å£çº¸"
setWallpaper: "设置å£çº¸"
@@ -190,6 +196,7 @@ followConfirm: "你确定è¦å…³æ³¨ {name} å—?"
proxyAccount: "代ç†è´¦æˆ·"
proxyAccountDescription: "代ç†è´¦æˆ·æ˜¯åœ¨æŸäº›æƒ…况下替代用户进行远程关注用的账户。 例如说,当用户将一ä½è¿œç¨‹ç”¨æˆ·æ”¾å…¥ä¸€ä¸ªåˆ—表中时,如果本地æœåŠ¡å™¨ä¸Šæ²¡æœ‰ä»»ä½•äººå…³æ³¨è¿™ä½è¿œç¨‹ç”¨æˆ·ï¼Œåˆ™è¿™ä½è¿œç¨‹ç”¨æˆ·çš„账户活动将ä¸ä¼šè¢«é€åˆ°æœ¬åœ°æœåŠ¡å™¨ä¸Šã€‚ä½œä¸ºæ›¿ä»£ï¼Œæ­¤æ—¶å°†ä½¿ç”¨ä»£ç†è´¦æˆ·è¿›è¡Œå…³æ³¨ã€‚"
host: "主机å"
+selectSelf: "选择自己"
selectUser: "选择用户"
recipient: "收件人"
annotation: "注解"
@@ -205,6 +212,7 @@ perDay: "æ¯å¤©"
stopActivityDelivery: "åœæ­¢å‘逿´»åЍ"
blockThisInstance: "阻止此æœåС噍呿œ¬æœåŠ¡å™¨æŽ¨æµ"
silenceThisInstance: "使æœåС噍é™éŸ³"
+mediaSilenceThisInstance: "éšè—æ­¤æœåŠ¡å™¨çš„åª’ä½“æ–‡ä»¶"
operations: "æ“作"
software: "软件"
version: "版本"
@@ -223,9 +231,11 @@ clearQueueConfirmText: "未é€è¾¾çš„帖å­å°†ä¸ä¼šè¢«æŠ•递。 通常无需执è
clearCachedFiles: "清除缓存"
clearCachedFilesConfirm: "ç¡®å®šè¦æ¸…除所有缓存的远程文件?"
blockedInstances: "被å°é”çš„æœåС噍"
-blockedInstancesDescription: "设定è¦å°é”çš„æœåŠ¡å™¨ï¼Œä»¥æ¢è¡Œæ¥è¿›è¡Œåˆ†å‰²ã€‚被å°é”çš„æœåŠ¡å™¨å°†æ— æ³•ä¸Žæœ¬æœåŠ¡å™¨è¿›è¡Œäº¤æ¢é€šè®¯ã€‚å­åŸŸåä¹ŸåŒæ ·ä¼šè¢«å°é”。"
+blockedInstancesDescription: "设定è¦å°é”çš„æœåŠ¡å™¨ï¼Œä»¥æ¢è¡Œåˆ†éš”。被å°é”çš„æœåŠ¡å™¨å°†æ— æ³•ä¸Žæœ¬æœåŠ¡å™¨è¿›è¡Œäº¤æ¢é€šè®¯ã€‚å­åŸŸåä¹ŸåŒæ ·ä¼šè¢«å°é”。"
silencedInstances: "被é™éŸ³çš„æœåŠ¡å™¨"
-silencedInstancesDescription: "设置è¦é™éŸ³çš„æœåŠ¡å™¨ï¼Œä»¥æ¢è¡Œç¬¦åˆ†éš”。被é™éŸ³çš„æœåŠ¡å™¨å†…æ‰€æœ‰çš„è´¦æˆ·å°†é»˜è®¤å¤„äºŽã€Œé™éŸ³ã€çжæ€ï¼Œä»…能å‘é€å…³æ³¨è¯·æ±‚,并且在未关注状æ€ä¸‹æ— æ³•æåŠæœ¬åœ°è´¦æˆ·ã€‚被阻止的实例ä¸å—å½±å“。"
+silencedInstancesDescription: "设置è¦é™éŸ³çš„æœåŠ¡å™¨ï¼Œä»¥æ¢è¡Œåˆ†éš”。被é™éŸ³çš„æœåŠ¡å™¨å†…æ‰€æœ‰çš„è´¦æˆ·å°†é»˜è®¤å¤„äºŽã€Œé™éŸ³ã€çжæ€ï¼Œä»…能å‘é€å…³æ³¨è¯·æ±‚,并且在未关注状æ€ä¸‹æ— æ³•æåŠæœ¬åœ°è´¦æˆ·ã€‚被阻止的实例ä¸å—å½±å“。"
+mediaSilencedInstances: "å·²éšè—媒体文件的æœåС噍"
+mediaSilencedInstancesDescription: "设置è¦éšè—媒体文件的æœåŠ¡å™¨ï¼Œä»¥æ¢è¡Œåˆ†éš”。被设置为éšè—媒体文件æœåŠ¡å™¨å†…æ‰€æœ‰è´¦å·çš„æ–‡ä»¶å‡æŒ‰ç…§ã€Œæ•感内容ã€å¤„ç†ï¼Œä¸”将无法使用自定义表情符å·ã€‚被阻止的实例ä¸å—å½±å“。"
muteAndBlock: "é™éŸ³/拉黑"
mutedUsers: "å·²é™éŸ³ç”¨æˆ·"
blockedUsers: "已拉黑的用户"
@@ -351,7 +361,7 @@ instanceName: "æœåС噍åç§°"
instanceDescription: "æœåŠ¡å™¨ç®€ä»‹"
maintainerName: "管ç†å‘˜åç§°"
maintainerEmail: "管ç†å‘˜ç”µå­é‚®ç®±"
-tosUrl: "æœåŠ¡æ¡æ¬¾ URL"
+tosUrl: "æœåŠ¡æ¡æ¬¾åœ°å€"
thisYear: "今年"
thisMonth: "本月"
today: "今天"
@@ -433,8 +443,8 @@ administrator: "管ç†å‘˜"
token: "Token (令牌)"
2fa: "åŒå› ç´ è®¤è¯"
setupOf2fa: "设置åŒå› ç´ è®¤è¯"
-totp: "身份验è¯åº”用"
-totpDescription: "使用认è¯åº”用输入一次性密ç ã€‚"
+totp: "验è¯å™¨"
+totpDescription: "使用验è¯å™¨è¾“入一次性密ç "
moderator: "监察员"
moderation: "管ç†"
moderationNote: "管ç†ç¬”è®°"
@@ -477,6 +487,7 @@ noMessagesYet: "现在没有新的èŠå¤©"
newMessageExists: "æ–°ä¿¡æ¯"
onlyOneFileCanBeAttached: "åªèƒ½æ·»åŠ ä¸€ä¸ªé™„ä»¶"
signinRequired: "请先登录"
+signinOrContinueOnRemote: "è‹¥è¦ç»§ç»­ï¼Œéœ€è¦è½¬åˆ°æ‚¨æ‰€ä½¿ç”¨çš„实例,或者在此æœåŠ¡å™¨ä¸Šæ³¨å†Œæˆ–ç™»å½•ã€‚"
invitations: "邀请"
invitationCode: "邀请ç "
checking: "正在确认"
@@ -837,6 +848,7 @@ administration: "管ç†"
accounts: "账户"
switch: "切æ¢"
noMaintainerInformationWarning: "管ç†äººå‘˜ä¿¡æ¯æœªè®¾ç½®ã€‚"
+noInquiryUrlWarning: "尚未设置è”络地å€ã€‚"
noBotProtectionWarning: "Bot 防御未设置。"
configure: "设置"
postToGallery: "å‘é€åˆ°å›¾åº“"
@@ -848,7 +860,7 @@ shareWithNote: "在帖å­ä¸­åˆ†äº«"
ads: "广告"
expiration: "截止时间"
startingperiod: "开始时间"
-memo: "便笺"
+memo: "备注"
priority: "优先级"
high: "高"
middle: "中"
@@ -1100,6 +1112,8 @@ preservedUsernames: "ä¿ç•™çš„用户å"
preservedUsernamesDescription: "列出需è¦ä¿ç•™çš„用户å,使用æ¢è¡Œæ¥ä½œä¸ºåˆ†å‰²ã€‚被指定的用户å在建立账户时无法使用,但由管ç†å‘˜æ‰€åˆ›å»ºçš„账户ä¸å—该é™åˆ¶ã€‚此外,现有的账户也ä¸ä¼šå—到影å“。"
createNoteFromTheFile: "从文件创建帖å­"
archive: "å½’æ¡£"
+archived: "已归档"
+unarchive: "å–æ¶ˆå½’æ¡£"
channelArchiveConfirmTitle: "è¦å°† {name} å½’æ¡£å—?"
channelArchiveConfirmDescription: "å½’æ¡£åŽï¼Œåœ¨é¢‘é“列表与æœç´¢ç»“果中ä¸ä¼šæ˜¾ç¤ºï¼Œä¹Ÿæ— æ³•å‘布新的贴文。"
thisChannelArchived: "该频é“已被归档。"
@@ -1110,6 +1124,9 @@ preventAiLearning: "æ‹’ç»æŽ¥å—生æˆå¼ AI 的学习"
preventAiLearningDescription: "è¦æ±‚æ–‡ç« ç”Ÿæˆ AI 或图åƒç”Ÿæˆ AI ä¸èƒ½å¤Ÿä»¥å‘布的帖å­å’Œå›¾åƒç­‰å†…容作为学习对象。这是通过在 HTML å“åº”ä¸­åŒ…å« noai 标志æ¥å®žçŽ°çš„ï¼Œè¿™ä¸èƒ½å®Œå…¨é˜»æ­¢ AI 学习你的å‘å¸ƒå†…å®¹ï¼Œå¹¶ä¸æ˜¯æ‰€æœ‰ AI 都会éµå®ˆè¿™ç±»è¯·æ±‚。"
options: "选项"
specifyUser: "用户指定"
+lookupConfirm: "确定查询?"
+openTagPageConfirm: "确定打开è¯é¢˜æ ‡ç­¾é¡µé¢ï¼Ÿ"
+specifyHost: "指定主机å"
failedToPreviewUrl: "无法预览"
update: "æ›´æ–°"
rolesThatCanBeUsedThisEmojiAsReaction: "å¯ä»¥ä½¿ç”¨è¡¨æƒ…作为回应的角色"
@@ -1180,7 +1197,7 @@ externalServices: "外部æœåŠ¡"
sourceCode: "æºä»£ç "
sourceCodeIsNotYetProvided: "还未æä¾›æºä»£ç ã€‚è¦è§£å†³æ­¤é—®é¢˜è¯·è”系管ç†å‘˜ã€‚"
repositoryUrl: "仓库地å€"
-repositoryUrlDescription: "è‹¥æºä»£ç æ‰€åœ¨çš„仓库是公开的,请填入对应的 URL。若是按原样使用 Misskey(并未追加或者修改代ç ï¼‰çš„æƒ…况请填入 https://github.com/misskey-dev/misskey。"
+repositoryUrlDescription: "è‹¥æºä»£ç æ‰€åœ¨çš„仓库是公开的,请填入对应的 URL。若并未追加或者修改 Misskey 的代ç ï¼Œè¯·å¡«å…¥ https://github.com/misskey-dev/misskey。"
repositoryUrlOrTarballRequired: "è‹¥ä»“åº“å¹¶æœªå…¬å¼€ï¼Œåˆ™éœ€è¦æä¾› tarball 作为替代。详情请看 .config/example.yml。"
feedback: "å馈"
feedbackUrl: "å馈地å€"
@@ -1241,6 +1258,11 @@ keepOriginalFilenameDescription: "若关闭此设置,上传文件时文件åå
noDescription: "没有æè¿°"
alwaysConfirmFollow: "总是确认关注"
inquiry: "è”系我们"
+tryAgain: "请å†è¯•一次"
+confirmWhenRevealingSensitiveMedia: "æ˜¾ç¤ºæ•æ„Ÿå†…容å‰éœ€è¦ç¡®è®¤"
+sensitiveMediaRevealConfirm: "è¿™æ˜¯æ•æ„Ÿå†…å®¹ã€‚æ˜¯å¦æ˜¾ç¤ºï¼Ÿ"
+createdLists: "已创建的列表"
+createdAntennas: "已创建的天线"
_delivery:
status: "投递状æ€"
stop: "åœæ­¢æŠ•递"
@@ -1375,6 +1397,8 @@ _serverSettings:
fanoutTimelineDescription: "当å¯ç”¨æ—¶ï¼Œå¯æ˜¾è‘—æé«˜èŽ·å–å„ç§æ—¶é—´çº¿æ—¶çš„æ€§èƒ½ï¼Œå¹¶å‡è½»æ•°æ®åº“的负è·ã€‚但是相对的 Redis 的内存使用é‡å°†ä¼šå¢žåŠ ã€‚å¦‚æžœæœåŠ¡å™¨çš„å†…å­˜ä¸æ˜¯å¾ˆå¤§ï¼Œåˆæˆ–者è¿è¡Œä¸ç¨³å®šçš„è¯å¯ä»¥æŠŠå®ƒå…³æŽ‰ã€‚"
fanoutTimelineDbFallback: "回退到数æ®åº“"
fanoutTimelineDbFallbackDescription: "当å¯ç”¨æ—¶ï¼Œè‹¥æ—¶é—´çº¿æœªè¢«ç¼“存,则将é¢å¤–查询数æ®åº“。ç¦ç”¨è¯¥åŠŸèƒ½å¯é€šè¿‡ä¸æ‰§è¡Œå›žé€€å¤„ç†è¿›ä¸€æ­¥å‡å°‘æœåŠ¡å™¨è´Ÿè½½ï¼Œä½†ä¼šé™åˆ¶å¯æ£€ç´¢çš„æ—¶é—´çº¿èŒƒå›´ã€‚"
+ inquiryUrl: "è”络地å€"
+ inquiryUrlDescription: "ç”¨æ¥æŒ‡å®šè¯¸å¦‚呿œåŠ¡è¿è¥å•†å’¨è¯¢çš„论å›åœ°å€ï¼Œæˆ–记载了è¿è¥å•†è”系方å¼ä¹‹ç±»çš„网页地å€ã€‚"
_accountMigration:
moveFrom: "从别的账å·è¿ç§»åˆ°æ­¤è´¦æˆ·"
moveFromSub: "为å¦ä¸€ä¸ªè´¦æˆ·å»ºç«‹åˆ«å"
@@ -1670,8 +1694,8 @@ _role:
descriptionOfIsExplorable: "打开åŽå°†å…¬å¼€è§’è‰²æ—¶é—´çº¿ã€‚å¦‚æžœè§’è‰²ä¸æ˜¯å…¬å¼€çš„,就无法公开时间线。"
displayOrder: "显示顺åº"
descriptionOfDisplayOrder: "数字越大,显示ä½ç½®è¶Šé å‰ã€‚"
- canEditMembersByModerator: "å…许监察者编辑æˆå‘˜"
- descriptionOfCanEditMembersByModerator: "如果选中,监察者和管ç†å‘˜éƒ½èƒ½å¤Ÿä¸ºç”¨æˆ·åˆ†é…/å–æ¶ˆåˆ†é…è§’è‰²ã€‚å¦‚æžœæœªé€‰ä¸­ï¼Œåˆ™åªæœ‰ç®¡ç†å‘˜å¯ä»¥æ‰§è¡Œæ­¤æ“作。"
+ canEditMembersByModerator: "å…许监察员编辑æˆå‘˜"
+ descriptionOfCanEditMembersByModerator: "如果选中,监察员和管ç†å‘˜éƒ½èƒ½å¤Ÿä¸ºç”¨æˆ·åˆ†é…/å–æ¶ˆåˆ†é…è§’è‰²ã€‚å¦‚æžœæœªé€‰ä¸­ï¼Œåˆ™åªæœ‰ç®¡ç†å‘˜å¯ä»¥æ‰§è¡Œæ­¤æ“作。"
priority: "优先级"
_priority:
low: "低"
@@ -1690,6 +1714,7 @@ _role:
canManageAvatarDecorations: "管ç†å¤´åƒæŒ‚ä»¶"
driveCapacity: "网盘容é‡"
alwaysMarkNsfw: "总是将文件标记为 NSFW"
+ canUpdateBioMedia: "å¯ä»¥æ›´æ–°å¤´åƒå’Œæ¨ªå¹…"
pinMax: "帖å­ç½®é¡¶æ•°é‡é™åˆ¶"
antennaMax: "å¯åˆ›å»ºçš„æœ€å¤§å¤©çº¿æ•°é‡"
wordMuteMax: "å±è”½è¯çš„å­—æ•°é™åˆ¶"
@@ -1933,8 +1958,6 @@ _sfx:
note: "帖å­"
noteMy: "我的帖å­"
notification: "通知"
- antenna: "天线接收"
- channel: "频é“通知"
reaction: "选择回应时"
_soundSettings:
driveFile: "使用网盘内的音频"
@@ -1943,6 +1966,7 @@ _soundSettings:
driveFileTypeWarnDescription: "请选择音频文件"
driveFileDurationWarn: "音频过长"
driveFileDurationWarnDescription: "使用长音频å¯èƒ½ä¼šå½±å“ Misskey 的使用。å³ä½¿è¿™æ ·ä¹Ÿè¦ç»§ç»­å—?"
+ driveFileError: "无法读å–声音。请更改设置。"
_ago:
future: "未æ¥"
justNow: "最近"
@@ -1969,7 +1993,7 @@ _time:
day: "æ—¥"
_2fa:
alreadyRegistered: "此设备已被注册"
- registerTOTP: "开始设置认è¯åº”用"
+ registerTOTP: "开始设置验è¯å™¨"
step1: "首先,在您的设备上安装验è¯åº”用,例如 {a} 或 {b}。"
step2: "ç„¶åŽï¼Œæ‰«æå±å¹•上显示的二维ç ã€‚"
step2Uri: "如果使用桌é¢åº”用程åºçš„è¯ï¼Œè¯·è¾“入下é¢çš„ URI"
@@ -1978,23 +2002,23 @@ _2fa:
setupCompleted: "设置完æˆ"
step4: "从现在开始,任何登录æ“ä½œéƒ½å°†è¦æ±‚您æä¾›åЍæ€å£ä»¤ã€‚"
securityKeyNotSupported: "您的æµè§ˆå™¨ä¸æ”¯æŒå®‰å…¨å¯†é’¥ã€‚"
- registerTOTPBeforeKey: "è¦æ³¨å†Œå®‰å…¨å¯†é’¥æˆ– Passkey,请先设置验è¯å™¨åº”用程åºã€‚"
+ registerTOTPBeforeKey: "è¦æ³¨å†Œå®‰å…¨å¯†é’¥æˆ– Passkey,请先设置验è¯å™¨ã€‚"
securityKeyInfo: "注册兼容 WebAuthn çš„å¯†é’¥ï¼Œä¾‹å¦‚æ”¯æŒ FIDO2 的硬件安全密钥ã€è®¾å¤‡ä¸Šçš„生物识别功能ã€PIN ç ä»¥åŠ Passkey 等。"
registerSecurityKey: "注册安全密钥或 Passkey"
securityKeyName: "输入密钥åç§°"
tapSecurityKey: "请按照æµè§ˆå™¨è¯´æ˜Žæ“ä½œæ¥æ³¨å†Œå®‰å…¨å¯†é’¥æˆ– Passkey。"
removeKey: "删除安全密钥"
removeKeyConfirm: "您确定è¦åˆ é™¤ {name} å—?"
- whyTOTPOnlyRenew: "å¦‚æžœæ³¨å†Œäº†å®‰å…¨å¯†é’¥ï¼Œåˆ™æ— æ³•å–æ¶ˆéªŒè¯å™¨åº”用程åºä¸Šçš„设置。"
- renewTOTP: "é‡ç½®éªŒè¯å™¨åº”用程åº"
- renewTOTPConfirm: "当å‰éªŒè¯å™¨åº”用程åºçš„验è¯ç å°†ä¸å†æœ‰æ•ˆ"
+ whyTOTPOnlyRenew: "å½“æ³¨å†Œäº†å®‰å…¨å¯†é’¥æ—¶ï¼Œæ— æ³•å–æ¶ˆä½¿ç”¨éªŒè¯å™¨ã€‚"
+ renewTOTP: "é‡ç½®éªŒè¯å™¨"
+ renewTOTPConfirm: "当å‰éªŒè¯å™¨çš„验è¯ç åŠå¤‡ç”¨ä»£ç å·²å¤±æ•ˆ"
renewTOTPOk: "釿–°é…ç½®"
renewTOTPCancel: "ä¸ç”¨ï¼Œè°¢è°¢"
checkBackupCodesBeforeCloseThisWizard: "在关闭此窗å£å‰ï¼Œè¯·ç¡®è®¤ä¸‹é¢çš„备用代ç "
backupCodes: "备用代ç "
- backupCodesDescription: "如果无法使用认è¯åº”用,å¯ä»¥ä½¿ç”¨ä»¥ä¸‹çš„å¤‡ç”¨ä»£ç æ¥è®¿é—®è´¦æˆ·ã€‚请务必将这些代ç ä¿å­˜åœ¨å®‰å…¨çš„地方。æ¯ä¸ªä»£ç ä»…å¯ä½¿ç”¨ä¸€æ¬¡ã€‚"
- backupCodeUsedWarning: "已使用备用代ç ã€‚如果无法使用认è¯åº”ç”¨ï¼Œè¯·å°½å¿«é‡æ–°è®¾å®šã€‚"
- backupCodesExhaustedWarning: "已使用完所有的备用代ç ã€‚如果无法使用认è¯åº”用,将无法å†è®¿é—®æ‚¨çš„è´¦æˆ·ã€‚è¯·å†æ¬¡è®¾å®šè®¤è¯åº”用。"
+ backupCodesDescription: "如果无法使用验è¯å™¨ï¼Œå¯ä»¥ä½¿ç”¨ä»¥ä¸‹çš„å¤‡ç”¨ä»£ç æ¥è®¿é—®è´¦æˆ·ã€‚请务必将这些代ç ä¿å­˜åœ¨å®‰å…¨çš„地方。æ¯ä¸ªä»£ç ä»…å¯ä½¿ç”¨ä¸€æ¬¡ã€‚"
+ backupCodeUsedWarning: "已使用备用代ç ã€‚若验è¯å™¨æ— æ³•使用,请尽快é‡ç½®éªŒè¯å™¨ã€‚"
+ backupCodesExhaustedWarning: "已使用完所有的备用代ç ã€‚若验è¯å™¨æ— æ³•使用,则无法å†è®¿é—®æ‚¨çš„账户。请é‡ç½®éªŒè¯å™¨ã€‚"
moreDetailedGuideHere: "此处为详细指å—"
_permissions:
"read:account": "查看账户信æ¯"
@@ -2398,9 +2422,10 @@ _drivecleaner:
orderByCreatedAtAsc: "按添加日期é™åºæŽ’列"
_webhookSettings:
createWebhook: "创建 Webhook"
+ modifyWebhook: "编辑 webhook"
name: "åç§°"
secret: "密钥"
- events: "何时è¿è¡Œ Webhook"
+ trigger: "触å‘器"
active: "å·²å¯ç”¨"
_events:
follow: "关注时"
@@ -2410,6 +2435,26 @@ _webhookSettings:
renote: "è¢«è½¬å‘æ—¶"
reaction: "被回应时"
mention: "被æåŠæ—¶"
+ _systemEvents:
+ abuseReport: "当收到举报时"
+ abuseReportResolved: "å½“ä¸¾æŠ¥è¢«å¤„ç†æ—¶"
+ userCreated: "当用户被创建时"
+ deleteConfirm: "è¦åˆ é™¤ webhook å—?"
+_abuseReport:
+ _notificationRecipient:
+ createRecipient: "新建举报通知"
+ modifyRecipient: "编辑举报通知"
+ recipientType: "通知类型"
+ _recipientType:
+ mail: "邮箱"
+ webhook: "Webhook"
+ _captions:
+ mail: "å½“æ”¶åˆ°æ–°ä¸¾æŠ¥æ—¶ï¼Œå‘æŒæœ‰ç›‘察员æƒé™çš„用户å‘é€é€šçŸ¥é‚®ä»¶"
+ webhook: "当收到新举报åŠä¸¾æŠ¥è¢«å¤„ç†æ—¶ï¼Œä½¿ç”¨æŒ‡å®šçš„ SystemWebhook å‘é€é€šçŸ¥"
+ keywords: "关键字"
+ notifiedUser: "通知的用户"
+ notifiedWebhook: "使用的 webhook"
+ deleteConfirm: "è¦åˆ é™¤é€šçŸ¥å—?"
_moderationLogTypes:
createRole: "创建角色"
deleteRole: "删除角色"
@@ -2447,6 +2492,12 @@ _moderationLogTypes:
deleteAvatarDecoration: "åˆ é™¤å¤´åƒæŒ‚ä»¶"
unsetUserAvatar: "清除用户头åƒ"
unsetUserBanner: "清除用户横幅"
+ createSystemWebhook: "新建了 SystemWebhook"
+ updateSystemWebhook: "更新了 SystemWebhook"
+ deleteSystemWebhook: "删除了 SystemWebhook"
+ createAbuseReportNotificationRecipient: "新建了举报通知"
+ updateAbuseReportNotificationRecipient: "更新了举报通知"
+ deleteAbuseReportNotificationRecipient: "删除了举报通知"
_fileViewer:
title: "文件信æ¯"
type: "文件类型"
@@ -2578,3 +2629,8 @@ _mediaControls:
pip: "画中画"
playbackRate: "播放速度"
loop: "循环播放"
+_contextMenu:
+ title: "上下文èœå•"
+ app: "应用"
+ appWithShift: "Shift 键应用"
+ native: "æµè§ˆå™¨çš„用户界é¢"
diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml
index aac3f7662c..16dc464e35 100644
--- a/locales/zh-TW.yml
+++ b/locales/zh-TW.yml
@@ -60,6 +60,7 @@ copyFileId: "複製檔案 ID"
copyFolderId: "複製資料夾ID"
copyProfileUrl: "複製個人資料網å€"
searchUser: "æœå°‹ä½¿ç”¨è€…"
+searchThisUsersNotes: "æœå°‹é€™å€‹ä½¿ç”¨è€…的貼文"
reply: "回覆"
loadMore: "載入更多"
showMore: "載入更多"
@@ -154,6 +155,7 @@ editList: "編輯清單"
selectChannel: "鏿“‡é »é“"
selectAntenna: "鏿“‡å¤©ç·š"
editAntenna: "編輯天線"
+createAntenna: "建立天線"
selectWidget: "鏿“‡å°å·¥å…·"
editWidgets: "編輯å°å·¥å…·"
editWidgetsExit: "完æˆ"
@@ -180,6 +182,10 @@ addAccount: "新增帳戶"
reloadAccountsList: "更新帳戶清單的資訊"
loginFailed: "登入失敗"
showOnRemote: "轉到所在實例顯示"
+continueOnRemote: "在é ç«¯ä¼ºæœå™¨ç¹¼çºŒ"
+chooseServerOnMisskeyHub: "從 Misskey Hub 鏿“‡ä¼ºæœå™¨"
+specifyServerHost: "直接指定伺æœå™¨ç¶²åŸŸ"
+inputHostName: "請輸入域å"
general: "一般"
wallpaper: "桌布"
setWallpaper: "設定桌布"
@@ -190,6 +196,7 @@ followConfirm: "你真的è¦è¿½éš¨{name}嗎?"
proxyAccount: "代ç†å¸³æˆ¶"
proxyAccountDescription: "代ç†å¸³æˆ¶æ˜¯åœ¨ç‰¹å®šæ¢ä»¶ä¸‹å……ç•¶é ç«¯è¿½éš¨è€…的帳戶。例如,當使用者新增é ç«¯ä½¿ç”¨è€…至其列表時,若沒有本地使用者追隨該é ç«¯ä½¿ç”¨è€…ï¼Œå‰‡å…¶æ´»å‹•å°‡ä¸æœƒå‚³é€è‡³ä¼ºæœå™¨ï¼Œæ­¤æ™‚便會由代ç†å¸³æˆ¶ä»£ç‚ºè¿½éš¨ä»¥è§£æ±ºå•題。"
host: "主機"
+selectSelf: "鏿“‡è‡ªå·±"
selectUser: "é¸å–使用者"
recipient: "收件人"
annotation: "註解"
@@ -205,6 +212,7 @@ perDay: "æ¯æ—¥"
stopActivityDelivery: "åœæ­¢ç™¼é€æ´»å‹•"
blockThisInstance: "å°éŽ–æ­¤ä¼ºæœå™¨"
silenceThisInstance: "ç¦è¨€æ­¤ä¼ºæœå™¨"
+mediaSilenceThisInstance: "將這個伺æœå™¨çš„媒體設為ç¦è¨€"
operations: "æ“作"
software: "軟體"
version: "版本"
@@ -226,6 +234,8 @@ blockedInstances: "å·²å°éŽ–çš„ä¼ºæœå™¨"
blockedInstancesDescription: "è«‹é€è¡Œè¼¸å…¥éœ€è¦å°éŽ–çš„ä¼ºæœå™¨ã€‚å·²å°éŽ–çš„ä¼ºæœå™¨å°‡ç„¡æ³•與本伺æœå™¨é€²è¡Œé€šè¨Šã€‚"
silencedInstances: "被ç¦è¨€çš„伺æœå™¨"
silencedInstancesDescription: "設定è¦ç¦è¨€çš„伺æœå™¨ä¸»æ©Ÿå稱,以æ›è¡Œåˆ†éš”。隸屬於ç¦è¨€ä¼ºæœå™¨çš„æ‰€æœ‰å¸³æˆ¶éƒ½å°‡è¢«è¦–為「ç¦è¨€å¸³æˆ¶ã€ï¼Œåªèƒ½ç™¼å‡ºã€Œè¿½éš¨è«‹æ±‚ã€ï¼Œè€Œä¸”無法æåŠæœªè¿½éš¨çš„æœ¬åœ°å¸³æˆ¶ã€‚這䏿œƒå½±éŸ¿å·²å°éŽ–çš„å¯¦ä¾‹ã€‚"
+mediaSilencedInstances: "媒體被ç¦è¨€çš„伺æœå™¨"
+mediaSilencedInstancesDescription: "設定您想è¦å°åª’體設定ç¦è¨€çš„伺æœå™¨ï¼Œä»¥æ›è¡Œç¬¦è™Ÿå€éš”。來自被媒體ç¦è¨€çš„伺æœå™¨æ‰€å±¬å¸³æˆ¶çš„æ‰€æœ‰æª”æ¡ˆéƒ½æœƒè¢«è¦–ç‚ºæ•æ„Ÿæª”案,且自訂表情符號ä¸èƒ½ä½¿ç”¨ã€‚被å°éŽ–çš„ä¼ºæœå™¨ä¸å—影響。"
muteAndBlock: "éœéŸ³å’Œå°éŽ–"
mutedUsers: "被éœéŸ³çš„使用者"
blockedUsers: "被å°éŽ–çš„ä½¿ç”¨è€…"
@@ -243,10 +253,10 @@ noCustomEmojis: "沒有自訂的表情符號"
noJobs: "沒有任務"
federating: "è¯é‚¦é‹ä½œä¸­"
blocked: "å·²å°éŽ–"
-suspended: "å·²å‡çµ"
+suspended: "åœæ­¢ç™¼é€"
all: "全部"
subscribing: "訂閱中"
-publishing: "直播中"
+publishing: "發é€ä¸­"
notResponding: "沒有回應"
instanceFollowing: "追隨的伺æœå™¨"
instanceFollowers: "伺æœå™¨çš„追隨者"
@@ -343,7 +353,7 @@ reload: "釿–°æ•´ç†"
doNothing: "無視"
reloadConfirm: "確定è¦é‡æ–°æ•´ç†å—Žï¼Ÿ"
watch: "關注"
-unwatch: "å–æ¶ˆè¿½éš¨"
+unwatch: "å–æ¶ˆé—œæ³¨"
accept: "接å—"
reject: "拒絕"
normal: "正常"
@@ -477,6 +487,7 @@ noMessagesYet: "沒有訊æ¯"
newMessageExists: "有新的訊æ¯"
onlyOneFileCanBeAttached: "åªèƒ½åР入䏀個附件"
signinRequired: "請先登入"
+signinOrContinueOnRemote: "è‹¥è¦ç¹¼çºŒï¼Œéœ€å‰å¾€æ‚¨æ‰€åœ¨çš„伺æœå™¨ï¼Œæˆ–者註冊並登入此伺æœå™¨"
invitations: "邀請"
invitationCode: "邀請碼"
checking: "確èªä¸­"
@@ -837,6 +848,7 @@ administration: "管ç†"
accounts: "帳戶"
switch: "切æ›"
noMaintainerInformationWarning: "尚未設定管ç†å“¡è¨Šæ¯ã€‚"
+noInquiryUrlWarning: "尚未設定è¯çµ¡è¡¨å–®ç¶²å€ã€‚"
noBotProtectionWarning: "尚未設定 Bot 防護。"
configure: "設定"
postToGallery: "發佈到相簿"
@@ -1100,6 +1112,8 @@ preservedUsernames: "ä¿ç•™çš„使用者å稱"
preservedUsernamesDescription: "æ›è¡Œåˆ—舉è¦ä¿ç•™çš„使用者å稱。此處出ç¾çš„å稱將在註冊時ç¦ç”¨ï¼Œä½†ç”±ç®¡ç†è€…建立帳戶則ä¸å—æ­¤é™ã€‚此外,既有的帳戶也ä¸å—影響。"
createNoteFromTheFile: "由此檔案建立貼文"
archive: "å°å­˜"
+archived: "å·²å°å­˜"
+unarchive: "å–æ¶ˆå°å­˜"
channelArchiveConfirmTitle: "è¦å°å­˜{name}嗎?"
channelArchiveConfirmDescription: "å°å­˜å¾Œï¼Œå°‡ä¸æœƒåœ¨é »é“列表與æœå°‹çµæžœä¸­é¡¯ç¤ºï¼Œä¹Ÿç„¡æ³•發佈新貼文。"
thisChannelArchived: "這個頻é“已被å°å­˜ã€‚"
@@ -1110,6 +1124,9 @@ preventAiLearning: "拒絕接å—生æˆå¼AI的訓練"
preventAiLearningDescription: "è¦æ±‚站外生æˆå¼ AI ä¸ä½¿ç”¨æ‚¨ç™¼ä½ˆçš„內容訓練模型。此功能會使伺æœå™¨æ–¼ HTML 回應新增「noaiã€æ¨™ç±¤ï¼Œè€Œå› ç‚ºè¦è¦–乎 AI 會å¦éµå®ˆè©²æ¨™ç±¤ï¼Œæ‰€ä»¥æ­¤åŠŸèƒ½ç„¡æ³•å®Œå…¨é˜»æ­¢æ‰€æœ‰ AI 使用您的內容。"
options: "é¸é …"
specifyUser: "指定使用者"
+lookupConfirm: "è¦æŸ¥è©¢å—Žï¼Ÿ"
+openTagPageConfirm: "è¦é–‹å•Ÿæ¨™ç±¤çš„é é¢å—Žï¼Ÿ"
+specifyHost: "指定主機"
failedToPreviewUrl: "無法é è¦½"
update: "æ›´æ–°"
rolesThatCanBeUsedThisEmojiAsReaction: "å¯ä»¥ä½¿ç”¨æ­¤è¡¨æƒ…ç¬¦è™Ÿç‚ºåæ‡‰çš„角色"
@@ -1241,12 +1258,17 @@ keepOriginalFilenameDescription: "如果關閉此設置,上傳時檔案å稱æ
noDescription: "沒有說明文字"
alwaysConfirmFollow: "點擊追隨時總是顯示確èªè¨Šæ¯"
inquiry: "è¯çµ¡æˆ‘們"
+tryAgain: "è«‹å†è©¦ä¸€æ¬¡ã€‚"
+confirmWhenRevealingSensitiveMedia: "è¦é¡¯ç¤ºæ•感媒體時需確èª"
+sensitiveMediaRevealConfirm: "é€™æ˜¯æ•æ„Ÿåª’體。確定è¦é¡¯ç¤ºå—Žï¼Ÿ"
+createdLists: "已建立的清單"
+createdAntennas: "已建立的天線"
_delivery:
status: "傳é€ç‹€æ…‹"
- stop: "åœæ­¢å‚³é€"
- resume: "æ¢å¾©å‚³é€"
+ stop: "åœæ­¢ç™¼é€"
+ resume: "æ¢å¾©ç™¼é€"
_type:
- none: "直播中"
+ none: "發é€ä¸­"
manuallySuspended: "手動暫åœä¸­"
goneSuspended: "因為伺æœå™¨åˆªé™¤æ‰€ä»¥æš«åœä¸­"
autoSuspendedForNotResponding: "因為伺æœå™¨æ²’有回應所以暫åœä¸­"
@@ -1376,7 +1398,7 @@ _serverSettings:
fanoutTimelineDbFallback: "資料庫的回退"
fanoutTimelineDbFallbackDescription: "若啟用,在時間軸沒有快å–的情æ³ä¸‹å°‡åŸ·è¡Œå›žé€€è™•ç†ä»¥é¡å¤–查詢資料庫。若åœç”¨ï¼Œå¯ä»¥é€éŽä¸åŸ·è¡Œå›žé€€è™•ç†ä¾†é€²ä¸€æ­¥æ¸›å°‘伺æœå™¨çš„è² è·ï¼Œä½†æœƒé™åˆ¶å¯å–得的時間軸範åœã€‚"
inquiryUrl: "è¯çµ¡è¡¨å–®ç¶²å€"
- inquiryUrlDescription: "指定伺æœå™¨é‹ç‡Ÿè€…çš„è¯çµ¡è¡¨å–®ç¶²å€æˆ–包å«é‹ç‡Ÿè€…è¯çµ¡è³‡è¨Šç¶²é çš„ç¶²å€ã€‚"
+ inquiryUrlDescription: "指定伺æœå™¨é‹ç‡Ÿè€…çš„è¯çµ¡è¡¨å–®ç¶²å€ï¼Œæˆ–包å«é‹ç‡Ÿè€…è¯çµ¡è³‡è¨Šç¶²é çš„ç¶²å€ã€‚"
_accountMigration:
moveFrom: "從其他帳戶é·ç§»åˆ°é€™å€‹å¸³æˆ¶"
moveFromSub: "為å¦ä¸€å€‹å¸³æˆ¶å»ºç«‹åˆ¥å"
@@ -1693,6 +1715,7 @@ _role:
canManageAvatarDecorations: "管ç†é ­åƒè£é£¾"
driveCapacity: "雲端硬碟容é‡"
alwaysMarkNsfw: "總是將檔案標記為NSFW"
+ canUpdateBioMedia: "å…許更新大頭貼和橫幅"
pinMax: "置頂貼文的最大數é‡"
antennaMax: "å¯å»ºç«‹çš„天線數é‡"
wordMuteMax: "éœéŸ³æ–‡å­—的最大字數"
@@ -1936,8 +1959,6 @@ _sfx:
note: "貼文"
noteMy: "我的貼文"
notification: "通知"
- antenna: "天線接收"
- channel: "é »é“通知"
reaction: "鏿“‡å應時"
_soundSettings:
driveFile: "使用雲端硬碟的音效檔案"
@@ -1946,6 +1967,7 @@ _soundSettings:
driveFileTypeWarnDescription: "è«‹é¸æ“‡éŸ³æ•ˆæª”案"
driveFileDurationWarn: "音效太長了"
driveFileDurationWarnDescription: "使用長音效檔å¯èƒ½æœƒå½±éŸ¿ Misskey 的使用體驗。ä»è¦ä½¿ç”¨æ­¤æª”案嗎?"
+ driveFileError: "無法載入語音。請更改設定"
_ago:
future: "未來"
justNow: "剛剛"
@@ -2217,7 +2239,7 @@ _charts:
federation: "è¯é‚¦å®‡å®™"
apRequest: "請求"
usersIncDec: "使用者增減"
- usersTotal: "使用者總數"
+ usersTotal: "使用者åˆè¨ˆ"
activeUsers: "æ´»èºä½¿ç”¨è€…"
notesIncDec: "貼文増減"
localNotesIncDec: "本地貼文増減"
@@ -2401,9 +2423,10 @@ _drivecleaner:
orderByCreatedAtAsc: "按新增日期é™åºæŽ’列"
_webhookSettings:
createWebhook: "建立 Webhook"
+ modifyWebhook: "編輯 Webhook"
name: "åå­—"
secret: "密鑰"
- events: "何時é‹è¡Œ Webhook"
+ trigger: "觸發器"
active: "已啟用"
_events:
follow: "當你追隨時"
@@ -2413,6 +2436,25 @@ _webhookSettings:
renote: "當被轉發時"
reaction: "ç•¶ç²å¾—忇‰æ™‚"
mention: "當被æåˆ°æ™‚"
+ _systemEvents:
+ abuseReport: "當使用者檢舉時"
+ abuseReportResolved: "當處ç†äº†ä½¿ç”¨è€…的檢舉時"
+ deleteConfirm: "è«‹å•æ˜¯å¦è¦åˆªé™¤ Webhook?"
+_abuseReport:
+ _notificationRecipient:
+ createRecipient: "新增接收檢舉的通知å°è±¡"
+ modifyRecipient: "編輯接收檢舉的通知å°è±¡"
+ recipientType: "通知å°è±¡çš„種類"
+ _recipientType:
+ mail: "é›»å­éƒµä»¶"
+ webhook: "Webhook"
+ _captions:
+ mail: "寄é€åˆ°æ“有監察員權é™çš„使用者電å­éƒµä»¶åœ°å€ï¼ˆåƒ…在收到檢舉時)"
+ webhook: "呿Œ‡å®šçš„ SystemWebhook 發é€é€šçŸ¥ï¼ˆåœ¨æ”¶åˆ°æª¢èˆ‰å’Œè§£æ±ºæª¢èˆ‰æ™‚發é€ï¼‰"
+ keywords: "é—œéµå­—"
+ notifiedUser: "被通知的使用者"
+ notifiedWebhook: "使用的 Webhook"
+ deleteConfirm: "確定è¦åˆªé™¤é€šçŸ¥å°è±¡å—Žï¼Ÿ"
_moderationLogTypes:
createRole: "新增角色"
deleteRole: "刪除角色 "
@@ -2450,6 +2492,12 @@ _moderationLogTypes:
deleteAvatarDecoration: "刪除頭åƒè£é£¾"
unsetUserAvatar: "移除使用者的大頭貼"
unsetUserBanner: "移除使用者的橫幅圖åƒ"
+ createSystemWebhook: "建立 SystemWebhook"
+ updateSystemWebhook: "æ›´æ–° SystemWebhook"
+ deleteSystemWebhook: "刪除 SystemWebhook"
+ createAbuseReportNotificationRecipient: "建立接收檢舉的通知å°è±¡"
+ updateAbuseReportNotificationRecipient: "更新接收檢舉的通知å°è±¡"
+ deleteAbuseReportNotificationRecipient: "刪除接收檢舉的通知å°è±¡"
_fileViewer:
title: "檔案詳細資訊"
type: "檔案類型 "
@@ -2581,3 +2629,7 @@ _mediaControls:
pip: "畫中畫"
playbackRate: "播放速度"
loop: "循環播放"
+_contextMenu:
+ title: "內容功能表"
+ app: "應用程å¼"
+ native: "ç€è¦½å™¨çš„使用者介é¢"
diff --git a/misskey-assets b/misskey-assets
deleted file mode 160000
-Subproject 0179793ec891856d6f37a3be16ba4c22f67a81b
diff --git a/package.json b/package.json
index b1786e16f1..4bf7b0a918 100644
--- a/package.json
+++ b/package.json
@@ -1,12 +1,12 @@
{
"name": "misskey",
- "version": "2024.5.0",
+ "version": "2024.7.0",
"codename": "nasubi",
"repository": {
"type": "git",
"url": "https://github.com/misskey-dev/misskey.git"
},
- "packageManager": "pnpm@9.0.6",
+ "packageManager": "pnpm@9.6.0",
"workspaces": [
"packages/frontend",
"packages/backend",
@@ -21,7 +21,7 @@
"build-assets": "node ./scripts/build-assets.mjs",
"build": "pnpm build-pre && pnpm -r build && pnpm build-assets",
"build-storybook": "pnpm --filter frontend build-storybook",
- "build-misskey-js-with-types": "pnpm build-pre && pnpm --filter backend... --filter=!misskey-js build && pnpm --filter backend generate-api-json && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api",
+ "build-misskey-js-with-types": "pnpm build-pre && pnpm --filter backend... --filter=!misskey-js build && pnpm --filter backend generate-api-json --no-build && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api",
"start": "pnpm check:connect && cd packages/backend && node ./built/boot/entry.js",
"start:test": "cd packages/backend && cross-env NODE_ENV=test node ./built/boot/entry.js",
"init": "pnpm migrate",
@@ -51,24 +51,26 @@
"cssnano": "6.1.2",
"execa": "8.0.1",
"fast-glob": "3.3.2",
- "ignore-walk": "6.0.4",
+ "ignore-walk": "6.0.5",
"js-yaml": "4.1.0",
- "postcss": "8.4.38",
+ "postcss": "8.4.40",
"tar": "6.2.1",
- "terser": "5.30.3",
- "typescript": "5.4.5",
- "esbuild": "0.20.2",
- "glob": "10.3.12"
+ "terser": "5.31.3",
+ "typescript": "5.5.4",
+ "esbuild": "0.23.0",
+ "glob": "11.0.0"
},
"devDependencies": {
- "@types/node": "20.12.7",
- "@typescript-eslint/eslint-plugin": "7.7.1",
- "@typescript-eslint/parser": "7.7.1",
+ "@misskey-dev/eslint-plugin": "2.0.2",
+ "@types/node": "20.14.12",
+ "@typescript-eslint/eslint-plugin": "7.17.0",
+ "@typescript-eslint/parser": "7.17.0",
"cross-env": "7.0.3",
- "cypress": "13.7.3",
- "eslint": "8.57.0",
+ "cypress": "13.13.1",
+ "eslint": "9.8.0",
+ "globals": "15.8.0",
"ncp": "2.0.0",
- "start-server-and-test": "2.0.3"
+ "start-server-and-test": "2.0.4"
},
"optionalDependencies": {
"@tensorflow/tfjs-core": "4.4.0"
diff --git a/packages/backend/.eslintignore b/packages/backend/.eslintignore
deleted file mode 100644
index 790eb90145..0000000000
--- a/packages/backend/.eslintignore
+++ /dev/null
@@ -1,4 +0,0 @@
-node_modules
-/built
-/.eslintrc.js
-/@types/**/*
diff --git a/packages/backend/.eslintrc.cjs b/packages/backend/.eslintrc.cjs
deleted file mode 100644
index f9fe4814e6..0000000000
--- a/packages/backend/.eslintrc.cjs
+++ /dev/null
@@ -1,32 +0,0 @@
-module.exports = {
- parserOptions: {
- tsconfigRootDir: __dirname,
- project: ['./tsconfig.json', './test/tsconfig.json'],
- },
- extends: [
- '../shared/.eslintrc.js',
- ],
- rules: {
- 'import/order': ['warn', {
- 'groups': ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],
- 'pathGroups': [
- {
- 'pattern': '@/**',
- 'group': 'external',
- 'position': 'after'
- }
- ],
- }],
- 'no-restricted-globals': [
- 'error',
- {
- 'name': '__dirname',
- 'message': 'Not in ESModule. Use `import.meta.url` instead.'
- },
- {
- 'name': '__filename',
- 'message': 'Not in ESModule. Use `import.meta.url` instead.'
- }
- ]
- },
-};
diff --git a/packages/backend/assets/api-doc.html b/packages/backend/assets/api-doc.html
new file mode 100644
index 0000000000..19e0349d47
--- /dev/null
+++ b/packages/backend/assets/api-doc.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Misskey API</title>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <style>
+ body {
+ margin: 0;
+ padding: 0;
+ }
+ </style>
+ </head>
+ <body>
+ <script
+ id="api-reference"
+ data-url="/api.json"></script>
+ <script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
+ </body>
+</html>
diff --git a/packages/backend/assets/redoc.html b/packages/backend/assets/redoc.html
deleted file mode 100644
index 2557b4532e..0000000000
--- a/packages/backend/assets/redoc.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>Misskey API</title>
- <!-- needed for adaptive design -->
- <meta charset="utf-8"/>
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
-
- <!--
- ReDoc doesn't change outer page styles
- -->
- <style>
- body {
- margin: 0;
- padding: 0;
- }
- </style>
- </head>
- <body>
- <redoc spec-url="/api.json" expand-responses="200" expand-single-schema-field="true"></redoc>
- <script src="https://cdn.redoc.ly/redoc/v2.1.3/bundles/redoc.standalone.js" integrity="sha256-u4DgqzYXoArvNF/Ymw3puKexfOC6lYfw0sfmeliBJ1I=" crossorigin="anonymous"></script>
- </body>
-</html>
diff --git a/packages/backend/eslint.config.js b/packages/backend/eslint.config.js
new file mode 100644
index 0000000000..4fd9f0cd51
--- /dev/null
+++ b/packages/backend/eslint.config.js
@@ -0,0 +1,46 @@
+import tsParser from '@typescript-eslint/parser';
+import sharedConfig from '../shared/eslint.config.js';
+
+export default [
+ ...sharedConfig,
+ {
+ ignores: ['**/node_modules', 'built', '@types/**/*', 'migration'],
+ },
+ {
+ files: ['**/*.ts', '**/*.tsx'],
+ languageOptions: {
+ parserOptions: {
+ parser: tsParser,
+ project: ['./tsconfig.json', './test/tsconfig.json'],
+ sourceType: 'module',
+ tsconfigRootDir: import.meta.dirname,
+ },
+ },
+ rules: {
+ 'import/order': ['warn', {
+ groups: [
+ 'builtin',
+ 'external',
+ 'internal',
+ 'parent',
+ 'sibling',
+ 'index',
+ 'object',
+ 'type',
+ ],
+ pathGroups: [{
+ pattern: '@/**',
+ group: 'external',
+ position: 'after',
+ }],
+ }],
+ 'no-restricted-globals': ['error', {
+ name: '__dirname',
+ message: 'Not in ESModule. Use `import.meta.url` instead.',
+ }, {
+ name: '__filename',
+ message: 'Not in ESModule. Use `import.meta.url` instead.',
+ }],
+ },
+ },
+];
diff --git a/packages/backend/migration/1713656541000-abuse-report-notification.js b/packages/backend/migration/1713656541000-abuse-report-notification.js
new file mode 100644
index 0000000000..4a754f81e2
--- /dev/null
+++ b/packages/backend/migration/1713656541000-abuse-report-notification.js
@@ -0,0 +1,62 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export class AbuseReportNotification1713656541000 {
+ name = 'AbuseReportNotification1713656541000'
+
+ async up(queryRunner) {
+ await queryRunner.query(`
+ CREATE TABLE "system_webhook" (
+ "id" varchar(32) NOT NULL,
+ "isActive" boolean NOT NULL DEFAULT true,
+ "updatedAt" timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "latestSentAt" timestamp with time zone NULL DEFAULT NULL,
+ "latestStatus" integer NULL DEFAULT NULL,
+ "name" varchar(255) NOT NULL,
+ "on" varchar(128) [] NOT NULL DEFAULT '{}'::character varying[],
+ "url" varchar(1024) NOT NULL,
+ "secret" varchar(1024) NOT NULL,
+ CONSTRAINT "PK_system_webhook_id" PRIMARY KEY ("id")
+ );
+ CREATE INDEX "IDX_system_webhook_isActive" ON "system_webhook" ("isActive");
+ CREATE INDEX "IDX_system_webhook_on" ON "system_webhook" USING gin ("on");
+
+ CREATE TABLE "abuse_report_notification_recipient" (
+ "id" varchar(32) NOT NULL,
+ "isActive" boolean NOT NULL DEFAULT true,
+ "updatedAt" timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "name" varchar(255) NOT NULL,
+ "method" varchar(64) NOT NULL,
+ "userId" varchar(32) NULL DEFAULT NULL,
+ "systemWebhookId" varchar(32) NULL DEFAULT NULL,
+ CONSTRAINT "PK_abuse_report_notification_recipient_id" PRIMARY KEY ("id"),
+ CONSTRAINT "FK_abuse_report_notification_recipient_userId1" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION,
+ CONSTRAINT "FK_abuse_report_notification_recipient_userId2" FOREIGN KEY ("userId") REFERENCES "user_profile"("userId") ON DELETE CASCADE ON UPDATE NO ACTION,
+ CONSTRAINT "FK_abuse_report_notification_recipient_systemWebhookId" FOREIGN KEY ("systemWebhookId") REFERENCES "system_webhook"("id") ON DELETE CASCADE ON UPDATE NO ACTION
+ );
+ CREATE INDEX "IDX_abuse_report_notification_recipient_isActive" ON "abuse_report_notification_recipient" ("isActive");
+ CREATE INDEX "IDX_abuse_report_notification_recipient_method" ON "abuse_report_notification_recipient" ("method");
+ CREATE INDEX "IDX_abuse_report_notification_recipient_userId" ON "abuse_report_notification_recipient" ("userId");
+ CREATE INDEX "IDX_abuse_report_notification_recipient_systemWebhookId" ON "abuse_report_notification_recipient" ("systemWebhookId");
+ `);
+ }
+
+ async down(queryRunner) {
+ await queryRunner.query(`
+ ALTER TABLE "abuse_report_notification_recipient" DROP CONSTRAINT "FK_abuse_report_notification_recipient_userId1";
+ ALTER TABLE "abuse_report_notification_recipient" DROP CONSTRAINT "FK_abuse_report_notification_recipient_userId2";
+ ALTER TABLE "abuse_report_notification_recipient" DROP CONSTRAINT "FK_abuse_report_notification_recipient_systemWebhookId";
+ DROP INDEX "IDX_abuse_report_notification_recipient_isActive";
+ DROP INDEX "IDX_abuse_report_notification_recipient_method";
+ DROP INDEX "IDX_abuse_report_notification_recipient_userId";
+ DROP INDEX "IDX_abuse_report_notification_recipient_systemWebhookId";
+ DROP TABLE "abuse_report_notification_recipient";
+
+ DROP INDEX "IDX_system_webhook_isActive";
+ DROP INDEX "IDX_system_webhook_on";
+ DROP TABLE "system_webhook";
+ `);
+ }
+}
diff --git a/packages/backend/migration/1716197366117-MediaSilenceForHosts.js b/packages/backend/migration/1716197366117-MediaSilenceForHosts.js
new file mode 100644
index 0000000000..10bb7f0255
--- /dev/null
+++ b/packages/backend/migration/1716197366117-MediaSilenceForHosts.js
@@ -0,0 +1,16 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export class MediaSilenceForHosts1716197366117 {
+ name = 'MediaSilenceForHosts1716197366117'
+
+ async up(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "meta" ADD "mediaSilencedHosts" character varying(1024) array NOT NULL DEFAULT '{}'`);
+ }
+
+ async down(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "mediaSilencedHosts"`);
+ }
+}
diff --git a/packages/backend/migration/1721666053703-fixDriveUrl.js b/packages/backend/migration/1721666053703-fixDriveUrl.js
new file mode 100644
index 0000000000..d8512fb835
--- /dev/null
+++ b/packages/backend/migration/1721666053703-fixDriveUrl.js
@@ -0,0 +1,24 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export class FixDriveUrl1721666053703 {
+ name = 'FixDriveUrl1721666053703'
+
+ async up(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "url" TYPE character varying(1024), ALTER COLUMN "url" SET NOT NULL`);
+ await queryRunner.query(`COMMENT ON COLUMN "drive_file"."url" IS 'The URL of the DriveFile.'`);
+ await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "uri" TYPE character varying(1024)`);
+ await queryRunner.query(`COMMENT ON COLUMN "drive_file"."uri" IS 'The URI of the DriveFile. it will be null when the DriveFile is local.'`);
+ await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "src" TYPE character varying(1024)`);
+ }
+
+ async down(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "src" TYPE character varying(512)`);
+ await queryRunner.query(`COMMENT ON COLUMN "drive_file"."uri" IS 'The URI of the DriveFile. it will be null when the DriveFile is local.'`);
+ await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "uri" TYPE character varying(512)`);
+ await queryRunner.query(`COMMENT ON COLUMN "drive_file"."url" IS 'The URL of the DriveFile.'`);
+ await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "url" TYPE character varying(512), ALTER COLUMN "url" SET NOT NULL`);
+ }
+}
diff --git a/packages/backend/package.json b/packages/backend/package.json
index e034f75dc5..f497610af9 100644
--- a/packages/backend/package.json
+++ b/packages/backend/package.json
@@ -4,7 +4,7 @@
"private": true,
"type": "module",
"engines": {
- "node": "^20.10.0"
+ "node": "^20.10.0 || ^22.0.0"
},
"scripts": {
"start": "node ./built/boot/entry.js",
@@ -31,7 +31,7 @@
"test:e2e": "pnpm build && pnpm build:test && pnpm jest:e2e",
"test-and-coverage": "pnpm jest-and-coverage",
"test-and-coverage:e2e": "pnpm build && pnpm build:test && pnpm jest-and-coverage:e2e",
- "generate-api-json": "pnpm build && node ./scripts/generate_api_json.js"
+ "generate-api-json": "node ./scripts/generate_api_json.js"
},
"optionalDependencies": {
"@swc/core-android-arm64": "1.3.11",
@@ -65,43 +65,43 @@
"utf-8-validate": "6.0.3"
},
"dependencies": {
- "@aws-sdk/client-s3": "3.412.0",
- "@aws-sdk/lib-storage": "3.412.0",
- "@bull-board/api": "5.17.0",
- "@bull-board/fastify": "5.17.0",
- "@bull-board/ui": "5.17.0",
+ "@aws-sdk/client-s3": "3.620.0",
+ "@aws-sdk/lib-storage": "3.620.0",
+ "@bull-board/api": "5.21.1",
+ "@bull-board/fastify": "5.21.1",
+ "@bull-board/ui": "5.21.1",
"@discordapp/twemoji": "15.0.3",
"@fastify/accepts": "4.3.0",
"@fastify/cookie": "9.3.1",
"@fastify/cors": "9.0.1",
"@fastify/express": "3.0.0",
"@fastify/http-proxy": "9.5.0",
- "@fastify/multipart": "8.2.0",
- "@fastify/static": "7.0.3",
+ "@fastify/multipart": "8.3.0",
+ "@fastify/static": "7.0.4",
"@fastify/view": "9.1.0",
"@misskey-dev/sharp-read-bmp": "1.2.0",
"@misskey-dev/summaly": "5.1.0",
- "@napi-rs/canvas": "^0.1.52",
- "@nestjs/common": "10.3.8",
- "@nestjs/core": "10.3.8",
- "@nestjs/testing": "10.3.8",
+ "@napi-rs/canvas": "^0.1.53",
+ "@nestjs/common": "10.3.10",
+ "@nestjs/core": "10.3.10",
+ "@nestjs/testing": "10.3.10",
"@peertube/http-signature": "1.7.0",
- "@sentry/node": "^8.5.0",
- "@sentry/profiling-node": "^8.5.0",
- "@simplewebauthn/server": "10.0.0",
+ "@sentry/node": "8.20.0",
+ "@sentry/profiling-node": "8.20.0",
+ "@simplewebauthn/server": "10.0.1",
"@sinonjs/fake-timers": "11.2.2",
"@smithy/node-http-handler": "2.5.0",
"@swc/cli": "0.3.12",
- "@swc/core": "1.4.17",
+ "@swc/core": "1.6.6",
"@twemoji/parser": "15.1.1",
"accepts": "1.3.8",
- "ajv": "8.13.0",
+ "ajv": "8.17.1",
"archiver": "7.0.1",
"async-mutex": "0.5.0",
"bcryptjs": "2.4.3",
"blurhash": "2.0.5",
"body-parser": "1.20.2",
- "bullmq": "5.7.8",
+ "bullmq": "5.10.4",
"cacheable-lookup": "7.0.0",
"cbor": "9.0.2",
"chalk": "5.3.0",
@@ -112,27 +112,27 @@
"content-disposition": "0.5.4",
"date-fns": "2.30.0",
"deep-email-validator": "0.1.21",
- "fastify": "4.26.2",
+ "fastify": "4.28.1",
"fastify-raw-body": "4.3.0",
"feed": "4.2.2",
- "file-type": "19.0.0",
- "fluent-ffmpeg": "2.1.2",
+ "file-type": "19.3.0",
+ "fluent-ffmpeg": "2.1.3",
"form-data": "4.0.0",
- "got": "14.2.1",
+ "got": "14.4.2",
"happy-dom": "10.0.3",
"hpagent": "1.2.0",
"htmlescape": "1.1.1",
"http-link-header": "1.1.3",
"ioredis": "5.4.1",
- "ip-cidr": "3.1.0",
+ "ip-cidr": "4.0.1",
"ipaddr.js": "2.2.0",
- "is-svg": "5.0.0",
+ "is-svg": "5.0.1",
"js-yaml": "4.1.0",
- "jsdom": "24.0.0",
+ "jsdom": "24.1.1",
"json5": "2.2.3",
"jsonld": "8.3.2",
"jsrsasign": "11.1.0",
- "meilisearch": "0.38.0",
+ "meilisearch": "0.41.0",
"mfm-js": "0.24.0",
"microformats-parser": "2.0.2",
"mime-types": "2.1.35",
@@ -142,24 +142,24 @@
"nanoid": "5.0.7",
"nested-property": "4.0.0",
"node-fetch": "3.3.2",
- "nodemailer": "6.9.13",
+ "nodemailer": "6.9.14",
"nsfwjs": "2.4.2",
"oauth": "0.10.0",
"oauth2orize": "1.12.0",
"oauth2orize-pkce": "0.1.2",
"os-utils": "0.0.14",
- "otpauth": "9.2.3",
+ "otpauth": "9.3.1",
"parse5": "7.1.2",
- "pg": "8.11.5",
+ "pg": "8.12.0",
"pkce-challenge": "4.1.0",
"probe-image-size": "7.2.3",
"promise-limit": "2.7.0",
- "pug": "3.0.2",
+ "pug": "3.0.3",
"punycode": "2.3.1",
"qrcode": "1.5.3",
"random-seed": "0.3.0",
"ratelimiter": "3.4.1",
- "re2": "1.20.10",
+ "re2": "1.21.3",
"redis-lock": "0.1.4",
"reflect-metadata": "0.2.2",
"rename": "1.0.4",
@@ -167,27 +167,26 @@
"rxjs": "7.8.1",
"sanitize-html": "2.13.0",
"secure-json-parse": "2.7.0",
- "sharp": "0.33.3",
+ "sharp": "0.33.4",
"slacc": "0.0.10",
"strict-event-emitter-types": "2.0.0",
"stringz": "2.1.0",
- "systeminformation": "5.22.7",
+ "systeminformation": "5.22.11",
"tinycolor2": "1.6.0",
"tmp": "0.2.3",
- "tsc-alias": "1.8.8",
+ "tsc-alias": "1.8.10",
"tsconfig-paths": "4.2.0",
"typeorm": "0.3.20",
- "typescript": "5.4.5",
+ "typescript": "5.5.4",
"ulid": "2.3.0",
"vary": "1.1.2",
"web-push": "3.6.7",
- "ws": "8.17.0",
+ "ws": "8.18.0",
"xev": "3.0.2"
},
"devDependencies": {
"@jest/globals": "29.7.0",
- "@misskey-dev/eslint-plugin": "1.0.0",
- "@nestjs/platform-express": "10.3.8",
+ "@nestjs/platform-express": "10.3.10",
"@simplewebauthn/types": "10.0.0",
"@swc/jest": "0.2.36",
"@types/accepts": "1.3.7",
@@ -197,22 +196,21 @@
"@types/color-convert": "2.0.3",
"@types/content-disposition": "0.5.8",
"@types/fluent-ffmpeg": "2.1.24",
- "@types/htmlescape": "^1.1.3",
- "@types/http-link-header": "1.0.5",
+ "@types/htmlescape": "1.1.3",
+ "@types/http-link-header": "1.0.7",
"@types/jest": "29.5.12",
"@types/js-yaml": "4.0.9",
- "@types/jsdom": "21.1.6",
- "@types/jsonld": "1.5.13",
+ "@types/jsdom": "21.1.7",
+ "@types/jsonld": "1.5.15",
"@types/jsrsasign": "10.5.14",
"@types/mime-types": "2.1.4",
"@types/ms": "0.7.34",
- "@types/node": "20.12.7",
- "@types/node-fetch": "3.0.3",
+ "@types/node": "20.14.12",
"@types/nodemailer": "6.4.15",
- "@types/oauth": "0.9.4",
+ "@types/oauth": "0.9.5",
"@types/oauth2orize": "1.11.5",
"@types/oauth2orize-pkce": "0.1.2",
- "@types/pg": "8.11.5",
+ "@types/pg": "8.11.6",
"@types/pug": "2.0.10",
"@types/punycode": "2.1.4",
"@types/qrcode": "1.5.5",
@@ -227,19 +225,18 @@
"@types/tmp": "0.2.6",
"@types/vary": "1.1.3",
"@types/web-push": "3.6.3",
- "@types/ws": "8.5.10",
- "@typescript-eslint/eslint-plugin": "7.7.1",
- "@typescript-eslint/parser": "7.7.1",
- "aws-sdk-client-mock": "3.0.1",
+ "@types/ws": "8.5.11",
+ "@typescript-eslint/eslint-plugin": "7.17.0",
+ "@typescript-eslint/parser": "7.17.0",
+ "aws-sdk-client-mock": "4.0.1",
"cross-env": "7.0.3",
- "eslint": "8.57.0",
"eslint-plugin-import": "2.29.1",
- "execa": "8.0.1",
- "fkill": "^9.0.0",
+ "execa": "9.3.0",
+ "fkill": "9.0.0",
"jest": "29.7.0",
"jest-mock": "29.7.0",
- "nodemon": "3.1.0",
+ "nodemon": "3.1.4",
"pid-port": "1.0.0",
- "simple-oauth2": "5.0.0"
+ "simple-oauth2": "5.1.0"
}
}
diff --git a/packages/backend/scripts/dev.mjs b/packages/backend/scripts/dev.mjs
index 2d0de0f916..a3e0558abd 100644
--- a/packages/backend/scripts/dev.mjs
+++ b/packages/backend/scripts/dev.mjs
@@ -30,6 +30,7 @@ function execStart() {
async function killProc() {
if (backendProcess) {
+ backendProcess.catch(() => {}); // backendProcess.kill()ã«ã‚ˆã£ã¦ç™ºç”Ÿã™ã‚‹ä¾‹å¤–を無視ã™ã‚‹ãŸã‚ã«catch()を呼ã³å‡ºã™
backendProcess.kill();
await new Promise(resolve => backendProcess.on('exit', resolve));
backendProcess = undefined;
@@ -46,6 +47,7 @@ async function killProc() {
],
{
stdio: [process.stdin, process.stdout, process.stderr, 'ipc'],
+ serialization: "json",
})
.on('message', async (message) => {
if (message.type === 'exit') {
diff --git a/packages/backend/scripts/generate_api_json.js b/packages/backend/scripts/generate_api_json.js
index b4769ef801..798e243004 100644
--- a/packages/backend/scripts/generate_api_json.js
+++ b/packages/backend/scripts/generate_api_json.js
@@ -3,11 +3,34 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
-import { loadConfig } from '../built/config.js'
-import { genOpenapiSpec } from '../built/server/api/openapi/gen-spec.js'
-import { writeFileSync } from "node:fs";
+import { execa } from 'execa';
+import { writeFileSync, existsSync } from "node:fs";
-const config = loadConfig();
-const spec = genOpenapiSpec(config, true);
+async function main() {
+ if (!process.argv.includes('--no-build')) {
+ await execa('pnpm', ['run', 'build'], {
+ stdout: process.stdout,
+ stderr: process.stderr,
+ });
+ }
-writeFileSync('./built/api.json', JSON.stringify(spec), 'utf-8');
+ if (!existsSync('./built')) {
+ throw new Error('`built` directory does not exist.');
+ }
+
+ /** @type {import('../src/config.js')} */
+ const { loadConfig } = await import('../built/config.js');
+
+ /** @type {import('../src/server/api/openapi/gen-spec.js')} */
+ const { genOpenapiSpec } = await import('../built/server/api/openapi/gen-spec.js');
+
+ const config = loadConfig();
+ const spec = genOpenapiSpec(config, true);
+
+ writeFileSync('./built/api.json', JSON.stringify(spec), 'utf-8');
+}
+
+main().catch(e => {
+ console.error(e);
+ process.exit(1);
+});
diff --git a/packages/backend/src/NestLogger.ts b/packages/backend/src/NestLogger.ts
index 80f1f7a024..d0be19664f 100644
--- a/packages/backend/src/NestLogger.ts
+++ b/packages/backend/src/NestLogger.ts
@@ -7,7 +7,7 @@ import { LoggerService } from '@nestjs/common';
import Logger from '@/logger.js';
const logger = new Logger('core', 'cyan');
-const nestLogger = logger.createSubLogger('nest', 'green', false);
+const nestLogger = logger.createSubLogger('nest', 'green');
export class NestLogger implements LoggerService {
/**
diff --git a/packages/backend/src/boot/entry.ts b/packages/backend/src/boot/entry.ts
index 04c6ca9723..25375c3015 100644
--- a/packages/backend/src/boot/entry.ts
+++ b/packages/backend/src/boot/entry.ts
@@ -25,7 +25,7 @@ Error.stackTraceLimit = Infinity;
EventEmitter.defaultMaxListeners = 128;
const logger = new Logger('core', 'cyan');
-const clusterLogger = logger.createSubLogger('cluster', 'orange', false);
+const clusterLogger = logger.createSubLogger('cluster', 'orange');
const ev = new Xev();
//#region Events
diff --git a/packages/backend/src/boot/master.ts b/packages/backend/src/boot/master.ts
index 75e1a80cd1..4bc5c799cf 100644
--- a/packages/backend/src/boot/master.ts
+++ b/packages/backend/src/boot/master.ts
@@ -25,7 +25,7 @@ const _dirname = dirname(_filename);
const meta = JSON.parse(fs.readFileSync(`${_dirname}/../../../../built/meta.json`, 'utf-8'));
const logger = new Logger('core', 'cyan');
-const bootLogger = logger.createSubLogger('boot', 'magenta', false);
+const bootLogger = logger.createSubLogger('boot', 'magenta');
const themeColor = chalk.hex('#86b300');
diff --git a/packages/backend/src/boot/worker.ts b/packages/backend/src/boot/worker.ts
index d4a7cd56e5..5d4a15b29f 100644
--- a/packages/backend/src/boot/worker.ts
+++ b/packages/backend/src/boot/worker.ts
@@ -4,13 +4,36 @@
*/
import cluster from 'node:cluster';
+import * as Sentry from '@sentry/node';
+import { nodeProfilingIntegration } from '@sentry/profiling-node';
import { envOption } from '@/env.js';
+import { loadConfig } from '@/config.js';
import { jobQueue, server } from './common.js';
/**
* Init worker process
*/
export async function workerMain() {
+ const config = loadConfig();
+
+ if (config.sentryForBackend) {
+ Sentry.init({
+ integrations: [
+ ...(config.sentryForBackend.enableNodeProfiling ? [nodeProfilingIntegration()] : []),
+ ],
+
+ // Performance Monitoring
+ tracesSampleRate: 1.0, // Capture 100% of the transactions
+
+ // Set sampling rate for profiling - this is relative to tracesSampleRate
+ profilesSampleRate: 1.0,
+
+ maxBreadcrumbs: 0,
+
+ ...config.sentryForBackend.options,
+ });
+ }
+
if (envOption.onlyServer) {
await server();
} else if (envOption.onlyQueue) {
diff --git a/packages/backend/src/config.ts b/packages/backend/src/config.ts
index 0ac521d409..3e5a1e81cd 100644
--- a/packages/backend/src/config.ts
+++ b/packages/backend/src/config.ts
@@ -23,7 +23,7 @@ type RedisOptionsSource = Partial<RedisOptions> & {
* 設定ファイルã®åž‹
*/
type Source = {
- url: string;
+ url?: string;
port?: number;
socket?: string;
chmodSocket?: string;
@@ -31,9 +31,9 @@ type Source = {
db: {
host: string;
port: number;
- db: string;
- user: string;
- pass: string;
+ db?: string;
+ user?: string;
+ pass?: string;
disableCache?: boolean;
extra?: { [x: string]: string };
};
@@ -202,13 +202,17 @@ export function loadConfig(): Config {
: { 'src/_boot_.ts': { file: 'src/_boot_.ts' } };
const config = yaml.load(fs.readFileSync(path, 'utf-8')) as Source;
- const url = tryCreateUrl(config.url);
+ const url = tryCreateUrl(config.url ?? process.env.MISSKEY_URL ?? '');
const version = meta.version;
const host = url.host;
const hostname = url.hostname;
const scheme = url.protocol.replace(/:$/, '');
const wsScheme = scheme.replace('http', 'ws');
+ const dbDb = config.db.db ?? process.env.DATABASE_DB ?? '';
+ const dbUser = config.db.user ?? process.env.DATABASE_USER ?? '';
+ const dbPass = config.db.pass ?? process.env.DATABASE_PASSWORD ?? '';
+
const externalMediaProxy = config.mediaProxy ?
config.mediaProxy.endsWith('/') ? config.mediaProxy.substring(0, config.mediaProxy.length - 1) : config.mediaProxy
: null;
@@ -231,7 +235,7 @@ export function loadConfig(): Config {
apiUrl: `${scheme}://${host}/api`,
authUrl: `${scheme}://${host}/auth`,
driveUrl: `${scheme}://${host}/files`,
- db: config.db,
+ db: { ...config.db, db: dbDb, user: dbUser, pass: dbPass },
dbReplications: config.dbReplications,
dbSlaves: config.dbSlaves,
meilisearch: config.meilisearch,
@@ -259,7 +263,7 @@ export function loadConfig(): Config {
deliverJobMaxAttempts: config.deliverJobMaxAttempts,
inboxJobMaxAttempts: config.inboxJobMaxAttempts,
proxyRemoteFiles: config.proxyRemoteFiles,
- signToActivityPubGet: config.signToActivityPubGet,
+ signToActivityPubGet: config.signToActivityPubGet ?? true,
mediaProxy: externalMediaProxy ?? internalMediaProxy,
externalMediaProxyEnabled: externalMediaProxy !== null && externalMediaProxy !== internalMediaProxy,
videoThumbnailGenerator: config.videoThumbnailGenerator ?
diff --git a/packages/backend/src/core/AbuseReportNotificationService.ts b/packages/backend/src/core/AbuseReportNotificationService.ts
new file mode 100644
index 0000000000..7be5335885
--- /dev/null
+++ b/packages/backend/src/core/AbuseReportNotificationService.ts
@@ -0,0 +1,405 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Inject, Injectable, type OnApplicationShutdown } from '@nestjs/common';
+import { Brackets, In, IsNull, Not } from 'typeorm';
+import * as Redis from 'ioredis';
+import sanitizeHtml from 'sanitize-html';
+import { DI } from '@/di-symbols.js';
+import { bindThis } from '@/decorators.js';
+import { GlobalEvents, GlobalEventService } from '@/core/GlobalEventService.js';
+import type {
+ AbuseReportNotificationRecipientRepository,
+ MiAbuseReportNotificationRecipient,
+ MiAbuseUserReport,
+ MiUser,
+} from '@/models/_.js';
+import { EmailService } from '@/core/EmailService.js';
+import { MetaService } from '@/core/MetaService.js';
+import { RoleService } from '@/core/RoleService.js';
+import { RecipientMethod } from '@/models/AbuseReportNotificationRecipient.js';
+import { ModerationLogService } from '@/core/ModerationLogService.js';
+import { SystemWebhookService } from '@/core/SystemWebhookService.js';
+import { IdService } from './IdService.js';
+
+@Injectable()
+export class AbuseReportNotificationService implements OnApplicationShutdown {
+ constructor(
+ @Inject(DI.abuseReportNotificationRecipientRepository)
+ private abuseReportNotificationRecipientRepository: AbuseReportNotificationRecipientRepository,
+ @Inject(DI.redisForSub)
+ private redisForSub: Redis.Redis,
+ private idService: IdService,
+ private roleService: RoleService,
+ private systemWebhookService: SystemWebhookService,
+ private emailService: EmailService,
+ private metaService: MetaService,
+ private moderationLogService: ModerationLogService,
+ private globalEventService: GlobalEventService,
+ ) {
+ this.redisForSub.on('message', this.onMessage);
+ }
+
+ /**
+ * 管ç†è€…用Redisイベントを用ã„ã¦{@link abuseReports}ã®å†…容を管ç†è€…å„ä½ã«é€šçŸ¥ã™ã‚‹.
+ * 通知先ユーザã¯{@link getModeratorIds}ã®å–å¾—çµæžœã«ä¾ã‚‹.
+ *
+ * @see RoleService.getModeratorIds
+ * @see GlobalEventService.publishAdminStream
+ */
+ @bindThis
+ public async notifyAdminStream(abuseReports: MiAbuseUserReport[]) {
+ if (abuseReports.length <= 0) {
+ return;
+ }
+
+ const moderatorIds = await this.roleService.getModeratorIds(true, true);
+
+ for (const moderatorId of moderatorIds) {
+ for (const abuseReport of abuseReports) {
+ this.globalEventService.publishAdminStream(
+ moderatorId,
+ 'newAbuseUserReport',
+ {
+ id: abuseReport.id,
+ targetUserId: abuseReport.targetUserId,
+ reporterId: abuseReport.reporterId,
+ comment: abuseReport.comment,
+ },
+ );
+ }
+ }
+ }
+
+ /**
+ * Mailを用ã„ã¦{@link abuseReports}ã®å†…容を管ç†è€…å„ä½ã«é€šçŸ¥ã™ã‚‹.
+ * メールアドレスã®é€ä¿¡å…ˆã¯ä»¥ä¸‹ã®é€šã‚Š.
+ * - ãƒ¢ãƒ‡ãƒ¬ãƒ¼ã‚¿æ¨©é™æ‰€æœ‰è€…ユーザ(設定画é¢ã‹ã‚‰ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã®è¨­å®šã‚’行ã£ã¦ã„るユーザã«é™ã‚‹)
+ * - metaテーブルã«è¨­å®šã•れã¦ã„るメールアドレス
+ *
+ * @see EmailService.sendEmail
+ */
+ @bindThis
+ public async notifyMail(abuseReports: MiAbuseUserReport[]) {
+ if (abuseReports.length <= 0) {
+ return;
+ }
+
+ const recipientEMailAddresses = await this.fetchEMailRecipients().then(it => it
+ .filter(it => it.isActive && it.userProfile?.emailVerified)
+ .map(it => it.userProfile?.email)
+ .filter(x => x != null),
+ );
+
+ // é€ä¿¡å…ˆã®é®®åº¦ã‚’ä¿ã¤ãŸã‚ã€æ¯Žå›žå–å¾—ã™ã‚‹
+ const meta = await this.metaService.fetch(true);
+ recipientEMailAddresses.push(
+ ...(meta.email ? [meta.email] : []),
+ );
+
+ if (recipientEMailAddresses.length <= 0) {
+ return;
+ }
+
+ for (const mailAddress of recipientEMailAddresses) {
+ await Promise.all(
+ abuseReports.map(it => {
+ // TODO: é€ä¿¡å‡¦ç†ã¯JobQueue化ã—ãŸã„
+ return this.emailService.sendEmail(
+ mailAddress,
+ 'New Abuse Report',
+ sanitizeHtml(it.comment),
+ sanitizeHtml(it.comment),
+ );
+ }),
+ );
+ }
+ }
+
+ /**
+ * SystemWebhookを用ã„ã¦{@link abuseReports}ã®å†…容を管ç†è€…å„ä½ã«é€šçŸ¥ã™ã‚‹.
+ * ã“ã“ã§ã¯JobQueueã¸ã®ã‚¨ãƒ³ã‚­ãƒ¥ãƒ¼ã®ã¿ã‚’行ã†ãŸã‚ã€å³æ™‚実行ã•れãªã„.
+ *
+ * @see SystemWebhookService.enqueueSystemWebhook
+ */
+ @bindThis
+ public async notifySystemWebhook(
+ abuseReports: MiAbuseUserReport[],
+ type: 'abuseReport' | 'abuseReportResolved',
+ ) {
+ if (abuseReports.length <= 0) {
+ return;
+ }
+
+ const recipientWebhookIds = await this.fetchWebhookRecipients()
+ .then(it => it
+ .filter(it => it.isActive && it.systemWebhookId && it.method === 'webhook')
+ .map(it => it.systemWebhookId)
+ .filter(x => x != null));
+ for (const webhookId of recipientWebhookIds) {
+ await Promise.all(
+ abuseReports.map(it => {
+ return this.systemWebhookService.enqueueSystemWebhook(
+ webhookId,
+ type,
+ it,
+ );
+ }),
+ );
+ }
+ }
+
+ /**
+ * 通報ã®é€šçŸ¥å…ˆä¸€è¦§ã‚’å–å¾—ã™ã‚‹.
+ *
+ * @param {Object} [params] クエリã®å–å¾—æ¡ä»¶
+ * @param {Object} [params.method] å–å¾—ã™ã‚‹é€šçŸ¥å…ˆã®é€šçŸ¥æ–¹æ³•
+ * @param {Object} [opts] 動作時ã®è©³ç´°ãªã‚ªãƒ—ション
+ * @param {boolean} [opts.removeUnauthorized] 副作用ã¨ã—ã¦ãƒ¢ãƒ‡ãƒ¬ãƒ¼ã‚¿æ¨©é™ã‚’æŒãŸãªã„é€ä¿¡å…ˆãƒ¦ãƒ¼ã‚¶ã‚’DBã‹ã‚‰å‰Šé™¤ã™ã‚‹ã‹ã©ã†ã‹(default: true)
+ * @param {boolean} [opts.joinUser] 通知先ã®ãƒ¦ãƒ¼ã‚¶æƒ…報をJOINã™ã‚‹ã‹ã©ã†ã‹(default: false)
+ * @param {boolean} [opts.joinSystemWebhook] 通知先ã®SystemWebhook情報をJOINã™ã‚‹ã‹ã©ã†ã‹(default: false)
+ * @see removeUnauthorizedRecipientUsers
+ */
+ @bindThis
+ public async fetchRecipients(
+ params?: {
+ ids?: MiAbuseReportNotificationRecipient['id'][],
+ method?: RecipientMethod[],
+ },
+ opts?: {
+ removeUnauthorized?: boolean,
+ joinUser?: boolean,
+ joinSystemWebhook?: boolean,
+ },
+ ): Promise<MiAbuseReportNotificationRecipient[]> {
+ const query = this.abuseReportNotificationRecipientRepository.createQueryBuilder('recipient');
+
+ if (opts?.joinUser) {
+ query.innerJoinAndSelect('user', 'user', 'recipient.userId = user.id');
+ query.innerJoinAndSelect('recipient.userProfile', 'userProfile');
+ }
+
+ if (opts?.joinSystemWebhook) {
+ query.innerJoinAndSelect('recipient.systemWebhook', 'systemWebhook');
+ }
+
+ if (params?.ids) {
+ query.andWhere({ id: In(params.ids) });
+ }
+
+ if (params?.method) {
+ query.andWhere(new Brackets(qb => {
+ if (params.method?.includes('email')) {
+ qb.orWhere({ method: 'email', userId: Not(IsNull()) });
+ }
+ if (params.method?.includes('webhook')) {
+ qb.orWhere({ method: 'webhook', userId: IsNull() });
+ }
+ }));
+ }
+
+ const recipients = await query.getMany();
+ if (recipients.length <= 0) {
+ return [];
+ }
+
+ // アサイン有効期é™åˆ‡ã‚Œã¯ã‚¤ãƒ™ãƒ³ãƒˆã§æ‹¾ãˆãªã„ã®ã§ã€ã“ã®ã‚¿ã‚¤ãƒŸãƒ³ã‚°ã§ãƒã‚§ãƒƒã‚¯åŠã³å‰Šé™¤ï¼ˆã‚ªãƒ—ション)
+ return (opts?.removeUnauthorized ?? true)
+ ? await this.removeUnauthorizedRecipientUsers(recipients)
+ : recipients;
+ }
+
+ /**
+ * EMailã®é€šçŸ¥å…ˆä¸€è¦§ã‚’å–å¾—ã™ã‚‹.
+ * リレーション先ã®{@link MiUser}ãŠã‚ˆã³{@link MiUserProfile}ã‚‚åŒæ™‚ã«å–å¾—ã™ã‚‹.
+ *
+ * @param {Object} [opts]
+ * @param {boolean} [opts.removeUnauthorized] 副作用ã¨ã—ã¦ãƒ¢ãƒ‡ãƒ¬ãƒ¼ã‚¿æ¨©é™ã‚’æŒãŸãªã„é€ä¿¡å…ˆãƒ¦ãƒ¼ã‚¶ã‚’DBã‹ã‚‰å‰Šé™¤ã™ã‚‹ã‹ã©ã†ã‹(default: true)
+ * @see removeUnauthorizedRecipientUsers
+ */
+ @bindThis
+ public async fetchEMailRecipients(opts?: {
+ removeUnauthorized?: boolean
+ }): Promise<MiAbuseReportNotificationRecipient[]> {
+ return this.fetchRecipients({ method: ['email'] }, { joinUser: true, ...opts });
+ }
+
+ /**
+ * Webhookã®é€šçŸ¥å…ˆä¸€è¦§ã‚’å–å¾—ã™ã‚‹.
+ * リレーション先ã®{@link MiSystemWebhook}ã‚‚åŒæ™‚ã«å–å¾—ã™ã‚‹.
+ */
+ @bindThis
+ public fetchWebhookRecipients(): Promise<MiAbuseReportNotificationRecipient[]> {
+ return this.fetchRecipients({ method: ['webhook'] }, { joinSystemWebhook: true });
+ }
+
+ /**
+ * 通知先を作æˆã™ã‚‹.
+ */
+ @bindThis
+ public async createRecipient(
+ params: {
+ isActive: MiAbuseReportNotificationRecipient['isActive'];
+ name: MiAbuseReportNotificationRecipient['name'];
+ method: MiAbuseReportNotificationRecipient['method'];
+ userId: MiAbuseReportNotificationRecipient['userId'];
+ systemWebhookId: MiAbuseReportNotificationRecipient['systemWebhookId'];
+ },
+ updater: MiUser,
+ ): Promise<MiAbuseReportNotificationRecipient> {
+ const id = this.idService.gen();
+ await this.abuseReportNotificationRecipientRepository.insert({
+ ...params,
+ id,
+ });
+
+ const created = await this.abuseReportNotificationRecipientRepository.findOneByOrFail({ id: id });
+
+ this.moderationLogService
+ .log(updater, 'createAbuseReportNotificationRecipient', {
+ recipientId: id,
+ recipient: created,
+ })
+ .then();
+
+ return created;
+ }
+
+ /**
+ * 通知先を更新ã™ã‚‹.
+ */
+ @bindThis
+ public async updateRecipient(
+ params: {
+ id: MiAbuseReportNotificationRecipient['id'];
+ isActive: MiAbuseReportNotificationRecipient['isActive'];
+ name: MiAbuseReportNotificationRecipient['name'];
+ method: MiAbuseReportNotificationRecipient['method'];
+ userId: MiAbuseReportNotificationRecipient['userId'];
+ systemWebhookId: MiAbuseReportNotificationRecipient['systemWebhookId'];
+ },
+ updater: MiUser,
+ ): Promise<MiAbuseReportNotificationRecipient> {
+ const beforeEntity = await this.abuseReportNotificationRecipientRepository.findOneByOrFail({ id: params.id });
+
+ await this.abuseReportNotificationRecipientRepository.update(params.id, {
+ isActive: params.isActive,
+ updatedAt: new Date(),
+ name: params.name,
+ method: params.method,
+ userId: params.userId,
+ systemWebhookId: params.systemWebhookId,
+ });
+
+ const afterEntity = await this.abuseReportNotificationRecipientRepository.findOneByOrFail({ id: params.id });
+
+ this.moderationLogService
+ .log(updater, 'updateAbuseReportNotificationRecipient', {
+ recipientId: params.id,
+ before: beforeEntity,
+ after: afterEntity,
+ })
+ .then();
+
+ return afterEntity;
+ }
+
+ /**
+ * 通知先を削除ã™ã‚‹.
+ */
+ @bindThis
+ public async deleteRecipient(
+ id: MiAbuseReportNotificationRecipient['id'],
+ updater: MiUser,
+ ) {
+ const entity = await this.abuseReportNotificationRecipientRepository.findBy({ id });
+
+ await this.abuseReportNotificationRecipientRepository.delete(id);
+
+ this.moderationLogService
+ .log(updater, 'deleteAbuseReportNotificationRecipient', {
+ recipientId: id,
+ recipient: entity,
+ })
+ .then();
+ }
+
+ /**
+ * モデレータ権é™ã‚’æŒãŸãªã„(*1)通知先ユーザを削除ã™ã‚‹.
+ *
+ * *1: 以下ã®ä¸¡æ–¹ã‚’満ãŸã™ã‚‚ã®ã®äº‹ã‚’言ã†
+ * - 通知先ã«ãƒ¦ãƒ¼ã‚¶IDãŒè¨­å®šã•れã¦ã„ã‚‹
+ * - 付与ロールã«ãƒ¢ãƒ‡ãƒ¬ãƒ¼ã‚¿æ¨©é™ãŒãªã„ or ã‚¢ã‚µã‚¤ãƒ³ã®æœ‰åŠ¹æœŸé™ãŒåˆ‡ã‚Œã¦ã„ã‚‹
+ *
+ * @param recipients 通知先一覧ã®é…列
+ * @returns {@lisk recipients}ã‹ã‚‰ãƒ¢ãƒ‡ãƒ¬ãƒ¼ã‚¿æ¨©é™ã‚’æŒãŸãªã„通知先を削除ã—ãŸé…列
+ */
+ @bindThis
+ private async removeUnauthorizedRecipientUsers(recipients: MiAbuseReportNotificationRecipient[]): Promise<MiAbuseReportNotificationRecipient[]> {
+ const userRecipients = recipients.filter(it => it.userId !== null);
+ const recipientUserIds = new Set(userRecipients.map(it => it.userId).filter(x => x != null));
+ if (recipientUserIds.size <= 0) {
+ // ユーザãŒé€šçŸ¥å…ˆã¨ã—ã¦è¨­å®šã•れã¦ã„ãªã„å ´åˆã€ã“ã®é–¢æ•°ã§ã®å‡¦ç†ã‚’行ã†ã¹ãレコードãŒç„¡ã„
+ return recipients;
+ }
+
+ // モデレータ権é™ã®æœ‰ç„¡ã§é€šçŸ¥å…ˆè¨­å®šã‚’振り分ã‘ã‚‹
+ const authorizedUserIds = await this.roleService.getModeratorIds(true, true);
+ const authorizedUserRecipients = Array.of<MiAbuseReportNotificationRecipient>();
+ const unauthorizedUserRecipients = Array.of<MiAbuseReportNotificationRecipient>();
+ for (const recipient of userRecipients) {
+ // eslint-disable-next-line
+ if (authorizedUserIds.includes(recipient.userId!)) {
+ authorizedUserRecipients.push(recipient);
+ } else {
+ unauthorizedUserRecipients.push(recipient);
+ }
+ }
+
+ // モデレータ権é™ã‚’æŒãŸãªã„通知先をDBã‹ã‚‰å‰Šé™¤ã™ã‚‹
+ if (unauthorizedUserRecipients.length > 0) {
+ await this.abuseReportNotificationRecipientRepository.delete(unauthorizedUserRecipients.map(it => it.id));
+ }
+ const nonUserRecipients = recipients.filter(it => it.userId === null);
+ return [...nonUserRecipients, ...authorizedUserRecipients].sort((a, b) => a.id.localeCompare(b.id));
+ }
+
+ @bindThis
+ private async onMessage(_: string, data: string): Promise<void> {
+ const obj = JSON.parse(data);
+ if (obj.channel !== 'internal') {
+ return;
+ }
+
+ const { type } = obj.message as GlobalEvents['internal']['payload'];
+ switch (type) {
+ case 'roleUpdated':
+ case 'roleDeleted':
+ case 'userRoleUnassigned': {
+ // å ´åˆã«ã‚ˆã£ã¦ã¯ã‚­ãƒ£ãƒƒã‚·ãƒ¥æ›´æ–°ã‚ˆã‚Šã‚‚å…ˆã«ã“ã“ãŒå‘¼ã°ã‚Œã¦ã—ã¾ã†å¯èƒ½æ€§ãŒã‚ã‚‹ã®ã§nextTickã§é…延実行
+ process.nextTick(async () => {
+ const recipients = await this.abuseReportNotificationRecipientRepository.findBy({
+ userId: Not(IsNull()),
+ });
+ await this.removeUnauthorizedRecipientUsers(recipients);
+ });
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+
+ @bindThis
+ public dispose(): void {
+ this.redisForSub.off('message', this.onMessage);
+ }
+
+ @bindThis
+ public onApplicationShutdown(signal?: string | undefined): void {
+ this.dispose();
+ }
+}
diff --git a/packages/backend/src/core/AbuseReportService.ts b/packages/backend/src/core/AbuseReportService.ts
new file mode 100644
index 0000000000..69c51509ba
--- /dev/null
+++ b/packages/backend/src/core/AbuseReportService.ts
@@ -0,0 +1,128 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Inject, Injectable } from '@nestjs/common';
+import { In } from 'typeorm';
+import { DI } from '@/di-symbols.js';
+import { bindThis } from '@/decorators.js';
+import type { AbuseUserReportsRepository, MiAbuseUserReport, MiUser, UsersRepository } from '@/models/_.js';
+import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js';
+import { QueueService } from '@/core/QueueService.js';
+import { InstanceActorService } from '@/core/InstanceActorService.js';
+import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
+import { ModerationLogService } from '@/core/ModerationLogService.js';
+import { IdService } from './IdService.js';
+
+@Injectable()
+export class AbuseReportService {
+ constructor(
+ @Inject(DI.abuseUserReportsRepository)
+ private abuseUserReportsRepository: AbuseUserReportsRepository,
+ @Inject(DI.usersRepository)
+ private usersRepository: UsersRepository,
+ private idService: IdService,
+ private abuseReportNotificationService: AbuseReportNotificationService,
+ private queueService: QueueService,
+ private instanceActorService: InstanceActorService,
+ private apRendererService: ApRendererService,
+ private moderationLogService: ModerationLogService,
+ ) {
+ }
+
+ /**
+ * ユーザã‹ã‚‰ã®é€šå ±ã‚’DBã«è¨˜éŒ²ã—ã€ãã®å†…å®¹ã‚’ä¸‹è¨˜ã®æ‰‹æ®µã§ç®¡ç†è€…å„ä½ã«é€šçŸ¥ã™ã‚‹.
+ * - 管ç†è€…用Redisイベント
+ * - EMailï¼ˆãƒ¢ãƒ‡ãƒ¬ãƒ¼ã‚¿æ¨©é™æ‰€æœ‰è€…ユーザ+metaテーブルã«è¨­å®šã•れã¦ã„るメールアドレス)
+ * - SystemWebhook
+ *
+ * @param params 通報内容. ã‚‚ã—複数件ã®é€šå ±ã«å¯¾å¿œã—ãŸæ™‚ã®ãŸã‚ã«ã€ã‚らã‹ã˜ã‚複数件を処ç†ã§ãã‚‹å‰æã§è€ƒãˆã‚‹
+ * @see AbuseReportNotificationService.notify
+ */
+ @bindThis
+ public async report(params: {
+ targetUserId: MiAbuseUserReport['targetUserId'],
+ targetUserHost: MiAbuseUserReport['targetUserHost'],
+ reporterId: MiAbuseUserReport['reporterId'],
+ reporterHost: MiAbuseUserReport['reporterHost'],
+ comment: string,
+ }[]) {
+ const entities = params.map(param => {
+ return {
+ id: this.idService.gen(),
+ targetUserId: param.targetUserId,
+ targetUserHost: param.targetUserHost,
+ reporterId: param.reporterId,
+ reporterHost: param.reporterHost,
+ comment: param.comment,
+ };
+ });
+
+ const reports = Array.of<MiAbuseUserReport>();
+ for (const entity of entities) {
+ const report = await this.abuseUserReportsRepository.insertOne(entity);
+ reports.push(report);
+ }
+
+ return Promise.all([
+ this.abuseReportNotificationService.notifyAdminStream(reports),
+ this.abuseReportNotificationService.notifySystemWebhook(reports, 'abuseReport'),
+ this.abuseReportNotificationService.notifyMail(reports),
+ ]);
+ }
+
+ /**
+ * 通報を解決ã—ã€ãã®å†…å®¹ã‚’ä¸‹è¨˜ã®æ‰‹æ®µã§ç®¡ç†è€…å„ä½ã«é€šçŸ¥ã™ã‚‹.
+ * - SystemWebhook
+ *
+ * @param params 通報内容. ã‚‚ã—複数件ã®é€šå ±ã«å¯¾å¿œã—ãŸæ™‚ã®ãŸã‚ã«ã€ã‚らã‹ã˜ã‚複数件を処ç†ã§ãã‚‹å‰æã§è€ƒãˆã‚‹
+ * @param operator 通報を処ç†ã—ãŸãƒ¦ãƒ¼ã‚¶
+ * @see AbuseReportNotificationService.notify
+ */
+ @bindThis
+ public async resolve(
+ params: {
+ reportId: string;
+ forward: boolean;
+ }[],
+ operator: MiUser,
+ ) {
+ const paramsMap = new Map(params.map(it => [it.reportId, it]));
+ const reports = await this.abuseUserReportsRepository.findBy({
+ id: In(params.map(it => it.reportId)),
+ });
+
+ for (const report of reports) {
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ const ps = paramsMap.get(report.id)!;
+
+ await this.abuseUserReportsRepository.update(report.id, {
+ resolved: true,
+ assigneeId: operator.id,
+ forwarded: ps.forward && report.targetUserHost !== null,
+ });
+
+ if (ps.forward && report.targetUserHost != null) {
+ const actor = await this.instanceActorService.getInstanceActor();
+ const targetUser = await this.usersRepository.findOneByOrFail({ id: report.targetUserId });
+
+ // eslint-disable-next-line
+ const flag = this.apRendererService.renderFlag(actor, targetUser.uri!, report.comment);
+ const contextAssignedFlag = this.apRendererService.addContext(flag);
+ this.queueService.deliver(actor, contextAssignedFlag, targetUser.inbox, false);
+ }
+
+ this.moderationLogService
+ .log(operator, 'resolveAbuseReport', {
+ reportId: report.id,
+ report: report,
+ forwarded: ps.forward && report.targetUserHost !== null,
+ })
+ .then();
+ }
+
+ return this.abuseUserReportsRepository.findBy({ id: In(reports.map(it => it.id)) })
+ .then(reports => this.abuseReportNotificationService.notifySystemWebhook(reports, 'abuseReportResolved'));
+ }
+}
diff --git a/packages/backend/src/core/ClipService.ts b/packages/backend/src/core/ClipService.ts
index 9fd1ebad87..929a9db064 100644
--- a/packages/backend/src/core/ClipService.ts
+++ b/packages/backend/src/core/ClipService.ts
@@ -41,7 +41,7 @@ export class ClipService {
const currentCount = await this.clipsRepository.countBy({
userId: me.id,
});
- if (currentCount > (await this.roleService.getUserPolicies(me.id)).clipLimit) {
+ if (currentCount >= (await this.roleService.getUserPolicies(me.id)).clipLimit) {
throw new ClipService.TooManyClipsError();
}
@@ -102,7 +102,7 @@ export class ClipService {
const currentCount = await this.clipNotesRepository.countBy({
clipId: clip.id,
});
- if (currentCount > (await this.roleService.getUserPolicies(me.id)).noteEachClipsLimit) {
+ if (currentCount >= (await this.roleService.getUserPolicies(me.id)).noteEachClipsLimit) {
throw new ClipService.TooManyClipNotesError();
}
diff --git a/packages/backend/src/core/CoreModule.ts b/packages/backend/src/core/CoreModule.ts
index be80df6f1c..c9427bbeb7 100644
--- a/packages/backend/src/core/CoreModule.ts
+++ b/packages/backend/src/core/CoreModule.ts
@@ -5,6 +5,14 @@
import { Module } from '@nestjs/common';
import { FanoutTimelineEndpointService } from '@/core/FanoutTimelineEndpointService.js';
+import { AbuseReportService } from '@/core/AbuseReportService.js';
+import { SystemWebhookEntityService } from '@/core/entities/SystemWebhookEntityService.js';
+import {
+ AbuseReportNotificationRecipientEntityService,
+} from '@/core/entities/AbuseReportNotificationRecipientEntityService.js';
+import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js';
+import { SystemWebhookService } from '@/core/SystemWebhookService.js';
+import { UserSearchService } from '@/core/UserSearchService.js';
import { AccountMoveService } from './AccountMoveService.js';
import { AccountUpdateService } from './AccountUpdateService.js';
import { AiService } from './AiService.js';
@@ -53,10 +61,11 @@ import { UserFollowingService } from './UserFollowingService.js';
import { UserKeypairService } from './UserKeypairService.js';
import { UserListService } from './UserListService.js';
import { UserMutingService } from './UserMutingService.js';
+import { UserRenoteMutingService } from './UserRenoteMutingService.js';
import { UserSuspendService } from './UserSuspendService.js';
import { UserAuthService } from './UserAuthService.js';
import { VideoProcessingService } from './VideoProcessingService.js';
-import { WebhookService } from './WebhookService.js';
+import { UserWebhookService } from './UserWebhookService.js';
import { ProxyAccountService } from './ProxyAccountService.js';
import { UtilityService } from './UtilityService.js';
import { FileInfoService } from './FileInfoService.js';
@@ -144,6 +153,8 @@ import type { Provider } from '@nestjs/common';
//#region 文字列ベースã§ã®injection用(循環å‚照対応ã®ãŸã‚)
const $LoggerService: Provider = { provide: 'LoggerService', useExisting: LoggerService };
+const $AbuseReportService: Provider = { provide: 'AbuseReportService', useExisting: AbuseReportService };
+const $AbuseReportNotificationService: Provider = { provide: 'AbuseReportNotificationService', useExisting: AbuseReportNotificationService };
const $AccountMoveService: Provider = { provide: 'AccountMoveService', useExisting: AccountMoveService };
const $AccountUpdateService: Provider = { provide: 'AccountUpdateService', useExisting: AccountUpdateService };
const $AiService: Provider = { provide: 'AiService', useExisting: AiService };
@@ -193,10 +204,13 @@ const $UserFollowingService: Provider = { provide: 'UserFollowingService', useEx
const $UserKeypairService: Provider = { provide: 'UserKeypairService', useExisting: UserKeypairService };
const $UserListService: Provider = { provide: 'UserListService', useExisting: UserListService };
const $UserMutingService: Provider = { provide: 'UserMutingService', useExisting: UserMutingService };
+const $UserRenoteMutingService: Provider = { provide: 'UserRenoteMutingService', useExisting: UserRenoteMutingService };
+const $UserSearchService: Provider = { provide: 'UserSearchService', useExisting: UserSearchService };
const $UserSuspendService: Provider = { provide: 'UserSuspendService', useExisting: UserSuspendService };
const $UserAuthService: Provider = { provide: 'UserAuthService', useExisting: UserAuthService };
const $VideoProcessingService: Provider = { provide: 'VideoProcessingService', useExisting: VideoProcessingService };
-const $WebhookService: Provider = { provide: 'WebhookService', useExisting: WebhookService };
+const $UserWebhookService: Provider = { provide: 'UserWebhookService', useExisting: UserWebhookService };
+const $SystemWebhookService: Provider = { provide: 'SystemWebhookService', useExisting: SystemWebhookService };
const $UtilityService: Provider = { provide: 'UtilityService', useExisting: UtilityService };
const $FileInfoService: Provider = { provide: 'FileInfoService', useExisting: FileInfoService };
const $SearchService: Provider = { provide: 'SearchService', useExisting: SearchService };
@@ -225,6 +239,7 @@ const $ChartManagementService: Provider = { provide: 'ChartManagementService', u
const $AbuseUserReportEntityService: Provider = { provide: 'AbuseUserReportEntityService', useExisting: AbuseUserReportEntityService };
const $AnnouncementEntityService: Provider = { provide: 'AnnouncementEntityService', useExisting: AnnouncementEntityService };
+const $AbuseReportNotificationRecipientEntityService: Provider = { provide: 'AbuseReportNotificationRecipientEntityService', useExisting: AbuseReportNotificationRecipientEntityService };
const $AntennaEntityService: Provider = { provide: 'AntennaEntityService', useExisting: AntennaEntityService };
const $AppEntityService: Provider = { provide: 'AppEntityService', useExisting: AppEntityService };
const $AuthSessionEntityService: Provider = { provide: 'AuthSessionEntityService', useExisting: AuthSessionEntityService };
@@ -258,6 +273,7 @@ const $FlashLikeEntityService: Provider = { provide: 'FlashLikeEntityService', u
const $RoleEntityService: Provider = { provide: 'RoleEntityService', useExisting: RoleEntityService };
const $ReversiGameEntityService: Provider = { provide: 'ReversiGameEntityService', useExisting: ReversiGameEntityService };
const $MetaEntityService: Provider = { provide: 'MetaEntityService', useExisting: MetaEntityService };
+const $SystemWebhookEntityService: Provider = { provide: 'SystemWebhookEntityService', useExisting: SystemWebhookEntityService };
const $ApAudienceService: Provider = { provide: 'ApAudienceService', useExisting: ApAudienceService };
const $ApDbResolverService: Provider = { provide: 'ApDbResolverService', useExisting: ApDbResolverService };
@@ -285,6 +301,8 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
],
providers: [
LoggerService,
+ AbuseReportService,
+ AbuseReportNotificationService,
AccountMoveService,
AccountUpdateService,
AiService,
@@ -334,10 +352,13 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
UserKeypairService,
UserListService,
UserMutingService,
+ UserRenoteMutingService,
+ UserSearchService,
UserSuspendService,
UserAuthService,
VideoProcessingService,
- WebhookService,
+ UserWebhookService,
+ SystemWebhookService,
UtilityService,
FileInfoService,
SearchService,
@@ -366,6 +387,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
AbuseUserReportEntityService,
AnnouncementEntityService,
+ AbuseReportNotificationRecipientEntityService,
AntennaEntityService,
AppEntityService,
AuthSessionEntityService,
@@ -399,6 +421,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
RoleEntityService,
ReversiGameEntityService,
MetaEntityService,
+ SystemWebhookEntityService,
ApAudienceService,
ApDbResolverService,
@@ -422,6 +445,8 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
//#region 文字列ベースã§ã®injection用(循環å‚照対応ã®ãŸã‚)
$LoggerService,
+ $AbuseReportService,
+ $AbuseReportNotificationService,
$AccountMoveService,
$AccountUpdateService,
$AiService,
@@ -471,10 +496,13 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$UserKeypairService,
$UserListService,
$UserMutingService,
+ $UserRenoteMutingService,
+ $UserSearchService,
$UserSuspendService,
$UserAuthService,
$VideoProcessingService,
- $WebhookService,
+ $UserWebhookService,
+ $SystemWebhookService,
$UtilityService,
$FileInfoService,
$SearchService,
@@ -503,6 +531,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$AbuseUserReportEntityService,
$AnnouncementEntityService,
+ $AbuseReportNotificationRecipientEntityService,
$AntennaEntityService,
$AppEntityService,
$AuthSessionEntityService,
@@ -536,6 +565,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$RoleEntityService,
$ReversiGameEntityService,
$MetaEntityService,
+ $SystemWebhookEntityService,
$ApAudienceService,
$ApDbResolverService,
@@ -560,6 +590,8 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
exports: [
QueueModule,
LoggerService,
+ AbuseReportService,
+ AbuseReportNotificationService,
AccountMoveService,
AccountUpdateService,
AiService,
@@ -609,10 +641,13 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
UserKeypairService,
UserListService,
UserMutingService,
+ UserRenoteMutingService,
+ UserSearchService,
UserSuspendService,
UserAuthService,
VideoProcessingService,
- WebhookService,
+ UserWebhookService,
+ SystemWebhookService,
UtilityService,
FileInfoService,
SearchService,
@@ -640,6 +675,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
AbuseUserReportEntityService,
AnnouncementEntityService,
+ AbuseReportNotificationRecipientEntityService,
AntennaEntityService,
AppEntityService,
AuthSessionEntityService,
@@ -673,6 +709,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
RoleEntityService,
ReversiGameEntityService,
MetaEntityService,
+ SystemWebhookEntityService,
ApAudienceService,
ApDbResolverService,
@@ -696,6 +733,8 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
//#region 文字列ベースã§ã®injection用(循環å‚照対応ã®ãŸã‚)
$LoggerService,
+ $AbuseReportService,
+ $AbuseReportNotificationService,
$AccountMoveService,
$AccountUpdateService,
$AiService,
@@ -745,10 +784,13 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$UserKeypairService,
$UserListService,
$UserMutingService,
+ $UserRenoteMutingService,
+ $UserSearchService,
$UserSuspendService,
$UserAuthService,
$VideoProcessingService,
- $WebhookService,
+ $UserWebhookService,
+ $SystemWebhookService,
$UtilityService,
$FileInfoService,
$SearchService,
@@ -776,6 +818,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$AbuseUserReportEntityService,
$AnnouncementEntityService,
+ $AbuseReportNotificationRecipientEntityService,
$AntennaEntityService,
$AppEntityService,
$AuthSessionEntityService,
@@ -809,6 +852,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$RoleEntityService,
$ReversiGameEntityService,
$MetaEntityService,
+ $SystemWebhookEntityService,
$ApAudienceService,
$ApDbResolverService,
diff --git a/packages/backend/src/core/DriveService.ts b/packages/backend/src/core/DriveService.ts
index 37c5d1adf7..8aa04b4da7 100644
--- a/packages/backend/src/core/DriveService.ts
+++ b/packages/backend/src/core/DriveService.ts
@@ -43,6 +43,7 @@ import { RoleService } from '@/core/RoleService.js';
import { correctFilename } from '@/misc/correct-filename.js';
import { isMimeImage } from '@/misc/is-mime-image.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
+import { UtilityService } from '@/core/UtilityService.js';
type AddFileArgs = {
/** User who wish to add file */
@@ -127,6 +128,7 @@ export class DriveService {
private driveChart: DriveChart,
private perUserDriveChart: PerUserDriveChart,
private instanceChart: InstanceChart,
+ private utilityService: UtilityService,
) {
const logger = new Logger('drive', 'blue');
this.registerLogger = logger.createSubLogger('register', 'yellow');
@@ -587,6 +589,7 @@ export class DriveService {
sensitive ?? false
: false;
+ if (user && this.utilityService.isMediaSilencedHost(instance.mediaSilencedHosts, user.host)) file.isSensitive = true;
if (info.sensitive && profile!.autoSensitive) file.isSensitive = true;
if (info.sensitive && instance.setSensitiveFlagAutomatically) file.isSensitive = true;
if (userRoleNSFW) file.isSensitive = true;
diff --git a/packages/backend/src/core/EmailService.ts b/packages/backend/src/core/EmailService.ts
index 08f8f80a6e..435dbbae28 100644
--- a/packages/backend/src/core/EmailService.ts
+++ b/packages/backend/src/core/EmailService.ts
@@ -16,6 +16,7 @@ import type { UserProfilesRepository } from '@/models/_.js';
import { LoggerService } from '@/core/LoggerService.js';
import { bindThis } from '@/decorators.js';
import { HttpRequestService } from '@/core/HttpRequestService.js';
+import { QueueService } from '@/core/QueueService.js';
@Injectable()
export class EmailService {
@@ -32,6 +33,7 @@ export class EmailService {
private loggerService: LoggerService,
private utilityService: UtilityService,
private httpRequestService: HttpRequestService,
+ private queueService: QueueService,
) {
this.logger = this.loggerService.getLogger('email');
}
diff --git a/packages/backend/src/core/FanoutTimelineEndpointService.ts b/packages/backend/src/core/FanoutTimelineEndpointService.ts
index d5058f37c2..b05af99c5e 100644
--- a/packages/backend/src/core/FanoutTimelineEndpointService.ts
+++ b/packages/backend/src/core/FanoutTimelineEndpointService.ts
@@ -55,9 +55,6 @@ export class FanoutTimelineEndpointService {
@bindThis
private async getMiNotes(ps: TimelineOptions): Promise<MiNote[]> {
- let noteIds: string[];
- let shouldFallbackToDb = false;
-
// 呼ã³å‡ºã—å…ƒã¨ä»¥ä¸‹ã®å‡¦ç†ã‚’シンプルã«ã™ã‚‹ãŸã‚ã«dbFallbackã‚’ç½®ãæ›ãˆã‚‹
if (!ps.useDbFallback) ps.dbFallback = () => Promise.resolve([]);
@@ -67,12 +64,11 @@ export class FanoutTimelineEndpointService {
const redisResult = await this.fanoutTimelineService.getMulti(ps.redisTimelines, ps.untilId, ps.sinceId);
// TODO: ã„ã„æ„Ÿã˜ã«getMulti内ã§ã‚½ãƒ¼ãƒˆæ¸ˆã ã‹ã‚‰uniqã™ã‚‹ã¨ãã«redisResultãŒå…¨ã¦ã‚½ãƒ¼ãƒˆæ¸ˆãªã®ã‚’利用ã—ã¦å†ã‚½ãƒ¼ãƒˆã‚’é¿ã‘ãŸã„
- const redisResultIds = Array.from(new Set(redisResult.flat(1)));
-
- redisResultIds.sort(idCompare);
- noteIds = redisResultIds.slice(0, ps.limit);
+ const redisResultIds = Array.from(new Set(redisResult.flat(1))).sort(idCompare);
- shouldFallbackToDb = shouldFallbackToDb || (noteIds.length === 0);
+ let noteIds = redisResultIds.slice(0, ps.limit);
+ const oldestNoteId = ascending ? redisResultIds[0] : redisResultIds[redisResultIds.length - 1];
+ const shouldFallbackToDb = noteIds.length === 0 || ps.sinceId != null && ps.sinceId < oldestNoteId;
if (!shouldFallbackToDb) {
let filter = ps.noteFilter ?? (_note => true);
diff --git a/packages/backend/src/core/FederatedInstanceService.ts b/packages/backend/src/core/FederatedInstanceService.ts
index 6799f2c5bb..7aeeb78178 100644
--- a/packages/backend/src/core/FederatedInstanceService.ts
+++ b/packages/backend/src/core/FederatedInstanceService.ts
@@ -40,6 +40,7 @@ export class FederatedInstanceService implements OnApplicationShutdown {
firstRetrievedAt: new Date(parsed.firstRetrievedAt),
latestRequestReceivedAt: parsed.latestRequestReceivedAt ? new Date(parsed.latestRequestReceivedAt) : null,
infoUpdatedAt: parsed.infoUpdatedAt ? new Date(parsed.infoUpdatedAt) : null,
+ notRespondingSince: parsed.notRespondingSince ? new Date(parsed.notRespondingSince) : null,
};
},
});
diff --git a/packages/backend/src/core/GlobalEventService.ts b/packages/backend/src/core/GlobalEventService.ts
index 90efd63f3a..87aa70713e 100644
--- a/packages/backend/src/core/GlobalEventService.ts
+++ b/packages/backend/src/core/GlobalEventService.ts
@@ -18,6 +18,7 @@ import type { MiAbuseUserReport } from '@/models/AbuseUserReport.js';
import type { MiSignin } from '@/models/Signin.js';
import type { MiPage } from '@/models/Page.js';
import type { MiWebhook } from '@/models/Webhook.js';
+import type { MiSystemWebhook } from '@/models/SystemWebhook.js';
import type { MiMeta } from '@/models/Meta.js';
import { MiAvatarDecoration, MiReversiGame, MiRole, MiRoleAssignment } from '@/models/_.js';
import type { Packed } from '@/misc/json-schema.js';
@@ -208,6 +209,10 @@ type SerializedAll<T> = {
[K in keyof T]: Serialized<T[K]>;
};
+type UndefinedAsNullAll<T> = {
+ [K in keyof T]: T[K] extends undefined ? null : T[K];
+}
+
export interface InternalEventTypes {
userChangeSuspendedState: { id: MiUser['id']; isSuspended: MiUser['isSuspended']; };
userChangeDeletedState: { id: MiUser['id']; isDeleted: MiUser['isDeleted']; };
@@ -227,6 +232,9 @@ export interface InternalEventTypes {
webhookCreated: MiWebhook;
webhookDeleted: MiWebhook;
webhookUpdated: MiWebhook;
+ systemWebhookCreated: MiSystemWebhook;
+ systemWebhookDeleted: MiSystemWebhook;
+ systemWebhookUpdated: MiSystemWebhook;
antennaCreated: MiAntenna;
antennaDeleted: MiAntenna;
antennaUpdated: MiAntenna;
@@ -243,43 +251,45 @@ export interface InternalEventTypes {
userListMemberRemoved: { userListId: MiUserList['id']; memberId: MiUser['id']; };
}
+type EventTypesToEventPayload<T> = EventUnionFromDictionary<UndefinedAsNullAll<SerializedAll<T>>>;
+
// name/messages(spec) pairs dictionary
export type GlobalEvents = {
internal: {
name: 'internal';
- payload: EventUnionFromDictionary<SerializedAll<InternalEventTypes>>;
+ payload: EventTypesToEventPayload<InternalEventTypes>;
};
broadcast: {
name: 'broadcast';
- payload: EventUnionFromDictionary<SerializedAll<BroadcastTypes>>;
+ payload: EventTypesToEventPayload<BroadcastTypes>;
};
main: {
name: `mainStream:${MiUser['id']}`;
- payload: EventUnionFromDictionary<SerializedAll<MainEventTypes>>;
+ payload: EventTypesToEventPayload<MainEventTypes>;
};
drive: {
name: `driveStream:${MiUser['id']}`;
- payload: EventUnionFromDictionary<SerializedAll<DriveEventTypes>>;
+ payload: EventTypesToEventPayload<DriveEventTypes>;
};
note: {
name: `noteStream:${MiNote['id']}`;
- payload: EventUnionFromDictionary<SerializedAll<NoteStreamEventTypes>>;
+ payload: EventTypesToEventPayload<NoteStreamEventTypes>;
};
userList: {
name: `userListStream:${MiUserList['id']}`;
- payload: EventUnionFromDictionary<SerializedAll<UserListEventTypes>>;
+ payload: EventTypesToEventPayload<UserListEventTypes>;
};
roleTimeline: {
name: `roleTimelineStream:${MiRole['id']}`;
- payload: EventUnionFromDictionary<SerializedAll<RoleTimelineEventTypes>>;
+ payload: EventTypesToEventPayload<RoleTimelineEventTypes>;
};
antenna: {
name: `antennaStream:${MiAntenna['id']}`;
- payload: EventUnionFromDictionary<SerializedAll<AntennaEventTypes>>;
+ payload: EventTypesToEventPayload<AntennaEventTypes>;
};
admin: {
name: `adminStream:${MiUser['id']}`;
- payload: EventUnionFromDictionary<SerializedAll<AdminEventTypes>>;
+ payload: EventTypesToEventPayload<AdminEventTypes>;
};
notes: {
name: 'notesStream';
@@ -287,11 +297,11 @@ export type GlobalEvents = {
};
reversi: {
name: `reversiStream:${MiUser['id']}`;
- payload: EventUnionFromDictionary<SerializedAll<ReversiEventTypes>>;
+ payload: EventTypesToEventPayload<ReversiEventTypes>;
};
reversiGame: {
name: `reversiGameStream:${MiReversiGame['id']}`;
- payload: EventUnionFromDictionary<SerializedAll<ReversiGameEventTypes>>;
+ payload: EventTypesToEventPayload<ReversiGameEventTypes>;
};
};
diff --git a/packages/backend/src/core/LoggerService.ts b/packages/backend/src/core/LoggerService.ts
index 96d9b09992..f102461a50 100644
--- a/packages/backend/src/core/LoggerService.ts
+++ b/packages/backend/src/core/LoggerService.ts
@@ -15,7 +15,7 @@ export class LoggerService {
}
@bindThis
- public getLogger(domain: string, color?: KEYWORD | undefined, store?: boolean) {
- return new Logger(domain, color, store);
+ public getLogger(domain: string, color?: KEYWORD | undefined) {
+ return new Logger(domain, color);
}
}
diff --git a/packages/backend/src/core/MfmService.ts b/packages/backend/src/core/MfmService.ts
index 9786f8b8bb..74536c68f5 100644
--- a/packages/backend/src/core/MfmService.ts
+++ b/packages/backend/src/core/MfmService.ts
@@ -13,10 +13,12 @@ import { intersperse } from '@/misc/prelude/array.js';
import { normalizeForSearch } from '@/misc/normalize-for-search.js';
import type { IMentionedRemoteUsers } from '@/models/Note.js';
import { bindThis } from '@/decorators.js';
-import * as TreeAdapter from '../../node_modules/parse5/dist/tree-adapters/default.js';
+import type { DefaultTreeAdapterMap } from 'parse5';
import type * as mfm from 'mfm-js';
-const treeAdapter = TreeAdapter.defaultTreeAdapter;
+const treeAdapter = parse5.defaultTreeAdapter;
+type Node = DefaultTreeAdapterMap['node'];
+type ChildNode = DefaultTreeAdapterMap['childNode'];
const urlRegex = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+/;
const urlRegexFull = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+$/;
@@ -46,7 +48,7 @@ export class MfmService {
return text.trim();
- function getText(node: TreeAdapter.Node): string {
+ function getText(node: Node): string {
if (treeAdapter.isTextNode(node)) return node.value;
if (!treeAdapter.isElementNode(node)) return '';
if (node.nodeName === 'br') return '\n';
@@ -58,7 +60,7 @@ export class MfmService {
return '';
}
- function appendChildren(childNodes: TreeAdapter.ChildNode[]): void {
+ function appendChildren(childNodes: ChildNode[]): void {
if (childNodes) {
for (const n of childNodes) {
analyze(n);
@@ -66,14 +68,16 @@ export class MfmService {
}
}
- function analyze(node: TreeAdapter.Node) {
+ function analyze(node: Node) {
if (treeAdapter.isTextNode(node)) {
text += node.value;
return;
}
// Skip comment or document type node
- if (!treeAdapter.isElementNode(node)) return;
+ if (!treeAdapter.isElementNode(node)) {
+ return;
+ }
switch (node.nodeName) {
case 'br': {
@@ -81,8 +85,7 @@ export class MfmService {
break;
}
- case 'a':
- {
+ case 'a': {
const txt = getText(node);
const rel = node.attrs.find(x => x.name === 'rel');
const href = node.attrs.find(x => x.name === 'href');
@@ -90,7 +93,7 @@ export class MfmService {
// ãƒãƒƒã‚·ãƒ¥ã‚¿ã‚°
if (normalizedHashtagNames && href && normalizedHashtagNames.has(normalizeForSearch(txt))) {
text += txt;
- // メンション
+ // メンション
} else if (txt.startsWith('@') && !(rel && rel.value.startsWith('me '))) {
const part = txt.split('@');
@@ -102,7 +105,7 @@ export class MfmService {
} else if (part.length === 3) {
text += txt;
}
- // ãã®ä»–
+ // ãã®ä»–
} else {
const generateLink = () => {
if (!href && !txt) {
@@ -130,8 +133,7 @@ export class MfmService {
break;
}
- case 'h1':
- {
+ case 'h1': {
text += 'ã€';
appendChildren(node.childNodes);
text += '】\n';
@@ -139,16 +141,14 @@ export class MfmService {
}
case 'b':
- case 'strong':
- {
+ case 'strong': {
text += '**';
appendChildren(node.childNodes);
text += '**';
break;
}
- case 'small':
- {
+ case 'small': {
text += '<small>';
appendChildren(node.childNodes);
text += '</small>';
@@ -156,8 +156,7 @@ export class MfmService {
}
case 's':
- case 'del':
- {
+ case 'del': {
text += '~~';
appendChildren(node.childNodes);
text += '~~';
@@ -165,8 +164,7 @@ export class MfmService {
}
case 'i':
- case 'em':
- {
+ case 'em': {
text += '<i>';
appendChildren(node.childNodes);
text += '</i>';
@@ -207,8 +205,7 @@ export class MfmService {
case 'h3':
case 'h4':
case 'h5':
- case 'h6':
- {
+ case 'h6': {
text += '\n\n';
appendChildren(node.childNodes);
break;
@@ -221,8 +218,7 @@ export class MfmService {
case 'article':
case 'li':
case 'dt':
- case 'dd':
- {
+ case 'dd': {
text += '\n';
appendChildren(node.childNodes);
break;
diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts
index e5580f36d1..32cf3f3e26 100644
--- a/packages/backend/src/core/NoteCreateService.ts
+++ b/packages/backend/src/core/NoteCreateService.ts
@@ -38,7 +38,7 @@ import InstanceChart from '@/core/chart/charts/instance.js';
import ActiveUsersChart from '@/core/chart/charts/active-users.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { NotificationService } from '@/core/NotificationService.js';
-import { WebhookService } from '@/core/WebhookService.js';
+import { UserWebhookService } from '@/core/UserWebhookService.js';
import { HashtagService } from '@/core/HashtagService.js';
import { AntennaService } from '@/core/AntennaService.js';
import { QueueService } from '@/core/QueueService.js';
@@ -59,7 +59,6 @@ import { UtilityService } from '@/core/UtilityService.js';
import { UserBlockingService } from '@/core/UserBlockingService.js';
import { isReply } from '@/misc/is-reply.js';
import { trackPromise } from '@/misc/promise-tracker.js';
-import { isNotNull } from '@/misc/is-not-null.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
type NotificationType = 'reply' | 'renote' | 'quote' | 'mention';
@@ -205,7 +204,7 @@ export class NoteCreateService implements OnApplicationShutdown {
private federatedInstanceService: FederatedInstanceService,
private hashtagService: HashtagService,
private antennaService: AntennaService,
- private webhookService: WebhookService,
+ private webhookService: UserWebhookService,
private featuredService: FeaturedService,
private remoteUserResolveService: RemoteUserResolveService,
private apDeliverManagerService: ApDeliverManagerService,
@@ -365,6 +364,9 @@ export class NoteCreateService implements OnApplicationShutdown {
mentionedUsers = data.apMentions ?? await this.extractMentionedUsers(user, combinedTokens);
}
+ // if the host is media-silenced, custom emojis are not allowed
+ if (this.utilityService.isMediaSilencedHost(meta.mediaSilencedHosts, user.host)) emojis = [];
+
tags = tags.filter(tag => Array.from(tag).length <= 128).splice(0, 32);
if (data.reply && (user.id !== data.reply.userId) && !mentionedUsers.some(u => u.id === data.reply!.userId)) {
@@ -606,7 +608,7 @@ export class NoteCreateService implements OnApplicationShutdown {
this.webhookService.getActiveWebhooks().then(webhooks => {
webhooks = webhooks.filter(x => x.userId === user.id && x.on.includes('note'));
for (const webhook of webhooks) {
- this.queueService.webhookDeliver(webhook, 'note', {
+ this.queueService.userWebhookDeliver(webhook, 'note', {
note: noteObj,
});
}
@@ -633,7 +635,7 @@ export class NoteCreateService implements OnApplicationShutdown {
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === data.reply!.userId && x.on.includes('reply'));
for (const webhook of webhooks) {
- this.queueService.webhookDeliver(webhook, 'reply', {
+ this.queueService.userWebhookDeliver(webhook, 'reply', {
note: noteObj,
});
}
@@ -656,7 +658,7 @@ export class NoteCreateService implements OnApplicationShutdown {
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === data.renote!.userId && x.on.includes('renote'));
for (const webhook of webhooks) {
- this.queueService.webhookDeliver(webhook, 'renote', {
+ this.queueService.userWebhookDeliver(webhook, 'renote', {
note: noteObj,
});
}
@@ -788,7 +790,7 @@ export class NoteCreateService implements OnApplicationShutdown {
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === u.id && x.on.includes('mention'));
for (const webhook of webhooks) {
- this.queueService.webhookDeliver(webhook, 'mention', {
+ this.queueService.userWebhookDeliver(webhook, 'mention', {
note: detailPackedNote,
});
}
@@ -839,7 +841,7 @@ export class NoteCreateService implements OnApplicationShutdown {
const mentions = extractMentions(tokens);
let mentionedUsers = (await Promise.all(mentions.map(m =>
this.remoteUserResolveService.resolveUser(m.username, m.host ?? user.host).catch(() => null),
- ))).filter(isNotNull);
+ ))).filter(x => x != null);
// Drop duplicate users
mentionedUsers = mentionedUsers.filter((u, i, self) =>
@@ -934,10 +936,13 @@ export class NoteCreateService implements OnApplicationShutdown {
}
}
- if (note.visibility !== 'specified' || !note.visibleUserIds.some(v => v === user.id)) { // 自分自身ã®HTL
- this.fanoutTimelineService.push(`homeTimeline:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax, r);
- if (note.fileIds.length > 0) {
- this.fanoutTimelineService.push(`homeTimelineWithFiles:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r);
+ // 自分自身ã®HTL
+ if (note.userHost == null) {
+ if (note.visibility !== 'specified' || !note.visibleUserIds.some(v => v === user.id)) {
+ this.fanoutTimelineService.push(`homeTimeline:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax, r);
+ if (note.fileIds.length > 0) {
+ this.fanoutTimelineService.push(`homeTimelineWithFiles:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r);
+ }
}
}
diff --git a/packages/backend/src/core/QueueModule.ts b/packages/backend/src/core/QueueModule.ts
index 216734e9e5..b10b8e5899 100644
--- a/packages/backend/src/core/QueueModule.ts
+++ b/packages/backend/src/core/QueueModule.ts
@@ -7,10 +7,17 @@ import { Inject, Module, OnApplicationShutdown } from '@nestjs/common';
import * as Bull from 'bullmq';
import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
-import { QUEUE, baseQueueOptions } from '@/queue/const.js';
+import { baseQueueOptions, QUEUE } from '@/queue/const.js';
import { allSettled } from '@/misc/promise-tracker.js';
+import {
+ DeliverJobData,
+ EndedPollNotificationJobData,
+ InboxJobData,
+ RelationshipJobData,
+ UserWebhookDeliverJobData,
+ SystemWebhookDeliverJobData,
+} from '../queue/types.js';
import type { Provider } from '@nestjs/common';
-import type { DeliverJobData, InboxJobData, EndedPollNotificationJobData, WebhookDeliverJobData, RelationshipJobData } from '../queue/types.js';
export type SystemQueue = Bull.Queue<Record<string, unknown>>;
export type EndedPollNotificationQueue = Bull.Queue<EndedPollNotificationJobData>;
@@ -19,7 +26,8 @@ export type InboxQueue = Bull.Queue<InboxJobData>;
export type DbQueue = Bull.Queue;
export type RelationshipQueue = Bull.Queue<RelationshipJobData>;
export type ObjectStorageQueue = Bull.Queue;
-export type WebhookDeliverQueue = Bull.Queue<WebhookDeliverJobData>;
+export type UserWebhookDeliverQueue = Bull.Queue<UserWebhookDeliverJobData>;
+export type SystemWebhookDeliverQueue = Bull.Queue<SystemWebhookDeliverJobData>;
const $system: Provider = {
provide: 'queue:system',
@@ -63,9 +71,15 @@ const $objectStorage: Provider = {
inject: [DI.config],
};
-const $webhookDeliver: Provider = {
- provide: 'queue:webhookDeliver',
- useFactory: (config: Config) => new Bull.Queue(QUEUE.WEBHOOK_DELIVER, baseQueueOptions(config, QUEUE.WEBHOOK_DELIVER)),
+const $userWebhookDeliver: Provider = {
+ provide: 'queue:userWebhookDeliver',
+ useFactory: (config: Config) => new Bull.Queue(QUEUE.USER_WEBHOOK_DELIVER, baseQueueOptions(config, QUEUE.USER_WEBHOOK_DELIVER)),
+ inject: [DI.config],
+};
+
+const $systemWebhookDeliver: Provider = {
+ provide: 'queue:systemWebhookDeliver',
+ useFactory: (config: Config) => new Bull.Queue(QUEUE.SYSTEM_WEBHOOK_DELIVER, baseQueueOptions(config, QUEUE.SYSTEM_WEBHOOK_DELIVER)),
inject: [DI.config],
};
@@ -80,7 +94,8 @@ const $webhookDeliver: Provider = {
$db,
$relationship,
$objectStorage,
- $webhookDeliver,
+ $userWebhookDeliver,
+ $systemWebhookDeliver,
],
exports: [
$system,
@@ -90,7 +105,8 @@ const $webhookDeliver: Provider = {
$db,
$relationship,
$objectStorage,
- $webhookDeliver,
+ $userWebhookDeliver,
+ $systemWebhookDeliver,
],
})
export class QueueModule implements OnApplicationShutdown {
@@ -102,7 +118,8 @@ export class QueueModule implements OnApplicationShutdown {
@Inject('queue:db') public dbQueue: DbQueue,
@Inject('queue:relationship') public relationshipQueue: RelationshipQueue,
@Inject('queue:objectStorage') public objectStorageQueue: ObjectStorageQueue,
- @Inject('queue:webhookDeliver') public webhookDeliverQueue: WebhookDeliverQueue,
+ @Inject('queue:userWebhookDeliver') public userWebhookDeliverQueue: UserWebhookDeliverQueue,
+ @Inject('queue:systemWebhookDeliver') public systemWebhookDeliverQueue: SystemWebhookDeliverQueue,
) {}
public async dispose(): Promise<void> {
@@ -117,7 +134,8 @@ export class QueueModule implements OnApplicationShutdown {
this.dbQueue.close(),
this.relationshipQueue.close(),
this.objectStorageQueue.close(),
- this.webhookDeliverQueue.close(),
+ this.userWebhookDeliverQueue.close(),
+ this.systemWebhookDeliverQueue.close(),
]);
}
diff --git a/packages/backend/src/core/QueueService.ts b/packages/backend/src/core/QueueService.ts
index c258a22927..80827a500b 100644
--- a/packages/backend/src/core/QueueService.ts
+++ b/packages/backend/src/core/QueueService.ts
@@ -8,15 +8,33 @@ import { Inject, Injectable } from '@nestjs/common';
import type { IActivity } from '@/core/activitypub/type.js';
import type { MiDriveFile } from '@/models/DriveFile.js';
import type { MiWebhook, webhookEventTypes } from '@/models/Webhook.js';
+import type { MiSystemWebhook, SystemWebhookEventType } from '@/models/SystemWebhook.js';
import type { Config } from '@/config.js';
import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';
import type { Antenna } from '@/server/api/endpoints/i/import-antennas.js';
-import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, ObjectStorageQueue, RelationshipQueue, SystemQueue, WebhookDeliverQueue } from './QueueModule.js';
-import type { DbJobData, DeliverJobData, RelationshipJobData, ThinUser } from '../queue/types.js';
+import { ApRequestCreator } from '@/core/activitypub/ApRequestService.js';
+import type {
+ DbJobData,
+ DeliverJobData,
+ RelationshipJobData,
+ SystemWebhookDeliverJobData,
+ ThinUser,
+ UserWebhookDeliverJobData,
+} from '../queue/types.js';
+import type {
+ DbQueue,
+ DeliverQueue,
+ EndedPollNotificationQueue,
+ InboxQueue,
+ ObjectStorageQueue,
+ RelationshipQueue,
+ SystemQueue,
+ UserWebhookDeliverQueue,
+ SystemWebhookDeliverQueue,
+} from './QueueModule.js';
import type httpSignature from '@peertube/http-signature';
import type * as Bull from 'bullmq';
-import { ApRequestCreator } from '@/core/activitypub/ApRequestService.js';
@Injectable()
export class QueueService {
@@ -31,7 +49,8 @@ export class QueueService {
@Inject('queue:db') public dbQueue: DbQueue,
@Inject('queue:relationship') public relationshipQueue: RelationshipQueue,
@Inject('queue:objectStorage') public objectStorageQueue: ObjectStorageQueue,
- @Inject('queue:webhookDeliver') public webhookDeliverQueue: WebhookDeliverQueue,
+ @Inject('queue:userWebhookDeliver') public userWebhookDeliverQueue: UserWebhookDeliverQueue,
+ @Inject('queue:systemWebhookDeliver') public systemWebhookDeliverQueue: SystemWebhookDeliverQueue,
) {
this.systemQueue.add('tickCharts', {
}, {
@@ -431,9 +450,13 @@ export class QueueService {
});
}
+ /**
+ * @see UserWebhookDeliverJobData
+ * @see WebhookDeliverProcessorService
+ */
@bindThis
- public webhookDeliver(webhook: MiWebhook, type: typeof webhookEventTypes[number], content: unknown) {
- const data = {
+ public userWebhookDeliver(webhook: MiWebhook, type: typeof webhookEventTypes[number], content: unknown) {
+ const data: UserWebhookDeliverJobData = {
type,
content,
webhookId: webhook.id,
@@ -444,7 +467,33 @@ export class QueueService {
eventId: randomUUID(),
};
- return this.webhookDeliverQueue.add(webhook.id, data, {
+ return this.userWebhookDeliverQueue.add(webhook.id, data, {
+ attempts: 4,
+ backoff: {
+ type: 'custom',
+ },
+ removeOnComplete: true,
+ removeOnFail: true,
+ });
+ }
+
+ /**
+ * @see SystemWebhookDeliverJobData
+ * @see WebhookDeliverProcessorService
+ */
+ @bindThis
+ public systemWebhookDeliver(webhook: MiSystemWebhook, type: SystemWebhookEventType, content: unknown) {
+ const data: SystemWebhookDeliverJobData = {
+ type,
+ content,
+ webhookId: webhook.id,
+ to: webhook.url,
+ secret: webhook.secret,
+ createdAt: Date.now(),
+ eventId: randomUUID(),
+ };
+
+ return this.systemWebhookDeliverQueue.add(webhook.id, data, {
attempts: 4,
backoff: {
type: 'custom',
diff --git a/packages/backend/src/core/ReactionService.ts b/packages/backend/src/core/ReactionService.ts
index cb0b079df0..371207c33a 100644
--- a/packages/backend/src/core/ReactionService.ts
+++ b/packages/backend/src/core/ReactionService.ts
@@ -29,6 +29,7 @@ import { CustomEmojiService } from '@/core/CustomEmojiService.js';
import { RoleService } from '@/core/RoleService.js';
import { FeaturedService } from '@/core/FeaturedService.js';
import { trackPromise } from '@/misc/promise-tracker.js';
+import { isQuote, isRenote } from '@/misc/is-renote.js';
const FALLBACK = '\u2764';
const PER_NOTE_REACTION_USER_PAIR_CACHE_MAX = 16;
@@ -104,6 +105,8 @@ export class ReactionService {
@bindThis
public async create(user: { id: MiUser['id']; host: MiUser['host']; isBot: MiUser['isBot'] }, note: MiNote, _reaction?: string | null) {
+ const meta = await this.metaService.fetch();
+
// Check blocking
if (note.userId !== user.id) {
const blocked = await this.userBlockingService.checkBlocked(note.userId, user.id);
@@ -117,11 +120,16 @@ export class ReactionService {
throw new IdentifiableError('68e9d2d1-48bf-42c2-b90a-b20e09fd3d48', 'Note not accessible for you.');
}
+ // Check if note is Renote
+ if (isRenote(note) && !isQuote(note)) {
+ throw new IdentifiableError('12c35529-3c79-4327-b1cc-e2cf63a71925', 'You cannot react to Renote.');
+ }
+
let reaction = _reaction ?? FALLBACK;
if (note.reactionAcceptance === 'likeOnly' || ((note.reactionAcceptance === 'likeOnlyForRemote' || note.reactionAcceptance === 'nonSensitiveOnlyForLocalLikeOnlyForRemote') && (user.host != null))) {
reaction = '\u2764';
- } else if (_reaction) {
+ } else if (_reaction != null) {
const custom = reaction.match(isCustomEmojiRegexp);
if (custom) {
const reacterHost = this.utilityService.toPunyNullable(user.host);
@@ -142,6 +150,11 @@ export class ReactionService {
if ((note.reactionAcceptance === 'nonSensitiveOnly' || note.reactionAcceptance === 'nonSensitiveOnlyForLocalLikeOnlyForRemote') && emoji.isSensitive) {
reaction = FALLBACK;
}
+
+ // for media silenced host, custom emoji reactions are not allowed
+ if (reacterHost != null && this.utilityService.isMediaSilencedHost(meta.mediaSilencedHosts, reacterHost)) {
+ reaction = FALLBACK;
+ }
} else {
// リアクションã¨ã—ã¦ä½¿ã†æ¨©é™ãŒãªã„
reaction = FALLBACK;
@@ -214,8 +227,6 @@ export class ReactionService {
}
}
- const meta = await this.metaService.fetch();
-
if (meta.enableChartsForRemoteUser || (user.host == null)) {
this.perUserReactionsChart.update(user, note);
}
diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts
index d6eea70297..7966774673 100644
--- a/packages/backend/src/core/RoleService.ts
+++ b/packages/backend/src/core/RoleService.ts
@@ -47,6 +47,7 @@ export type RolePolicies = {
canHideAds: boolean;
driveCapacityMb: number;
alwaysMarkNsfw: boolean;
+ canUpdateBioMedia: boolean;
pinLimit: number;
antennaLimit: number;
wordMuteLimit: number;
@@ -75,6 +76,7 @@ export const DEFAULT_POLICIES: RolePolicies = {
canHideAds: false,
driveCapacityMb: 100,
alwaysMarkNsfw: false,
+ canUpdateBioMedia: true,
pinLimit: 5,
antennaLimit: 5,
wordMuteLimit: 200,
@@ -376,6 +378,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
canHideAds: calc('canHideAds', vs => vs.some(v => v === true)),
driveCapacityMb: calc('driveCapacityMb', vs => Math.max(...vs)),
alwaysMarkNsfw: calc('alwaysMarkNsfw', vs => vs.some(v => v === true)),
+ canUpdateBioMedia: calc('canUpdateBioMedia', vs => vs.some(v => v === true)),
pinLimit: calc('pinLimit', vs => Math.max(...vs)),
antennaLimit: calc('antennaLimit', vs => Math.max(...vs)),
wordMuteLimit: calc('wordMuteLimit', vs => Math.max(...vs)),
@@ -410,14 +413,32 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
}
@bindThis
- public async getModeratorIds(includeAdmins = true): Promise<MiUser['id'][]> {
+ public async getModeratorIds(includeAdmins = true, excludeExpire = false): Promise<MiUser['id'][]> {
const roles = await this.rolesCache.fetch(() => this.rolesRepository.findBy({}));
- const moderatorRoles = includeAdmins ? roles.filter(r => r.isModerator || r.isAdministrator) : roles.filter(r => r.isModerator);
- const assigns = moderatorRoles.length > 0 ? await this.roleAssignmentsRepository.findBy({
- roleId: In(moderatorRoles.map(r => r.id)),
- }) : [];
+ const moderatorRoles = includeAdmins
+ ? roles.filter(r => r.isModerator || r.isAdministrator)
+ : roles.filter(r => r.isModerator);
+
// TODO: isRootãªã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‚‚å«ã‚ã‚‹
- return assigns.map(a => a.userId);
+ const assigns = moderatorRoles.length > 0
+ ? await this.roleAssignmentsRepository.findBy({ roleId: In(moderatorRoles.map(r => r.id)) })
+ : [];
+
+ const now = Date.now();
+ const result = [
+ // Setを経由ã—ã¦é‡è¤‡ã‚’除去(ユーザIDã¯é‡è¤‡ã™ã‚‹å¯èƒ½æ€§ãŒã‚ã‚‹ã®ã§ï¼‰
+ ...new Set(
+ assigns
+ .filter(it =>
+ (excludeExpire)
+ ? (it.expiresAt == null || it.expiresAt.getTime() > now)
+ : true,
+ )
+ .map(a => a.userId),
+ ),
+ ];
+
+ return result.sort((x, y) => x.localeCompare(y));
}
@bindThis
@@ -484,14 +505,15 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
this.globalEventService.publishInternalEvent('userRoleAssigned', created);
- if (role.isPublic) {
+ const user = await this.usersRepository.findOneByOrFail({ id: userId });
+
+ if (role.isPublic && user.host === null) {
this.notificationService.createNotification(userId, 'roleAssigned', {
roleId: roleId,
});
}
if (moderator) {
- const user = await this.usersRepository.findOneByOrFail({ id: userId });
this.moderationLogService.log(moderator, 'assignRole', {
roleId: roleId,
roleName: role.name,
diff --git a/packages/backend/src/core/SignupService.ts b/packages/backend/src/core/SignupService.ts
index 5522ecd6cc..de45898328 100644
--- a/packages/backend/src/core/SignupService.ts
+++ b/packages/backend/src/core/SignupService.ts
@@ -21,6 +21,7 @@ import { bindThis } from '@/decorators.js';
import UsersChart from '@/core/chart/charts/users.js';
import { UtilityService } from '@/core/UtilityService.js';
import { MetaService } from '@/core/MetaService.js';
+import { UserService } from '@/core/UserService.js';
@Injectable()
export class SignupService {
@@ -35,6 +36,7 @@ export class SignupService {
private usedUsernamesRepository: UsedUsernamesRepository,
private utilityService: UtilityService,
+ private userService: UserService,
private userEntityService: UserEntityService,
private idService: IdService,
private metaService: MetaService,
@@ -148,7 +150,8 @@ export class SignupService {
}));
});
- this.usersChart.update(account, true);
+ this.usersChart.update(account, true).then();
+ this.userService.notifySystemWebhook(account, 'userCreated').then();
return { account, secret };
}
diff --git a/packages/backend/src/core/SystemWebhookService.ts b/packages/backend/src/core/SystemWebhookService.ts
new file mode 100644
index 0000000000..bc6851f788
--- /dev/null
+++ b/packages/backend/src/core/SystemWebhookService.ts
@@ -0,0 +1,233 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Inject, Injectable } from '@nestjs/common';
+import * as Redis from 'ioredis';
+import type { MiUser, SystemWebhooksRepository } from '@/models/_.js';
+import { DI } from '@/di-symbols.js';
+import { bindThis } from '@/decorators.js';
+import { GlobalEvents, GlobalEventService } from '@/core/GlobalEventService.js';
+import { MiSystemWebhook, type SystemWebhookEventType } from '@/models/SystemWebhook.js';
+import { IdService } from '@/core/IdService.js';
+import { QueueService } from '@/core/QueueService.js';
+import { ModerationLogService } from '@/core/ModerationLogService.js';
+import { LoggerService } from '@/core/LoggerService.js';
+import Logger from '@/logger.js';
+import type { OnApplicationShutdown } from '@nestjs/common';
+
+@Injectable()
+export class SystemWebhookService implements OnApplicationShutdown {
+ private logger: Logger;
+ private activeSystemWebhooksFetched = false;
+ private activeSystemWebhooks: MiSystemWebhook[] = [];
+
+ constructor(
+ @Inject(DI.redisForSub)
+ private redisForSub: Redis.Redis,
+ @Inject(DI.systemWebhooksRepository)
+ private systemWebhooksRepository: SystemWebhooksRepository,
+ private idService: IdService,
+ private queueService: QueueService,
+ private moderationLogService: ModerationLogService,
+ private loggerService: LoggerService,
+ private globalEventService: GlobalEventService,
+ ) {
+ this.redisForSub.on('message', this.onMessage);
+ this.logger = this.loggerService.getLogger('webhook');
+ }
+
+ @bindThis
+ public async fetchActiveSystemWebhooks() {
+ if (!this.activeSystemWebhooksFetched) {
+ this.activeSystemWebhooks = await this.systemWebhooksRepository.findBy({
+ isActive: true,
+ });
+ this.activeSystemWebhooksFetched = true;
+ }
+
+ return this.activeSystemWebhooks;
+ }
+
+ /**
+ * SystemWebhook ã®ä¸€è¦§ã‚’å–å¾—ã™ã‚‹.
+ */
+ @bindThis
+ public async fetchSystemWebhooks(params?: {
+ ids?: MiSystemWebhook['id'][];
+ isActive?: MiSystemWebhook['isActive'];
+ on?: MiSystemWebhook['on'];
+ }): Promise<MiSystemWebhook[]> {
+ const query = this.systemWebhooksRepository.createQueryBuilder('systemWebhook');
+ if (params) {
+ if (params.ids && params.ids.length > 0) {
+ query.andWhere('systemWebhook.id IN (:...ids)', { ids: params.ids });
+ }
+ if (params.isActive !== undefined) {
+ query.andWhere('systemWebhook.isActive = :isActive', { isActive: params.isActive });
+ }
+ if (params.on && params.on.length > 0) {
+ query.andWhere(':on <@ systemWebhook.on', { on: params.on });
+ }
+ }
+
+ return query.getMany();
+ }
+
+ /**
+ * SystemWebhook を作æˆã™ã‚‹.
+ */
+ @bindThis
+ public async createSystemWebhook(
+ params: {
+ isActive: MiSystemWebhook['isActive'];
+ name: MiSystemWebhook['name'];
+ on: MiSystemWebhook['on'];
+ url: MiSystemWebhook['url'];
+ secret: MiSystemWebhook['secret'];
+ },
+ updater: MiUser,
+ ): Promise<MiSystemWebhook> {
+ const id = this.idService.gen();
+ await this.systemWebhooksRepository.insert({
+ ...params,
+ id,
+ });
+
+ const webhook = await this.systemWebhooksRepository.findOneByOrFail({ id });
+ this.globalEventService.publishInternalEvent('systemWebhookCreated', webhook);
+ this.moderationLogService
+ .log(updater, 'createSystemWebhook', {
+ systemWebhookId: webhook.id,
+ webhook: webhook,
+ })
+ .then();
+
+ return webhook;
+ }
+
+ /**
+ * SystemWebhook ã‚’æ›´æ–°ã™ã‚‹.
+ */
+ @bindThis
+ public async updateSystemWebhook(
+ params: {
+ id: MiSystemWebhook['id'];
+ isActive: MiSystemWebhook['isActive'];
+ name: MiSystemWebhook['name'];
+ on: MiSystemWebhook['on'];
+ url: MiSystemWebhook['url'];
+ secret: MiSystemWebhook['secret'];
+ },
+ updater: MiUser,
+ ): Promise<MiSystemWebhook> {
+ const beforeEntity = await this.systemWebhooksRepository.findOneByOrFail({ id: params.id });
+ await this.systemWebhooksRepository.update(beforeEntity.id, {
+ updatedAt: new Date(),
+ isActive: params.isActive,
+ name: params.name,
+ on: params.on,
+ url: params.url,
+ secret: params.secret,
+ });
+
+ const afterEntity = await this.systemWebhooksRepository.findOneByOrFail({ id: beforeEntity.id });
+ this.globalEventService.publishInternalEvent('systemWebhookUpdated', afterEntity);
+ this.moderationLogService
+ .log(updater, 'updateSystemWebhook', {
+ systemWebhookId: beforeEntity.id,
+ before: beforeEntity,
+ after: afterEntity,
+ })
+ .then();
+
+ return afterEntity;
+ }
+
+ /**
+ * SystemWebhook を削除ã™ã‚‹.
+ */
+ @bindThis
+ public async deleteSystemWebhook(id: MiSystemWebhook['id'], updater: MiUser) {
+ const webhook = await this.systemWebhooksRepository.findOneByOrFail({ id });
+ await this.systemWebhooksRepository.delete(id);
+
+ this.globalEventService.publishInternalEvent('systemWebhookDeleted', webhook);
+ this.moderationLogService
+ .log(updater, 'deleteSystemWebhook', {
+ systemWebhookId: webhook.id,
+ webhook,
+ })
+ .then();
+ }
+
+ /**
+ * SystemWebhook ã‚’Webhooké…é€ã‚­ãƒ¥ãƒ¼ã«è¿½åŠ ã™ã‚‹
+ * @see QueueService.systemWebhookDeliver
+ */
+ @bindThis
+ public async enqueueSystemWebhook(webhook: MiSystemWebhook | MiSystemWebhook['id'], type: SystemWebhookEventType, content: unknown) {
+ const webhookEntity = typeof webhook === 'string'
+ ? (await this.fetchActiveSystemWebhooks()).find(a => a.id === webhook)
+ : webhook;
+ if (!webhookEntity || !webhookEntity.isActive) {
+ this.logger.info(`Webhook is not active or not found : ${webhook}`);
+ return;
+ }
+
+ if (!webhookEntity.on.includes(type)) {
+ this.logger.info(`Webhook ${webhookEntity.id} is not listening to ${type}`);
+ return;
+ }
+
+ return this.queueService.systemWebhookDeliver(webhookEntity, type, content);
+ }
+
+ @bindThis
+ private async onMessage(_: string, data: string): Promise<void> {
+ const obj = JSON.parse(data);
+ if (obj.channel !== 'internal') {
+ return;
+ }
+
+ const { type, body } = obj.message as GlobalEvents['internal']['payload'];
+ switch (type) {
+ case 'systemWebhookCreated': {
+ if (body.isActive) {
+ this.activeSystemWebhooks.push(MiSystemWebhook.deserialize(body));
+ }
+ break;
+ }
+ case 'systemWebhookUpdated': {
+ if (body.isActive) {
+ const i = this.activeSystemWebhooks.findIndex(a => a.id === body.id);
+ if (i > -1) {
+ this.activeSystemWebhooks[i] = MiSystemWebhook.deserialize(body);
+ } else {
+ this.activeSystemWebhooks.push(MiSystemWebhook.deserialize(body));
+ }
+ } else {
+ this.activeSystemWebhooks = this.activeSystemWebhooks.filter(a => a.id !== body.id);
+ }
+ break;
+ }
+ case 'systemWebhookDeleted': {
+ this.activeSystemWebhooks = this.activeSystemWebhooks.filter(a => a.id !== body.id);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ @bindThis
+ public dispose(): void {
+ this.redisForSub.off('message', this.onMessage);
+ }
+
+ @bindThis
+ public onApplicationShutdown(signal?: string | undefined): void {
+ this.dispose();
+ }
+}
diff --git a/packages/backend/src/core/UserBlockingService.ts b/packages/backend/src/core/UserBlockingService.ts
index 96f389b54c..2f1310b8ef 100644
--- a/packages/backend/src/core/UserBlockingService.ts
+++ b/packages/backend/src/core/UserBlockingService.ts
@@ -16,7 +16,7 @@ import Logger from '@/logger.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
import { LoggerService } from '@/core/LoggerService.js';
-import { WebhookService } from '@/core/WebhookService.js';
+import { UserWebhookService } from '@/core/UserWebhookService.js';
import { bindThis } from '@/decorators.js';
import { CacheService } from '@/core/CacheService.js';
import { UserFollowingService } from '@/core/UserFollowingService.js';
@@ -46,7 +46,7 @@ export class UserBlockingService implements OnModuleInit {
private idService: IdService,
private queueService: QueueService,
private globalEventService: GlobalEventService,
- private webhookService: WebhookService,
+ private webhookService: UserWebhookService,
private apRendererService: ApRendererService,
private loggerService: LoggerService,
) {
@@ -121,7 +121,7 @@ export class UserBlockingService implements OnModuleInit {
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === follower.id && x.on.includes('unfollow'));
for (const webhook of webhooks) {
- this.queueService.webhookDeliver(webhook, 'unfollow', {
+ this.queueService.userWebhookDeliver(webhook, 'unfollow', {
user: packed,
});
}
diff --git a/packages/backend/src/core/UserFollowingService.ts b/packages/backend/src/core/UserFollowingService.ts
index 406ea04031..6aab8fde70 100644
--- a/packages/backend/src/core/UserFollowingService.ts
+++ b/packages/backend/src/core/UserFollowingService.ts
@@ -16,7 +16,7 @@ import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js
import type { Packed } from '@/misc/json-schema.js';
import InstanceChart from '@/core/chart/charts/instance.js';
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
-import { WebhookService } from '@/core/WebhookService.js';
+import { UserWebhookService } from '@/core/UserWebhookService.js';
import { NotificationService } from '@/core/NotificationService.js';
import { DI } from '@/di-symbols.js';
import type { FollowingsRepository, FollowRequestsRepository, InstancesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js';
@@ -82,7 +82,7 @@ export class UserFollowingService implements OnModuleInit {
private metaService: MetaService,
private notificationService: NotificationService,
private federatedInstanceService: FederatedInstanceService,
- private webhookService: WebhookService,
+ private webhookService: UserWebhookService,
private apRendererService: ApRendererService,
private accountMoveService: AccountMoveService,
private fanoutTimelineService: FanoutTimelineService,
@@ -279,8 +279,10 @@ export class UserFollowingService implements OnModuleInit {
});
// 通知を作æˆ
- this.notificationService.createNotification(follower.id, 'followRequestAccepted', {
- }, followee.id);
+ if (follower.host === null) {
+ this.notificationService.createNotification(follower.id, 'followRequestAccepted', {
+ }, followee.id);
+ }
}
if (alreadyFollowed) return;
@@ -331,7 +333,7 @@ export class UserFollowingService implements OnModuleInit {
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === follower.id && x.on.includes('follow'));
for (const webhook of webhooks) {
- this.queueService.webhookDeliver(webhook, 'follow', {
+ this.queueService.userWebhookDeliver(webhook, 'follow', {
user: packed,
});
}
@@ -345,7 +347,7 @@ export class UserFollowingService implements OnModuleInit {
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === followee.id && x.on.includes('followed'));
for (const webhook of webhooks) {
- this.queueService.webhookDeliver(webhook, 'followed', {
+ this.queueService.userWebhookDeliver(webhook, 'followed', {
user: packed,
});
}
@@ -398,7 +400,7 @@ export class UserFollowingService implements OnModuleInit {
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === follower.id && x.on.includes('unfollow'));
for (const webhook of webhooks) {
- this.queueService.webhookDeliver(webhook, 'unfollow', {
+ this.queueService.userWebhookDeliver(webhook, 'unfollow', {
user: packed,
});
}
@@ -740,7 +742,7 @@ export class UserFollowingService implements OnModuleInit {
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === follower.id && x.on.includes('unfollow'));
for (const webhook of webhooks) {
- this.queueService.webhookDeliver(webhook, 'unfollow', {
+ this.queueService.userWebhookDeliver(webhook, 'unfollow', {
user: packedFollowee,
});
}
diff --git a/packages/backend/src/core/UserListService.ts b/packages/backend/src/core/UserListService.ts
index bbdcfed738..6333356fe9 100644
--- a/packages/backend/src/core/UserListService.ts
+++ b/packages/backend/src/core/UserListService.ts
@@ -95,7 +95,7 @@ export class UserListService implements OnApplicationShutdown, OnModuleInit {
const currentCount = await this.userListMembershipsRepository.countBy({
userListId: list.id,
});
- if (currentCount > (await this.roleService.getUserPolicies(me.id)).userEachUserListsLimit) {
+ if (currentCount >= (await this.roleService.getUserPolicies(me.id)).userEachUserListsLimit) {
throw new UserListService.TooManyUsersError();
}
diff --git a/packages/backend/src/core/UserRenoteMutingService.ts b/packages/backend/src/core/UserRenoteMutingService.ts
new file mode 100644
index 0000000000..bdc5e23f4b
--- /dev/null
+++ b/packages/backend/src/core/UserRenoteMutingService.ts
@@ -0,0 +1,52 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project , Type4ny-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Inject, Injectable } from '@nestjs/common';
+import { In } from 'typeorm';
+import type { RenoteMutingsRepository } from '@/models/_.js';
+import type { MiRenoteMuting } from '@/models/RenoteMuting.js';
+
+import { IdService } from '@/core/IdService.js';
+import type { MiUser } from '@/models/User.js';
+import { DI } from '@/di-symbols.js';
+import { bindThis } from '@/decorators.js';
+import { CacheService } from '@/core/CacheService.js';
+
+@Injectable()
+export class UserRenoteMutingService {
+ constructor(
+ @Inject(DI.renoteMutingsRepository)
+ private renoteMutingsRepository: RenoteMutingsRepository,
+
+ private idService: IdService,
+ private cacheService: CacheService,
+ ) {
+ }
+
+ @bindThis
+ public async mute(user: MiUser, target: MiUser, expiresAt: Date | null = null): Promise<void> {
+ await this.renoteMutingsRepository.insert({
+ id: this.idService.gen(),
+ muterId: user.id,
+ muteeId: target.id,
+ });
+
+ await this.cacheService.renoteMutingsCache.refresh(user.id);
+ }
+
+ @bindThis
+ public async unmute(mutings: MiRenoteMuting[]): Promise<void> {
+ if (mutings.length === 0) return;
+
+ await this.renoteMutingsRepository.delete({
+ id: In(mutings.map(m => m.id)),
+ });
+
+ const muterIds = [...new Set(mutings.map(m => m.muterId))];
+ for (const muterId of muterIds) {
+ await this.cacheService.renoteMutingsCache.refresh(muterId);
+ }
+ }
+}
diff --git a/packages/backend/src/core/UserSearchService.ts b/packages/backend/src/core/UserSearchService.ts
new file mode 100644
index 0000000000..0d03cf6ee0
--- /dev/null
+++ b/packages/backend/src/core/UserSearchService.ts
@@ -0,0 +1,205 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Inject, Injectable } from '@nestjs/common';
+import { Brackets, SelectQueryBuilder } from 'typeorm';
+import { DI } from '@/di-symbols.js';
+import { type FollowingsRepository, MiUser, type UsersRepository } from '@/models/_.js';
+import { bindThis } from '@/decorators.js';
+import { sqlLikeEscape } from '@/misc/sql-like-escape.js';
+import type { Config } from '@/config.js';
+import { UserEntityService } from '@/core/entities/UserEntityService.js';
+import { Packed } from '@/misc/json-schema.js';
+
+function defaultActiveThreshold() {
+ return new Date(Date.now() - 1000 * 60 * 60 * 24 * 30);
+}
+
+@Injectable()
+export class UserSearchService {
+ constructor(
+ @Inject(DI.config)
+ private config: Config,
+ @Inject(DI.usersRepository)
+ private usersRepository: UsersRepository,
+ @Inject(DI.followingsRepository)
+ private followingsRepository: FollowingsRepository,
+ private userEntityService: UserEntityService,
+ ) {
+ }
+
+ /**
+ * ユーザåã¨ãƒ›ã‚¹ãƒˆåã«ã‚ˆã‚‹ãƒ¦ãƒ¼ã‚¶æ¤œç´¢ã‚’行ã†.
+ *
+ * - æ¤œç´¢çµæžœã«ã¯å„ªå…ˆé †ä½ãŒã¤ã‘られã¦ãŠã‚Šã€ä»¥ä¸‹ã®é †åºã§æ¤œç´¢ãŒè¡Œã‚れる.
+ * 1. フォローã—ã¦ã„るユーザã®ã†ã¡ã€ä¸€å®šæœŸé–“ä»¥å†…ï¼ˆâ€»ï¼‰ã«æ›´æ–°ã•れãŸãƒ¦ãƒ¼ã‚¶
+ * 2. フォローã—ã¦ã„るユーザã®ã†ã¡ã€ä¸€å®šæœŸé–“ä»¥å†…ã«æ›´æ–°ã•れã¦ã„ãªã„ユーザ
+ * 3. フォローã—ã¦ã„ãªã„ユーザã®ã†ã¡ã€ä¸€å®šæœŸé–“ä»¥å†…ã«æ›´æ–°ã•れãŸãƒ¦ãƒ¼ã‚¶
+ * 4. フォローã—ã¦ã„ãªã„ユーザã®ã†ã¡ã€ä¸€å®šæœŸé–“ä»¥å†…ã«æ›´æ–°ã•れã¦ã„ãªã„ユーザ
+ * - ログインã—ã¦ã„ãªã„å ´åˆã¯ã€ä»¥ä¸‹ã®é †åºã§æ¤œç´¢ãŒè¡Œã‚れる.
+ * 1. ä¸€å®šæœŸé–“ä»¥å†…ã«æ›´æ–°ã•れãŸãƒ¦ãƒ¼ã‚¶
+ * 2. ä¸€å®šæœŸé–“ä»¥å†…ã«æ›´æ–°ã•れã¦ã„ãªã„ユーザ
+ * - ãれãžã‚Œã®æ¤œç´¢çµæžœã¯ãƒ¦ãƒ¼ã‚¶åã®æ˜‡é †ã§ã‚½ãƒ¼ãƒˆã•れる.
+ * - 動作的ã«ã¯å…ˆã«ç™»å ´ã—ãŸæ¤œç´¢çµæžœã®ç™»å ´ä½ç½®ãŒå„ªå…ˆã•れる(æ¡ä»¶çš„ã«ãƒ¦ãƒ¼ã‚¶IDãŒé‡è¤‡ã™ã‚‹ã“ã¨ã¯ãªã„ãŒ).
+ * (1ã§æ—¢ã«ãƒ’ットã—ã¦ã„ãŸå ´åˆã€2, 3, 4ã§ãƒ’ットã—ã¦ã‚‚無視ã•れる)
+ * - ユーザåã¨ãƒ›ã‚¹ãƒˆåã®æ¤œç´¢æ¡ä»¶ã¯ãれãžã‚Œå‰æ–¹ä¸€è‡´ã§æ¤œç´¢ã•れる.
+ * - ユーザåã®æ¤œç´¢ã¯å¤§æ–‡å­—å°æ–‡å­—を区別ã—ãªã„.
+ * - ホストåã®æ¤œç´¢ã¯å¤§æ–‡å­—å°æ–‡å­—を区別ã—ãªã„.
+ * - æ¤œç´¢çµæžœã¯æœ€å¤§ã§ {@link opts.limit} ä»¶ã¾ã§ã¨ãªã‚‹.
+ *
+ * ※一定期間ã¨ã¯ {@link params.activeThreshold} ã§æŒ‡å®šã•ã‚ŒãŸæ—¥æ™‚ã‹ã‚‰ç¾åœ¨ã¾ã§ã®æœŸé–“を指ã™.
+ *
+ * @param params 検索æ¡ä»¶.
+ * @param opts 関数ã®å‹•作を制御ã™ã‚‹ã‚ªãƒ—ション.
+ * @param me 検索を実行ã™ã‚‹ãƒ¦ãƒ¼ã‚¶ã®æƒ…å ±. 未ログインã®å ´åˆã¯æŒ‡å®šã—ãªã„.
+ * @see {@link UserSearchService#buildSearchUserQueries}
+ * @see {@link UserSearchService#buildSearchUserNoLoginQueries}
+ */
+ @bindThis
+ public async search(
+ params: {
+ username?: string | null,
+ host?: string | null,
+ activeThreshold?: Date,
+ },
+ opts?: {
+ limit?: number,
+ detail?: boolean,
+ },
+ me?: MiUser | null,
+ ): Promise<Packed<'User'>[]> {
+ const queries = me ? this.buildSearchUserQueries(me, params) : this.buildSearchUserNoLoginQueries(params);
+
+ let resultSet = new Set<MiUser['id']>();
+ const limit = opts?.limit ?? 10;
+ for (const query of queries) {
+ const ids = await query
+ .select('user.id')
+ .limit(limit - resultSet.size)
+ .orderBy('user.usernameLower', 'ASC')
+ .getRawMany<{ user_id: MiUser['id'] }>()
+ .then(res => res.map(x => x.user_id));
+
+ resultSet = new Set([...resultSet, ...ids]);
+ if (resultSet.size >= limit) {
+ break;
+ }
+ }
+
+ return this.userEntityService.packMany<'UserLite' | 'UserDetailed'>(
+ [...resultSet].slice(0, limit),
+ me,
+ { schema: opts?.detail ? 'UserDetailed' : 'UserLite' },
+ );
+ }
+
+ /**
+ * ログイン済ã¿ãƒ¦ãƒ¼ã‚¶ã«ã‚ˆã‚‹æ¤œç´¢å®Ÿè¡Œæ™‚ã®ã‚¯ã‚¨ãƒªä¸€è¦§ã‚’構築ã™ã‚‹.
+ * @param me
+ * @param params
+ * @private
+ */
+ @bindThis
+ private buildSearchUserQueries(
+ me: MiUser,
+ params: {
+ username?: string | null,
+ host?: string | null,
+ activeThreshold?: Date,
+ },
+ ) {
+ // デフォルト30æ—¥ä»¥å†…ã«æ›´æ–°ã•れãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚’アクティブユーザーã¨ã™ã‚‹
+ const activeThreshold = params.activeThreshold ?? defaultActiveThreshold();
+
+ const followingUserQuery = this.followingsRepository.createQueryBuilder('following')
+ .select('following.followeeId')
+ .where('following.followerId = :followerId', { followerId: me.id });
+
+ const activeFollowingUsersQuery = this.generateUserQueryBuilder(params)
+ .andWhere(`user.id IN (${followingUserQuery.getQuery()})`)
+ .andWhere('user.updatedAt > :activeThreshold', { activeThreshold });
+ activeFollowingUsersQuery.setParameters(followingUserQuery.getParameters());
+
+ const inactiveFollowingUsersQuery = this.generateUserQueryBuilder(params)
+ .andWhere(`user.id IN (${followingUserQuery.getQuery()})`)
+ .andWhere(new Brackets(qb => {
+ qb
+ .where('user.updatedAt IS NULL')
+ .orWhere('user.updatedAt <= :activeThreshold', { activeThreshold });
+ }));
+ inactiveFollowingUsersQuery.setParameters(followingUserQuery.getParameters());
+
+ // 自分自身ãŒãƒ’ットã™ã‚‹ã¨ã—ãŸã‚‰ã“ã“
+ const activeUserQuery = this.generateUserQueryBuilder(params)
+ .andWhere(`user.id NOT IN (${followingUserQuery.getQuery()})`)
+ .andWhere('user.updatedAt > :activeThreshold', { activeThreshold });
+ activeUserQuery.setParameters(followingUserQuery.getParameters());
+
+ const inactiveUserQuery = this.generateUserQueryBuilder(params)
+ .andWhere(`user.id NOT IN (${followingUserQuery.getQuery()})`)
+ .andWhere('user.updatedAt <= :activeThreshold', { activeThreshold });
+ inactiveUserQuery.setParameters(followingUserQuery.getParameters());
+
+ return [activeFollowingUsersQuery, inactiveFollowingUsersQuery, activeUserQuery, inactiveUserQuery];
+ }
+
+ /**
+ * ログインã—ã¦ã„ãªã„ユーザã«ã‚ˆã‚‹æ¤œç´¢å®Ÿè¡Œæ™‚ã®ã‚¯ã‚¨ãƒªä¸€è¦§ã‚’構築ã™ã‚‹.
+ * @param params
+ * @private
+ */
+ @bindThis
+ private buildSearchUserNoLoginQueries(params: {
+ username?: string | null,
+ host?: string | null,
+ activeThreshold?: Date,
+ }) {
+ // デフォルト30æ—¥ä»¥å†…ã«æ›´æ–°ã•れãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚’アクティブユーザーã¨ã™ã‚‹
+ const activeThreshold = params.activeThreshold ?? defaultActiveThreshold();
+
+ const activeUserQuery = this.generateUserQueryBuilder(params)
+ .andWhere(new Brackets(qb => {
+ qb
+ .where('user.updatedAt IS NULL')
+ .orWhere('user.updatedAt > :activeThreshold', { activeThreshold });
+ }));
+
+ const inactiveUserQuery = this.generateUserQueryBuilder(params)
+ .andWhere('user.updatedAt <= :activeThreshold', { activeThreshold });
+
+ return [activeUserQuery, inactiveUserQuery];
+ }
+
+ /**
+ * ユーザ検索クエリã§å…±é€šã™ã‚‹æŠ½å‡ºæ¡ä»¶ã‚’ã‚らã‹ã˜ã‚設定ã—ãŸã‚¯ã‚¨ãƒªãƒ“ルダを生æˆã™ã‚‹.
+ * @param params
+ * @private
+ */
+ @bindThis
+ private generateUserQueryBuilder(params: {
+ username?: string | null,
+ host?: string | null,
+ }): SelectQueryBuilder<MiUser> {
+ const userQuery = this.usersRepository.createQueryBuilder('user');
+
+ if (params.username) {
+ userQuery.andWhere('user.usernameLower LIKE :username', { username: sqlLikeEscape(params.username.toLowerCase()) + '%' });
+ }
+
+ if (params.host) {
+ if (params.host === this.config.hostname || params.host === '.') {
+ userQuery.andWhere('user.host IS NULL');
+ } else {
+ userQuery.andWhere('user.host LIKE :host', {
+ host: sqlLikeEscape(params.host.toLowerCase()) + '%',
+ });
+ }
+ }
+
+ userQuery.andWhere('user.isSuspended = FALSE');
+
+ return userQuery;
+ }
+}
diff --git a/packages/backend/src/core/UserService.ts b/packages/backend/src/core/UserService.ts
index 72fa4d928d..9b1961c631 100644
--- a/packages/backend/src/core/UserService.ts
+++ b/packages/backend/src/core/UserService.ts
@@ -8,15 +8,18 @@ import type { FollowingsRepository, UsersRepository } from '@/models/_.js';
import type { MiUser } from '@/models/User.js';
import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';
+import { SystemWebhookService } from '@/core/SystemWebhookService.js';
+import { UserEntityService } from '@/core/entities/UserEntityService.js';
@Injectable()
export class UserService {
constructor(
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
-
@Inject(DI.followingsRepository)
private followingsRepository: FollowingsRepository,
+ private systemWebhookService: SystemWebhookService,
+ private userEntityService: UserEntityService,
) {
}
@@ -50,4 +53,23 @@ export class UserService {
});
}
}
+
+ /**
+ * SystemWebhookを用ã„ã¦ãƒ¦ãƒ¼ã‚¶ã«é–¢ã™ã‚‹æ“作内容を管ç†è€…å„ä½ã«é€šçŸ¥ã™ã‚‹.
+ * ã“ã“ã§ã¯JobQueueã¸ã®ã‚¨ãƒ³ã‚­ãƒ¥ãƒ¼ã®ã¿ã‚’行ã†ãŸã‚ã€å³æ™‚実行ã•れãªã„.
+ *
+ * @see SystemWebhookService.enqueueSystemWebhook
+ */
+ @bindThis
+ public async notifySystemWebhook(user: MiUser, type: 'userCreated') {
+ const packedUser = await this.userEntityService.pack(user, null, { schema: 'UserLite' });
+ const recipientWebhookIds = await this.systemWebhookService.fetchSystemWebhooks({ isActive: true, on: [type] });
+ for (const webhookId of recipientWebhookIds) {
+ await this.systemWebhookService.enqueueSystemWebhook(
+ webhookId,
+ type,
+ packedUser,
+ );
+ }
+ }
}
diff --git a/packages/backend/src/core/UserWebhookService.ts b/packages/backend/src/core/UserWebhookService.ts
new file mode 100644
index 0000000000..e96bfeea95
--- /dev/null
+++ b/packages/backend/src/core/UserWebhookService.ts
@@ -0,0 +1,99 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Inject, Injectable } from '@nestjs/common';
+import * as Redis from 'ioredis';
+import type { WebhooksRepository } from '@/models/_.js';
+import type { MiWebhook } from '@/models/Webhook.js';
+import { DI } from '@/di-symbols.js';
+import { bindThis } from '@/decorators.js';
+import { GlobalEvents } from '@/core/GlobalEventService.js';
+import type { OnApplicationShutdown } from '@nestjs/common';
+
+@Injectable()
+export class UserWebhookService implements OnApplicationShutdown {
+ private activeWebhooksFetched = false;
+ private activeWebhooks: MiWebhook[] = [];
+
+ constructor(
+ @Inject(DI.redisForSub)
+ private redisForSub: Redis.Redis,
+ @Inject(DI.webhooksRepository)
+ private webhooksRepository: WebhooksRepository,
+ ) {
+ this.redisForSub.on('message', this.onMessage);
+ }
+
+ @bindThis
+ public async getActiveWebhooks() {
+ if (!this.activeWebhooksFetched) {
+ this.activeWebhooks = await this.webhooksRepository.findBy({
+ active: true,
+ });
+ this.activeWebhooksFetched = true;
+ }
+
+ return this.activeWebhooks;
+ }
+
+ @bindThis
+ private async onMessage(_: string, data: string): Promise<void> {
+ const obj = JSON.parse(data);
+ if (obj.channel !== 'internal') {
+ return;
+ }
+
+ const { type, body } = obj.message as GlobalEvents['internal']['payload'];
+ switch (type) {
+ case 'webhookCreated': {
+ if (body.active) {
+ this.activeWebhooks.push({ // TODO: ã“ã®ã‚ãŸã‚Šã®ãƒ‡ã‚·ãƒªã‚¢ãƒ©ã‚¤ã‚ºå‡¦ç†ã¯å„modelファイル内ã«é–¢æ•°ã¨ã—ã¦exportã—ãŸã„
+ ...body,
+ latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null,
+ user: null, // joinãªã‚«ãƒ©ãƒ ã¯é€šå¸¸å–ã£ã¦ã“ãªã„ã®ã§
+ });
+ }
+ break;
+ }
+ case 'webhookUpdated': {
+ if (body.active) {
+ const i = this.activeWebhooks.findIndex(a => a.id === body.id);
+ if (i > -1) {
+ this.activeWebhooks[i] = { // TODO: ã“ã®ã‚ãŸã‚Šã®ãƒ‡ã‚·ãƒªã‚¢ãƒ©ã‚¤ã‚ºå‡¦ç†ã¯å„modelファイル内ã«é–¢æ•°ã¨ã—ã¦exportã—ãŸã„
+ ...body,
+ latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null,
+ user: null, // joinãªã‚«ãƒ©ãƒ ã¯é€šå¸¸å–ã£ã¦ã“ãªã„ã®ã§
+ };
+ } else {
+ this.activeWebhooks.push({ // TODO: ã“ã®ã‚ãŸã‚Šã®ãƒ‡ã‚·ãƒªã‚¢ãƒ©ã‚¤ã‚ºå‡¦ç†ã¯å„modelファイル内ã«é–¢æ•°ã¨ã—ã¦exportã—ãŸã„
+ ...body,
+ latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null,
+ user: null, // joinãªã‚«ãƒ©ãƒ ã¯é€šå¸¸å–ã£ã¦ã“ãªã„ã®ã§
+ });
+ }
+ } else {
+ this.activeWebhooks = this.activeWebhooks.filter(a => a.id !== body.id);
+ }
+ break;
+ }
+ case 'webhookDeleted': {
+ this.activeWebhooks = this.activeWebhooks.filter(a => a.id !== body.id);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ @bindThis
+ public dispose(): void {
+ this.redisForSub.off('message', this.onMessage);
+ }
+
+ @bindThis
+ public onApplicationShutdown(signal?: string | undefined): void {
+ this.dispose();
+ }
+}
diff --git a/packages/backend/src/core/UtilityService.ts b/packages/backend/src/core/UtilityService.ts
index 652e8f7449..94729250a6 100644
--- a/packages/backend/src/core/UtilityService.ts
+++ b/packages/backend/src/core/UtilityService.ts
@@ -43,6 +43,12 @@ export class UtilityService {
}
@bindThis
+ public isMediaSilencedHost(silencedHosts: string[] | undefined, host: string | null): boolean {
+ if (!silencedHosts || host == null) return false;
+ return silencedHosts.some(x => host.toLowerCase() === x);
+ }
+
+ @bindThis
public concatNoteContentsForKeyWordCheck(content: {
cw?: string | null;
text?: string | null;
diff --git a/packages/backend/src/core/WebhookService.ts b/packages/backend/src/core/WebhookService.ts
deleted file mode 100644
index 6be34977b0..0000000000
--- a/packages/backend/src/core/WebhookService.ts
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { Inject, Injectable } from '@nestjs/common';
-import * as Redis from 'ioredis';
-import type { WebhooksRepository } from '@/models/_.js';
-import type { MiWebhook } from '@/models/Webhook.js';
-import { DI } from '@/di-symbols.js';
-import { bindThis } from '@/decorators.js';
-import type { GlobalEvents } from '@/core/GlobalEventService.js';
-import type { OnApplicationShutdown } from '@nestjs/common';
-
-@Injectable()
-export class WebhookService implements OnApplicationShutdown {
- private webhooksFetched = false;
- private webhooks: MiWebhook[] = [];
-
- constructor(
- @Inject(DI.redisForSub)
- private redisForSub: Redis.Redis,
-
- @Inject(DI.webhooksRepository)
- private webhooksRepository: WebhooksRepository,
- ) {
- //this.onMessage = this.onMessage.bind(this);
- this.redisForSub.on('message', this.onMessage);
- }
-
- @bindThis
- public async getActiveWebhooks() {
- if (!this.webhooksFetched) {
- this.webhooks = await this.webhooksRepository.findBy({
- active: true,
- });
- this.webhooksFetched = true;
- }
-
- return this.webhooks;
- }
-
- @bindThis
- private async onMessage(_: string, data: string): Promise<void> {
- const obj = JSON.parse(data);
-
- if (obj.channel === 'internal') {
- const { type, body } = obj.message as GlobalEvents['internal']['payload'];
- switch (type) {
- case 'webhookCreated':
- if (body.active) {
- this.webhooks.push({ // TODO: ã“ã®ã‚ãŸã‚Šã®ãƒ‡ã‚·ãƒªã‚¢ãƒ©ã‚¤ã‚ºå‡¦ç†ã¯å„modelファイル内ã«é–¢æ•°ã¨ã—ã¦exportã—ãŸã„
- ...body,
- latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null,
- user: null, // joinãªã‚«ãƒ©ãƒ ã¯é€šå¸¸å–ã£ã¦ã“ãªã„ã®ã§
- });
- }
- break;
- case 'webhookUpdated':
- if (body.active) {
- const i = this.webhooks.findIndex(a => a.id === body.id);
- if (i > -1) {
- this.webhooks[i] = { // TODO: ã“ã®ã‚ãŸã‚Šã®ãƒ‡ã‚·ãƒªã‚¢ãƒ©ã‚¤ã‚ºå‡¦ç†ã¯å„modelファイル内ã«é–¢æ•°ã¨ã—ã¦exportã—ãŸã„
- ...body,
- latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null,
- user: null, // joinãªã‚«ãƒ©ãƒ ã¯é€šå¸¸å–ã£ã¦ã“ãªã„ã®ã§
- };
- } else {
- this.webhooks.push({ // TODO: ã“ã®ã‚ãŸã‚Šã®ãƒ‡ã‚·ãƒªã‚¢ãƒ©ã‚¤ã‚ºå‡¦ç†ã¯å„modelファイル内ã«é–¢æ•°ã¨ã—ã¦exportã—ãŸã„
- ...body,
- latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null,
- user: null, // joinãªã‚«ãƒ©ãƒ ã¯é€šå¸¸å–ã£ã¦ã“ãªã„ã®ã§
- });
- }
- } else {
- this.webhooks = this.webhooks.filter(a => a.id !== body.id);
- }
- break;
- case 'webhookDeleted':
- this.webhooks = this.webhooks.filter(a => a.id !== body.id);
- break;
- default:
- break;
- }
- }
- }
-
- @bindThis
- public dispose(): void {
- this.redisForSub.off('message', this.onMessage);
- }
-
- @bindThis
- public onApplicationShutdown(signal?: string | undefined): void {
- this.dispose();
- }
-}
diff --git a/packages/backend/src/core/activitypub/ApAudienceService.ts b/packages/backend/src/core/activitypub/ApAudienceService.ts
index 0fccc7b950..5a5a76f7d6 100644
--- a/packages/backend/src/core/activitypub/ApAudienceService.ts
+++ b/packages/backend/src/core/activitypub/ApAudienceService.ts
@@ -8,7 +8,6 @@ import promiseLimit from 'promise-limit';
import type { MiRemoteUser, MiUser } from '@/models/User.js';
import { concat, unique } from '@/misc/prelude/array.js';
import { bindThis } from '@/decorators.js';
-import { isNotNull } from '@/misc/is-not-null.js';
import { getApIds } from './type.js';
import { ApPersonService } from './models/ApPersonService.js';
import type { ApObject } from './type.js';
@@ -41,7 +40,7 @@ export class ApAudienceService {
const limit = promiseLimit<MiUser | null>(2);
const mentionedUsers = (await Promise.all(
others.map(id => limit(() => this.apPersonService.resolvePerson(id, resolver).catch(() => null))),
- )).filter(isNotNull);
+ )).filter(x => x != null);
if (toGroups.public.length > 0) {
return {
diff --git a/packages/backend/src/core/activitypub/ApInboxService.ts b/packages/backend/src/core/activitypub/ApInboxService.ts
index d0d206760c..e2164fec1d 100644
--- a/packages/backend/src/core/activitypub/ApInboxService.ts
+++ b/packages/backend/src/core/activitypub/ApInboxService.ts
@@ -27,8 +27,8 @@ import { QueueService } from '@/core/QueueService.js';
import type { UsersRepository, NotesRepository, FollowingsRepository, AbuseUserReportsRepository, FollowRequestsRepository } from '@/models/_.js';
import { bindThis } from '@/decorators.js';
import type { MiRemoteUser } from '@/models/User.js';
-import { isNotNull } from '@/misc/is-not-null.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
+import { AbuseReportService } from '@/core/AbuseReportService.js';
import { getApHrefNullable, getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isMove, isPost, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js';
import { ApNoteService } from './models/ApNoteService.js';
import { ApLoggerService } from './ApLoggerService.js';
@@ -57,9 +57,6 @@ export class ApInboxService {
@Inject(DI.followingsRepository)
private followingsRepository: FollowingsRepository,
- @Inject(DI.abuseUserReportsRepository)
- private abuseUserReportsRepository: AbuseUserReportsRepository,
-
@Inject(DI.followRequestsRepository)
private followRequestsRepository: FollowRequestsRepository,
@@ -68,6 +65,7 @@ export class ApInboxService {
private utilityService: UtilityService,
private idService: IdService,
private metaService: MetaService,
+ private abuseReportService: AbuseReportService,
private userFollowingService: UserFollowingService,
private apAudienceService: ApAudienceService,
private reactionService: ReactionService,
@@ -539,20 +537,19 @@ export class ApInboxService {
const userIds = uris
.filter(uri => uri.startsWith(this.config.url + '/users/'))
.map(uri => uri.split('/').at(-1))
- .filter(isNotNull);
+ .filter(x => x != null);
const users = await this.usersRepository.findBy({
id: In(userIds),
});
if (users.length < 1) return 'skip';
- await this.abuseUserReportsRepository.insert({
- id: this.idService.gen(),
+ await this.abuseReportService.report([{
targetUserId: users[0].id,
targetUserHost: users[0].host,
reporterId: actor.id,
reporterHost: actor.host,
comment: `${activity.content}\n${JSON.stringify(uris, null, 2)}`,
- });
+ }]);
return 'ok';
}
diff --git a/packages/backend/src/core/activitypub/ApMfmService.ts b/packages/backend/src/core/activitypub/ApMfmService.ts
index ab75b9abbd..4036d2794a 100644
--- a/packages/backend/src/core/activitypub/ApMfmService.ts
+++ b/packages/backend/src/core/activitypub/ApMfmService.ts
@@ -25,7 +25,7 @@ export class ApMfmService {
}
@bindThis
- public getNoteHtml(note: MiNote, apAppend?: string) {
+ public getNoteHtml(note: Pick<MiNote, 'text' | 'mentionedRemoteUsers'>, apAppend?: string) {
let noMisskeyContent = false;
const srcMfm = (note.text ?? '') + (apAppend ?? '');
diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts
index 4fc724b548..98e944f347 100644
--- a/packages/backend/src/core/activitypub/ApRendererService.ts
+++ b/packages/backend/src/core/activitypub/ApRendererService.ts
@@ -26,7 +26,6 @@ import type { MiUserKeypair } from '@/models/UserKeypair.js';
import type { UsersRepository, UserProfilesRepository, NotesRepository, DriveFilesRepository, PollsRepository } from '@/models/_.js';
import { bindThis } from '@/decorators.js';
import { CustomEmojiService } from '@/core/CustomEmojiService.js';
-import { isNotNull } from '@/misc/is-not-null.js';
import { IdService } from '@/core/IdService.js';
import { JsonLdService } from './JsonLdService.js';
import { ApMfmService } from './ApMfmService.js';
@@ -317,7 +316,7 @@ export class ApRendererService {
const getPromisedFiles = async (ids: string[]): Promise<MiDriveFile[]> => {
if (ids.length === 0) return [];
const items = await this.driveFilesRepository.findBy({ id: In(ids) });
- return ids.map(id => items.find(item => item.id === id)).filter(isNotNull);
+ return ids.map(id => items.find(item => item.id === id)).filter(x => x != null);
};
let inReplyTo;
@@ -686,7 +685,7 @@ export class ApRendererService {
if (names.length === 0) return [];
const allEmojis = await this.customEmojiService.localEmojisCache.fetch();
- const emojis = names.map(name => allEmojis.get(name)).filter(isNotNull);
+ const emojis = names.map(name => allEmojis.get(name)).filter(x => x != null);
return emojis;
}
diff --git a/packages/backend/src/core/activitypub/models/ApMentionService.ts b/packages/backend/src/core/activitypub/models/ApMentionService.ts
index 0ced7e88af..2cd151fa04 100644
--- a/packages/backend/src/core/activitypub/models/ApMentionService.ts
+++ b/packages/backend/src/core/activitypub/models/ApMentionService.ts
@@ -8,7 +8,6 @@ import promiseLimit from 'promise-limit';
import type { MiUser } from '@/models/_.js';
import { toArray, unique } from '@/misc/prelude/array.js';
import { bindThis } from '@/decorators.js';
-import { isNotNull } from '@/misc/is-not-null.js';
import { isMention } from '../type.js';
import { Resolver } from '../ApResolverService.js';
import { ApPersonService } from './ApPersonService.js';
@@ -28,7 +27,7 @@ export class ApMentionService {
const limit = promiseLimit<MiUser | null>(2);
const mentionedUsers = (await Promise.all(
hrefs.map(x => limit(() => this.apPersonService.resolvePerson(x, resolver).catch(() => null))),
- )).filter(isNotNull);
+ )).filter(x => x != null);
return mentionedUsers;
}
diff --git a/packages/backend/src/core/activitypub/models/ApNoteService.ts b/packages/backend/src/core/activitypub/models/ApNoteService.ts
index c6e6b3a1e8..fc7aa1e0b9 100644
--- a/packages/backend/src/core/activitypub/models/ApNoteService.ts
+++ b/packages/backend/src/core/activitypub/models/ApNoteService.ts
@@ -24,7 +24,6 @@ import { UtilityService } from '@/core/UtilityService.js';
import { bindThis } from '@/decorators.js';
import { checkHttps } from '@/misc/check-https.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
-import { isNotNull } from '@/misc/is-not-null.js';
import { getOneApId, getApId, getOneApHrefNullable, validPost, isEmoji, getApType } from '../type.js';
import { ApLoggerService } from '../ApLoggerService.js';
import { ApMfmService } from '../ApMfmService.js';
@@ -253,7 +252,7 @@ export class ApNoteService {
}
};
- const uris = unique([note._misskey_quote, note.quoteUrl].filter(isNotNull));
+ const uris = unique([note._misskey_quote, note.quoteUrl].filter(x => x != null));
const results = await Promise.all(uris.map(tryResolveNote));
quote = results.filter((x): x is { status: 'ok', res: MiNote } => x.status === 'ok').map(x => x.res).at(0);
diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts
index 744b1ea683..457205e023 100644
--- a/packages/backend/src/core/activitypub/models/ApPersonService.ts
+++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts
@@ -34,11 +34,11 @@ import { StatusError } from '@/misc/status-error.js';
import type { UtilityService } from '@/core/UtilityService.js';
import type { UserEntityService } from '@/core/entities/UserEntityService.js';
import { bindThis } from '@/decorators.js';
+import { RoleService } from '@/core/RoleService.js';
import { MetaService } from '@/core/MetaService.js';
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
import type { AccountMoveService } from '@/core/AccountMoveService.js';
import { checkHttps } from '@/misc/check-https.js';
-import { isNotNull } from '@/misc/is-not-null.js';
import { getApId, getApType, getOneApHrefNullable, isActor, isCollection, isCollectionOrOrderedCollection, isPropertyValue } from '../type.js';
import { extractApHashtags } from './tag.js';
import type { OnModuleInit } from '@nestjs/common';
@@ -101,6 +101,8 @@ export class ApPersonService implements OnModuleInit {
@Inject(DI.followingsRepository)
private followingsRepository: FollowingsRepository,
+
+ private roleService: RoleService,
) {
}
@@ -239,6 +241,11 @@ export class ApPersonService implements OnModuleInit {
return this.apImageService.resolveImage(user, img).catch(() => null);
}));
+ if (((avatar != null && avatar.id != null) || (banner != null && banner.id != null))
+ && !(await this.roleService.getUserPolicies(user.id)).canUpdateBioMedia) {
+ return {};
+ }
+
/*
we don't want to return nulls on errors! if the database fields
are already null, nothing changes; if the database has old
@@ -637,7 +644,7 @@ export class ApPersonService implements OnModuleInit {
// ã¨ã‚Šã‚ãˆãšidã‚’åˆ¥ã®æ™‚é–“ã§ç”Ÿæˆã—ã¦é †ç•ªã‚’ç¶­æŒ
let td = 0;
- for (const note of featuredNotes.filter(isNotNull)) {
+ for (const note of featuredNotes.filter(x => x != null)) {
td -= 1000;
transactionalEntityManager.insert(MiUserNotePining, {
id: this.idService.gen(Date.now() + td),
diff --git a/packages/backend/src/core/activitypub/models/ApQuestionService.ts b/packages/backend/src/core/activitypub/models/ApQuestionService.ts
index d1936cfe1d..73004d10b0 100644
--- a/packages/backend/src/core/activitypub/models/ApQuestionService.ts
+++ b/packages/backend/src/core/activitypub/models/ApQuestionService.ts
@@ -10,7 +10,6 @@ import type { Config } from '@/config.js';
import type { IPoll } from '@/models/Poll.js';
import type Logger from '@/logger.js';
import { bindThis } from '@/decorators.js';
-import { isNotNull } from '@/misc/is-not-null.js';
import { isQuestion } from '../type.js';
import { ApLoggerService } from '../ApLoggerService.js';
import { ApResolverService } from '../ApResolverService.js';
@@ -52,7 +51,7 @@ export class ApQuestionService {
const choices = question[multiple ? 'anyOf' : 'oneOf']
?.map((x) => x.name)
- .filter(isNotNull)
+ .filter(x => x != null)
?? [];
const votes = question[multiple ? 'anyOf' : 'oneOf']?.map((x) => x.replies?.totalItems ?? x._misskey_votes ?? 0);
@@ -75,10 +74,10 @@ export class ApQuestionService {
//#region ã“ã®ã‚µãƒ¼ãƒãƒ¼ã«æ—¢ã«ç™»éŒ²ã•れã¦ã„ã‚‹ã‹
const note = await this.notesRepository.findOneBy({ uri });
- if (note == null) throw new Error('Question is not registed');
+ if (note == null) throw new Error('Question is not registered');
const poll = await this.pollsRepository.findOneBy({ noteId: note.id });
- if (poll == null) throw new Error('Question is not registed');
+ if (poll == null) throw new Error('Question is not registered');
//#endregion
// resolve new Question object
diff --git a/packages/backend/src/core/activitypub/models/tag.ts b/packages/backend/src/core/activitypub/models/tag.ts
index e7ceec3262..f75cc45f7e 100644
--- a/packages/backend/src/core/activitypub/models/tag.ts
+++ b/packages/backend/src/core/activitypub/models/tag.ts
@@ -4,7 +4,6 @@
*/
import { toArray } from '@/misc/prelude/array.js';
-import { isNotNull } from '@/misc/is-not-null.js';
import { isHashtag } from '../type.js';
import type { IObject, IApHashtag } from '../type.js';
@@ -16,7 +15,7 @@ export function extractApHashtags(tags: IObject | IObject[] | null | undefined):
return hashtags.map(tag => {
const m = tag.name.match(/^#(.+)/);
return m ? m[1] : null;
- }).filter(isNotNull);
+ }).filter(x => x != null);
}
export function extractApHashtagObjects(tags: IObject | IObject[] | null | undefined): IApHashtag[] {
diff --git a/packages/backend/src/core/chart/ChartLoggerService.ts b/packages/backend/src/core/chart/ChartLoggerService.ts
index afc728d564..20815ea968 100644
--- a/packages/backend/src/core/chart/ChartLoggerService.ts
+++ b/packages/backend/src/core/chart/ChartLoggerService.ts
@@ -14,6 +14,6 @@ export class ChartLoggerService {
constructor(
private loggerService: LoggerService,
) {
- this.logger = this.loggerService.getLogger('chart', 'white', process.env.NODE_ENV !== 'test');
+ this.logger = this.loggerService.getLogger('chart', 'white');
}
}
diff --git a/packages/backend/src/core/chart/charts/federation.ts b/packages/backend/src/core/chart/charts/federation.ts
index 5e4555ee96..c2329a2f73 100644
--- a/packages/backend/src/core/chart/charts/federation.ts
+++ b/packages/backend/src/core/chart/charts/federation.ts
@@ -47,7 +47,7 @@ export default class FederationChart extends Chart<typeof schema> { // eslint-di
const suspendedInstancesQuery = this.instancesRepository.createQueryBuilder('instance')
.select('instance.host')
- .where('instance.isSuspended = true');
+ .where('instance.suspensionState != \'none\'');
const pubsubSubQuery = this.followingsRepository.createQueryBuilder('f')
.select('f.followerHost')
@@ -89,7 +89,7 @@ export default class FederationChart extends Chart<typeof schema> { // eslint-di
.select('COUNT(instance.id)')
.where(`instance.host IN (${ subInstancesQuery.getQuery() })`)
.andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'instance.host NOT ILIKE ANY(ARRAY[:...blocked])', { blocked: meta.blockedHosts.flatMap(x => [x, `%.${x}`]) })
- .andWhere('instance.isSuspended = false')
+ .andWhere('instance.suspensionState = \'none\'')
.andWhere('instance.isNotResponding = false')
.getRawOne()
.then(x => parseInt(x.count, 10)),
@@ -97,7 +97,7 @@ export default class FederationChart extends Chart<typeof schema> { // eslint-di
.select('COUNT(instance.id)')
.where(`instance.host IN (${ pubInstancesQuery.getQuery() })`)
.andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'instance.host NOT ILIKE ANY(ARRAY[:...blocked])', { blocked: meta.blockedHosts.flatMap(x => [x, `%.${x}`]) })
- .andWhere('instance.isSuspended = false')
+ .andWhere('instance.suspensionState = \'none\'')
.andWhere('instance.isNotResponding = false')
.getRawOne()
.then(x => parseInt(x.count, 10)),
diff --git a/packages/backend/src/core/entities/AbuseReportNotificationRecipientEntityService.ts b/packages/backend/src/core/entities/AbuseReportNotificationRecipientEntityService.ts
new file mode 100644
index 0000000000..1e23c194c5
--- /dev/null
+++ b/packages/backend/src/core/entities/AbuseReportNotificationRecipientEntityService.ts
@@ -0,0 +1,87 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Inject, Injectable } from '@nestjs/common';
+import { In } from 'typeorm';
+import { DI } from '@/di-symbols.js';
+import type { AbuseReportNotificationRecipientRepository, MiAbuseReportNotificationRecipient } from '@/models/_.js';
+import { bindThis } from '@/decorators.js';
+import { UserEntityService } from '@/core/entities/UserEntityService.js';
+import { Packed } from '@/misc/json-schema.js';
+import { SystemWebhookEntityService } from '@/core/entities/SystemWebhookEntityService.js';
+
+@Injectable()
+export class AbuseReportNotificationRecipientEntityService {
+ constructor(
+ @Inject(DI.abuseReportNotificationRecipientRepository)
+ private abuseReportNotificationRecipientRepository: AbuseReportNotificationRecipientRepository,
+ private userEntityService: UserEntityService,
+ private systemWebhookEntityService: SystemWebhookEntityService,
+ ) {
+ }
+
+ @bindThis
+ public async pack(
+ src: MiAbuseReportNotificationRecipient['id'] | MiAbuseReportNotificationRecipient,
+ opts?: {
+ users: Map<string, Packed<'UserLite'>>,
+ webhooks: Map<string, Packed<'SystemWebhook'>>,
+ },
+ ): Promise<Packed<'AbuseReportNotificationRecipient'>> {
+ const recipient = typeof src === 'object'
+ ? src
+ : await this.abuseReportNotificationRecipientRepository.findOneByOrFail({ id: src });
+ const user = recipient.userId
+ ? (opts?.users.get(recipient.userId) ?? await this.userEntityService.pack<'UserLite'>(recipient.userId))
+ : undefined;
+ const webhook = recipient.systemWebhookId
+ ? (opts?.webhooks.get(recipient.systemWebhookId) ?? await this.systemWebhookEntityService.pack(recipient.systemWebhookId))
+ : undefined;
+
+ return {
+ id: recipient.id,
+ isActive: recipient.isActive,
+ updatedAt: recipient.updatedAt.toISOString(),
+ name: recipient.name,
+ method: recipient.method,
+ userId: recipient.userId ?? undefined,
+ user: user,
+ systemWebhookId: recipient.systemWebhookId ?? undefined,
+ systemWebhook: webhook,
+ };
+ }
+
+ @bindThis
+ public async packMany(
+ src: MiAbuseReportNotificationRecipient['id'][] | MiAbuseReportNotificationRecipient[],
+ ): Promise<Packed<'AbuseReportNotificationRecipient'>[]> {
+ const objs = src.filter((it): it is MiAbuseReportNotificationRecipient => typeof it === 'object');
+ const ids = src.filter((it): it is MiAbuseReportNotificationRecipient['id'] => typeof it === 'string');
+ if (ids.length > 0) {
+ objs.push(
+ ...await this.abuseReportNotificationRecipientRepository.findBy({ id: In(ids) }),
+ );
+ }
+
+ const userIds = objs.map(it => it.userId).filter(x => x != null);
+ const users: Map<string, Packed<'UserLite'>> = (userIds.length > 0)
+ ? await this.userEntityService.packMany(userIds)
+ .then(it => new Map(it.map(it => [it.id, it])))
+ : new Map();
+
+ const systemWebhookIds = objs.map(it => it.systemWebhookId).filter(x => x != null);
+ const systemWebhooks: Map<string, Packed<'SystemWebhook'>> = (systemWebhookIds.length > 0)
+ ? await this.systemWebhookEntityService.packMany(systemWebhookIds)
+ .then(it => new Map(it.map(it => [it.id, it])))
+ : new Map();
+
+ return Promise
+ .all(
+ objs.map(it => this.pack(it, { users: users, webhooks: systemWebhooks })),
+ )
+ .then(it => it.sort((a, b) => a.id.localeCompare(b.id)));
+ }
+}
+
diff --git a/packages/backend/src/core/entities/AbuseUserReportEntityService.ts b/packages/backend/src/core/entities/AbuseUserReportEntityService.ts
index b0e1d1ab36..a13c244c19 100644
--- a/packages/backend/src/core/entities/AbuseUserReportEntityService.ts
+++ b/packages/backend/src/core/entities/AbuseUserReportEntityService.ts
@@ -10,7 +10,6 @@ import { awaitAll } from '@/misc/prelude/await-all.js';
import type { MiAbuseUserReport } from '@/models/AbuseUserReport.js';
import { bindThis } from '@/decorators.js';
import { IdService } from '@/core/IdService.js';
-import { isNotNull } from '@/misc/is-not-null.js';
import type { Packed } from '@/misc/json-schema.js';
import { UserEntityService } from './UserEntityService.js';
@@ -63,7 +62,7 @@ export class AbuseUserReportEntityService {
) {
const _reporters = reports.map(({ reporter, reporterId }) => reporter ?? reporterId);
const _targetUsers = reports.map(({ targetUser, targetUserId }) => targetUser ?? targetUserId);
- const _assignees = reports.map(({ assignee, assigneeId }) => assignee ?? assigneeId).filter(isNotNull);
+ const _assignees = reports.map(({ assignee, assigneeId }) => assignee ?? assigneeId).filter(x => x != null);
const _userMap = await this.userEntityService.packMany(
[..._reporters, ..._targetUsers, ..._assignees],
null,
diff --git a/packages/backend/src/core/entities/ClipEntityService.ts b/packages/backend/src/core/entities/ClipEntityService.ts
index 3855a28436..d915645906 100644
--- a/packages/backend/src/core/entities/ClipEntityService.ts
+++ b/packages/backend/src/core/entities/ClipEntityService.ts
@@ -53,7 +53,7 @@ export class ClipEntityService {
isPublic: clip.isPublic,
favoritedCount: await this.clipFavoritesRepository.countBy({ clipId: clip.id }),
isFavorited: meId ? await this.clipFavoritesRepository.exists({ where: { clipId: clip.id, userId: meId } }) : undefined,
- notesCount: meId ? await this.clipNotesRepository.countBy({ clipId: clip.id }) : undefined,
+ notesCount: (meId === clip.userId) ? await this.clipNotesRepository.countBy({ clipId: clip.id }) : undefined,
});
}
diff --git a/packages/backend/src/core/entities/DriveFileEntityService.ts b/packages/backend/src/core/entities/DriveFileEntityService.ts
index 02ff2e7754..c485555f90 100644
--- a/packages/backend/src/core/entities/DriveFileEntityService.ts
+++ b/packages/backend/src/core/entities/DriveFileEntityService.ts
@@ -16,7 +16,6 @@ import { appendQuery, query } from '@/misc/prelude/url.js';
import { deepClone } from '@/misc/clone.js';
import { bindThis } from '@/decorators.js';
import { isMimeImage } from '@/misc/is-mime-image.js';
-import { isNotNull } from '@/misc/is-not-null.js';
import { IdService } from '@/core/IdService.js';
import { UtilityService } from '../UtilityService.js';
import { VideoProcessingService } from '../VideoProcessingService.js';
@@ -261,11 +260,11 @@ export class DriveFileEntityService {
files: MiDriveFile[],
options?: PackOptions,
): Promise<Packed<'DriveFile'>[]> {
- const _user = files.map(({ user, userId }) => user ?? userId).filter(isNotNull);
+ const _user = files.map(({ user, userId }) => user ?? userId).filter(x => x != null);
const _userMap = await this.userEntityService.packMany(_user)
.then(users => new Map(users.map(user => [user.id, user])));
const items = await Promise.all(files.map(f => this.packNullable(f, options, f.userId ? { packedUser: _userMap.get(f.userId) } : {})));
- return items.filter(isNotNull);
+ return items.filter(x => x != null);
}
@bindThis
@@ -290,6 +289,6 @@ export class DriveFileEntityService {
): Promise<Packed<'DriveFile'>[]> {
if (fileIds.length === 0) return [];
const filesMap = await this.packManyByIdsMap(fileIds, options);
- return fileIds.map(id => filesMap.get(id)).filter(isNotNull);
+ return fileIds.map(id => filesMap.get(id)).filter(x => x != null);
}
}
diff --git a/packages/backend/src/core/entities/InstanceEntityService.ts b/packages/backend/src/core/entities/InstanceEntityService.ts
index 9117b13914..4c45c13167 100644
--- a/packages/backend/src/core/entities/InstanceEntityService.ts
+++ b/packages/backend/src/core/entities/InstanceEntityService.ts
@@ -50,6 +50,7 @@ export class InstanceEntityService {
maintainerName: instance.maintainerName,
maintainerEmail: instance.maintainerEmail,
isSilenced: this.utilityService.isSilencedHost(meta.silencedHosts, instance.host),
+ isMediaSilenced: this.utilityService.isMediaSilencedHost(meta.mediaSilencedHosts, instance.host),
iconUrl: instance.iconUrl,
faviconUrl: instance.faviconUrl,
themeColor: instance.themeColor,
diff --git a/packages/backend/src/core/entities/InviteCodeEntityService.ts b/packages/backend/src/core/entities/InviteCodeEntityService.ts
index 26f57e1299..5d3e823a2a 100644
--- a/packages/backend/src/core/entities/InviteCodeEntityService.ts
+++ b/packages/backend/src/core/entities/InviteCodeEntityService.ts
@@ -12,7 +12,6 @@ import type { MiUser } from '@/models/User.js';
import type { MiRegistrationTicket } from '@/models/RegistrationTicket.js';
import { bindThis } from '@/decorators.js';
import { IdService } from '@/core/IdService.js';
-import { isNotNull } from '@/misc/is-not-null.js';
import { UserEntityService } from './UserEntityService.js';
@Injectable()
@@ -59,8 +58,8 @@ export class InviteCodeEntityService {
tickets: MiRegistrationTicket[],
me: { id: MiUser['id'] },
) {
- const _createdBys = tickets.map(({ createdBy, createdById }) => createdBy ?? createdById).filter(isNotNull);
- const _usedBys = tickets.map(({ usedBy, usedById }) => usedBy ?? usedById).filter(isNotNull);
+ const _createdBys = tickets.map(({ createdBy, createdById }) => createdBy ?? createdById).filter(x => x != null);
+ const _usedBys = tickets.map(({ usedBy, usedById }) => usedBy ?? usedById).filter(x => x != null);
const _userMap = await this.userEntityService.packMany([..._createdBys, ..._usedBys], me)
.then(users => new Map(users.map(u => [u.id, u])));
return Promise.all(
diff --git a/packages/backend/src/core/entities/MetaEntityService.ts b/packages/backend/src/core/entities/MetaEntityService.ts
index 5dfec589e1..44ec0d6a7b 100644
--- a/packages/backend/src/core/entities/MetaEntityService.ts
+++ b/packages/backend/src/core/entities/MetaEntityService.ts
@@ -50,6 +50,22 @@ export class MetaEntityService {
}))
.getMany();
+ // ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆã®æ‰‹é–“を減らã™ãŸã‚ã‚らã‹ã˜ã‚JSONã«å¤‰æ›ã—ã¦ãŠã
+ let defaultLightTheme = null;
+ let defaultDarkTheme = null;
+ if (instance.defaultLightTheme) {
+ try {
+ defaultLightTheme = JSON.stringify(JSON5.parse(instance.defaultLightTheme));
+ } catch (e) {
+ }
+ }
+ if (instance.defaultDarkTheme) {
+ try {
+ defaultDarkTheme = JSON.stringify(JSON5.parse(instance.defaultDarkTheme));
+ } catch (e) {
+ }
+ }
+
const packed: Packed<'MetaLite'> = {
maintainerName: instance.maintainerName,
maintainerEmail: instance.maintainerEmail,
@@ -90,9 +106,8 @@ export class MetaEntityService {
backgroundImageUrl: instance.backgroundImageUrl,
logoImageUrl: instance.logoImageUrl,
maxNoteTextLength: MAX_NOTE_TEXT_LENGTH,
- // ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆã®æ‰‹é–“を減らã™ãŸã‚ã‚らã‹ã˜ã‚JSONã«å¤‰æ›ã—ã¦ãŠã
- defaultLightTheme: instance.defaultLightTheme ? JSON.stringify(JSON5.parse(instance.defaultLightTheme)) : null,
- defaultDarkTheme: instance.defaultDarkTheme ? JSON.stringify(JSON5.parse(instance.defaultDarkTheme)) : null,
+ defaultLightTheme,
+ defaultDarkTheme,
ads: ads.map(ad => ({
id: ad.id,
url: ad.url,
@@ -113,6 +128,7 @@ export class MetaEntityService {
mediaProxy: this.config.mediaProxy,
enableUrlPreview: instance.urlPreviewEnabled,
+ noteSearchableScope: (this.config.meilisearch == null || this.config.meilisearch.scope !== 'local') ? 'global' : 'local',
};
return packed;
diff --git a/packages/backend/src/core/entities/NoteEntityService.ts b/packages/backend/src/core/entities/NoteEntityService.ts
index 2ce72c50b8..2cd092231c 100644
--- a/packages/backend/src/core/entities/NoteEntityService.ts
+++ b/packages/backend/src/core/entities/NoteEntityService.ts
@@ -14,7 +14,6 @@ import type { MiNote } from '@/models/Note.js';
import type { MiNoteReaction } from '@/models/NoteReaction.js';
import type { UsersRepository, NotesRepository, FollowingsRepository, PollsRepository, PollVotesRepository, NoteReactionsRepository, ChannelsRepository } from '@/models/_.js';
import { bindThis } from '@/decorators.js';
-import { isNotNull } from '@/misc/is-not-null.js';
import { DebounceLoader } from '@/misc/loader.js';
import { IdService } from '@/core/IdService.js';
import type { OnModuleInit } from '@nestjs/common';
@@ -276,7 +275,7 @@ export class NoteEntityService implements OnModuleInit {
packedFiles.set(k, v);
}
}
- return fileIds.map(id => packedFiles.get(id)).filter(isNotNull);
+ return fileIds.map(id => packedFiles.get(id)).filter(x => x != null);
}
@bindThis
@@ -449,12 +448,12 @@ export class NoteEntityService implements OnModuleInit {
await this.customEmojiService.prefetchEmojis(this.aggregateNoteEmojis(notes));
// TODO: 本当㯠renote ã¨ã‹ reply ãŒãªã„ã®ã« renoteId ã¨ã‹ replyId ãŒã‚ã£ãŸã‚‰ã“ã“ã§è§£æ±ºã—ã¦ãŠã
- const fileIds = notes.map(n => [n.fileIds, n.renote?.fileIds, n.reply?.fileIds]).flat(2).filter(isNotNull);
+ const fileIds = notes.map(n => [n.fileIds, n.renote?.fileIds, n.reply?.fileIds]).flat(2).filter(x => x != null);
const packedFiles = fileIds.length > 0 ? await this.driveFileEntityService.packManyByIdsMap(fileIds) : new Map();
const users = [
...notes.map(({ user, userId }) => user ?? userId),
- ...notes.map(({ replyUserId }) => replyUserId).filter(isNotNull),
- ...notes.map(({ renoteUserId }) => renoteUserId).filter(isNotNull),
+ ...notes.map(({ replyUserId }) => replyUserId).filter(x => x != null),
+ ...notes.map(({ renoteUserId }) => renoteUserId).filter(x => x != null),
];
const packedUsers = await this.userEntityService.packMany(users, me)
.then(users => new Map(users.map(u => [u.id, u])));
diff --git a/packages/backend/src/core/entities/NotificationEntityService.ts b/packages/backend/src/core/entities/NotificationEntityService.ts
index 94d56c883b..f393513510 100644
--- a/packages/backend/src/core/entities/NotificationEntityService.ts
+++ b/packages/backend/src/core/entities/NotificationEntityService.ts
@@ -13,7 +13,6 @@ import type { MiGroupedNotification, MiNotification } from '@/models/Notificatio
import type { MiNote } from '@/models/Note.js';
import type { Packed } from '@/misc/json-schema.js';
import { bindThis } from '@/decorators.js';
-import { isNotNull } from '@/misc/is-not-null.js';
import { FilterUnionByProperty, groupedNotificationTypes } from '@/types.js';
import { CacheService } from '@/core/CacheService.js';
import { RoleEntityService } from './RoleEntityService.js';
@@ -103,7 +102,7 @@ export class NotificationEntityService implements OnModuleInit {
user,
reaction: reaction.reaction,
};
- }))).filter(r => isNotNull(r.user));
+ }))).filter(r => r.user != null);
// if all users have been deleted, don't show this notification
if (reactions.length === 0) {
return null;
@@ -124,7 +123,7 @@ export class NotificationEntityService implements OnModuleInit {
}
return this.userEntityService.pack(userId, { id: meId });
- }))).filter(isNotNull);
+ }))).filter(x => x != null);
// if all users have been deleted, don't show this notification
if (users.length === 0) {
return null;
@@ -181,7 +180,7 @@ export class NotificationEntityService implements OnModuleInit {
validNotifications = await this.#filterValidNotifier(validNotifications, meId);
- const noteIds = validNotifications.map(x => 'noteId' in x ? x.noteId : null).filter(isNotNull);
+ const noteIds = validNotifications.map(x => 'noteId' in x ? x.noteId : null).filter(x => x != null);
const notes = noteIds.length > 0 ? await this.notesRepository.find({
where: { id: In(noteIds) },
relations: ['user', 'reply', 'reply.user', 'renote', 'renote.user'],
@@ -223,7 +222,7 @@ export class NotificationEntityService implements OnModuleInit {
);
});
- return (await Promise.all(packPromises)).filter(isNotNull);
+ return (await Promise.all(packPromises)).filter(x => x != null);
}
@bindThis
@@ -305,7 +304,7 @@ export class NotificationEntityService implements OnModuleInit {
this.cacheService.userProfileCache.fetch(meId).then(p => new Set(p.mutedInstances)),
]);
- const notifierIds = notifications.map(notification => 'notifierId' in notification ? notification.notifierId : null).filter(isNotNull);
+ const notifierIds = notifications.map(notification => 'notifierId' in notification ? notification.notifierId : null).filter(x => x != null);
const notifiers = notifierIds.length > 0 ? await this.usersRepository.find({
where: { id: In(notifierIds) },
}) : [];
@@ -313,7 +312,7 @@ export class NotificationEntityService implements OnModuleInit {
const filteredNotifications = ((await Promise.all(notifications.map(async (notification) => {
const isValid = this.#validateNotifier(notification, userIdsWhoMeMuting, userMutedInstances, notifiers);
return isValid ? notification : null;
- }))) as [T | null] ).filter(isNotNull);
+ }))) as [T | null] ).filter(x => x != null);
return filteredNotifications;
}
diff --git a/packages/backend/src/core/entities/PageEntityService.ts b/packages/backend/src/core/entities/PageEntityService.ts
index 142d9e81db..46bf51bb6d 100644
--- a/packages/backend/src/core/entities/PageEntityService.ts
+++ b/packages/backend/src/core/entities/PageEntityService.ts
@@ -14,7 +14,6 @@ import type { MiPage } from '@/models/Page.js';
import type { MiDriveFile } from '@/models/DriveFile.js';
import { bindThis } from '@/decorators.js';
import { IdService } from '@/core/IdService.js';
-import { isNotNull } from '@/misc/is-not-null.js';
import { UserEntityService } from './UserEntityService.js';
import { DriveFileEntityService } from './DriveFileEntityService.js';
@@ -106,7 +105,7 @@ export class PageEntityService {
script: page.script,
eyeCatchingImageId: page.eyeCatchingImageId,
eyeCatchingImage: page.eyeCatchingImageId ? await this.driveFileEntityService.pack(page.eyeCatchingImageId) : null,
- attachedFiles: this.driveFileEntityService.packMany((await Promise.all(attachedFiles)).filter(isNotNull)),
+ attachedFiles: this.driveFileEntityService.packMany((await Promise.all(attachedFiles)).filter(x => x != null)),
likedCount: page.likedCount,
isLiked: meId ? await this.pageLikesRepository.exists({ where: { pageId: page.id, userId: meId } }) : undefined,
});
diff --git a/packages/backend/src/core/entities/SystemWebhookEntityService.ts b/packages/backend/src/core/entities/SystemWebhookEntityService.ts
new file mode 100644
index 0000000000..e18734091c
--- /dev/null
+++ b/packages/backend/src/core/entities/SystemWebhookEntityService.ts
@@ -0,0 +1,74 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Inject, Injectable } from '@nestjs/common';
+import { In } from 'typeorm';
+import { DI } from '@/di-symbols.js';
+import type { MiSystemWebhook, SystemWebhooksRepository } from '@/models/_.js';
+import { bindThis } from '@/decorators.js';
+import { Packed } from '@/misc/json-schema.js';
+
+@Injectable()
+export class SystemWebhookEntityService {
+ constructor(
+ @Inject(DI.systemWebhooksRepository)
+ private systemWebhooksRepository: SystemWebhooksRepository,
+ ) {
+ }
+
+ @bindThis
+ public async pack(
+ src: MiSystemWebhook['id'] | MiSystemWebhook,
+ opts?: {
+ webhooks: Map<string, MiSystemWebhook>
+ },
+ ): Promise<Packed<'SystemWebhook'>> {
+ const webhook = typeof src === 'object'
+ ? src
+ : opts?.webhooks.get(src) ?? await this.systemWebhooksRepository.findOneByOrFail({ id: src });
+
+ return {
+ id: webhook.id,
+ isActive: webhook.isActive,
+ updatedAt: webhook.updatedAt.toISOString(),
+ latestSentAt: webhook.latestSentAt?.toISOString() ?? null,
+ latestStatus: webhook.latestStatus,
+ name: webhook.name,
+ on: webhook.on,
+ url: webhook.url,
+ secret: webhook.secret,
+ };
+ }
+
+ @bindThis
+ public async packMany(src: MiSystemWebhook['id'][] | MiSystemWebhook[]): Promise<Packed<'SystemWebhook'>[]> {
+ if (src.length === 0) {
+ return [];
+ }
+
+ const webhooks = Array.of<MiSystemWebhook>();
+ webhooks.push(
+ ...src.filter((it): it is MiSystemWebhook => typeof it === 'object'),
+ );
+
+ const ids = src.filter((it): it is MiSystemWebhook['id'] => typeof it === 'string');
+ if (ids.length > 0) {
+ webhooks.push(
+ ...await this.systemWebhooksRepository.findBy({ id: In(ids) }),
+ );
+ }
+
+ return Promise
+ .all(
+ webhooks.map(x =>
+ this.pack(x, {
+ webhooks: new Map(webhooks.map(x => [x.id, x])),
+ }),
+ ),
+ )
+ .then(it => it.sort((a, b) => a.id.localeCompare(b.id)));
+ }
+}
+
diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts
index b80a1ec206..7fd093c191 100644
--- a/packages/backend/src/core/entities/UserEntityService.ts
+++ b/packages/backend/src/core/entities/UserEntityService.ts
@@ -47,7 +47,6 @@ import { IdService } from '@/core/IdService.js';
import type { AnnouncementService } from '@/core/AnnouncementService.js';
import type { CustomEmojiService } from '@/core/CustomEmojiService.js';
import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
-import { isNotNull } from '@/misc/is-not-null.js';
import type { OnModuleInit } from '@nestjs/common';
import type { NoteEntityService } from './NoteEntityService.js';
import type { DriveFileEntityService } from './DriveFileEntityService.js';
@@ -502,11 +501,15 @@ export class UserEntityService implements OnModuleInit {
emojis: this.customEmojiService.populateEmojis(user.emojis, user.host),
onlineStatus: this.getOnlineStatus(user),
// パフォーマンス上ã®ç†ç”±ã§ãƒ­ãƒ¼ã‚«ãƒ«ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ã¿
- badgeRoles: user.host == null ? this.roleService.getUserBadgeRoles(user.id).then(rs => rs.sort((a, b) => b.displayOrder - a.displayOrder).map(r => ({
- name: r.name,
- iconUrl: r.iconUrl,
- displayOrder: r.displayOrder,
- }))) : undefined,
+ badgeRoles: user.host == null ? this.roleService.getUserBadgeRoles(user.id).then((rs) => rs
+ .filter((r) => r.isPublic || iAmModerator)
+ .sort((a, b) => b.displayOrder - a.displayOrder)
+ .map((r) => ({
+ name: r.name,
+ iconUrl: r.iconUrl,
+ displayOrder: r.displayOrder,
+ }))
+ ) : undefined,
...(isDetailed ? {
url: profile!.url,
@@ -514,7 +517,7 @@ export class UserEntityService implements OnModuleInit {
movedTo: user.movedToUri ? this.apPersonService.resolvePerson(user.movedToUri).then(user => user.id).catch(() => null) : null,
alsoKnownAs: user.alsoKnownAs
? Promise.all(user.alsoKnownAs.map(uri => this.apPersonService.fetchPerson(uri).then(user => user?.id).catch(() => null)))
- .then(xs => xs.length === 0 ? null : xs.filter(isNotNull))
+ .then(xs => xs.length === 0 ? null : xs.filter(x => x != null))
: null,
createdAt: this.idService.parse(user.id).date.toISOString(),
updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null,
diff --git a/packages/backend/src/di-symbols.ts b/packages/backend/src/di-symbols.ts
index 919f4794a3..271082b4ff 100644
--- a/packages/backend/src/di-symbols.ts
+++ b/packages/backend/src/di-symbols.ts
@@ -49,6 +49,7 @@ export const DI = {
swSubscriptionsRepository: Symbol('swSubscriptionsRepository'),
hashtagsRepository: Symbol('hashtagsRepository'),
abuseUserReportsRepository: Symbol('abuseUserReportsRepository'),
+ abuseReportNotificationRecipientRepository: Symbol('abuseReportNotificationRecipientRepository'),
registrationTicketsRepository: Symbol('registrationTicketsRepository'),
authSessionsRepository: Symbol('authSessionsRepository'),
accessTokensRepository: Symbol('accessTokensRepository'),
@@ -70,6 +71,7 @@ export const DI = {
channelFavoritesRepository: Symbol('channelFavoritesRepository'),
registryItemsRepository: Symbol('registryItemsRepository'),
webhooksRepository: Symbol('webhooksRepository'),
+ systemWebhooksRepository: Symbol('systemWebhooksRepository'),
adsRepository: Symbol('adsRepository'),
passwordResetRequestsRepository: Symbol('passwordResetRequestsRepository'),
retentionAggregationsRepository: Symbol('retentionAggregationsRepository'),
diff --git a/packages/backend/src/logger.ts b/packages/backend/src/logger.ts
index d4705af601..ff5363a425 100644
--- a/packages/backend/src/logger.ts
+++ b/packages/backend/src/logger.ts
@@ -22,31 +22,27 @@ type Level = 'error' | 'success' | 'warning' | 'debug' | 'info';
export default class Logger {
private context: Context;
private parentLogger: Logger | null = null;
- private store: boolean;
- constructor(context: string, color?: KEYWORD, store = true) {
+ constructor(context: string, color?: KEYWORD) {
this.context = {
name: context,
color: color,
};
- this.store = store;
}
@bindThis
- public createSubLogger(context: string, color?: KEYWORD, store = true): Logger {
- const logger = new Logger(context, color, store);
+ public createSubLogger(context: string, color?: KEYWORD): Logger {
+ const logger = new Logger(context, color);
logger.parentLogger = this;
return logger;
}
@bindThis
- private log(level: Level, message: string, data?: Record<string, any> | null, important = false, subContexts: Context[] = [], store = true): void {
+ private log(level: Level, message: string, data?: Record<string, any> | null, important = false, subContexts: Context[] = []): void {
if (envOption.quiet) return;
- if (!this.store) store = false;
- if (level === 'debug') store = false;
if (this.parentLogger) {
- this.parentLogger.log(level, message, data, important, [this.context].concat(subContexts), store);
+ this.parentLogger.log(level, message, data, important, [this.context].concat(subContexts));
return;
}
diff --git a/packages/backend/src/misc/is-not-null.ts b/packages/backend/src/misc/is-not-null.ts
deleted file mode 100644
index 8d9dc8bb39..0000000000
--- a/packages/backend/src/misc/is-not-null.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export function isNotNull<T extends NonNullable<unknown>>(input: T | undefined | null): input is T {
- return input != null;
-}
diff --git a/packages/backend/src/misc/is-user-related.ts b/packages/backend/src/misc/is-user-related.ts
index 93c9b2b814..862d6e6a38 100644
--- a/packages/backend/src/misc/is-user-related.ts
+++ b/packages/backend/src/misc/is-user-related.ts
@@ -4,6 +4,10 @@
*/
export function isUserRelated(note: any, userIds: Set<string>, ignoreAuthor = false): boolean {
+ if (!note) {
+ return false;
+ }
+
if (userIds.has(note.userId) && !ignoreAuthor) {
return true;
}
diff --git a/packages/backend/src/misc/json-schema.ts b/packages/backend/src/misc/json-schema.ts
index 41e5bfe9e4..a721b8663c 100644
--- a/packages/backend/src/misc/json-schema.ts
+++ b/packages/backend/src/misc/json-schema.ts
@@ -4,12 +4,12 @@
*/
import {
- packedUserLiteSchema,
- packedUserDetailedNotMeOnlySchema,
packedMeDetailedOnlySchema,
- packedUserDetailedNotMeSchema,
packedMeDetailedSchema,
+ packedUserDetailedNotMeOnlySchema,
+ packedUserDetailedNotMeSchema,
packedUserDetailedSchema,
+ packedUserLiteSchema,
packedUserSchema,
} from '@/models/json-schema/user.js';
import { packedNoteSchema } from '@/models/json-schema/note.js';
@@ -25,7 +25,7 @@ import { packedBlockingSchema } from '@/models/json-schema/blocking.js';
import { packedNoteReactionSchema } from '@/models/json-schema/note-reaction.js';
import { packedHashtagSchema } from '@/models/json-schema/hashtag.js';
import { packedInviteCodeSchema } from '@/models/json-schema/invite-code.js';
-import { packedPageSchema, packedPageBlockSchema } from '@/models/json-schema/page.js';
+import { packedPageBlockSchema, packedPageSchema } from '@/models/json-schema/page.js';
import { packedNoteFavoriteSchema } from '@/models/json-schema/note-favorite.js';
import { packedChannelSchema } from '@/models/json-schema/channel.js';
import { packedAntennaSchema } from '@/models/json-schema/antenna.js';
@@ -38,25 +38,27 @@ import { packedFlashSchema } from '@/models/json-schema/flash.js';
import { packedAnnouncementSchema } from '@/models/json-schema/announcement.js';
import { packedSigninSchema } from '@/models/json-schema/signin.js';
import {
- packedRoleLiteSchema,
- packedRoleSchema,
- packedRolePoliciesSchema,
+ packedRoleCondFormulaFollowersOrFollowingOrNotesSchema,
packedRoleCondFormulaLogicsSchema,
- packedRoleCondFormulaValueNot,
- packedRoleCondFormulaValueIsLocalOrRemoteSchema,
packedRoleCondFormulaValueAssignedRoleSchema,
packedRoleCondFormulaValueCreatedSchema,
- packedRoleCondFormulaFollowersOrFollowingOrNotesSchema,
+ packedRoleCondFormulaValueIsLocalOrRemoteSchema,
+ packedRoleCondFormulaValueNot,
packedRoleCondFormulaValueSchema,
packedRoleCondFormulaValueUserSettingBooleanSchema,
+ packedRoleLiteSchema,
+ packedRolePoliciesSchema,
+ packedRoleSchema,
} from '@/models/json-schema/role.js';
import { packedAdSchema } from '@/models/json-schema/ad.js';
-import { packedReversiGameLiteSchema, packedReversiGameDetailedSchema } from '@/models/json-schema/reversi-game.js';
+import { packedReversiGameDetailedSchema, packedReversiGameLiteSchema } from '@/models/json-schema/reversi-game.js';
import {
- packedMetaLiteSchema,
packedMetaDetailedOnlySchema,
packedMetaDetailedSchema,
+ packedMetaLiteSchema,
} from '@/models/json-schema/meta.js';
+import { packedSystemWebhookSchema } from '@/models/json-schema/system-webhook.js';
+import { packedAbuseReportNotificationRecipientSchema } from '@/models/json-schema/abuse-report-notification-recipient.js';
export const refs = {
UserLite: packedUserLiteSchema,
@@ -111,6 +113,8 @@ export const refs = {
MetaLite: packedMetaLiteSchema,
MetaDetailedOnly: packedMetaDetailedOnlySchema,
MetaDetailed: packedMetaDetailedSchema,
+ SystemWebhook: packedSystemWebhookSchema,
+ AbuseReportNotificationRecipient: packedAbuseReportNotificationRecipientSchema,
};
export type Packed<x extends keyof typeof refs> = SchemaType<typeof refs[x]>;
diff --git a/packages/backend/src/misc/json-value.ts b/packages/backend/src/misc/json-value.ts
new file mode 100644
index 0000000000..7994441791
--- /dev/null
+++ b/packages/backend/src/misc/json-value.ts
@@ -0,0 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export type JsonValue = JsonArray | JsonObject | string | number | boolean | null;
+export type JsonObject = {[K in string]?: JsonValue};
+export type JsonArray = JsonValue[];
diff --git a/packages/backend/src/misc/prelude/array.ts b/packages/backend/src/misc/prelude/array.ts
index dbfe1fff18..f741a0c913 100644
--- a/packages/backend/src/misc/prelude/array.ts
+++ b/packages/backend/src/misc/prelude/array.ts
@@ -66,44 +66,6 @@ export function maximum(xs: number[]): number {
}
/**
- * Splits an array based on the equivalence relation.
- * The concatenation of the result is equal to the argument.
- */
-export function groupBy<T>(f: EndoRelation<T>, xs: T[]): T[][] {
- const groups = [] as T[][];
- for (const x of xs) {
- const lastGroup = groups.at(-1);
- if (lastGroup !== undefined && f(lastGroup[0], x)) {
- lastGroup.push(x);
- } else {
- groups.push([x]);
- }
- }
- return groups;
-}
-
-/**
- * Splits an array based on the equivalence relation induced by the function.
- * The concatenation of the result is equal to the argument.
- */
-export function groupOn<T, S>(f: (x: T) => S, xs: T[]): T[][] {
- return groupBy((a, b) => f(a) === f(b), xs);
-}
-
-export function groupByX<T>(collections: T[], keySelector: (x: T) => string) {
- return collections.reduce((obj: Record<string, T[]>, item: T) => {
- const key = keySelector(item);
- if (!Object.prototype.hasOwnProperty.call(obj, key)) {
- obj[key] = [];
- }
-
- obj[key].push(item);
-
- return obj;
- }, {});
-}
-
-/**
* Compare two arrays by lexicographical order
*/
export function lessThan(xs: number[], ys: number[]): boolean {
diff --git a/packages/backend/src/misc/prelude/maybe.ts b/packages/backend/src/misc/prelude/maybe.ts
deleted file mode 100644
index 1c58ccb9c7..0000000000
--- a/packages/backend/src/misc/prelude/maybe.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export interface IMaybe<T> {
- isJust(): this is IJust<T>;
-}
-
-export interface IJust<T> extends IMaybe<T> {
- get(): T;
-}
-
-export function just<T>(value: T): IJust<T> {
- return {
- isJust: () => true,
- get: () => value,
- };
-}
-
-export function nothing<T>(): IMaybe<T> {
- return {
- isJust: () => false,
- };
-}
diff --git a/packages/backend/src/misc/prelude/string.ts b/packages/backend/src/misc/prelude/string.ts
deleted file mode 100644
index 67ea529961..0000000000
--- a/packages/backend/src/misc/prelude/string.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export function concat(xs: string[]): string {
- return xs.join('');
-}
-
-export function capitalize(s: string): string {
- return toUpperCase(s.charAt(0)) + toLowerCase(s.slice(1));
-}
-
-export function toUpperCase(s: string): string {
- return s.toUpperCase();
-}
-
-export function toLowerCase(s: string): string {
- return s.toLowerCase();
-}
diff --git a/packages/backend/src/models/AbuseReportNotificationRecipient.ts b/packages/backend/src/models/AbuseReportNotificationRecipient.ts
new file mode 100644
index 0000000000..fbff880afc
--- /dev/null
+++ b/packages/backend/src/models/AbuseReportNotificationRecipient.ts
@@ -0,0 +1,100 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Column, Entity, Index, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm';
+import { MiSystemWebhook } from '@/models/SystemWebhook.js';
+import { MiUserProfile } from '@/models/UserProfile.js';
+import { id } from './util/id.js';
+import { MiUser } from './User.js';
+
+/**
+ * 通報å—信時ã«é€šçŸ¥ã‚’é€ä¿¡ã™ã‚‹æ–¹æ³•.
+ */
+export type RecipientMethod = 'email' | 'webhook';
+
+@Entity('abuse_report_notification_recipient')
+export class MiAbuseReportNotificationRecipient {
+ @PrimaryColumn(id())
+ public id: string;
+
+ /**
+ * 有効ã‹ã©ã†ã‹.
+ */
+ @Index()
+ @Column('boolean', {
+ default: true,
+ })
+ public isActive: boolean;
+
+ /**
+ * 更新日時.
+ */
+ @Column('timestamp with time zone', {
+ default: () => 'CURRENT_TIMESTAMP',
+ })
+ public updatedAt: Date;
+
+ /**
+ * 通知設定å.
+ */
+ @Column('varchar', {
+ length: 255,
+ })
+ public name: string;
+
+ /**
+ * 通知方法.
+ */
+ @Index()
+ @Column('varchar', {
+ length: 64,
+ })
+ public method: RecipientMethod;
+
+ /**
+ * 通知先ã®ãƒ¦ãƒ¼ã‚¶ID.
+ */
+ @Index()
+ @Column({
+ ...id(),
+ nullable: true,
+ })
+ public userId: MiUser['id'] | null;
+
+ /**
+ * 通知先ã®ãƒ¦ãƒ¼ã‚¶.
+ */
+ @ManyToOne(type => MiUser, {
+ onDelete: 'CASCADE',
+ })
+ @JoinColumn({ name: 'userId', referencedColumnName: 'id', foreignKeyConstraintName: 'FK_abuse_report_notification_recipient_userId1' })
+ public user: MiUser | null;
+
+ /**
+ * 通知先ã®ãƒ¦ãƒ¼ã‚¶ãƒ—ロフィール.
+ */
+ @ManyToOne(type => MiUserProfile, {})
+ @JoinColumn({ name: 'userId', referencedColumnName: 'userId', foreignKeyConstraintName: 'FK_abuse_report_notification_recipient_userId2' })
+ public userProfile: MiUserProfile | null;
+
+ /**
+ * 通知先ã®ã‚·ã‚¹ãƒ†ãƒ WebhookId.
+ */
+ @Index()
+ @Column({
+ ...id(),
+ nullable: true,
+ })
+ public systemWebhookId: string | null;
+
+ /**
+ * 通知先ã®ã‚·ã‚¹ãƒ†ãƒ Webhook.
+ */
+ @ManyToOne(type => MiSystemWebhook, {
+ onDelete: 'CASCADE',
+ })
+ @JoinColumn()
+ public systemWebhook: MiSystemWebhook | null;
+}
diff --git a/packages/backend/src/models/DriveFile.ts b/packages/backend/src/models/DriveFile.ts
index 438b32f79a..7b03e3e494 100644
--- a/packages/backend/src/models/DriveFile.ts
+++ b/packages/backend/src/models/DriveFile.ts
@@ -82,7 +82,7 @@ export class MiDriveFile {
public storedInternal: boolean;
@Column('varchar', {
- length: 512,
+ length: 1024,
comment: 'The URL of the DriveFile.',
})
public url: string;
@@ -124,13 +124,13 @@ export class MiDriveFile {
@Index()
@Column('varchar', {
- length: 512, nullable: true,
+ length: 1024, nullable: true,
comment: 'The URI of the DriveFile. it will be null when the DriveFile is local.',
})
public uri: string | null;
@Column('varchar', {
- length: 512, nullable: true,
+ length: 1024, nullable: true,
})
public src: string | null;
diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts
index ad306fcad6..70d41801b5 100644
--- a/packages/backend/src/models/Meta.ts
+++ b/packages/backend/src/models/Meta.ts
@@ -87,6 +87,11 @@ export class MiMeta {
public silencedHosts: string[];
@Column('varchar', {
+ length: 1024, array: true, default: '{}',
+ })
+ public mediaSilencedHosts: string[];
+
+ @Column('varchar', {
length: 1024,
nullable: true,
})
diff --git a/packages/backend/src/models/RepositoryModule.ts b/packages/backend/src/models/RepositoryModule.ts
index d3062d6b36..ea0f88baba 100644
--- a/packages/backend/src/models/RepositoryModule.ts
+++ b/packages/backend/src/models/RepositoryModule.ts
@@ -3,11 +3,83 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
+import type { Provider } from '@nestjs/common';
import { Module } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
-import { MiRepository, MiAbuseUserReport, MiAccessToken, MiAd, MiAnnouncement, MiAnnouncementRead, MiAntenna, MiApp, MiAuthSession, MiAvatarDecoration, MiBlocking, MiChannel, MiChannelFavorite, MiChannelFollowing, MiClip, MiClipFavorite, MiClipNote, MiDriveFile, MiDriveFolder, MiEmoji, MiFlash, MiFlashLike, MiFollowRequest, MiFollowing, MiGalleryLike, MiGalleryPost, MiHashtag, MiInstance, MiMeta, MiModerationLog, MiMuting, MiNote, MiNoteFavorite, MiNoteReaction, MiNoteThreadMuting, MiNoteUnread, MiPage, MiPageLike, MiPasswordResetRequest, MiPoll, MiPollVote, MiPromoNote, MiPromoRead, MiRegistrationTicket, MiRegistryItem, MiRelay, MiRenoteMuting, MiRetentionAggregation, MiRole, MiRoleAssignment, MiSignin, MiSwSubscription, MiUsedUsername, MiUser, MiUserIp, MiUserKeypair, MiUserList, MiUserListFavorite, MiUserListMembership, MiUserMemo, MiUserNotePining, MiUserPending, MiUserProfile, MiUserPublickey, MiUserSecurityKey, MiWebhook, MiBubbleGameRecord, MiReversiGame, miRepository } from './_.js';
+import {
+ MiAbuseReportNotificationRecipient,
+ MiAbuseUserReport,
+ MiAccessToken,
+ MiAd,
+ MiAnnouncement,
+ MiAnnouncementRead,
+ MiAntenna,
+ MiApp,
+ MiAuthSession,
+ MiAvatarDecoration,
+ MiBlocking,
+ MiBubbleGameRecord,
+ MiChannel,
+ MiChannelFavorite,
+ MiChannelFollowing,
+ MiClip,
+ MiClipFavorite,
+ MiClipNote,
+ MiDriveFile,
+ MiDriveFolder,
+ MiEmoji,
+ MiFlash,
+ MiFlashLike,
+ MiFollowing,
+ MiFollowRequest,
+ MiGalleryLike,
+ MiGalleryPost,
+ MiHashtag,
+ MiInstance,
+ MiMeta,
+ MiModerationLog,
+ MiMuting,
+ MiNote,
+ MiNoteFavorite,
+ MiNoteReaction,
+ MiNoteThreadMuting,
+ MiNoteUnread,
+ MiPage,
+ MiPageLike,
+ MiPasswordResetRequest,
+ MiPoll,
+ MiPollVote,
+ MiPromoNote,
+ MiPromoRead,
+ MiRegistrationTicket,
+ MiRegistryItem,
+ MiRelay,
+ MiRenoteMuting,
+ MiRepository,
+ miRepository,
+ MiRetentionAggregation,
+ MiReversiGame,
+ MiRole,
+ MiRoleAssignment,
+ MiSignin,
+ MiSwSubscription,
+ MiSystemWebhook,
+ MiUsedUsername,
+ MiUser,
+ MiUserIp,
+ MiUserKeypair,
+ MiUserList,
+ MiUserListFavorite,
+ MiUserListMembership,
+ MiUserMemo,
+ MiUserNotePining,
+ MiUserPending,
+ MiUserProfile,
+ MiUserPublickey,
+ MiUserSecurityKey,
+ MiWebhook
+} from './_.js';
import type { DataSource } from 'typeorm';
-import type { Provider } from '@nestjs/common';
const $usersRepository: Provider = {
provide: DI.usersRepository,
@@ -225,6 +297,12 @@ const $abuseUserReportsRepository: Provider = {
inject: [DI.db],
};
+const $abuseReportNotificationRecipientRepository: Provider = {
+ provide: DI.abuseReportNotificationRecipientRepository,
+ useFactory: (db: DataSource) => db.getRepository(MiAbuseReportNotificationRecipient),
+ inject: [DI.db],
+};
+
const $registrationTicketsRepository: Provider = {
provide: DI.registrationTicketsRepository,
useFactory: (db: DataSource) => db.getRepository(MiRegistrationTicket).extend(miRepository as MiRepository<MiRegistrationTicket>),
@@ -351,6 +429,12 @@ const $webhooksRepository: Provider = {
inject: [DI.db],
};
+const $systemWebhooksRepository: Provider = {
+ provide: DI.systemWebhooksRepository,
+ useFactory: (db: DataSource) => db.getRepository(MiSystemWebhook),
+ inject: [DI.db],
+};
+
const $adsRepository: Provider = {
provide: DI.adsRepository,
useFactory: (db: DataSource) => db.getRepository(MiAd).extend(miRepository as MiRepository<MiAd>),
@@ -412,8 +496,7 @@ const $reversiGamesRepository: Provider = {
};
@Module({
- imports: [
- ],
+ imports: [],
providers: [
$usersRepository,
$notesRepository,
@@ -451,6 +534,7 @@ const $reversiGamesRepository: Provider = {
$swSubscriptionsRepository,
$hashtagsRepository,
$abuseUserReportsRepository,
+ $abuseReportNotificationRecipientRepository,
$registrationTicketsRepository,
$authSessionsRepository,
$accessTokensRepository,
@@ -472,6 +556,7 @@ const $reversiGamesRepository: Provider = {
$channelFavoritesRepository,
$registryItemsRepository,
$webhooksRepository,
+ $systemWebhooksRepository,
$adsRepository,
$passwordResetRequestsRepository,
$retentionAggregationsRepository,
@@ -520,6 +605,7 @@ const $reversiGamesRepository: Provider = {
$swSubscriptionsRepository,
$hashtagsRepository,
$abuseUserReportsRepository,
+ $abuseReportNotificationRecipientRepository,
$registrationTicketsRepository,
$authSessionsRepository,
$accessTokensRepository,
@@ -541,6 +627,7 @@ const $reversiGamesRepository: Provider = {
$channelFavoritesRepository,
$registryItemsRepository,
$webhooksRepository,
+ $systemWebhooksRepository,
$adsRepository,
$passwordResetRequestsRepository,
$retentionAggregationsRepository,
@@ -553,4 +640,5 @@ const $reversiGamesRepository: Provider = {
$reversiGamesRepository,
],
})
-export class RepositoryModule {}
+export class RepositoryModule {
+}
diff --git a/packages/backend/src/models/SystemWebhook.ts b/packages/backend/src/models/SystemWebhook.ts
new file mode 100644
index 0000000000..d6c27eae51
--- /dev/null
+++ b/packages/backend/src/models/SystemWebhook.ts
@@ -0,0 +1,100 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Column, Entity, Index, PrimaryColumn } from 'typeorm';
+import { Serialized } from '@/types.js';
+import { id } from './util/id.js';
+
+export const systemWebhookEventTypes = [
+ // ユーザã‹ã‚‰ã®é€šå ±ã‚’å—ã‘ãŸã¨ã
+ 'abuseReport',
+ // 通報を処ç†ã—ãŸã¨ã
+ 'abuseReportResolved',
+ // ユーザãŒä½œæˆã•ã‚ŒãŸæ™‚
+ 'userCreated',
+] as const;
+export type SystemWebhookEventType = typeof systemWebhookEventTypes[number];
+
+@Entity('system_webhook')
+export class MiSystemWebhook {
+ @PrimaryColumn(id())
+ public id: string;
+
+ /**
+ * 有効ã‹ã©ã†ã‹.
+ */
+ @Index('IDX_system_webhook_isActive', { synchronize: false })
+ @Column('boolean', {
+ default: true,
+ })
+ public isActive: boolean;
+
+ /**
+ * 更新日時.
+ */
+ @Column('timestamp with time zone', {
+ default: () => 'CURRENT_TIMESTAMP',
+ })
+ public updatedAt: Date;
+
+ /**
+ * 最後ã«é€ä¿¡ã•ã‚ŒãŸæ—¥æ™‚.
+ */
+ @Column('timestamp with time zone', {
+ nullable: true,
+ })
+ public latestSentAt: Date | null;
+
+ /**
+ * 最後ã«é€ä¿¡ã•れãŸã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹ã‚³ãƒ¼ãƒ‰
+ */
+ @Column('integer', {
+ nullable: true,
+ })
+ public latestStatus: number | null;
+
+ /**
+ * 通知設定å.
+ */
+ @Column('varchar', {
+ length: 255,
+ })
+ public name: string;
+
+ /**
+ * イベント種別.
+ */
+ @Index('IDX_system_webhook_on', { synchronize: false })
+ @Column('varchar', {
+ length: 128,
+ array: true,
+ default: '{}',
+ })
+ public on: SystemWebhookEventType[];
+
+ /**
+ * Webhooké€ä¿¡å…ˆã®URL.
+ */
+ @Column('varchar', {
+ length: 1024,
+ })
+ public url: string;
+
+ /**
+ * Webhook検証用ã®å€¤.
+ */
+ @Column('varchar', {
+ length: 1024,
+ })
+ public secret: string;
+
+ static deserialize(obj: Serialized<MiSystemWebhook>): MiSystemWebhook {
+ return {
+ ...obj,
+ updatedAt: new Date(obj.updatedAt),
+ latestSentAt: obj.latestSentAt ? new Date(obj.latestSentAt) : null,
+ };
+ }
+}
diff --git a/packages/backend/src/models/_.ts b/packages/backend/src/models/_.ts
index 2e6a41586e..c72bdaa727 100644
--- a/packages/backend/src/models/_.ts
+++ b/packages/backend/src/models/_.ts
@@ -11,6 +11,7 @@ import { RawSqlResultsToEntityTransformer } from 'typeorm/query-builder/transfor
import { ObjectUtils } from 'typeorm/util/ObjectUtils.js';
import { OrmUtils } from 'typeorm/util/OrmUtils.js';
import { MiAbuseUserReport } from '@/models/AbuseUserReport.js';
+import { MiAbuseReportNotificationRecipient } from '@/models/AbuseReportNotificationRecipient.js';
import { MiAccessToken } from '@/models/AccessToken.js';
import { MiAd } from '@/models/Ad.js';
import { MiAnnouncement } from '@/models/Announcement.js';
@@ -68,6 +69,7 @@ import { MiUserPublickey } from '@/models/UserPublickey.js';
import { MiUserSecurityKey } from '@/models/UserSecurityKey.js';
import { MiUserMemo } from '@/models/UserMemo.js';
import { MiWebhook } from '@/models/Webhook.js';
+import { MiSystemWebhook } from '@/models/SystemWebhook.js';
import { MiChannel } from '@/models/Channel.js';
import { MiRetentionAggregation } from '@/models/RetentionAggregation.js';
import { MiRole } from '@/models/Role.js';
@@ -80,34 +82,14 @@ import { MiReversiGame } from '@/models/ReversiGame.js';
import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity.js';
export interface MiRepository<T extends ObjectLiteral> {
- createTableColumnNames(this: Repository<T> & MiRepository<T>, queryBuilder: InsertQueryBuilder<T>): string[];
- createTableColumnNamesWithPrimaryKey(this: Repository<T> & MiRepository<T>, queryBuilder: InsertQueryBuilder<T>): string[];
+ createTableColumnNames(this: Repository<T> & MiRepository<T>): string[];
insertOne(this: Repository<T> & MiRepository<T>, entity: QueryDeepPartialEntity<T>, findOptions?: Pick<FindOneOptions<T>, 'relations'>): Promise<T>;
selectAliasColumnNames(this: Repository<T> & MiRepository<T>, queryBuilder: InsertQueryBuilder<T>, builder: SelectQueryBuilder<T>): void;
}
export const miRepository = {
- createTableColumnNames(queryBuilder) {
- // @ts-expect-error -- protected
- const insertedColumns = queryBuilder.getInsertedColumns();
- if (insertedColumns.length) {
- return insertedColumns.map(column => column.databaseName);
- }
- if (!queryBuilder.expressionMap.mainAlias?.hasMetadata && !queryBuilder.expressionMap.insertColumns.length) {
- // @ts-expect-error -- protected
- const valueSets = queryBuilder.getValueSets();
- if (valueSets.length === 1) {
- return Object.keys(valueSets[0]);
- }
- }
- return queryBuilder.expressionMap.insertColumns;
- },
- createTableColumnNamesWithPrimaryKey(queryBuilder) {
- const columnNames = this.createTableColumnNames(queryBuilder);
- if (!columnNames.includes('id')) {
- columnNames.unshift('id');
- }
- return columnNames;
+ createTableColumnNames() {
+ return this.metadata.columns.filter(column => column.isSelect && !column.isVirtual).map(column => column.databaseName);
},
async insertOne(entity, findOptions?) {
const queryBuilder = this.createQueryBuilder().insert().values(entity);
@@ -115,7 +97,7 @@ export const miRepository = {
const mainAlias = queryBuilder.expressionMap.mainAlias!;
const name = mainAlias.name;
mainAlias.name = 't';
- const columnNames = this.createTableColumnNamesWithPrimaryKey(queryBuilder);
+ const columnNames = this.createTableColumnNames();
queryBuilder.returning(columnNames.reduce((a, c) => `${a}, ${queryBuilder.escape(c)}`, '').slice(2));
const builder = this.createQueryBuilder().addCommonTableExpression(queryBuilder, 'cte', { columnNames });
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -136,7 +118,7 @@ export const miRepository = {
selectOrAddSelect = (selection, selectionAliasName) => builder.addSelect(selection, selectionAliasName);
return builder.select(selection, selectionAliasName);
};
- for (const columnName of this.createTableColumnNamesWithPrimaryKey(queryBuilder)) {
+ for (const columnName of this.createTableColumnNames()) {
selectOrAddSelect(`${builder.alias}.${columnName}`, `${builder.alias}_${columnName}`);
}
},
@@ -144,6 +126,7 @@ export const miRepository = {
export {
MiAbuseUserReport,
+ MiAbuseReportNotificationRecipient,
MiAccessToken,
MiAd,
MiAnnouncement,
@@ -201,6 +184,7 @@ export {
MiUserPublickey,
MiUserSecurityKey,
MiWebhook,
+ MiSystemWebhook,
MiChannel,
MiRetentionAggregation,
MiRole,
@@ -213,6 +197,7 @@ export {
};
export type AbuseUserReportsRepository = Repository<MiAbuseUserReport> & MiRepository<MiAbuseUserReport>;
+export type AbuseReportNotificationRecipientRepository = Repository<MiAbuseReportNotificationRecipient> & MiRepository<MiAbuseReportNotificationRecipient>;
export type AccessTokensRepository = Repository<MiAccessToken> & MiRepository<MiAccessToken>;
export type AdsRepository = Repository<MiAd> & MiRepository<MiAd>;
export type AnnouncementsRepository = Repository<MiAnnouncement> & MiRepository<MiAnnouncement>;
@@ -270,6 +255,7 @@ export type UserProfilesRepository = Repository<MiUserProfile> & MiRepository<Mi
export type UserPublickeysRepository = Repository<MiUserPublickey> & MiRepository<MiUserPublickey>;
export type UserSecurityKeysRepository = Repository<MiUserSecurityKey> & MiRepository<MiUserSecurityKey>;
export type WebhooksRepository = Repository<MiWebhook> & MiRepository<MiWebhook>;
+export type SystemWebhooksRepository = Repository<MiSystemWebhook> & MiRepository<MiWebhook>;
export type ChannelsRepository = Repository<MiChannel> & MiRepository<MiChannel>;
export type RetentionAggregationsRepository = Repository<MiRetentionAggregation> & MiRepository<MiRetentionAggregation>;
export type RolesRepository = Repository<MiRole> & MiRepository<MiRole>;
diff --git a/packages/backend/src/models/json-schema/abuse-report-notification-recipient.ts b/packages/backend/src/models/json-schema/abuse-report-notification-recipient.ts
new file mode 100644
index 0000000000..6215f0f5a2
--- /dev/null
+++ b/packages/backend/src/models/json-schema/abuse-report-notification-recipient.ts
@@ -0,0 +1,50 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export const packedAbuseReportNotificationRecipientSchema = {
+ type: 'object',
+ properties: {
+ id: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ isActive: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
+ updatedAt: {
+ type: 'string',
+ format: 'date-time',
+ optional: false, nullable: false,
+ },
+ name: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ method: {
+ type: 'string',
+ optional: false, nullable: false,
+ enum: ['email', 'webhook'],
+ },
+ userId: {
+ type: 'string',
+ optional: true, nullable: false,
+ },
+ user: {
+ type: 'object',
+ optional: true, nullable: false,
+ ref: 'UserLite',
+ },
+ systemWebhookId: {
+ type: 'string',
+ optional: true, nullable: false,
+ },
+ systemWebhook: {
+ type: 'object',
+ optional: true, nullable: false,
+ ref: 'SystemWebhook',
+ },
+ },
+} as const;
diff --git a/packages/backend/src/models/json-schema/drive-file.ts b/packages/backend/src/models/json-schema/drive-file.ts
index ca88cc0e39..5ee1561c50 100644
--- a/packages/backend/src/models/json-schema/drive-file.ts
+++ b/packages/backend/src/models/json-schema/drive-file.ts
@@ -20,7 +20,7 @@ export const packedDriveFileSchema = {
name: {
type: 'string',
optional: false, nullable: false,
- example: 'lenna.jpg',
+ example: '192.jpg',
},
type: {
type: 'string',
diff --git a/packages/backend/src/models/json-schema/federation-instance.ts b/packages/backend/src/models/json-schema/federation-instance.ts
index ed40d405c6..912a0399d8 100644
--- a/packages/backend/src/models/json-schema/federation-instance.ts
+++ b/packages/backend/src/models/json-schema/federation-instance.ts
@@ -88,6 +88,10 @@ export const packedFederationInstanceSchema = {
type: 'boolean',
optional: false, nullable: false,
},
+ isMediaSilenced: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
iconUrl: {
type: 'string',
optional: false, nullable: true,
diff --git a/packages/backend/src/models/json-schema/meta.ts b/packages/backend/src/models/json-schema/meta.ts
index e7bc6356e5..3bcf9cac92 100644
--- a/packages/backend/src/models/json-schema/meta.ts
+++ b/packages/backend/src/models/json-schema/meta.ts
@@ -247,6 +247,12 @@ export const packedMetaLiteSchema = {
optional: false, nullable: false,
ref: 'RolePolicies',
},
+ noteSearchableScope: {
+ type: 'string',
+ enum: ['local', 'global'],
+ optional: false, nullable: false,
+ default: 'local',
+ },
},
} as const;
diff --git a/packages/backend/src/models/json-schema/note.ts b/packages/backend/src/models/json-schema/note.ts
index 2641161c8b..432c096e48 100644
--- a/packages/backend/src/models/json-schema/note.ts
+++ b/packages/backend/src/models/json-schema/note.ts
@@ -204,6 +204,7 @@ export const packedNoteSchema = {
reactionAcceptance: {
type: 'string',
optional: false, nullable: true,
+ enum: ['likeOnly', 'likeOnlyForRemote', 'nonSensitiveOnly', 'nonSensitiveOnlyForLocalLikeOnlyForRemote', null],
},
reactionEmojis: {
type: 'object',
diff --git a/packages/backend/src/models/json-schema/role.ts b/packages/backend/src/models/json-schema/role.ts
index d9987a70c3..7366f05356 100644
--- a/packages/backend/src/models/json-schema/role.ts
+++ b/packages/backend/src/models/json-schema/role.ts
@@ -228,6 +228,10 @@ export const packedRolePoliciesSchema = {
type: 'boolean',
optional: false, nullable: false,
},
+ canUpdateBioMedia: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
pinLimit: {
type: 'integer',
optional: false, nullable: false,
diff --git a/packages/backend/src/models/json-schema/system-webhook.ts b/packages/backend/src/models/json-schema/system-webhook.ts
new file mode 100644
index 0000000000..d83065a743
--- /dev/null
+++ b/packages/backend/src/models/json-schema/system-webhook.ts
@@ -0,0 +1,54 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { systemWebhookEventTypes } from '@/models/SystemWebhook.js';
+
+export const packedSystemWebhookSchema = {
+ type: 'object',
+ properties: {
+ id: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ isActive: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
+ updatedAt: {
+ type: 'string',
+ format: 'date-time',
+ optional: false, nullable: false,
+ },
+ latestSentAt: {
+ type: 'string',
+ format: 'date-time',
+ optional: false, nullable: true,
+ },
+ latestStatus: {
+ type: 'number',
+ optional: false, nullable: true,
+ },
+ name: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ on: {
+ type: 'array',
+ items: {
+ type: 'string',
+ optional: false, nullable: false,
+ enum: systemWebhookEventTypes,
+ },
+ },
+ url: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ secret: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ },
+} as const;
diff --git a/packages/backend/src/postgres.ts b/packages/backend/src/postgres.ts
index 2d14537bbb..251a03c303 100644
--- a/packages/backend/src/postgres.ts
+++ b/packages/backend/src/postgres.ts
@@ -5,13 +5,12 @@
// https://github.com/typeorm/typeorm/issues/2400
import pg from 'pg';
-pg.types.setTypeParser(20, Number);
-
import { DataSource, Logger } from 'typeorm';
import * as highlight from 'cli-highlight';
import { entities as charts } from '@/core/chart/entities.js';
import { MiAbuseUserReport } from '@/models/AbuseUserReport.js';
+import { MiAbuseReportNotificationRecipient } from '@/models/AbuseReportNotificationRecipient.js';
import { MiAccessToken } from '@/models/AccessToken.js';
import { MiAd } from '@/models/Ad.js';
import { MiAnnouncement } from '@/models/Announcement.js';
@@ -69,6 +68,7 @@ import { MiUserProfile } from '@/models/UserProfile.js';
import { MiUserPublickey } from '@/models/UserPublickey.js';
import { MiUserSecurityKey } from '@/models/UserSecurityKey.js';
import { MiWebhook } from '@/models/Webhook.js';
+import { MiSystemWebhook } from '@/models/SystemWebhook.js';
import { MiChannel } from '@/models/Channel.js';
import { MiRetentionAggregation } from '@/models/RetentionAggregation.js';
import { MiRole } from '@/models/Role.js';
@@ -83,9 +83,11 @@ import { Config } from '@/config.js';
import MisskeyLogger from '@/logger.js';
import { bindThis } from '@/decorators.js';
+pg.types.setTypeParser(20, Number);
+
export const dbLogger = new MisskeyLogger('db');
-const sqlLogger = dbLogger.createSubLogger('sql', 'gray', false);
+const sqlLogger = dbLogger.createSubLogger('sql', 'gray');
class MyCustomLogger implements Logger {
@bindThis
@@ -167,6 +169,7 @@ export const entities = [
MiHashtag,
MiSwSubscription,
MiAbuseUserReport,
+ MiAbuseReportNotificationRecipient,
MiRegistrationTicket,
MiSignin,
MiModerationLog,
@@ -185,6 +188,7 @@ export const entities = [
MiPasswordResetRequest,
MiUserPending,
MiWebhook,
+ MiSystemWebhook,
MiUserIp,
MiRetentionAggregation,
MiRole,
diff --git a/packages/backend/src/queue/QueueProcessorModule.ts b/packages/backend/src/queue/QueueProcessorModule.ts
index 8086158997..a1fd38fcc5 100644
--- a/packages/backend/src/queue/QueueProcessorModule.ts
+++ b/packages/backend/src/queue/QueueProcessorModule.ts
@@ -11,7 +11,8 @@ import { QueueProcessorService } from './QueueProcessorService.js';
import { DeliverProcessorService } from './processors/DeliverProcessorService.js';
import { EndedPollNotificationProcessorService } from './processors/EndedPollNotificationProcessorService.js';
import { InboxProcessorService } from './processors/InboxProcessorService.js';
-import { WebhookDeliverProcessorService } from './processors/WebhookDeliverProcessorService.js';
+import { UserWebhookDeliverProcessorService } from './processors/UserWebhookDeliverProcessorService.js';
+import { SystemWebhookDeliverProcessorService } from './processors/SystemWebhookDeliverProcessorService.js';
import { CheckExpiredMutingsProcessorService } from './processors/CheckExpiredMutingsProcessorService.js';
import { CleanChartsProcessorService } from './processors/CleanChartsProcessorService.js';
import { CleanProcessorService } from './processors/CleanProcessorService.js';
@@ -71,7 +72,8 @@ import { RelationshipProcessorService } from './processors/RelationshipProcessor
DeleteFileProcessorService,
CleanRemoteFilesProcessorService,
RelationshipProcessorService,
- WebhookDeliverProcessorService,
+ UserWebhookDeliverProcessorService,
+ SystemWebhookDeliverProcessorService,
EndedPollNotificationProcessorService,
DeliverProcessorService,
InboxProcessorService,
diff --git a/packages/backend/src/queue/QueueProcessorService.ts b/packages/backend/src/queue/QueueProcessorService.ts
index ce999d9cef..7bd74f3210 100644
--- a/packages/backend/src/queue/QueueProcessorService.ts
+++ b/packages/backend/src/queue/QueueProcessorService.ts
@@ -5,11 +5,13 @@
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
import * as Bull from 'bullmq';
+import * as Sentry from '@sentry/node';
import type { Config } from '@/config.js';
import { DI } from '@/di-symbols.js';
import type Logger from '@/logger.js';
import { bindThis } from '@/decorators.js';
-import { WebhookDeliverProcessorService } from './processors/WebhookDeliverProcessorService.js';
+import { UserWebhookDeliverProcessorService } from './processors/UserWebhookDeliverProcessorService.js';
+import { SystemWebhookDeliverProcessorService } from './processors/SystemWebhookDeliverProcessorService.js';
import { EndedPollNotificationProcessorService } from './processors/EndedPollNotificationProcessorService.js';
import { DeliverProcessorService } from './processors/DeliverProcessorService.js';
import { InboxProcessorService } from './processors/InboxProcessorService.js';
@@ -75,7 +77,8 @@ export class QueueProcessorService implements OnApplicationShutdown {
private dbQueueWorker: Bull.Worker;
private deliverQueueWorker: Bull.Worker;
private inboxQueueWorker: Bull.Worker;
- private webhookDeliverQueueWorker: Bull.Worker;
+ private userWebhookDeliverQueueWorker: Bull.Worker;
+ private systemWebhookDeliverQueueWorker: Bull.Worker;
private relationshipQueueWorker: Bull.Worker;
private objectStorageQueueWorker: Bull.Worker;
private endedPollNotificationQueueWorker: Bull.Worker;
@@ -85,7 +88,8 @@ export class QueueProcessorService implements OnApplicationShutdown {
private config: Config,
private queueLoggerService: QueueLoggerService,
- private webhookDeliverProcessorService: WebhookDeliverProcessorService,
+ private userWebhookDeliverProcessorService: UserWebhookDeliverProcessorService,
+ private systemWebhookDeliverProcessorService: SystemWebhookDeliverProcessorService,
private endedPollNotificationProcessorService: EndedPollNotificationProcessorService,
private deliverProcessorService: DeliverProcessorService,
private inboxProcessorService: InboxProcessorService,
@@ -135,199 +139,367 @@ export class QueueProcessorService implements OnApplicationShutdown {
}
//#region system
- this.systemQueueWorker = new Bull.Worker(QUEUE.SYSTEM, (job) => {
- switch (job.name) {
- case 'tickCharts': return this.tickChartsProcessorService.process();
- case 'resyncCharts': return this.resyncChartsProcessorService.process();
- case 'cleanCharts': return this.cleanChartsProcessorService.process();
- case 'aggregateRetention': return this.aggregateRetentionProcessorService.process();
- case 'checkExpiredMutings': return this.checkExpiredMutingsProcessorService.process();
- case 'clean': return this.cleanProcessorService.process();
- default: throw new Error(`unrecognized job type ${job.name} for system`);
- }
- }, {
- ...baseQueueOptions(this.config, QUEUE.SYSTEM),
- autorun: false,
- });
+ {
+ const processer = (job: Bull.Job) => {
+ switch (job.name) {
+ case 'tickCharts': return this.tickChartsProcessorService.process();
+ case 'resyncCharts': return this.resyncChartsProcessorService.process();
+ case 'cleanCharts': return this.cleanChartsProcessorService.process();
+ case 'aggregateRetention': return this.aggregateRetentionProcessorService.process();
+ case 'checkExpiredMutings': return this.checkExpiredMutingsProcessorService.process();
+ case 'clean': return this.cleanProcessorService.process();
+ default: throw new Error(`unrecognized job type ${job.name} for system`);
+ }
+ };
+
+ this.systemQueueWorker = new Bull.Worker(QUEUE.SYSTEM, (job) => {
+ if (this.config.sentryForBackend) {
+ return Sentry.startSpan({ name: 'Queue: System: ' + job.name }, () => processer(job));
+ } else {
+ return processer(job);
+ }
+ }, {
+ ...baseQueueOptions(this.config, QUEUE.SYSTEM),
+ autorun: false,
+ });
- const systemLogger = this.logger.createSubLogger('system');
+ const logger = this.logger.createSubLogger('system');
- this.systemQueueWorker
- .on('active', (job) => systemLogger.debug(`active id=${job.id}`))
- .on('completed', (job, result) => systemLogger.debug(`completed(${result}) id=${job.id}`))
- .on('failed', (job, err) => systemLogger.warn(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) }))
- .on('error', (err: Error) => systemLogger.error(`error ${err.stack}`, { e: renderError(err) }))
- .on('stalled', (jobId) => systemLogger.warn(`stalled id=${jobId}`));
+ this.systemQueueWorker
+ .on('active', (job) => logger.debug(`active id=${job.id}`))
+ .on('completed', (job, result) => logger.debug(`completed(${result}) id=${job.id}`))
+ .on('failed', (job, err: Error) => {
+ logger.error(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) });
+ if (config.sentryForBackend) {
+ Sentry.captureMessage(`Queue: System: ${job?.name ?? '?'}: ${err.message}`, {
+ level: 'error',
+ extra: { job, err },
+ });
+ }
+ })
+ .on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) }))
+ .on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`));
+ }
//#endregion
//#region db
- this.dbQueueWorker = new Bull.Worker(QUEUE.DB, (job) => {
- switch (job.name) {
- case 'deleteDriveFiles': return this.deleteDriveFilesProcessorService.process(job);
- case 'exportCustomEmojis': return this.exportCustomEmojisProcessorService.process(job);
- case 'exportNotes': return this.exportNotesProcessorService.process(job);
- case 'exportClips': return this.exportClipsProcessorService.process(job);
- case 'exportFavorites': return this.exportFavoritesProcessorService.process(job);
- case 'exportFollowing': return this.exportFollowingProcessorService.process(job);
- case 'exportMuting': return this.exportMutingProcessorService.process(job);
- case 'exportBlocking': return this.exportBlockingProcessorService.process(job);
- case 'exportUserLists': return this.exportUserListsProcessorService.process(job);
- case 'exportAntennas': return this.exportAntennasProcessorService.process(job);
- case 'importFollowing': return this.importFollowingProcessorService.process(job);
- case 'importFollowingToDb': return this.importFollowingProcessorService.processDb(job);
- case 'importMuting': return this.importMutingProcessorService.process(job);
- case 'importBlocking': return this.importBlockingProcessorService.process(job);
- case 'importBlockingToDb': return this.importBlockingProcessorService.processDb(job);
- case 'importUserLists': return this.importUserListsProcessorService.process(job);
- case 'importCustomEmojis': return this.importCustomEmojisProcessorService.process(job);
- case 'importAntennas': return this.importAntennasProcessorService.process(job);
- case 'deleteAccount': return this.deleteAccountProcessorService.process(job);
- default: throw new Error(`unrecognized job type ${job.name} for db`);
- }
- }, {
- ...baseQueueOptions(this.config, QUEUE.DB),
- autorun: false,
- });
+ {
+ const processer = (job: Bull.Job) => {
+ switch (job.name) {
+ case 'deleteDriveFiles': return this.deleteDriveFilesProcessorService.process(job);
+ case 'exportCustomEmojis': return this.exportCustomEmojisProcessorService.process(job);
+ case 'exportNotes': return this.exportNotesProcessorService.process(job);
+ case 'exportClips': return this.exportClipsProcessorService.process(job);
+ case 'exportFavorites': return this.exportFavoritesProcessorService.process(job);
+ case 'exportFollowing': return this.exportFollowingProcessorService.process(job);
+ case 'exportMuting': return this.exportMutingProcessorService.process(job);
+ case 'exportBlocking': return this.exportBlockingProcessorService.process(job);
+ case 'exportUserLists': return this.exportUserListsProcessorService.process(job);
+ case 'exportAntennas': return this.exportAntennasProcessorService.process(job);
+ case 'importFollowing': return this.importFollowingProcessorService.process(job);
+ case 'importFollowingToDb': return this.importFollowingProcessorService.processDb(job);
+ case 'importMuting': return this.importMutingProcessorService.process(job);
+ case 'importBlocking': return this.importBlockingProcessorService.process(job);
+ case 'importBlockingToDb': return this.importBlockingProcessorService.processDb(job);
+ case 'importUserLists': return this.importUserListsProcessorService.process(job);
+ case 'importCustomEmojis': return this.importCustomEmojisProcessorService.process(job);
+ case 'importAntennas': return this.importAntennasProcessorService.process(job);
+ case 'deleteAccount': return this.deleteAccountProcessorService.process(job);
+ default: throw new Error(`unrecognized job type ${job.name} for db`);
+ }
+ };
+
+ this.dbQueueWorker = new Bull.Worker(QUEUE.DB, (job) => {
+ if (this.config.sentryForBackend) {
+ return Sentry.startSpan({ name: 'Queue: DB: ' + job.name }, () => processer(job));
+ } else {
+ return processer(job);
+ }
+ }, {
+ ...baseQueueOptions(this.config, QUEUE.DB),
+ autorun: false,
+ });
- const dbLogger = this.logger.createSubLogger('db');
+ const logger = this.logger.createSubLogger('db');
- this.dbQueueWorker
- .on('active', (job) => dbLogger.debug(`active id=${job.id}`))
- .on('completed', (job, result) => dbLogger.debug(`completed(${result}) id=${job.id}`))
- .on('failed', (job, err) => dbLogger.warn(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) }))
- .on('error', (err: Error) => dbLogger.error(`error ${err.stack}`, { e: renderError(err) }))
- .on('stalled', (jobId) => dbLogger.warn(`stalled id=${jobId}`));
+ this.dbQueueWorker
+ .on('active', (job) => logger.debug(`active id=${job.id}`))
+ .on('completed', (job, result) => logger.debug(`completed(${result}) id=${job.id}`))
+ .on('failed', (job, err) => {
+ logger.error(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) });
+ if (config.sentryForBackend) {
+ Sentry.captureMessage(`Queue: DB: ${job?.name ?? '?'}: ${err.message}`, {
+ level: 'error',
+ extra: { job, err },
+ });
+ }
+ })
+ .on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) }))
+ .on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`));
+ }
//#endregion
//#region deliver
- this.deliverQueueWorker = new Bull.Worker(QUEUE.DELIVER, (job) => this.deliverProcessorService.process(job), {
- ...baseQueueOptions(this.config, QUEUE.DELIVER),
- autorun: false,
- concurrency: this.config.deliverJobConcurrency ?? 128,
- limiter: {
- max: this.config.deliverJobPerSec ?? 128,
- duration: 1000,
- },
- settings: {
- backoffStrategy: httpRelatedBackoff,
- },
- });
+ {
+ this.deliverQueueWorker = new Bull.Worker(QUEUE.DELIVER, (job) => {
+ if (this.config.sentryForBackend) {
+ return Sentry.startSpan({ name: 'Queue: Deliver' }, () => this.deliverProcessorService.process(job));
+ } else {
+ return this.deliverProcessorService.process(job);
+ }
+ }, {
+ ...baseQueueOptions(this.config, QUEUE.DELIVER),
+ autorun: false,
+ concurrency: this.config.deliverJobConcurrency ?? 128,
+ limiter: {
+ max: this.config.deliverJobPerSec ?? 128,
+ duration: 1000,
+ },
+ settings: {
+ backoffStrategy: httpRelatedBackoff,
+ },
+ });
- const deliverLogger = this.logger.createSubLogger('deliver');
+ const logger = this.logger.createSubLogger('deliver');
- this.deliverQueueWorker
- .on('active', (job) => deliverLogger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`))
- .on('completed', (job, result) => deliverLogger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`))
- .on('failed', (job, err) => deliverLogger.warn(`failed(${err.stack}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`))
- .on('error', (err: Error) => deliverLogger.error(`error ${err.stack}`, { e: renderError(err) }))
- .on('stalled', (jobId) => deliverLogger.warn(`stalled id=${jobId}`));
+ this.deliverQueueWorker
+ .on('active', (job) => logger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`))
+ .on('completed', (job, result) => logger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`))
+ .on('failed', (job, err) => {
+ logger.error(`failed(${err.stack}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`);
+ if (config.sentryForBackend) {
+ Sentry.captureMessage(`Queue: Deliver: ${err.message}`, {
+ level: 'error',
+ extra: { job, err },
+ });
+ }
+ })
+ .on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) }))
+ .on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`));
+ }
//#endregion
//#region inbox
- this.inboxQueueWorker = new Bull.Worker(QUEUE.INBOX, (job) => this.inboxProcessorService.process(job), {
- ...baseQueueOptions(this.config, QUEUE.INBOX),
- autorun: false,
- concurrency: this.config.inboxJobConcurrency ?? 16,
- limiter: {
- max: this.config.inboxJobPerSec ?? 32,
- duration: 1000,
- },
- settings: {
- backoffStrategy: httpRelatedBackoff,
- },
- });
+ {
+ this.inboxQueueWorker = new Bull.Worker(QUEUE.INBOX, (job) => {
+ if (this.config.sentryForBackend) {
+ return Sentry.startSpan({ name: 'Queue: Inbox' }, () => this.inboxProcessorService.process(job));
+ } else {
+ return this.inboxProcessorService.process(job);
+ }
+ }, {
+ ...baseQueueOptions(this.config, QUEUE.INBOX),
+ autorun: false,
+ concurrency: this.config.inboxJobConcurrency ?? 16,
+ limiter: {
+ max: this.config.inboxJobPerSec ?? 32,
+ duration: 1000,
+ },
+ settings: {
+ backoffStrategy: httpRelatedBackoff,
+ },
+ });
- const inboxLogger = this.logger.createSubLogger('inbox');
+ const logger = this.logger.createSubLogger('inbox');
- this.inboxQueueWorker
- .on('active', (job) => inboxLogger.debug(`active ${getJobInfo(job, true)}`))
- .on('completed', (job, result) => inboxLogger.debug(`completed(${result}) ${getJobInfo(job, true)}`))
- .on('failed', (job, err) => inboxLogger.warn(`failed(${err.stack}) ${getJobInfo(job)} activity=${job ? (job.data.activity ? job.data.activity.id : 'none') : '-'}`, { job, e: renderError(err) }))
- .on('error', (err: Error) => inboxLogger.error(`error ${err.stack}`, { e: renderError(err) }))
- .on('stalled', (jobId) => inboxLogger.warn(`stalled id=${jobId}`));
+ this.inboxQueueWorker
+ .on('active', (job) => logger.debug(`active ${getJobInfo(job, true)}`))
+ .on('completed', (job, result) => logger.debug(`completed(${result}) ${getJobInfo(job, true)}`))
+ .on('failed', (job, err) => {
+ logger.error(`failed(${err.stack}) ${getJobInfo(job)} activity=${job ? (job.data.activity ? job.data.activity.id : 'none') : '-'}`, { job, e: renderError(err) });
+ if (config.sentryForBackend) {
+ Sentry.captureMessage(`Queue: Inbox: ${err.message}`, {
+ level: 'error',
+ extra: { job, err },
+ });
+ }
+ })
+ .on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) }))
+ .on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`));
+ }
//#endregion
- //#region webhook deliver
- this.webhookDeliverQueueWorker = new Bull.Worker(QUEUE.WEBHOOK_DELIVER, (job) => this.webhookDeliverProcessorService.process(job), {
- ...baseQueueOptions(this.config, QUEUE.WEBHOOK_DELIVER),
- autorun: false,
- concurrency: 64,
- limiter: {
- max: 64,
- duration: 1000,
- },
- settings: {
- backoffStrategy: httpRelatedBackoff,
- },
- });
+ //#region user-webhook deliver
+ {
+ this.userWebhookDeliverQueueWorker = new Bull.Worker(QUEUE.USER_WEBHOOK_DELIVER, (job) => {
+ if (this.config.sentryForBackend) {
+ return Sentry.startSpan({ name: 'Queue: UserWebhookDeliver' }, () => this.userWebhookDeliverProcessorService.process(job));
+ } else {
+ return this.userWebhookDeliverProcessorService.process(job);
+ }
+ }, {
+ ...baseQueueOptions(this.config, QUEUE.USER_WEBHOOK_DELIVER),
+ autorun: false,
+ concurrency: 64,
+ limiter: {
+ max: 64,
+ duration: 1000,
+ },
+ settings: {
+ backoffStrategy: httpRelatedBackoff,
+ },
+ });
- const webhookLogger = this.logger.createSubLogger('webhook');
+ const logger = this.logger.createSubLogger('user-webhook');
- this.webhookDeliverQueueWorker
- .on('active', (job) => webhookLogger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`))
- .on('completed', (job, result) => webhookLogger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`))
- .on('failed', (job, err) => webhookLogger.warn(`failed(${err.stack}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`))
- .on('error', (err: Error) => webhookLogger.error(`error ${err.stack}`, { e: renderError(err) }))
- .on('stalled', (jobId) => webhookLogger.warn(`stalled id=${jobId}`));
+ this.userWebhookDeliverQueueWorker
+ .on('active', (job) => logger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`))
+ .on('completed', (job, result) => logger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`))
+ .on('failed', (job, err) => {
+ logger.error(`failed(${err.stack}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`);
+ if (config.sentryForBackend) {
+ Sentry.captureMessage(`Queue: UserWebhookDeliver: ${err.message}`, {
+ level: 'error',
+ extra: { job, err },
+ });
+ }
+ })
+ .on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) }))
+ .on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`));
+ }
+ //#endregion
+
+ //#region system-webhook deliver
+ {
+ this.systemWebhookDeliverQueueWorker = new Bull.Worker(QUEUE.SYSTEM_WEBHOOK_DELIVER, (job) => {
+ if (this.config.sentryForBackend) {
+ return Sentry.startSpan({ name: 'Queue: SystemWebhookDeliver' }, () => this.systemWebhookDeliverProcessorService.process(job));
+ } else {
+ return this.systemWebhookDeliverProcessorService.process(job);
+ }
+ }, {
+ ...baseQueueOptions(this.config, QUEUE.SYSTEM_WEBHOOK_DELIVER),
+ autorun: false,
+ concurrency: 16,
+ limiter: {
+ max: 16,
+ duration: 1000,
+ },
+ settings: {
+ backoffStrategy: httpRelatedBackoff,
+ },
+ });
+
+ const logger = this.logger.createSubLogger('system-webhook');
+
+ this.systemWebhookDeliverQueueWorker
+ .on('active', (job) => logger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`))
+ .on('completed', (job, result) => logger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`))
+ .on('failed', (job, err) => {
+ logger.error(`failed(${err.stack}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`);
+ if (config.sentryForBackend) {
+ Sentry.captureMessage(`Queue: SystemWebhookDeliver: ${err.message}`, {
+ level: 'error',
+ extra: { job, err },
+ });
+ }
+ })
+ .on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) }))
+ .on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`));
+ }
//#endregion
//#region relationship
- this.relationshipQueueWorker = new Bull.Worker(QUEUE.RELATIONSHIP, (job) => {
- switch (job.name) {
- case 'follow': return this.relationshipProcessorService.processFollow(job);
- case 'unfollow': return this.relationshipProcessorService.processUnfollow(job);
- case 'block': return this.relationshipProcessorService.processBlock(job);
- case 'unblock': return this.relationshipProcessorService.processUnblock(job);
- default: throw new Error(`unrecognized job type ${job.name} for relationship`);
- }
- }, {
- ...baseQueueOptions(this.config, QUEUE.RELATIONSHIP),
- autorun: false,
- concurrency: this.config.relationshipJobConcurrency ?? 16,
- limiter: {
- max: this.config.relationshipJobPerSec ?? 64,
- duration: 1000,
- },
- });
+ {
+ const processer = (job: Bull.Job) => {
+ switch (job.name) {
+ case 'follow': return this.relationshipProcessorService.processFollow(job);
+ case 'unfollow': return this.relationshipProcessorService.processUnfollow(job);
+ case 'block': return this.relationshipProcessorService.processBlock(job);
+ case 'unblock': return this.relationshipProcessorService.processUnblock(job);
+ default: throw new Error(`unrecognized job type ${job.name} for relationship`);
+ }
+ };
+
+ this.relationshipQueueWorker = new Bull.Worker(QUEUE.RELATIONSHIP, (job) => {
+ if (this.config.sentryForBackend) {
+ return Sentry.startSpan({ name: 'Queue: Relationship: ' + job.name }, () => processer(job));
+ } else {
+ return processer(job);
+ }
+ }, {
+ ...baseQueueOptions(this.config, QUEUE.RELATIONSHIP),
+ autorun: false,
+ concurrency: this.config.relationshipJobConcurrency ?? 16,
+ limiter: {
+ max: this.config.relationshipJobPerSec ?? 64,
+ duration: 1000,
+ },
+ });
- const relationshipLogger = this.logger.createSubLogger('relationship');
+ const logger = this.logger.createSubLogger('relationship');
- this.relationshipQueueWorker
- .on('active', (job) => relationshipLogger.debug(`active id=${job.id}`))
- .on('completed', (job, result) => relationshipLogger.debug(`completed(${result}) id=${job.id}`))
- .on('failed', (job, err) => relationshipLogger.warn(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) }))
- .on('error', (err: Error) => relationshipLogger.error(`error ${err.stack}`, { e: renderError(err) }))
- .on('stalled', (jobId) => relationshipLogger.warn(`stalled id=${jobId}`));
+ this.relationshipQueueWorker
+ .on('active', (job) => logger.debug(`active id=${job.id}`))
+ .on('completed', (job, result) => logger.debug(`completed(${result}) id=${job.id}`))
+ .on('failed', (job, err) => {
+ logger.error(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) });
+ if (config.sentryForBackend) {
+ Sentry.captureMessage(`Queue: Relationship: ${job?.name ?? '?'}: ${err.message}`, {
+ level: 'error',
+ extra: { job, err },
+ });
+ }
+ })
+ .on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) }))
+ .on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`));
+ }
//#endregion
//#region object storage
- this.objectStorageQueueWorker = new Bull.Worker(QUEUE.OBJECT_STORAGE, (job) => {
- switch (job.name) {
- case 'deleteFile': return this.deleteFileProcessorService.process(job);
- case 'cleanRemoteFiles': return this.cleanRemoteFilesProcessorService.process(job);
- default: throw new Error(`unrecognized job type ${job.name} for objectStorage`);
- }
- }, {
- ...baseQueueOptions(this.config, QUEUE.OBJECT_STORAGE),
- autorun: false,
- concurrency: 16,
- });
+ {
+ const processer = (job: Bull.Job) => {
+ switch (job.name) {
+ case 'deleteFile': return this.deleteFileProcessorService.process(job);
+ case 'cleanRemoteFiles': return this.cleanRemoteFilesProcessorService.process(job);
+ default: throw new Error(`unrecognized job type ${job.name} for objectStorage`);
+ }
+ };
+
+ this.objectStorageQueueWorker = new Bull.Worker(QUEUE.OBJECT_STORAGE, (job) => {
+ if (this.config.sentryForBackend) {
+ return Sentry.startSpan({ name: 'Queue: ObjectStorage: ' + job.name }, () => processer(job));
+ } else {
+ return processer(job);
+ }
+ }, {
+ ...baseQueueOptions(this.config, QUEUE.OBJECT_STORAGE),
+ autorun: false,
+ concurrency: 16,
+ });
- const objectStorageLogger = this.logger.createSubLogger('objectStorage');
+ const logger = this.logger.createSubLogger('objectStorage');
- this.objectStorageQueueWorker
- .on('active', (job) => objectStorageLogger.debug(`active id=${job.id}`))
- .on('completed', (job, result) => objectStorageLogger.debug(`completed(${result}) id=${job.id}`))
- .on('failed', (job, err) => objectStorageLogger.warn(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) }))
- .on('error', (err: Error) => objectStorageLogger.error(`error ${err.stack}`, { e: renderError(err) }))
- .on('stalled', (jobId) => objectStorageLogger.warn(`stalled id=${jobId}`));
+ this.objectStorageQueueWorker
+ .on('active', (job) => logger.debug(`active id=${job.id}`))
+ .on('completed', (job, result) => logger.debug(`completed(${result}) id=${job.id}`))
+ .on('failed', (job, err) => {
+ logger.error(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) });
+ if (config.sentryForBackend) {
+ Sentry.captureMessage(`Queue: ObjectStorage: ${job?.name ?? '?'}: ${err.message}`, {
+ level: 'error',
+ extra: { job, err },
+ });
+ }
+ })
+ .on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) }))
+ .on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`));
+ }
//#endregion
//#region ended poll notification
- this.endedPollNotificationQueueWorker = new Bull.Worker(QUEUE.ENDED_POLL_NOTIFICATION, (job) => this.endedPollNotificationProcessorService.process(job), {
- ...baseQueueOptions(this.config, QUEUE.ENDED_POLL_NOTIFICATION),
- autorun: false,
- });
+ {
+ this.endedPollNotificationQueueWorker = new Bull.Worker(QUEUE.ENDED_POLL_NOTIFICATION, (job) => {
+ if (this.config.sentryForBackend) {
+ return Sentry.startSpan({ name: 'Queue: EndedPollNotification' }, () => this.endedPollNotificationProcessorService.process(job));
+ } else {
+ return this.endedPollNotificationProcessorService.process(job);
+ }
+ }, {
+ ...baseQueueOptions(this.config, QUEUE.ENDED_POLL_NOTIFICATION),
+ autorun: false,
+ });
+ }
//#endregion
}
@@ -338,7 +510,8 @@ export class QueueProcessorService implements OnApplicationShutdown {
this.dbQueueWorker.run(),
this.deliverQueueWorker.run(),
this.inboxQueueWorker.run(),
- this.webhookDeliverQueueWorker.run(),
+ this.userWebhookDeliverQueueWorker.run(),
+ this.systemWebhookDeliverQueueWorker.run(),
this.relationshipQueueWorker.run(),
this.objectStorageQueueWorker.run(),
this.endedPollNotificationQueueWorker.run(),
@@ -352,7 +525,8 @@ export class QueueProcessorService implements OnApplicationShutdown {
this.dbQueueWorker.close(),
this.deliverQueueWorker.close(),
this.inboxQueueWorker.close(),
- this.webhookDeliverQueueWorker.close(),
+ this.userWebhookDeliverQueueWorker.close(),
+ this.systemWebhookDeliverQueueWorker.close(),
this.relationshipQueueWorker.close(),
this.objectStorageQueueWorker.close(),
this.endedPollNotificationQueueWorker.close(),
diff --git a/packages/backend/src/queue/const.ts b/packages/backend/src/queue/const.ts
index 132e916612..67f689b618 100644
--- a/packages/backend/src/queue/const.ts
+++ b/packages/backend/src/queue/const.ts
@@ -14,7 +14,8 @@ export const QUEUE = {
DB: 'db',
RELATIONSHIP: 'relationship',
OBJECT_STORAGE: 'objectStorage',
- WEBHOOK_DELIVER: 'webhookDeliver',
+ USER_WEBHOOK_DELIVER: 'userWebhookDeliver',
+ SYSTEM_WEBHOOK_DELIVER: 'systemWebhookDeliver',
};
export function baseQueueOptions(config: Config, queueName: typeof QUEUE[keyof typeof QUEUE]): Bull.QueueOptions {
diff --git a/packages/backend/src/queue/processors/DeliverProcessorService.ts b/packages/backend/src/queue/processors/DeliverProcessorService.ts
index b73195afc3..d665945861 100644
--- a/packages/backend/src/queue/processors/DeliverProcessorService.ts
+++ b/packages/backend/src/queue/processors/DeliverProcessorService.ts
@@ -109,6 +109,12 @@ export class DeliverProcessorService {
suspensionState: 'autoSuspendedForNotResponding',
});
}
+ } else {
+ // isNotRespondingãŒtrueã§notRespondingSinceãŒnullã®å ´åˆã¯notRespondingSinceをセット
+ // notRespondingSinceã¯æ–°ãŸãªæ©Ÿèƒ½ãªã®ã§ã€ãれ以å‰ã®ãƒ‡ãƒ¼ã‚¿ã«ã¯notRespondingSinceãŒãªã„å ´åˆãŒã‚ã‚‹
+ this.federatedInstanceService.update(i.id, {
+ notRespondingSince: new Date(),
+ });
}
this.apRequestChart.deliverFail();
diff --git a/packages/backend/src/queue/processors/EndedPollNotificationProcessorService.ts b/packages/backend/src/queue/processors/EndedPollNotificationProcessorService.ts
index 29c1f27bb1..34180e5f2b 100644
--- a/packages/backend/src/queue/processors/EndedPollNotificationProcessorService.ts
+++ b/packages/backend/src/queue/processors/EndedPollNotificationProcessorService.ts
@@ -7,6 +7,7 @@ import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { PollVotesRepository, NotesRepository } from '@/models/_.js';
import type Logger from '@/logger.js';
+import { CacheService } from '@/core/CacheService.js';
import { NotificationService } from '@/core/NotificationService.js';
import { bindThis } from '@/decorators.js';
import { QueueLoggerService } from '../QueueLoggerService.js';
@@ -24,6 +25,7 @@ export class EndedPollNotificationProcessorService {
@Inject(DI.pollVotesRepository)
private pollVotesRepository: PollVotesRepository,
+ private cacheService: CacheService,
private notificationService: NotificationService,
private queueLoggerService: QueueLoggerService,
) {
@@ -47,9 +49,12 @@ export class EndedPollNotificationProcessorService {
const userIds = [...new Set([note.userId, ...votes.map(v => v.userId)])];
for (const userId of userIds) {
- this.notificationService.createNotification(userId, 'pollEnded', {
- noteId: note.id,
- });
+ const profile = await this.cacheService.userProfileCache.fetch(userId);
+ if (profile.userHost === null) {
+ this.notificationService.createNotification(userId, 'pollEnded', {
+ noteId: note.id,
+ });
+ }
}
}
}
diff --git a/packages/backend/src/queue/processors/SystemWebhookDeliverProcessorService.ts b/packages/backend/src/queue/processors/SystemWebhookDeliverProcessorService.ts
new file mode 100644
index 0000000000..f6bef52684
--- /dev/null
+++ b/packages/backend/src/queue/processors/SystemWebhookDeliverProcessorService.ts
@@ -0,0 +1,87 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Inject, Injectable } from '@nestjs/common';
+import * as Bull from 'bullmq';
+import { DI } from '@/di-symbols.js';
+import type { SystemWebhooksRepository } from '@/models/_.js';
+import type { Config } from '@/config.js';
+import type Logger from '@/logger.js';
+import { HttpRequestService } from '@/core/HttpRequestService.js';
+import { StatusError } from '@/misc/status-error.js';
+import { bindThis } from '@/decorators.js';
+import { QueueLoggerService } from '../QueueLoggerService.js';
+import { SystemWebhookDeliverJobData } from '../types.js';
+
+@Injectable()
+export class SystemWebhookDeliverProcessorService {
+ private logger: Logger;
+
+ constructor(
+ @Inject(DI.config)
+ private config: Config,
+
+ @Inject(DI.systemWebhooksRepository)
+ private systemWebhooksRepository: SystemWebhooksRepository,
+
+ private httpRequestService: HttpRequestService,
+ private queueLoggerService: QueueLoggerService,
+ ) {
+ this.logger = this.queueLoggerService.logger.createSubLogger('webhook');
+ }
+
+ @bindThis
+ public async process(job: Bull.Job<SystemWebhookDeliverJobData>): Promise<string> {
+ try {
+ this.logger.debug(`delivering ${job.data.webhookId}`);
+
+ const res = await this.httpRequestService.send(job.data.to, {
+ method: 'POST',
+ headers: {
+ 'User-Agent': 'Misskey-Hooks',
+ 'X-Misskey-Host': this.config.host,
+ 'X-Misskey-Hook-Id': job.data.webhookId,
+ 'X-Misskey-Hook-Secret': job.data.secret,
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ server: this.config.url,
+ hookId: job.data.webhookId,
+ eventId: job.data.eventId,
+ createdAt: job.data.createdAt,
+ type: job.data.type,
+ body: job.data.content,
+ }),
+ });
+
+ this.systemWebhooksRepository.update({ id: job.data.webhookId }, {
+ latestSentAt: new Date(),
+ latestStatus: res.status,
+ });
+
+ return 'Success';
+ } catch (res) {
+ this.logger.error(res as Error);
+
+ this.systemWebhooksRepository.update({ id: job.data.webhookId }, {
+ latestSentAt: new Date(),
+ latestStatus: res instanceof StatusError ? res.statusCode : 1,
+ });
+
+ if (res instanceof StatusError) {
+ // 4xx
+ if (!res.isRetryable) {
+ throw new Bull.UnrecoverableError(`${res.statusCode} ${res.statusMessage}`);
+ }
+
+ // 5xx etc.
+ throw new Error(`${res.statusCode} ${res.statusMessage}`);
+ } else {
+ // DNS error, socket error, timeout ...
+ throw res;
+ }
+ }
+ }
+}
diff --git a/packages/backend/src/queue/processors/WebhookDeliverProcessorService.ts b/packages/backend/src/queue/processors/UserWebhookDeliverProcessorService.ts
index 8c260c0137..9ec630ef70 100644
--- a/packages/backend/src/queue/processors/WebhookDeliverProcessorService.ts
+++ b/packages/backend/src/queue/processors/UserWebhookDeliverProcessorService.ts
@@ -13,10 +13,10 @@ import { HttpRequestService } from '@/core/HttpRequestService.js';
import { StatusError } from '@/misc/status-error.js';
import { bindThis } from '@/decorators.js';
import { QueueLoggerService } from '../QueueLoggerService.js';
-import type { WebhookDeliverJobData } from '../types.js';
+import { UserWebhookDeliverJobData } from '../types.js';
@Injectable()
-export class WebhookDeliverProcessorService {
+export class UserWebhookDeliverProcessorService {
private logger: Logger;
constructor(
@@ -33,7 +33,7 @@ export class WebhookDeliverProcessorService {
}
@bindThis
- public async process(job: Bull.Job<WebhookDeliverJobData>): Promise<string> {
+ public async process(job: Bull.Job<UserWebhookDeliverJobData>): Promise<string> {
try {
this.logger.debug(`delivering ${job.data.webhookId}`);
diff --git a/packages/backend/src/queue/types.ts b/packages/backend/src/queue/types.ts
index ce57ba745e..a4077a0547 100644
--- a/packages/backend/src/queue/types.ts
+++ b/packages/backend/src/queue/types.ts
@@ -106,7 +106,17 @@ export type EndedPollNotificationJobData = {
noteId: MiNote['id'];
};
-export type WebhookDeliverJobData = {
+export type SystemWebhookDeliverJobData = {
+ type: string;
+ content: unknown;
+ webhookId: MiWebhook['id'];
+ to: string;
+ secret: string;
+ createdAt: number;
+ eventId: string;
+};
+
+export type UserWebhookDeliverJobData = {
type: string;
content: unknown;
webhookId: MiWebhook['id'];
diff --git a/packages/backend/src/server/FileServerService.ts b/packages/backend/src/server/FileServerService.ts
index 9db3aa1bfb..77a637d895 100644
--- a/packages/backend/src/server/FileServerService.ts
+++ b/packages/backend/src/server/FileServerService.ts
@@ -53,7 +53,7 @@ export class FileServerService {
private internalStorageService: InternalStorageService,
private loggerService: LoggerService,
) {
- this.logger = this.loggerService.getLogger('server', 'gray', false);
+ this.logger = this.loggerService.getLogger('server', 'gray');
//this.createServer = this.createServer.bind(this);
}
diff --git a/packages/backend/src/server/ServerService.ts b/packages/backend/src/server/ServerService.ts
index 3572f16627..9c849480f2 100644
--- a/packages/backend/src/server/ServerService.ts
+++ b/packages/backend/src/server/ServerService.ts
@@ -68,7 +68,7 @@ export class ServerService implements OnApplicationShutdown {
private loggerService: LoggerService,
private oauth2ProviderService: OAuth2ProviderService,
) {
- this.logger = this.loggerService.getLogger('server', 'gray', false);
+ this.logger = this.loggerService.getLogger('server', 'gray');
}
@bindThis
diff --git a/packages/backend/src/server/api/ApiCallService.ts b/packages/backend/src/server/api/ApiCallService.ts
index 271ef80554..47f64f6609 100644
--- a/packages/backend/src/server/api/ApiCallService.ts
+++ b/packages/backend/src/server/api/ApiCallService.ts
@@ -73,6 +73,16 @@ export class ApiCallService implements OnApplicationShutdown {
reply.header('WWW-Authenticate', `Bearer realm="Misskey", error="insufficient_scope", error_description="${err.message}"`);
}
statusCode = statusCode ?? 403;
+ } else if (err.code === 'RATE_LIMIT_EXCEEDED') {
+ const info: unknown = err.info;
+ const unixEpochInSeconds = Date.now();
+ if (typeof(info) === 'object' && info && 'resetMs' in info && typeof(info.resetMs) === 'number') {
+ const cooldownInSeconds = Math.ceil((info.resetMs - unixEpochInSeconds) / 1000);
+ // ã‚‚ã—ã‹ã™ã‚‹ã¨ãƒžã‚¤ãƒŠã‚¹ã«ãªã‚‹å¯èƒ½æ€§ãŒãªãã¯ãªã„ã®ã§ãƒžã‚¤ãƒŠã‚¹ã ã£ãŸã‚‰0ã«ã—ã¦ãŠã
+ reply.header('Retry-After', Math.max(cooldownInSeconds, 0).toString(10));
+ } else {
+ this.logger.warn(`rate limit information has unexpected type ${typeof(err.info?.reset)}`);
+ }
} else if (!statusCode) {
statusCode = 500;
}
@@ -93,7 +103,7 @@ export class ApiCallService implements OnApplicationShutdown {
}
}
- #onExecError(ep: IEndpoint, data: any, err: Error): void {
+ #onExecError(ep: IEndpoint, data: any, err: Error, userId?: MiUser['id']): void {
if (err instanceof ApiError || err instanceof AuthenticationError) {
throw err;
} else {
@@ -108,10 +118,13 @@ export class ApiCallService implements OnApplicationShutdown {
id: errId,
},
});
- console.error(err, errId);
if (this.config.sentryForBackend) {
Sentry.captureMessage(`Internal error occurred in ${ep.name}: ${err.message}`, {
+ level: 'error',
+ user: {
+ id: userId,
+ },
extra: {
ep: ep.name,
ps: data,
@@ -305,12 +318,17 @@ export class ApiCallService implements OnApplicationShutdown {
if (factor > 0) {
// Rate limit
await this.rateLimiterService.limit(limit as IEndpointMeta['limit'] & { key: NonNullable<string> }, limitActor, factor).catch(err => {
- throw new ApiError({
- message: 'Rate limit exceeded. Please try again later.',
- code: 'RATE_LIMIT_EXCEEDED',
- id: 'd5826d14-3982-4d2e-8011-b9e9f02499ef',
- httpStatusCode: 429,
- });
+ if ('info' in err) {
+ // errã¯Limiter.LimiterInfoã§ã‚ã‚‹ã“ã¨ãŒæœŸå¾…ã•れる
+ throw new ApiError({
+ message: 'Rate limit exceeded. Please try again later.',
+ code: 'RATE_LIMIT_EXCEEDED',
+ id: 'd5826d14-3982-4d2e-8011-b9e9f02499ef',
+ httpStatusCode: 429,
+ }, err.info);
+ } else {
+ throw new TypeError('information must be a rate-limiter information.');
+ }
});
}
}
@@ -410,9 +428,13 @@ export class ApiCallService implements OnApplicationShutdown {
// API invoking
if (this.config.sentryForBackend) {
- return await Sentry.startSpan({ name: 'API: ' + ep.name }, () => ep.exec(data, user, token, file, request.ip, request.headers).catch((err: Error) => this.#onExecError(ep, data, err)));
+ return await Sentry.startSpan({
+ name: 'API: ' + ep.name,
+ }, () => ep.exec(data, user, token, file, request.ip, request.headers)
+ .catch((err: Error) => this.#onExecError(ep, data, err, user?.id)));
} else {
- return await ep.exec(data, user, token, file, request.ip, request.headers).catch((err: Error) => this.#onExecError(ep, data, err));
+ return await ep.exec(data, user, token, file, request.ip, request.headers)
+ .catch((err: Error) => this.#onExecError(ep, data, err, user?.id));
}
}
diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts
index c645f4bcc6..41576bedaa 100644
--- a/packages/backend/src/server/api/EndpointsModule.ts
+++ b/packages/backend/src/server/api/EndpointsModule.ts
@@ -6,8 +6,13 @@
import { Module } from '@nestjs/common';
import { CoreModule } from '@/core/CoreModule.js';
-import * as ep___admin_meta from './endpoints/admin/meta.js';
+import * as ep___admin_abuseReport_notificationRecipient_list from '@/server/api/endpoints/admin/abuse-report/notification-recipient/list.js';
+import * as ep___admin_abuseReport_notificationRecipient_show from '@/server/api/endpoints/admin/abuse-report/notification-recipient/show.js';
+import * as ep___admin_abuseReport_notificationRecipient_create from '@/server/api/endpoints/admin/abuse-report/notification-recipient/create.js';
+import * as ep___admin_abuseReport_notificationRecipient_update from '@/server/api/endpoints/admin/abuse-report/notification-recipient/update.js';
+import * as ep___admin_abuseReport_notificationRecipient_delete from '@/server/api/endpoints/admin/abuse-report/notification-recipient/delete.js';
import * as ep___admin_abuseUserReports from './endpoints/admin/abuse-user-reports.js';
+import * as ep___admin_meta from './endpoints/admin/meta.js';
import * as ep___admin_accounts_create from './endpoints/admin/accounts/create.js';
import * as ep___admin_accounts_delete from './endpoints/admin/accounts/delete.js';
import * as ep___admin_accounts_findByEmail from './endpoints/admin/accounts/find-by-email.js';
@@ -82,6 +87,11 @@ import * as ep___admin_roles_assign from './endpoints/admin/roles/assign.js';
import * as ep___admin_roles_unassign from './endpoints/admin/roles/unassign.js';
import * as ep___admin_roles_updateDefaultPolicies from './endpoints/admin/roles/update-default-policies.js';
import * as ep___admin_roles_users from './endpoints/admin/roles/users.js';
+import * as ep___admin_systemWebhook_create from './endpoints/admin/system-webhook/create.js';
+import * as ep___admin_systemWebhook_delete from './endpoints/admin/system-webhook/delete.js';
+import * as ep___admin_systemWebhook_list from './endpoints/admin/system-webhook/list.js';
+import * as ep___admin_systemWebhook_show from './endpoints/admin/system-webhook/show.js';
+import * as ep___admin_systemWebhook_update from './endpoints/admin/system-webhook/update.js';
import * as ep___announcements from './endpoints/announcements.js';
import * as ep___announcements_show from './endpoints/announcements/show.js';
import * as ep___antennas_create from './endpoints/antennas/create.js';
@@ -381,6 +391,11 @@ import type { Provider } from '@nestjs/common';
const $admin_meta: Provider = { provide: 'ep:admin/meta', useClass: ep___admin_meta.default };
const $admin_abuseUserReports: Provider = { provide: 'ep:admin/abuse-user-reports', useClass: ep___admin_abuseUserReports.default };
+const $admin_abuseReport_notificationRecipient_list: Provider = { provide: 'ep:admin/abuse-report/notification-recipient/list', useClass: ep___admin_abuseReport_notificationRecipient_list.default };
+const $admin_abuseReport_notificationRecipient_show: Provider = { provide: 'ep:admin/abuse-report/notification-recipient/show', useClass: ep___admin_abuseReport_notificationRecipient_show.default };
+const $admin_abuseReport_notificationRecipient_create: Provider = { provide: 'ep:admin/abuse-report/notification-recipient/create', useClass: ep___admin_abuseReport_notificationRecipient_create.default };
+const $admin_abuseReport_notificationRecipient_update: Provider = { provide: 'ep:admin/abuse-report/notification-recipient/update', useClass: ep___admin_abuseReport_notificationRecipient_update.default };
+const $admin_abuseReport_notificationRecipient_delete: Provider = { provide: 'ep:admin/abuse-report/notification-recipient/delete', useClass: ep___admin_abuseReport_notificationRecipient_delete.default };
const $admin_accounts_create: Provider = { provide: 'ep:admin/accounts/create', useClass: ep___admin_accounts_create.default };
const $admin_accounts_delete: Provider = { provide: 'ep:admin/accounts/delete', useClass: ep___admin_accounts_delete.default };
const $admin_accounts_findByEmail: Provider = { provide: 'ep:admin/accounts/find-by-email', useClass: ep___admin_accounts_findByEmail.default };
@@ -455,6 +470,11 @@ const $admin_roles_assign: Provider = { provide: 'ep:admin/roles/assign', useCla
const $admin_roles_unassign: Provider = { provide: 'ep:admin/roles/unassign', useClass: ep___admin_roles_unassign.default };
const $admin_roles_updateDefaultPolicies: Provider = { provide: 'ep:admin/roles/update-default-policies', useClass: ep___admin_roles_updateDefaultPolicies.default };
const $admin_roles_users: Provider = { provide: 'ep:admin/roles/users', useClass: ep___admin_roles_users.default };
+const $admin_systemWebhook_create: Provider = { provide: 'ep:admin/system-webhook/create', useClass: ep___admin_systemWebhook_create.default };
+const $admin_systemWebhook_delete: Provider = { provide: 'ep:admin/system-webhook/delete', useClass: ep___admin_systemWebhook_delete.default };
+const $admin_systemWebhook_list: Provider = { provide: 'ep:admin/system-webhook/list', useClass: ep___admin_systemWebhook_list.default };
+const $admin_systemWebhook_show: Provider = { provide: 'ep:admin/system-webhook/show', useClass: ep___admin_systemWebhook_show.default };
+const $admin_systemWebhook_update: Provider = { provide: 'ep:admin/system-webhook/update', useClass: ep___admin_systemWebhook_update.default };
const $announcements: Provider = { provide: 'ep:announcements', useClass: ep___announcements.default };
const $announcements_show: Provider = { provide: 'ep:announcements/show', useClass: ep___announcements_show.default };
const $antennas_create: Provider = { provide: 'ep:antennas/create', useClass: ep___antennas_create.default };
@@ -758,6 +778,11 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
ApiLoggerService,
$admin_meta,
$admin_abuseUserReports,
+ $admin_abuseReport_notificationRecipient_list,
+ $admin_abuseReport_notificationRecipient_show,
+ $admin_abuseReport_notificationRecipient_create,
+ $admin_abuseReport_notificationRecipient_update,
+ $admin_abuseReport_notificationRecipient_delete,
$admin_accounts_create,
$admin_accounts_delete,
$admin_accounts_findByEmail,
@@ -832,6 +857,11 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
$admin_roles_unassign,
$admin_roles_updateDefaultPolicies,
$admin_roles_users,
+ $admin_systemWebhook_create,
+ $admin_systemWebhook_delete,
+ $admin_systemWebhook_list,
+ $admin_systemWebhook_show,
+ $admin_systemWebhook_update,
$announcements,
$announcements_show,
$antennas_create,
@@ -1129,6 +1159,11 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
exports: [
$admin_meta,
$admin_abuseUserReports,
+ $admin_abuseReport_notificationRecipient_list,
+ $admin_abuseReport_notificationRecipient_show,
+ $admin_abuseReport_notificationRecipient_create,
+ $admin_abuseReport_notificationRecipient_update,
+ $admin_abuseReport_notificationRecipient_delete,
$admin_accounts_create,
$admin_accounts_delete,
$admin_accounts_findByEmail,
@@ -1203,6 +1238,11 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
$admin_roles_unassign,
$admin_roles_updateDefaultPolicies,
$admin_roles_users,
+ $admin_systemWebhook_create,
+ $admin_systemWebhook_delete,
+ $admin_systemWebhook_list,
+ $admin_systemWebhook_show,
+ $admin_systemWebhook_update,
$announcements,
$announcements_show,
$antennas_create,
diff --git a/packages/backend/src/server/api/RateLimiterService.ts b/packages/backend/src/server/api/RateLimiterService.ts
index 0439cdfe5e..52d73baa0a 100644
--- a/packages/backend/src/server/api/RateLimiterService.ts
+++ b/packages/backend/src/server/api/RateLimiterService.ts
@@ -32,11 +32,13 @@ export class RateLimiterService {
@bindThis
public limit(limitation: IEndpointMeta['limit'] & { key: NonNullable<string> }, actor: string, factor = 1) {
- return new Promise<void>((ok, reject) => {
- if (this.disabled) ok();
+ {
+ if (this.disabled) {
+ return Promise.resolve();
+ }
// Short-term limit
- const min = (): void => {
+ const min = new Promise<void>((ok, reject) => {
const minIntervalLimiter = new Limiter({
id: `${actor}:${limitation.key}:min`,
duration: limitation.minInterval! * factor,
@@ -46,25 +48,25 @@ export class RateLimiterService {
minIntervalLimiter.get((err, info) => {
if (err) {
- return reject('ERR');
+ return reject({ code: 'ERR', info });
}
this.logger.debug(`${actor} ${limitation.key} min remaining: ${info.remaining}`);
if (info.remaining === 0) {
- reject('BRIEF_REQUEST_INTERVAL');
+ return reject({ code: 'BRIEF_REQUEST_INTERVAL', info });
} else {
if (hasLongTermLimit) {
- max();
+ return max.then(ok, reject);
} else {
- ok();
+ return ok();
}
}
});
- };
+ });
// Long term limit
- const max = (): void => {
+ const max = new Promise<void>((ok, reject) => {
const limiter = new Limiter({
id: `${actor}:${limitation.key}`,
duration: limitation.duration! * factor,
@@ -74,18 +76,18 @@ export class RateLimiterService {
limiter.get((err, info) => {
if (err) {
- return reject('ERR');
+ return reject({ code: 'ERR', info });
}
this.logger.debug(`${actor} ${limitation.key} max remaining: ${info.remaining}`);
if (info.remaining === 0) {
- reject('RATE_LIMIT_EXCEEDED');
+ return reject({ code: 'RATE_LIMIT_EXCEEDED', info });
} else {
- ok();
+ return ok();
}
});
- };
+ });
const hasShortTermLimit = typeof limitation.minInterval === 'number';
@@ -94,12 +96,12 @@ export class RateLimiterService {
typeof limitation.max === 'number';
if (hasShortTermLimit) {
- min();
+ return min;
} else if (hasLongTermLimit) {
- max();
+ return max;
} else {
- ok();
+ return Promise.resolve();
}
- });
+ }
}
}
diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts
index a38c62f35a..3dfb7fdad4 100644
--- a/packages/backend/src/server/api/endpoints.ts
+++ b/packages/backend/src/server/api/endpoints.ts
@@ -6,8 +6,18 @@
import { permissions } from 'misskey-js';
import type { KeyOf, Schema } from '@/misc/json-schema.js';
-import * as ep___admin_meta from './endpoints/admin/meta.js';
+import * as ep___admin_abuseReport_notificationRecipient_list
+ from '@/server/api/endpoints/admin/abuse-report/notification-recipient/list.js';
+import * as ep___admin_abuseReport_notificationRecipient_show
+ from '@/server/api/endpoints/admin/abuse-report/notification-recipient/show.js';
+import * as ep___admin_abuseReport_notificationRecipient_create
+ from '@/server/api/endpoints/admin/abuse-report/notification-recipient/create.js';
+import * as ep___admin_abuseReport_notificationRecipient_update
+ from '@/server/api/endpoints/admin/abuse-report/notification-recipient/update.js';
+import * as ep___admin_abuseReport_notificationRecipient_delete
+ from '@/server/api/endpoints/admin/abuse-report/notification-recipient/delete.js';
import * as ep___admin_abuseUserReports from './endpoints/admin/abuse-user-reports.js';
+import * as ep___admin_meta from './endpoints/admin/meta.js';
import * as ep___admin_accounts_create from './endpoints/admin/accounts/create.js';
import * as ep___admin_accounts_delete from './endpoints/admin/accounts/delete.js';
import * as ep___admin_accounts_findByEmail from './endpoints/admin/accounts/find-by-email.js';
@@ -44,7 +54,8 @@ import * as ep___admin_emoji_setCategoryBulk from './endpoints/admin/emoji/set-c
import * as ep___admin_emoji_setLicenseBulk from './endpoints/admin/emoji/set-license-bulk.js';
import * as ep___admin_emoji_update from './endpoints/admin/emoji/update.js';
import * as ep___admin_federation_deleteAllFiles from './endpoints/admin/federation/delete-all-files.js';
-import * as ep___admin_federation_refreshRemoteInstanceMetadata from './endpoints/admin/federation/refresh-remote-instance-metadata.js';
+import * as ep___admin_federation_refreshRemoteInstanceMetadata
+ from './endpoints/admin/federation/refresh-remote-instance-metadata.js';
import * as ep___admin_federation_removeAllFollowing from './endpoints/admin/federation/remove-all-following.js';
import * as ep___admin_federation_updateInstance from './endpoints/admin/federation/update-instance.js';
import * as ep___admin_getIndexStats from './endpoints/admin/get-index-stats.js';
@@ -82,6 +93,11 @@ import * as ep___admin_roles_assign from './endpoints/admin/roles/assign.js';
import * as ep___admin_roles_unassign from './endpoints/admin/roles/unassign.js';
import * as ep___admin_roles_updateDefaultPolicies from './endpoints/admin/roles/update-default-policies.js';
import * as ep___admin_roles_users from './endpoints/admin/roles/users.js';
+import * as ep___admin_systemWebhook_create from './endpoints/admin/system-webhook/create.js';
+import * as ep___admin_systemWebhook_delete from './endpoints/admin/system-webhook/delete.js';
+import * as ep___admin_systemWebhook_list from './endpoints/admin/system-webhook/list.js';
+import * as ep___admin_systemWebhook_show from './endpoints/admin/system-webhook/show.js';
+import * as ep___admin_systemWebhook_update from './endpoints/admin/system-webhook/update.js';
import * as ep___announcements from './endpoints/announcements.js';
import * as ep___announcements_show from './endpoints/announcements/show.js';
import * as ep___antennas_create from './endpoints/antennas/create.js';
@@ -379,6 +395,11 @@ import * as ep___reversi_verify from './endpoints/reversi/verify.js';
const eps = [
['admin/meta', ep___admin_meta],
['admin/abuse-user-reports', ep___admin_abuseUserReports],
+ ['admin/abuse-report/notification-recipient/list', ep___admin_abuseReport_notificationRecipient_list],
+ ['admin/abuse-report/notification-recipient/show', ep___admin_abuseReport_notificationRecipient_show],
+ ['admin/abuse-report/notification-recipient/create', ep___admin_abuseReport_notificationRecipient_create],
+ ['admin/abuse-report/notification-recipient/update', ep___admin_abuseReport_notificationRecipient_update],
+ ['admin/abuse-report/notification-recipient/delete', ep___admin_abuseReport_notificationRecipient_delete],
['admin/accounts/create', ep___admin_accounts_create],
['admin/accounts/delete', ep___admin_accounts_delete],
['admin/accounts/find-by-email', ep___admin_accounts_findByEmail],
@@ -453,6 +474,11 @@ const eps = [
['admin/roles/unassign', ep___admin_roles_unassign],
['admin/roles/update-default-policies', ep___admin_roles_updateDefaultPolicies],
['admin/roles/users', ep___admin_roles_users],
+ ['admin/system-webhook/create', ep___admin_systemWebhook_create],
+ ['admin/system-webhook/delete', ep___admin_systemWebhook_delete],
+ ['admin/system-webhook/list', ep___admin_systemWebhook_list],
+ ['admin/system-webhook/show', ep___admin_systemWebhook_show],
+ ['admin/system-webhook/update', ep___admin_systemWebhook_update],
['announcements', ep___announcements],
['announcements/show', ep___announcements_show],
['antennas/create', ep___antennas_create],
@@ -873,8 +899,12 @@ export interface IEndpoint {
const endpoints: IEndpoint[] = (eps as [string, any]).map(([name, ep]) => {
return {
name: name,
- get meta() { return ep.meta ?? {}; },
- get params() { return ep.paramDef; },
+ get meta() {
+ return ep.meta ?? {};
+ },
+ get params() {
+ return ep.paramDef;
+ },
};
});
diff --git a/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/create.ts b/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/create.ts
new file mode 100644
index 0000000000..bdfbcba518
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/create.ts
@@ -0,0 +1,122 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Inject, Injectable } from '@nestjs/common';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import { ApiError } from '@/server/api/error.js';
+import {
+ AbuseReportNotificationRecipientEntityService,
+} from '@/core/entities/AbuseReportNotificationRecipientEntityService.js';
+import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js';
+import { DI } from '@/di-symbols.js';
+import type { UserProfilesRepository } from '@/models/_.js';
+
+export const meta = {
+ tags: ['admin', 'abuse-report', 'notification-recipient'],
+
+ requireCredential: true,
+ requireModerator: true,
+ secure: true,
+ kind: 'write:admin:abuse-report:notification-recipient',
+
+ res: {
+ type: 'object',
+ ref: 'AbuseReportNotificationRecipient',
+ },
+
+ errors: {
+ correlationCheckEmail: {
+ message: 'If "method" is email, "userId" must be set.',
+ code: 'CORRELATION_CHECK_EMAIL',
+ id: '348bb8ae-575a-6fe9-4327-5811999def8f',
+ httpStatusCode: 400,
+ },
+ correlationCheckWebhook: {
+ message: 'If "method" is webhook, "systemWebhookId" must be set.',
+ code: 'CORRELATION_CHECK_WEBHOOK',
+ id: 'b0c15051-de2d-29ef-260c-9585cddd701a',
+ httpStatusCode: 400,
+ },
+ emailAddressNotSet: {
+ message: 'Email address is not set.',
+ code: 'EMAIL_ADDRESS_NOT_SET',
+ id: '7cc1d85e-2f58-fc31-b644-3de8d0d3421f',
+ httpStatusCode: 400,
+ },
+ },
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {
+ isActive: {
+ type: 'boolean',
+ },
+ name: {
+ type: 'string',
+ minLength: 1,
+ maxLength: 255,
+ },
+ method: {
+ type: 'string',
+ enum: ['email', 'webhook'],
+ },
+ userId: {
+ type: 'string',
+ format: 'misskey:id',
+ },
+ systemWebhookId: {
+ type: 'string',
+ format: 'misskey:id',
+ },
+ },
+ required: [
+ 'isActive',
+ 'name',
+ 'method',
+ ],
+} as const;
+
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
+ constructor(
+ @Inject(DI.userProfilesRepository)
+ private userProfilesRepository: UserProfilesRepository,
+ private abuseReportNotificationService: AbuseReportNotificationService,
+ private abuseReportNotificationRecipientEntityService: AbuseReportNotificationRecipientEntityService,
+ ) {
+ super(meta, paramDef, async (ps, me) => {
+ if (ps.method === 'email') {
+ const userProfile = await this.userProfilesRepository.findOneBy({ userId: ps.userId });
+ if (!ps.userId || !userProfile) {
+ throw new ApiError(meta.errors.correlationCheckEmail);
+ }
+
+ if (!userProfile.email || !userProfile.emailVerified) {
+ throw new ApiError(meta.errors.emailAddressNotSet);
+ }
+ }
+
+ if (ps.method === 'webhook' && !ps.systemWebhookId) {
+ throw new ApiError(meta.errors.correlationCheckWebhook);
+ }
+
+ const userId = ps.method === 'email' ? ps.userId : null;
+ const systemWebhookId = ps.method === 'webhook' ? ps.systemWebhookId : null;
+ const result = await this.abuseReportNotificationService.createRecipient(
+ {
+ isActive: ps.isActive,
+ name: ps.name,
+ method: ps.method,
+ userId: userId ?? null,
+ systemWebhookId: systemWebhookId ?? null,
+ },
+ me,
+ );
+
+ return this.abuseReportNotificationRecipientEntityService.pack(result);
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/delete.ts b/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/delete.ts
new file mode 100644
index 0000000000..b6dc44e09c
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/delete.ts
@@ -0,0 +1,44 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Injectable } from '@nestjs/common';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js';
+
+export const meta = {
+ tags: ['admin', 'abuse-report', 'notification-recipient'],
+
+ requireCredential: true,
+ requireModerator: true,
+ secure: true,
+ kind: 'write:admin:abuse-report:notification-recipient',
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {
+ id: {
+ type: 'string',
+ format: 'misskey:id',
+ },
+ },
+ required: [
+ 'id',
+ ],
+} as const;
+
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
+ constructor(
+ private abuseReportNotificationService: AbuseReportNotificationService,
+ ) {
+ super(meta, paramDef, async (ps, me) => {
+ await this.abuseReportNotificationService.deleteRecipient(
+ ps.id,
+ me,
+ );
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/list.ts b/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/list.ts
new file mode 100644
index 0000000000..dad9161a8a
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/list.ts
@@ -0,0 +1,55 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Injectable } from '@nestjs/common';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import {
+ AbuseReportNotificationRecipientEntityService,
+} from '@/core/entities/AbuseReportNotificationRecipientEntityService.js';
+import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js';
+
+export const meta = {
+ tags: ['admin', 'abuse-report', 'notification-recipient'],
+
+ requireCredential: true,
+ requireModerator: true,
+ secure: true,
+ kind: 'read:admin:abuse-report:notification-recipient',
+
+ res: {
+ type: 'array',
+ items: {
+ type: 'object',
+ ref: 'AbuseReportNotificationRecipient',
+ },
+ },
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {
+ method: {
+ type: 'array',
+ items: {
+ type: 'string',
+ enum: ['email', 'webhook'],
+ },
+ },
+ },
+ required: [],
+} as const;
+
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
+ constructor(
+ private abuseReportNotificationService: AbuseReportNotificationService,
+ private abuseReportNotificationRecipientEntityService: AbuseReportNotificationRecipientEntityService,
+ ) {
+ super(meta, paramDef, async (ps) => {
+ const recipients = await this.abuseReportNotificationService.fetchRecipients({ method: ps.method });
+ return this.abuseReportNotificationRecipientEntityService.packMany(recipients);
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/show.ts b/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/show.ts
new file mode 100644
index 0000000000..557798f946
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/show.ts
@@ -0,0 +1,64 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Injectable } from '@nestjs/common';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import {
+ AbuseReportNotificationRecipientEntityService,
+} from '@/core/entities/AbuseReportNotificationRecipientEntityService.js';
+import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js';
+import { ApiError } from '@/server/api/error.js';
+
+export const meta = {
+ tags: ['admin', 'abuse-report', 'notification-recipient'],
+
+ requireCredential: true,
+ requireModerator: true,
+ secure: true,
+ kind: 'read:admin:abuse-report:notification-recipient',
+
+ res: {
+ type: 'object',
+ ref: 'AbuseReportNotificationRecipient',
+ },
+
+ errors: {
+ noSuchRecipient: {
+ message: 'No such recipient.',
+ code: 'NO_SUCH_RECIPIENT',
+ id: '013de6a8-f757-04cb-4d73-cc2a7e3368e4',
+ kind: 'server',
+ httpStatusCode: 404,
+ },
+ },
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {
+ id: {
+ type: 'string',
+ format: 'misskey:id',
+ },
+ },
+ required: ['id'],
+} as const;
+
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
+ constructor(
+ private abuseReportNotificationService: AbuseReportNotificationService,
+ private abuseReportNotificationRecipientEntityService: AbuseReportNotificationRecipientEntityService,
+ ) {
+ super(meta, paramDef, async (ps) => {
+ const recipients = await this.abuseReportNotificationService.fetchRecipients({ ids: [ps.id] });
+ if (recipients.length === 0) {
+ throw new ApiError(meta.errors.noSuchRecipient);
+ }
+
+ return this.abuseReportNotificationRecipientEntityService.pack(recipients[0]);
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/update.ts b/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/update.ts
new file mode 100644
index 0000000000..bd4b485217
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/update.ts
@@ -0,0 +1,128 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Inject, Injectable } from '@nestjs/common';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import { ApiError } from '@/server/api/error.js';
+import {
+ AbuseReportNotificationRecipientEntityService,
+} from '@/core/entities/AbuseReportNotificationRecipientEntityService.js';
+import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js';
+import { DI } from '@/di-symbols.js';
+import type { UserProfilesRepository } from '@/models/_.js';
+
+export const meta = {
+ tags: ['admin', 'abuse-report', 'notification-recipient'],
+
+ requireCredential: true,
+ requireModerator: true,
+ secure: true,
+ kind: 'write:admin:abuse-report:notification-recipient',
+
+ res: {
+ type: 'object',
+ ref: 'AbuseReportNotificationRecipient',
+ },
+
+ errors: {
+ correlationCheckEmail: {
+ message: 'If "method" is email, "userId" must be set.',
+ code: 'CORRELATION_CHECK_EMAIL',
+ id: '348bb8ae-575a-6fe9-4327-5811999def8f',
+ httpStatusCode: 400,
+ },
+ correlationCheckWebhook: {
+ message: 'If "method" is webhook, "systemWebhookId" must be set.',
+ code: 'CORRELATION_CHECK_WEBHOOK',
+ id: 'b0c15051-de2d-29ef-260c-9585cddd701a',
+ httpStatusCode: 400,
+ },
+ emailAddressNotSet: {
+ message: 'Email address is not set.',
+ code: 'EMAIL_ADDRESS_NOT_SET',
+ id: '7cc1d85e-2f58-fc31-b644-3de8d0d3421f',
+ httpStatusCode: 400,
+ },
+ },
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {
+ id: {
+ type: 'string',
+ format: 'misskey:id',
+ },
+ isActive: {
+ type: 'boolean',
+ },
+ name: {
+ type: 'string',
+ minLength: 1,
+ maxLength: 255,
+ },
+ method: {
+ type: 'string',
+ enum: ['email', 'webhook'],
+ },
+ userId: {
+ type: 'string',
+ format: 'misskey:id',
+ },
+ systemWebhookId: {
+ type: 'string',
+ format: 'misskey:id',
+ },
+ },
+ required: [
+ 'id',
+ 'isActive',
+ 'name',
+ 'method',
+ ],
+} as const;
+
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
+ constructor(
+ @Inject(DI.userProfilesRepository)
+ private userProfilesRepository: UserProfilesRepository,
+ private abuseReportNotificationService: AbuseReportNotificationService,
+ private abuseReportNotificationRecipientEntityService: AbuseReportNotificationRecipientEntityService,
+ ) {
+ super(meta, paramDef, async (ps, me) => {
+ if (ps.method === 'email') {
+ const userProfile = await this.userProfilesRepository.findOneBy({ userId: ps.userId });
+ if (!ps.userId || !userProfile) {
+ throw new ApiError(meta.errors.correlationCheckEmail);
+ }
+
+ if (!userProfile.email || !userProfile.emailVerified) {
+ throw new ApiError(meta.errors.emailAddressNotSet);
+ }
+ }
+
+ if (ps.method === 'webhook' && !ps.systemWebhookId) {
+ throw new ApiError(meta.errors.correlationCheckWebhook);
+ }
+
+ const userId = ps.method === 'email' ? ps.userId : null;
+ const systemWebhookId = ps.method === 'webhook' ? ps.systemWebhookId : null;
+ const result = await this.abuseReportNotificationService.updateRecipient(
+ {
+ id: ps.id,
+ isActive: ps.isActive,
+ name: ps.name,
+ method: ps.method,
+ userId: userId ?? null,
+ systemWebhookId: systemWebhookId ?? null,
+ },
+ me,
+ );
+
+ return this.abuseReportNotificationRecipientEntityService.pack(result);
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/endpoints/admin/ad/update.ts b/packages/backend/src/server/api/endpoints/admin/ad/update.ts
index 62358457ff..4e3d731aca 100644
--- a/packages/backend/src/server/api/endpoints/admin/ad/update.ts
+++ b/packages/backend/src/server/api/endpoints/admin/ad/update.ts
@@ -40,7 +40,7 @@ export const paramDef = {
startsAt: { type: 'integer' },
dayOfWeek: { type: 'integer' },
},
- required: ['id', 'memo', 'url', 'imageUrl', 'place', 'priority', 'ratio', 'expiresAt', 'startsAt', 'dayOfWeek'],
+ required: ['id'],
} as const;
@Injectable()
@@ -63,8 +63,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
ratio: ps.ratio,
memo: ps.memo,
imageUrl: ps.imageUrl,
- expiresAt: new Date(ps.expiresAt),
- startsAt: new Date(ps.startsAt),
+ expiresAt: ps.expiresAt ? new Date(ps.expiresAt) : undefined,
+ startsAt: ps.startsAt ? new Date(ps.startsAt) : undefined,
dayOfWeek: ps.dayOfWeek,
});
diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts
index 87eaad31a3..7596bf44e3 100644
--- a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts
+++ b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts
@@ -69,6 +69,7 @@ export const paramDef = {
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
userId: { type: 'string', format: 'misskey:id', nullable: true },
+ status: { type: 'string', enum: ['all', 'active', 'archived'], default: 'active' },
},
required: [],
} as const;
@@ -87,7 +88,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
) {
super(meta, paramDef, async (ps, me) => {
const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId);
- query.andWhere('announcement.isActive = true');
+
+ if (ps.status === 'archived') {
+ query.andWhere('announcement.isActive = false');
+ } else if (ps.status === 'active') {
+ query.andWhere('announcement.isActive = true');
+ }
+
if (ps.userId) {
query.andWhere('announcement.userId = :userId', { userId: ps.userId });
} else {
diff --git a/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts b/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts
index 459d8880fa..a7136d8c8c 100644
--- a/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts
+++ b/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts
@@ -61,7 +61,7 @@ export const meta = {
name: {
type: 'string',
optional: false, nullable: false,
- example: 'lenna.jpg',
+ example: '192.jpg',
},
type: {
type: 'string',
diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts
index eee02a7123..2e7f73da73 100644
--- a/packages/backend/src/server/api/endpoints/admin/meta.ts
+++ b/packages/backend/src/server/api/endpoints/admin/meta.ts
@@ -128,6 +128,16 @@ export const meta = {
nullable: false,
},
},
+ mediaSilencedHosts: {
+ type: 'array',
+ optional: false,
+ nullable: false,
+ items: {
+ type: 'string',
+ optional: false,
+ nullable: false,
+ },
+ },
pinnedUsers: {
type: 'array',
optional: false, nullable: false,
@@ -552,6 +562,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
hiddenTags: instance.hiddenTags,
blockedHosts: instance.blockedHosts,
silencedHosts: instance.silencedHosts,
+ mediaSilencedHosts: instance.mediaSilencedHosts,
sensitiveWords: instance.sensitiveWords,
prohibitedWords: instance.prohibitedWords,
preservedUsernames: instance.preservedUsernames,
diff --git a/packages/backend/src/server/api/endpoints/admin/queue/stats.ts b/packages/backend/src/server/api/endpoints/admin/queue/stats.ts
index 9694b3fa40..d7f9e4eaa3 100644
--- a/packages/backend/src/server/api/endpoints/admin/queue/stats.ts
+++ b/packages/backend/src/server/api/endpoints/admin/queue/stats.ts
@@ -5,7 +5,7 @@
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
-import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, ObjectStorageQueue, SystemQueue, WebhookDeliverQueue } from '@/core/QueueModule.js';
+import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, ObjectStorageQueue, SystemQueue, UserWebhookDeliverQueue, SystemWebhookDeliverQueue } from '@/core/QueueModule.js';
export const meta = {
tags: ['admin'],
@@ -53,7 +53,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
@Inject('queue:inbox') public inboxQueue: InboxQueue,
@Inject('queue:db') public dbQueue: DbQueue,
@Inject('queue:objectStorage') public objectStorageQueue: ObjectStorageQueue,
- @Inject('queue:webhookDeliver') public webhookDeliverQueue: WebhookDeliverQueue,
+ @Inject('queue:userWebhookDeliver') public userWebhookDeliverQueue: UserWebhookDeliverQueue,
+ @Inject('queue:systemWebhookDeliver') public systemWebhookDeliverQueue: SystemWebhookDeliverQueue,
) {
super(meta, paramDef, async (ps, me) => {
const deliverJobCounts = await this.deliverQueue.getJobCounts();
diff --git a/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts b/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts
index 8b0456068b..9b79100fcf 100644
--- a/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts
+++ b/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts
@@ -5,12 +5,10 @@
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
-import type { UsersRepository, AbuseUserReportsRepository } from '@/models/_.js';
-import { InstanceActorService } from '@/core/InstanceActorService.js';
-import { QueueService } from '@/core/QueueService.js';
-import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
+import type { AbuseUserReportsRepository } from '@/models/_.js';
import { DI } from '@/di-symbols.js';
-import { ModerationLogService } from '@/core/ModerationLogService.js';
+import { ApiError } from '@/server/api/error.js';
+import { AbuseReportService } from '@/core/AbuseReportService.js';
export const meta = {
tags: ['admin'],
@@ -18,6 +16,16 @@ export const meta = {
requireCredential: true,
requireModerator: true,
kind: 'write:admin:resolve-abuse-user-report',
+
+ errors: {
+ noSuchAbuseReport: {
+ message: 'No such abuse report.',
+ code: 'NO_SUCH_ABUSE_REPORT',
+ id: 'ac3794dd-2ce4-d878-e546-73c60c06b398',
+ kind: 'server',
+ httpStatusCode: 404,
+ },
+ },
} as const;
export const paramDef = {
@@ -29,47 +37,20 @@ export const paramDef = {
required: ['reportId'],
} as const;
-// TODO: ロジックをサービスã«åˆ‡ã‚Šå‡ºã™
-
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
- @Inject(DI.usersRepository)
- private usersRepository: UsersRepository,
-
@Inject(DI.abuseUserReportsRepository)
private abuseUserReportsRepository: AbuseUserReportsRepository,
-
- private queueService: QueueService,
- private instanceActorService: InstanceActorService,
- private apRendererService: ApRendererService,
- private moderationLogService: ModerationLogService,
+ private abuseReportService: AbuseReportService,
) {
super(meta, paramDef, async (ps, me) => {
const report = await this.abuseUserReportsRepository.findOneBy({ id: ps.reportId });
-
- if (report == null) {
- throw new Error('report not found');
+ if (!report) {
+ throw new ApiError(meta.errors.noSuchAbuseReport);
}
- if (ps.forward && report.targetUserHost != null) {
- const actor = await this.instanceActorService.getInstanceActor();
- const targetUser = await this.usersRepository.findOneByOrFail({ id: report.targetUserId });
-
- this.queueService.deliver(actor, this.apRendererService.addContext(this.apRendererService.renderFlag(actor, targetUser.uri!, report.comment)), targetUser.inbox, false);
- }
-
- await this.abuseUserReportsRepository.update(report.id, {
- resolved: true,
- assigneeId: me.id,
- forwarded: ps.forward && report.targetUserHost != null,
- });
-
- this.moderationLogService.log(me, 'resolveAbuseReport', {
- reportId: report.id,
- report: report,
- forwarded: ps.forward && report.targetUserHost != null,
- });
+ await this.abuseReportService.resolve([{ reportId: report.id, forward: ps.forward }], me);
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/admin/roles/update.ts b/packages/backend/src/server/api/endpoints/admin/roles/update.ts
index 5242e0be2f..465ad7aaaf 100644
--- a/packages/backend/src/server/api/endpoints/admin/roles/update.ts
+++ b/packages/backend/src/server/api/endpoints/admin/roles/update.ts
@@ -6,7 +6,6 @@
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import type { RolesRepository } from '@/models/_.js';
-import { GlobalEventService } from '@/core/GlobalEventService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '@/server/api/error.js';
import { RoleService } from '@/core/RoleService.js';
@@ -50,19 +49,6 @@ export const paramDef = {
},
required: [
'roleId',
- 'name',
- 'description',
- 'color',
- 'iconUrl',
- 'target',
- 'condFormula',
- 'isPublic',
- 'isModerator',
- 'isAdministrator',
- 'asBadge',
- 'canEditMembersByModerator',
- 'displayOrder',
- 'policies',
],
} as const;
diff --git a/packages/backend/src/server/api/endpoints/admin/system-webhook/create.ts b/packages/backend/src/server/api/endpoints/admin/system-webhook/create.ts
new file mode 100644
index 0000000000..28071e7a33
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/admin/system-webhook/create.ts
@@ -0,0 +1,85 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Injectable } from '@nestjs/common';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import { SystemWebhookEntityService } from '@/core/entities/SystemWebhookEntityService.js';
+import { systemWebhookEventTypes } from '@/models/SystemWebhook.js';
+import { SystemWebhookService } from '@/core/SystemWebhookService.js';
+
+export const meta = {
+ tags: ['admin', 'system-webhook'],
+
+ requireCredential: true,
+ requireModerator: true,
+ secure: true,
+ kind: 'write:admin:system-webhook',
+
+ res: {
+ type: 'object',
+ ref: 'SystemWebhook',
+ },
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {
+ isActive: {
+ type: 'boolean',
+ },
+ name: {
+ type: 'string',
+ minLength: 1,
+ maxLength: 255,
+ },
+ on: {
+ type: 'array',
+ items: {
+ type: 'string',
+ enum: systemWebhookEventTypes,
+ },
+ },
+ url: {
+ type: 'string',
+ minLength: 1,
+ maxLength: 1024,
+ },
+ secret: {
+ type: 'string',
+ minLength: 1,
+ maxLength: 1024,
+ },
+ },
+ required: [
+ 'isActive',
+ 'name',
+ 'on',
+ 'url',
+ 'secret',
+ ],
+} as const;
+
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
+ constructor(
+ private systemWebhookService: SystemWebhookService,
+ private systemWebhookEntityService: SystemWebhookEntityService,
+ ) {
+ super(meta, paramDef, async (ps, me) => {
+ const result = await this.systemWebhookService.createSystemWebhook(
+ {
+ isActive: ps.isActive,
+ name: ps.name,
+ on: ps.on,
+ url: ps.url,
+ secret: ps.secret,
+ },
+ me,
+ );
+
+ return this.systemWebhookEntityService.pack(result);
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/endpoints/admin/system-webhook/delete.ts b/packages/backend/src/server/api/endpoints/admin/system-webhook/delete.ts
new file mode 100644
index 0000000000..9cdfc7e70f
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/admin/system-webhook/delete.ts
@@ -0,0 +1,44 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Injectable } from '@nestjs/common';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import { SystemWebhookService } from '@/core/SystemWebhookService.js';
+
+export const meta = {
+ tags: ['admin', 'system-webhook'],
+
+ requireCredential: true,
+ requireModerator: true,
+ secure: true,
+ kind: 'write:admin:system-webhook',
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {
+ id: {
+ type: 'string',
+ format: 'misskey:id',
+ },
+ },
+ required: [
+ 'id',
+ ],
+} as const;
+
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
+ constructor(
+ private systemWebhookService: SystemWebhookService,
+ ) {
+ super(meta, paramDef, async (ps, me) => {
+ await this.systemWebhookService.deleteSystemWebhook(
+ ps.id,
+ me,
+ );
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/endpoints/admin/system-webhook/list.ts b/packages/backend/src/server/api/endpoints/admin/system-webhook/list.ts
new file mode 100644
index 0000000000..7a440a774e
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/admin/system-webhook/list.ts
@@ -0,0 +1,60 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Injectable } from '@nestjs/common';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import { SystemWebhookEntityService } from '@/core/entities/SystemWebhookEntityService.js';
+import { systemWebhookEventTypes } from '@/models/SystemWebhook.js';
+import { SystemWebhookService } from '@/core/SystemWebhookService.js';
+
+export const meta = {
+ tags: ['admin', 'system-webhook'],
+
+ requireCredential: true,
+ requireModerator: true,
+ secure: true,
+ kind: 'write:admin:system-webhook',
+
+ res: {
+ type: 'array',
+ items: {
+ type: 'object',
+ ref: 'SystemWebhook',
+ },
+ },
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {
+ isActive: {
+ type: 'boolean',
+ },
+ on: {
+ type: 'array',
+ items: {
+ type: 'string',
+ enum: systemWebhookEventTypes,
+ },
+ },
+ },
+ required: [],
+} as const;
+
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
+ constructor(
+ private systemWebhookService: SystemWebhookService,
+ private systemWebhookEntityService: SystemWebhookEntityService,
+ ) {
+ super(meta, paramDef, async (ps) => {
+ const webhooks = await this.systemWebhookService.fetchSystemWebhooks({
+ isActive: ps.isActive,
+ on: ps.on,
+ });
+ return this.systemWebhookEntityService.packMany(webhooks);
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/endpoints/admin/system-webhook/show.ts b/packages/backend/src/server/api/endpoints/admin/system-webhook/show.ts
new file mode 100644
index 0000000000..75862c96a7
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/admin/system-webhook/show.ts
@@ -0,0 +1,62 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Injectable } from '@nestjs/common';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import { SystemWebhookEntityService } from '@/core/entities/SystemWebhookEntityService.js';
+import { ApiError } from '@/server/api/error.js';
+import { SystemWebhookService } from '@/core/SystemWebhookService.js';
+
+export const meta = {
+ tags: ['admin', 'system-webhook'],
+
+ requireCredential: true,
+ requireModerator: true,
+ secure: true,
+ kind: 'write:admin:system-webhook',
+
+ res: {
+ type: 'object',
+ ref: 'SystemWebhook',
+ },
+
+ errors: {
+ noSuchSystemWebhook: {
+ message: 'No such SystemWebhook.',
+ code: 'NO_SUCH_SYSTEM_WEBHOOK',
+ id: '38dd1ffe-04b4-6ff5-d8ba-4e6a6ae22c9d',
+ kind: 'server',
+ httpStatusCode: 404,
+ },
+ },
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {
+ id: {
+ type: 'string',
+ format: 'misskey:id',
+ },
+ },
+ required: ['id'],
+} as const;
+
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
+ constructor(
+ private systemWebhookService: SystemWebhookService,
+ private systemWebhookEntityService: SystemWebhookEntityService,
+ ) {
+ super(meta, paramDef, async (ps) => {
+ const webhooks = await this.systemWebhookService.fetchSystemWebhooks({ ids: [ps.id] });
+ if (webhooks.length === 0) {
+ throw new ApiError(meta.errors.noSuchSystemWebhook);
+ }
+
+ return this.systemWebhookEntityService.pack(webhooks[0]);
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/endpoints/admin/system-webhook/update.ts b/packages/backend/src/server/api/endpoints/admin/system-webhook/update.ts
new file mode 100644
index 0000000000..8d68bb8f87
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/admin/system-webhook/update.ts
@@ -0,0 +1,91 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Injectable } from '@nestjs/common';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import { SystemWebhookEntityService } from '@/core/entities/SystemWebhookEntityService.js';
+import { systemWebhookEventTypes } from '@/models/SystemWebhook.js';
+import { SystemWebhookService } from '@/core/SystemWebhookService.js';
+
+export const meta = {
+ tags: ['admin', 'system-webhook'],
+
+ requireCredential: true,
+ requireModerator: true,
+ secure: true,
+ kind: 'write:admin:system-webhook',
+
+ res: {
+ type: 'object',
+ ref: 'SystemWebhook',
+ },
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {
+ id: {
+ type: 'string',
+ format: 'misskey:id',
+ },
+ isActive: {
+ type: 'boolean',
+ },
+ name: {
+ type: 'string',
+ minLength: 1,
+ maxLength: 255,
+ },
+ on: {
+ type: 'array',
+ items: {
+ type: 'string',
+ enum: systemWebhookEventTypes,
+ },
+ },
+ url: {
+ type: 'string',
+ minLength: 1,
+ maxLength: 1024,
+ },
+ secret: {
+ type: 'string',
+ minLength: 1,
+ maxLength: 1024,
+ },
+ },
+ required: [
+ 'id',
+ 'isActive',
+ 'name',
+ 'on',
+ 'url',
+ 'secret',
+ ],
+} as const;
+
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
+ constructor(
+ private systemWebhookService: SystemWebhookService,
+ private systemWebhookEntityService: SystemWebhookEntityService,
+ ) {
+ super(meta, paramDef, async (ps, me) => {
+ const result = await this.systemWebhookService.updateSystemWebhook(
+ {
+ id: ps.id,
+ isActive: ps.isActive,
+ name: ps.name,
+ on: ps.on,
+ url: ps.url,
+ secret: ps.secret,
+ },
+ me,
+ );
+
+ return this.systemWebhookEntityService.pack(result);
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts
index 4e28ee6877..5efdc9d8c4 100644
--- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts
+++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts
@@ -150,6 +150,13 @@ export const paramDef = {
type: 'string',
},
},
+ mediaSilencedHosts: {
+ type: 'array',
+ nullable: true,
+ items: {
+ type: 'string',
+ },
+ },
summalyProxy: {
type: 'string', nullable: true,
description: '[Deprecated] Use "urlPreviewSummaryProxyUrl" instead.',
@@ -203,6 +210,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
return h !== '' && h !== lv && !set.blockedHosts?.includes(h);
});
}
+ if (Array.isArray(ps.mediaSilencedHosts)) {
+ let lastValue = '';
+ set.mediaSilencedHosts = ps.mediaSilencedHosts.sort().filter((h) => {
+ const lv = lastValue;
+ lastValue = h;
+ return h !== '' && h !== lv && !set.blockedHosts?.includes(h);
+ });
+ }
if (ps.themeColor !== undefined) {
set.themeColor = ps.themeColor;
}
diff --git a/packages/backend/src/server/api/endpoints/antennas/create.ts b/packages/backend/src/server/api/endpoints/antennas/create.ts
index ec08198514..577b9e1b1f 100644
--- a/packages/backend/src/server/api/endpoints/antennas/create.ts
+++ b/packages/backend/src/server/api/endpoints/antennas/create.ts
@@ -93,7 +93,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const currentAntennasCount = await this.antennasRepository.countBy({
userId: me.id,
});
- if (currentAntennasCount > (await this.roleService.getUserPolicies(me.id)).antennaLimit) {
+ if (currentAntennasCount >= (await this.roleService.getUserPolicies(me.id)).antennaLimit) {
throw new ApiError(meta.errors.tooManyAntennas);
}
diff --git a/packages/backend/src/server/api/endpoints/clips/update.ts b/packages/backend/src/server/api/endpoints/clips/update.ts
index 3b44ba81b3..603a3ccf3d 100644
--- a/packages/backend/src/server/api/endpoints/clips/update.ts
+++ b/packages/backend/src/server/api/endpoints/clips/update.ts
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
-import { Inject, Injectable } from '@nestjs/common';
+import { Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { ClipEntityService } from '@/core/entities/ClipEntityService.js';
import { ClipService } from '@/core/ClipService.js';
@@ -41,7 +41,7 @@ export const paramDef = {
isPublic: { type: 'boolean' },
description: { type: 'string', nullable: true, minLength: 1, maxLength: 2048 },
},
- required: ['clipId', 'name'],
+ required: ['clipId'],
} as const;
@Injectable()
diff --git a/packages/backend/src/server/api/endpoints/drive/folders/update.ts b/packages/backend/src/server/api/endpoints/drive/folders/update.ts
index 52b8b335b5..62b04e1df3 100644
--- a/packages/backend/src/server/api/endpoints/drive/folders/update.ts
+++ b/packages/backend/src/server/api/endpoints/drive/folders/update.ts
@@ -95,15 +95,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
// Check if the circular reference will occur
const checkCircle = async (folderId: string): Promise<boolean> => {
- // Fetch folder
- const folder2 = await this.driveFoldersRepository.findOneBy({
+ const folder2 = await this.driveFoldersRepository.findOneByOrFail({
id: folderId,
});
- if (folder2!.id === folder!.id) {
+ if (folder2.id === folder.id) {
return true;
- } else if (folder2!.parentId) {
- return await checkCircle(folder2!.parentId);
+ } else if (folder2.parentId) {
+ return await checkCircle(folder2.parentId);
} else {
return false;
}
diff --git a/packages/backend/src/server/api/endpoints/federation/instances.ts b/packages/backend/src/server/api/endpoints/federation/instances.ts
index 4ef4315fb3..36f4bf5aa6 100644
--- a/packages/backend/src/server/api/endpoints/federation/instances.ts
+++ b/packages/backend/src/server/api/endpoints/federation/instances.ts
@@ -117,9 +117,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
if (typeof ps.suspended === 'boolean') {
if (ps.suspended) {
- query.andWhere('instance.isSuspended = TRUE');
+ query.andWhere('instance.suspensionState != \'none\'');
} else {
- query.andWhere('instance.isSuspended = FALSE');
+ query.andWhere('instance.suspensionState = \'none\'');
}
}
diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/create.ts b/packages/backend/src/server/api/endpoints/gallery/posts/create.ts
index 46f8998810..504a9c789e 100644
--- a/packages/backend/src/server/api/endpoints/gallery/posts/create.ts
+++ b/packages/backend/src/server/api/endpoints/gallery/posts/create.ts
@@ -12,7 +12,6 @@ import type { MiDriveFile } from '@/models/DriveFile.js';
import { IdService } from '@/core/IdService.js';
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
import { DI } from '@/di-symbols.js';
-import { isNotNull } from '@/misc/is-not-null.js';
export const meta = {
tags: ['gallery'],
@@ -70,7 +69,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
id: fileId,
userId: me.id,
}),
- ))).filter(isNotNull);
+ ))).filter(x => x != null);
if (files.length === 0) {
throw new Error();
diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/update.ts b/packages/backend/src/server/api/endpoints/gallery/posts/update.ts
index 8bd83ff5ba..5243ee9603 100644
--- a/packages/backend/src/server/api/endpoints/gallery/posts/update.ts
+++ b/packages/backend/src/server/api/endpoints/gallery/posts/update.ts
@@ -10,7 +10,6 @@ import type { DriveFilesRepository, GalleryPostsRepository } from '@/models/_.js
import type { MiDriveFile } from '@/models/DriveFile.js';
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
import { DI } from '@/di-symbols.js';
-import { isNotNull } from '@/misc/is-not-null.js';
export const meta = {
tags: ['gallery'],
@@ -48,7 +47,7 @@ export const paramDef = {
} },
isSensitive: { type: 'boolean', default: false },
},
- required: ['postId', 'title', 'fileIds'],
+ required: ['postId'],
} as const;
@Injectable()
@@ -63,15 +62,19 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private galleryPostEntityService: GalleryPostEntityService,
) {
super(meta, paramDef, async (ps, me) => {
- const files = (await Promise.all(ps.fileIds.map(fileId =>
- this.driveFilesRepository.findOneBy({
- id: fileId,
- userId: me.id,
- }),
- ))).filter(isNotNull);
+ let files: Array<MiDriveFile> | undefined;
- if (files.length === 0) {
- throw new Error();
+ if (ps.fileIds) {
+ files = (await Promise.all(ps.fileIds.map(fileId =>
+ this.driveFilesRepository.findOneBy({
+ id: fileId,
+ userId: me.id,
+ }),
+ ))).filter(x => x != null);
+
+ if (files.length === 0) {
+ throw new Error();
+ }
}
await this.galleryPostsRepository.update({
@@ -82,7 +85,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
title: ps.title,
description: ps.description,
isSensitive: ps.isSensitive,
- fileIds: files.map(file => file.id),
+ fileIds: files ? files.map(file => file.id) : undefined,
});
const post = await this.galleryPostsRepository.findOneByOrFail({ id: ps.postId });
diff --git a/packages/backend/src/server/api/endpoints/i/import-antennas.ts b/packages/backend/src/server/api/endpoints/i/import-antennas.ts
index b4661a93e2..bc46163e3d 100644
--- a/packages/backend/src/server/api/endpoints/i/import-antennas.ts
+++ b/packages/backend/src/server/api/endpoints/i/import-antennas.ts
@@ -78,7 +78,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
if (file.size === 0) throw new ApiError(meta.errors.emptyFile);
const antennas: (_Antenna & { userListAccts: string[] | null })[] = JSON.parse(await this.downloadService.downloadTextFile(file.url));
const currentAntennasCount = await this.antennasRepository.countBy({ userId: me.id });
- if (currentAntennasCount + antennas.length > (await this.roleService.getUserPolicies(me.id)).antennaLimit) {
+ if (currentAntennasCount + antennas.length >= (await this.roleService.getUserPolicies(me.id)).antennaLimit) {
throw new ApiError(meta.errors.tooManyAntennas);
}
this.queueService.createImportAntennasJob(me, antennas);
diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts
index a8e702f328..a1e2fa5e4c 100644
--- a/packages/backend/src/server/api/endpoints/i/update.ts
+++ b/packages/backend/src/server/api/endpoints/i/update.ts
@@ -25,7 +25,7 @@ import { UserFollowingService } from '@/core/UserFollowingService.js';
import { AccountUpdateService } from '@/core/AccountUpdateService.js';
import { HashtagService } from '@/core/HashtagService.js';
import { DI } from '@/di-symbols.js';
-import { RoleService } from '@/core/RoleService.js';
+import { RolePolicies, RoleService } from '@/core/RoleService.js';
import { CacheService } from '@/core/CacheService.js';
import { RemoteUserResolveService } from '@/core/RemoteUserResolveService.js';
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
@@ -256,8 +256,16 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const profileUpdates = {} as Partial<MiUserProfile>;
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id });
+ let policies: RolePolicies | null = null;
- if (ps.name !== undefined) updates.name = ps.name;
+ if (ps.name !== undefined) {
+ if (ps.name === null) {
+ updates.name = null;
+ } else {
+ const trimmedName = ps.name.trim();
+ updates.name = trimmedName === '' ? null : trimmedName;
+ }
+ }
if (ps.description !== undefined) profileUpdates.description = ps.description;
if (ps.lang !== undefined) profileUpdates.lang = ps.lang;
if (ps.location !== undefined) profileUpdates.location = ps.location;
@@ -289,14 +297,16 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
}
if (ps.mutedWords !== undefined) {
- checkMuteWordCount(ps.mutedWords, (await this.roleService.getUserPolicies(user.id)).wordMuteLimit);
+ policies ??= await this.roleService.getUserPolicies(user.id);
+ checkMuteWordCount(ps.mutedWords, policies.wordMuteLimit);
validateMuteWordRegex(ps.mutedWords);
profileUpdates.mutedWords = ps.mutedWords;
profileUpdates.enableWordMute = ps.mutedWords.length > 0;
}
if (ps.hardMutedWords !== undefined) {
- checkMuteWordCount(ps.hardMutedWords, (await this.roleService.getUserPolicies(user.id)).wordMuteLimit);
+ policies ??= await this.roleService.getUserPolicies(user.id);
+ checkMuteWordCount(ps.hardMutedWords, policies.wordMuteLimit);
validateMuteWordRegex(ps.hardMutedWords);
profileUpdates.hardMutedWords = ps.hardMutedWords;
}
@@ -315,13 +325,17 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
if (typeof ps.injectFeaturedNote === 'boolean') profileUpdates.injectFeaturedNote = ps.injectFeaturedNote;
if (typeof ps.receiveAnnouncementEmail === 'boolean') profileUpdates.receiveAnnouncementEmail = ps.receiveAnnouncementEmail;
if (typeof ps.alwaysMarkNsfw === 'boolean') {
- if ((await roleService.getUserPolicies(user.id)).alwaysMarkNsfw) throw new ApiError(meta.errors.restrictedByRole);
+ policies ??= await this.roleService.getUserPolicies(user.id);
+ if (policies.alwaysMarkNsfw) throw new ApiError(meta.errors.restrictedByRole);
profileUpdates.alwaysMarkNsfw = ps.alwaysMarkNsfw;
}
if (typeof ps.autoSensitive === 'boolean') profileUpdates.autoSensitive = ps.autoSensitive;
if (ps.emailNotificationTypes !== undefined) profileUpdates.emailNotificationTypes = ps.emailNotificationTypes;
if (ps.avatarId) {
+ policies ??= await this.roleService.getUserPolicies(user.id);
+ if (!policies.canUpdateBioMedia) throw new ApiError(meta.errors.restrictedByRole);
+
const avatar = await this.driveFilesRepository.findOneBy({ id: ps.avatarId });
if (avatar == null || avatar.userId !== user.id) throw new ApiError(meta.errors.noSuchAvatar);
@@ -337,6 +351,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
}
if (ps.bannerId) {
+ policies ??= await this.roleService.getUserPolicies(user.id);
+ if (!policies.canUpdateBioMedia) throw new ApiError(meta.errors.restrictedByRole);
+
const banner = await this.driveFilesRepository.findOneBy({ id: ps.bannerId });
if (banner == null || banner.userId !== user.id) throw new ApiError(meta.errors.noSuchBanner);
@@ -352,14 +369,15 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
}
if (ps.avatarDecorations) {
+ policies ??= await this.roleService.getUserPolicies(user.id);
const decorations = await this.avatarDecorationService.getAll(true);
- const [myRoles, myPolicies] = await Promise.all([this.roleService.getUserRoles(user.id), this.roleService.getUserPolicies(user.id)]);
+ const myRoles = await this.roleService.getUserRoles(user.id);
const allRoles = await this.roleService.getRoles();
const decorationIds = decorations
.filter(d => d.roleIdsThatCanBeUsedThisDecoration.filter(roleId => allRoles.some(r => r.id === roleId)).length === 0 || myRoles.some(r => d.roleIdsThatCanBeUsedThisDecoration.includes(r.id)))
.map(d => d.id);
- if (ps.avatarDecorations.length > myPolicies.avatarDecorationLimit) throw new ApiError(meta.errors.restrictedByRole);
+ if (ps.avatarDecorations.length > policies.avatarDecorationLimit) throw new ApiError(meta.errors.restrictedByRole);
updates.avatarDecorations = ps.avatarDecorations.filter(d => decorationIds.includes(d.id)).map(d => ({
id: d.id,
diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/create.ts b/packages/backend/src/server/api/endpoints/i/webhooks/create.ts
index c692380288..9eb7f5b3a0 100644
--- a/packages/backend/src/server/api/endpoints/i/webhooks/create.ts
+++ b/packages/backend/src/server/api/endpoints/i/webhooks/create.ts
@@ -85,7 +85,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const currentWebhooksCount = await this.webhooksRepository.countBy({
userId: me.id,
});
- if (currentWebhooksCount > (await this.roleService.getUserPolicies(me.id)).webhookLimit) {
+ if (currentWebhooksCount >= (await this.roleService.getUserPolicies(me.id)).webhookLimit) {
throw new ApiError(meta.errors.tooManyWebhooks);
}
diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/update.ts b/packages/backend/src/server/api/endpoints/i/webhooks/update.ts
index 6e380d76f8..07a25bd82a 100644
--- a/packages/backend/src/server/api/endpoints/i/webhooks/update.ts
+++ b/packages/backend/src/server/api/endpoints/i/webhooks/update.ts
@@ -34,13 +34,13 @@ export const paramDef = {
webhookId: { type: 'string', format: 'misskey:id' },
name: { type: 'string', minLength: 1, maxLength: 100 },
url: { type: 'string', minLength: 1, maxLength: 1024 },
- secret: { type: 'string', maxLength: 1024, default: '' },
+ secret: { type: 'string', nullable: true, maxLength: 1024 },
on: { type: 'array', items: {
type: 'string', enum: webhookEventTypes,
} },
active: { type: 'boolean' },
},
- required: ['webhookId', 'name', 'url', 'on', 'active'],
+ required: ['webhookId'],
} as const;
// TODO: ロジックをサービスã«åˆ‡ã‚Šå‡ºã™
@@ -66,7 +66,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
await this.webhooksRepository.update(webhook.id, {
name: ps.name,
url: ps.url,
- secret: ps.secret,
+ secret: ps.secret === null ? '' : ps.secret,
on: ps.on,
active: ps.active,
});
diff --git a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts
index 5acc9706d3..2a2c659942 100644
--- a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts
+++ b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts
@@ -139,9 +139,16 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
timelineConfig = [
`homeTimeline:${me.id}`,
'localTimeline',
+ `localTimelineWithReplyTo:${me.id}`,
];
}
+ const [
+ followings,
+ ] = await Promise.all([
+ this.cacheService.userFollowingsCache.fetch(me.id),
+ ]);
+
const redisTimeline = await this.fanoutTimelineEndpointService.timeline({
untilId,
sinceId,
@@ -152,6 +159,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
useDbFallback: serverSettings.enableFanoutTimelineDbFallback,
alwaysIncludeMyNotes: true,
excludePureRenotes: !ps.withRenotes,
+ noteFilter: note => {
+ if (note.reply && note.reply.visibility === 'followers') {
+ if (!Object.hasOwn(followings, note.reply.userId) && note.reply.userId !== me.id) return false;
+ }
+
+ return true;
+ },
dbFallback: async (untilId, sinceId, limit) => await this.getFromDb({
untilId,
sinceId,
diff --git a/packages/backend/src/server/api/endpoints/notes/reactions/create.ts b/packages/backend/src/server/api/endpoints/notes/reactions/create.ts
index b9899608bf..0f0dcca605 100644
--- a/packages/backend/src/server/api/endpoints/notes/reactions/create.ts
+++ b/packages/backend/src/server/api/endpoints/notes/reactions/create.ts
@@ -36,6 +36,12 @@ export const meta = {
code: 'YOU_HAVE_BEEN_BLOCKED',
id: '20ef5475-9f38-4e4c-bd33-de6d979498ec',
},
+
+ cannotReactToRenote: {
+ message: 'You cannot react to Renote.',
+ code: 'CANNOT_REACT_TO_RENOTE',
+ id: 'eaccdc08-ddef-43fe-908f-d108faad57f5',
+ },
},
} as const;
@@ -62,6 +68,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
await this.reactionService.create(me, note, ps.reaction).catch(err => {
if (err.id === '51c42bb4-931a-456b-bff7-e5a8a70dd298') throw new ApiError(meta.errors.alreadyReacted);
if (err.id === 'e70412a4-7197-4726-8e74-f3e0deb92aa7') throw new ApiError(meta.errors.youHaveBeenBlocked);
+ if (err.id === '12c35529-3c79-4327-b1cc-e2cf63a71925') throw new ApiError(meta.errors.cannotReactToRenote);
throw err;
});
return;
diff --git a/packages/backend/src/server/api/endpoints/notes/timeline.ts b/packages/backend/src/server/api/endpoints/notes/timeline.ts
index 8b87908bd3..c9b43b5359 100644
--- a/packages/backend/src/server/api/endpoints/notes/timeline.ts
+++ b/packages/backend/src/server/api/endpoints/notes/timeline.ts
@@ -114,7 +114,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
excludePureRenotes: !ps.withRenotes,
noteFilter: note => {
if (note.reply && note.reply.visibility === 'followers') {
- if (!Object.hasOwn(followings, note.reply.userId)) return false;
+ if (!Object.hasOwn(followings, note.reply.userId) && note.reply.userId !== me.id) return false;
}
return true;
diff --git a/packages/backend/src/server/api/endpoints/pages/update.ts b/packages/backend/src/server/api/endpoints/pages/update.ts
index b8e5e70a25..f11bbbcb1a 100644
--- a/packages/backend/src/server/api/endpoints/pages/update.ts
+++ b/packages/backend/src/server/api/endpoints/pages/update.ts
@@ -70,7 +70,7 @@ export const paramDef = {
alignCenter: { type: 'boolean' },
hideTitleWhenPinned: { type: 'boolean' },
},
- required: ['pageId', 'title', 'name', 'content', 'variables', 'script'],
+ required: ['pageId'],
} as const;
@Injectable()
@@ -91,9 +91,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.accessDenied);
}
- let eyeCatchingImage = null;
if (ps.eyeCatchingImageId != null) {
- eyeCatchingImage = await this.driveFilesRepository.findOneBy({
+ const eyeCatchingImage = await this.driveFilesRepository.findOneBy({
id: ps.eyeCatchingImageId,
userId: me.id,
});
@@ -116,23 +115,15 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
await this.pagesRepository.update(page.id, {
updatedAt: new Date(),
title: ps.title,
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
- name: ps.name === undefined ? page.name : ps.name,
+ name: ps.name,
summary: ps.summary === undefined ? page.summary : ps.summary,
content: ps.content,
variables: ps.variables,
script: ps.script,
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
- alignCenter: ps.alignCenter === undefined ? page.alignCenter : ps.alignCenter,
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
- hideTitleWhenPinned: ps.hideTitleWhenPinned === undefined ? page.hideTitleWhenPinned : ps.hideTitleWhenPinned,
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
- font: ps.font === undefined ? page.font : ps.font,
- eyeCatchingImageId: ps.eyeCatchingImageId === null
- ? null
- : ps.eyeCatchingImageId === undefined
- ? page.eyeCatchingImageId
- : eyeCatchingImage!.id,
+ alignCenter: ps.alignCenter,
+ hideTitleWhenPinned: ps.hideTitleWhenPinned,
+ font: ps.font,
+ eyeCatchingImageId: ps.eyeCatchingImageId,
});
});
}
diff --git a/packages/backend/src/server/api/endpoints/pinned-users.ts b/packages/backend/src/server/api/endpoints/pinned-users.ts
index 784766bcb5..15832ef7f8 100644
--- a/packages/backend/src/server/api/endpoints/pinned-users.ts
+++ b/packages/backend/src/server/api/endpoints/pinned-users.ts
@@ -12,7 +12,6 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import { MetaService } from '@/core/MetaService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { DI } from '@/di-symbols.js';
-import { isNotNull } from '@/misc/is-not-null.js';
export const meta = {
tags: ['users'],
@@ -53,7 +52,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
host: acct.host ?? IsNull(),
})));
- return await this.userEntityService.packMany(users.filter(isNotNull), me, { schema: 'UserDetailed' });
+ return await this.userEntityService.packMany(users.filter(x => x != null), me, { schema: 'UserDetailed' });
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/renote-mute/create.ts b/packages/backend/src/server/api/endpoints/renote-mute/create.ts
index 39bf0cc428..84a1f010d4 100644
--- a/packages/backend/src/server/api/endpoints/renote-mute/create.ts
+++ b/packages/backend/src/server/api/endpoints/renote-mute/create.ts
@@ -6,12 +6,11 @@
import { Inject, Injectable } from '@nestjs/common';
import ms from 'ms';
import { Endpoint } from '@/server/api/endpoint-base.js';
-import { IdService } from '@/core/IdService.js';
-import type { RenoteMutingsRepository } from '@/models/_.js';
-import type { MiRenoteMuting } from '@/models/RenoteMuting.js';
import { DI } from '@/di-symbols.js';
import { GetterService } from '@/server/api/GetterService.js';
import { ApiError } from '../../error.js';
+import { UserRenoteMutingService } from "@/core/UserRenoteMutingService.js";
+import type { RenoteMutingsRepository } from '@/models/_.js';
export const meta = {
tags: ['account'],
@@ -62,7 +61,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private renoteMutingsRepository: RenoteMutingsRepository,
private getterService: GetterService,
- private idService: IdService,
+ private userRenoteMutingService: UserRenoteMutingService,
) {
super(meta, paramDef, async (ps, me) => {
const muter = me;
@@ -79,21 +78,19 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
});
// Check if already muting
- const exist = await this.renoteMutingsRepository.findOneBy({
- muterId: muter.id,
- muteeId: mutee.id,
+ const exist = await this.renoteMutingsRepository.exists({
+ where: {
+ muterId: muter.id,
+ muteeId: mutee.id,
+ },
});
- if (exist != null) {
+ if (exist === true) {
throw new ApiError(meta.errors.alreadyMuting);
}
// Create mute
- await this.renoteMutingsRepository.insert({
- id: this.idService.gen(),
- muterId: muter.id,
- muteeId: mutee.id,
- } as MiRenoteMuting);
+ await this.userRenoteMutingService.mute(muter, mutee);
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/renote-mute/delete.ts b/packages/backend/src/server/api/endpoints/renote-mute/delete.ts
index 6e037cc07e..1a584b8404 100644
--- a/packages/backend/src/server/api/endpoints/renote-mute/delete.ts
+++ b/packages/backend/src/server/api/endpoints/renote-mute/delete.ts
@@ -5,10 +5,11 @@
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
-import type { RenoteMutingsRepository } from '@/models/_.js';
import { DI } from '@/di-symbols.js';
import { GetterService } from '@/server/api/GetterService.js';
import { ApiError } from '../../error.js';
+import { UserRenoteMutingService } from "@/core/UserRenoteMutingService.js";
+import type { RenoteMutingsRepository } from '@/models/_.js';
export const meta = {
tags: ['account'],
@@ -53,6 +54,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private renoteMutingsRepository: RenoteMutingsRepository,
private getterService: GetterService,
+ private userRenoteMutingService: UserRenoteMutingService,
) {
super(meta, paramDef, async (ps, me) => {
const muter = me;
@@ -79,9 +81,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
}
// Delete mute
- await this.renoteMutingsRepository.delete({
- id: exist.id,
- });
+ await this.userRenoteMutingService.unmute([exist]);
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts b/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts
index 8504da0209..7e44d501ab 100644
--- a/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts
+++ b/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts
@@ -100,7 +100,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const currentCount = await this.userListsRepository.countBy({
userId: me.id,
});
- if (currentCount > (await this.roleService.getUserPolicies(me.id)).userListLimit) {
+ if (currentCount >= (await this.roleService.getUserPolicies(me.id)).userListLimit) {
throw new ApiError(meta.errors.tooManyUserLists);
}
diff --git a/packages/backend/src/server/api/endpoints/users/lists/create.ts b/packages/backend/src/server/api/endpoints/users/lists/create.ts
index 9378bde5cb..7daf05ba4e 100644
--- a/packages/backend/src/server/api/endpoints/users/lists/create.ts
+++ b/packages/backend/src/server/api/endpoints/users/lists/create.ts
@@ -61,7 +61,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const currentCount = await this.userListsRepository.countBy({
userId: me.id,
});
- if (currentCount > (await this.roleService.getUserPolicies(me.id)).userListLimit) {
+ if (currentCount >= (await this.roleService.getUserPolicies(me.id)).userListLimit) {
throw new ApiError(meta.errors.tooManyUserLists);
}
diff --git a/packages/backend/src/server/api/endpoints/users/reactions.ts b/packages/backend/src/server/api/endpoints/users/reactions.ts
index aca883a052..7805ae3288 100644
--- a/packages/backend/src/server/api/endpoints/users/reactions.ts
+++ b/packages/backend/src/server/api/endpoints/users/reactions.ts
@@ -12,6 +12,7 @@ import { DI } from '@/di-symbols.js';
import { CacheService } from '@/core/CacheService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { RoleService } from '@/core/RoleService.js';
+import { isUserRelated } from '@/misc/is-user-related.js';
import { ApiError } from '../../error.js';
export const meta = {
@@ -74,6 +75,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private roleService: RoleService,
) {
super(meta, paramDef, async (ps, me) => {
+ const userIdsWhoBlockingMe = me ? await this.cacheService.userBlockedCache.fetch(me.id) : new Set<string>();
const iAmModerator = me ? await this.roleService.isModerator(me) : false; // Moderators can see reactions of all users
if (!iAmModerator) {
const user = await this.cacheService.findUserById(ps.userId);
@@ -85,8 +87,15 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
if ((me == null || me.id !== ps.userId) && !profile.publicReactions) {
throw new ApiError(meta.errors.reactionsNotPublic);
}
+
+ // early return if me is blocked by requesting user
+ if (userIdsWhoBlockingMe.has(ps.userId)) {
+ return [];
+ }
}
+ const userIdsWhoMeMuting = me ? await this.cacheService.userMutingsCache.fetch(me.id) : new Set<string>();
+
const query = this.queryService.makePaginationQuery(this.noteReactionsRepository.createQueryBuilder('reaction'),
ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
.andWhere('reaction.userId = :userId', { userId: ps.userId })
@@ -94,9 +103,15 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
this.queryService.generateVisibilityQuery(query, me);
- const reactions = await query
+ const reactions = (await query
.limit(ps.limit)
- .getMany();
+ .getMany()).filter(reaction => {
+ if (reaction.note?.userId === ps.userId) return true; // we can see reactions to note of requesting user
+ if (me && isUserRelated(reaction.note, userIdsWhoBlockingMe)) return false;
+ if (me && isUserRelated(reaction.note, userIdsWhoMeMuting)) return false;
+
+ return true;
+ });
return await this.noteReactionEntityService.packMany(reactions, me, { withNote: true });
});
diff --git a/packages/backend/src/server/api/endpoints/users/report-abuse.ts b/packages/backend/src/server/api/endpoints/users/report-abuse.ts
index 48e14b68cc..5ff6de37d2 100644
--- a/packages/backend/src/server/api/endpoints/users/report-abuse.ts
+++ b/packages/backend/src/server/api/endpoints/users/report-abuse.ts
@@ -3,17 +3,11 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
-import sanitizeHtml from 'sanitize-html';
-import { Inject, Injectable } from '@nestjs/common';
-import type { AbuseUserReportsRepository } from '@/models/_.js';
-import { IdService } from '@/core/IdService.js';
+import { Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
-import { GlobalEventService } from '@/core/GlobalEventService.js';
-import { MetaService } from '@/core/MetaService.js';
-import { EmailService } from '@/core/EmailService.js';
-import { DI } from '@/di-symbols.js';
import { GetterService } from '@/server/api/GetterService.js';
import { RoleService } from '@/core/RoleService.js';
+import { AbuseReportService } from '@/core/AbuseReportService.js';
import { ApiError } from '../../error.js';
export const meta = {
@@ -57,60 +51,32 @@ export const paramDef = {
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
- @Inject(DI.abuseUserReportsRepository)
- private abuseUserReportsRepository: AbuseUserReportsRepository,
-
- private idService: IdService,
- private metaService: MetaService,
- private emailService: EmailService,
private getterService: GetterService,
private roleService: RoleService,
- private globalEventService: GlobalEventService,
+ private abuseReportService: AbuseReportService,
) {
super(meta, paramDef, async (ps, me) => {
// Lookup user
- const user = await this.getterService.getUser(ps.userId).catch(err => {
+ const targetUser = await this.getterService.getUser(ps.userId).catch(err => {
if (err.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser);
throw err;
});
- if (user.id === me.id) {
+ if (targetUser.id === me.id) {
throw new ApiError(meta.errors.cannotReportYourself);
}
- if (await this.roleService.isAdministrator(user)) {
+ if (await this.roleService.isAdministrator(targetUser)) {
throw new ApiError(meta.errors.cannotReportAdmin);
}
- const report = await this.abuseUserReportsRepository.insertOne({
- id: this.idService.gen(),
- targetUserId: user.id,
- targetUserHost: user.host,
+ await this.abuseReportService.report([{
+ targetUserId: targetUser.id,
+ targetUserHost: targetUser.host,
reporterId: me.id,
reporterHost: null,
comment: ps.comment,
- });
-
- // Publish event to moderators
- setImmediate(async () => {
- const moderators = await this.roleService.getModerators();
-
- for (const moderator of moderators) {
- this.globalEventService.publishAdminStream(moderator.id, 'newAbuseUserReport', {
- id: report.id,
- targetUserId: report.targetUserId,
- reporterId: report.reporterId,
- comment: report.comment,
- });
- }
-
- const meta = await this.metaService.fetch();
- if (meta.email) {
- this.emailService.sendEmail(meta.email, 'New abuse report',
- sanitizeHtml(ps.comment),
- sanitizeHtml(ps.comment));
- }
- });
+ }]);
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts
index 7b3bdab327..8ff952dcb5 100644
--- a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts
+++ b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts
@@ -3,15 +3,9 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
-import { Brackets } from 'typeorm';
-import { Inject, Injectable } from '@nestjs/common';
-import type { UsersRepository, FollowingsRepository } from '@/models/_.js';
-import type { Config } from '@/config.js';
-import type { MiUser } from '@/models/User.js';
+import { Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
-import { UserEntityService } from '@/core/entities/UserEntityService.js';
-import { DI } from '@/di-symbols.js';
-import { sqlLikeEscape } from '@/misc/sql-like-escape.js';
+import { UserSearchService } from '@/core/UserSearchService.js';
export const meta = {
tags: ['users'],
@@ -49,89 +43,16 @@ export const paramDef = {
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
- @Inject(DI.config)
- private config: Config,
-
- @Inject(DI.usersRepository)
- private usersRepository: UsersRepository,
-
- @Inject(DI.followingsRepository)
- private followingsRepository: FollowingsRepository,
-
- private userEntityService: UserEntityService,
+ private userSearchService: UserSearchService,
) {
- super(meta, paramDef, async (ps, me) => {
- const setUsernameAndHostQuery = (query = this.usersRepository.createQueryBuilder('user')) => {
- if (ps.username) {
- query.andWhere('user.usernameLower LIKE :username', { username: sqlLikeEscape(ps.username.toLowerCase()) + '%' });
- }
-
- if (ps.host) {
- if (ps.host === this.config.hostname || ps.host === '.') {
- query.andWhere('user.host IS NULL');
- } else {
- query.andWhere('user.host LIKE :host', {
- host: sqlLikeEscape(ps.host.toLowerCase()) + '%',
- });
- }
- }
-
- return query;
- };
-
- const activeThreshold = new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)); // 30æ—¥
-
- let users: MiUser[] = [];
-
- if (me) {
- const followingQuery = this.followingsRepository.createQueryBuilder('following')
- .select('following.followeeId')
- .where('following.followerId = :followerId', { followerId: me.id });
-
- const query = setUsernameAndHostQuery()
- .andWhere(`user.id IN (${ followingQuery.getQuery() })`)
- .andWhere('user.id != :meId', { meId: me.id })
- .andWhere('user.isSuspended = FALSE')
- .andWhere(new Brackets(qb => {
- qb
- .where('user.updatedAt IS NULL')
- .orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold });
- }));
-
- query.setParameters(followingQuery.getParameters());
-
- users = await query
- .orderBy('user.usernameLower', 'ASC')
- .limit(ps.limit)
- .getMany();
-
- if (users.length < ps.limit) {
- const otherQuery = setUsernameAndHostQuery()
- .andWhere(`user.id NOT IN (${ followingQuery.getQuery() })`)
- .andWhere('user.isSuspended = FALSE')
- .andWhere('user.updatedAt IS NOT NULL');
-
- otherQuery.setParameters(followingQuery.getParameters());
-
- const otherUsers = await otherQuery
- .orderBy('user.updatedAt', 'DESC')
- .limit(ps.limit - users.length)
- .getMany();
-
- users = users.concat(otherUsers);
- }
- } else {
- const query = setUsernameAndHostQuery()
- .andWhere('user.isSuspended = FALSE')
- .andWhere('user.updatedAt IS NOT NULL');
-
- users = await query
- .orderBy('user.updatedAt', 'DESC')
- .limit(ps.limit - users.length)
- .getMany();
- }
-
- return await this.userEntityService.packMany(users, me, { schema: ps.detail ? 'UserDetailed' : 'UserLite' });
+ super(meta, paramDef, (ps, me) => {
+ return this.userSearchService.search({
+ username: ps.username,
+ host: ps.host,
+ }, {
+ limit: ps.limit,
+ detail: ps.detail,
+ }, me);
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/users/search.ts b/packages/backend/src/server/api/endpoints/users/search.ts
index df9d9f6312..0b0136066d 100644
--- a/packages/backend/src/server/api/endpoints/users/search.ts
+++ b/packages/backend/src/server/api/endpoints/users/search.ts
@@ -57,88 +57,66 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const activeThreshold = new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)); // 30æ—¥
ps.query = ps.query.trim();
- const isUsername = ps.query.startsWith('@');
+ const isUsername = ps.query.startsWith('@') && !ps.query.includes(' ') && ps.query.indexOf('@', 1) === -1;
let users: MiUser[] = [];
- if (isUsername) {
- const usernameQuery = this.usersRepository.createQueryBuilder('user')
- .where('user.usernameLower LIKE :username', { username: sqlLikeEscape(ps.query.replace('@', '').toLowerCase()) + '%' })
- .andWhere(new Brackets(qb => {
- qb
- .where('user.updatedAt IS NULL')
- .orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold });
- }))
- .andWhere('user.isSuspended = FALSE');
+ const nameQuery = this.usersRepository.createQueryBuilder('user')
+ .where(new Brackets(qb => {
+ qb.where('user.name ILIKE :query', { query: '%' + sqlLikeEscape(ps.query) + '%' });
+
+ if (isUsername) {
+ qb.orWhere('user.usernameLower LIKE :username', { username: sqlLikeEscape(ps.query.replace('@', '').toLowerCase()) + '%' });
+ } else if (this.userEntityService.validateLocalUsername(ps.query)) { // Also search username if it qualifies as username
+ qb.orWhere('user.usernameLower LIKE :username', { username: '%' + sqlLikeEscape(ps.query.toLowerCase()) + '%' });
+ }
+ }))
+ .andWhere(new Brackets(qb => {
+ qb
+ .where('user.updatedAt IS NULL')
+ .orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold });
+ }))
+ .andWhere('user.isSuspended = FALSE');
+
+ if (ps.origin === 'local') {
+ nameQuery.andWhere('user.host IS NULL');
+ } else if (ps.origin === 'remote') {
+ nameQuery.andWhere('user.host IS NOT NULL');
+ }
+
+ users = await nameQuery
+ .orderBy('user.updatedAt', 'DESC', 'NULLS LAST')
+ .limit(ps.limit)
+ .offset(ps.offset)
+ .getMany();
+
+ if (users.length < ps.limit) {
+ const profQuery = this.userProfilesRepository.createQueryBuilder('prof')
+ .select('prof.userId')
+ .where('prof.description ILIKE :query', { query: '%' + sqlLikeEscape(ps.query) + '%' });
if (ps.origin === 'local') {
- usernameQuery.andWhere('user.host IS NULL');
+ profQuery.andWhere('prof.userHost IS NULL');
} else if (ps.origin === 'remote') {
- usernameQuery.andWhere('user.host IS NOT NULL');
+ profQuery.andWhere('prof.userHost IS NOT NULL');
}
- users = await usernameQuery
- .orderBy('user.updatedAt', 'DESC', 'NULLS LAST')
- .limit(ps.limit)
- .offset(ps.offset)
- .getMany();
- } else {
- const nameQuery = this.usersRepository.createQueryBuilder('user')
- .where(new Brackets(qb => {
- qb.where('user.name ILIKE :query', { query: '%' + sqlLikeEscape(ps.query) + '%' });
-
- // Also search username if it qualifies as username
- if (this.userEntityService.validateLocalUsername(ps.query)) {
- qb.orWhere('user.usernameLower LIKE :username', { username: '%' + sqlLikeEscape(ps.query.toLowerCase()) + '%' });
- }
- }))
+ const query = this.usersRepository.createQueryBuilder('user')
+ .where(`user.id IN (${ profQuery.getQuery() })`)
.andWhere(new Brackets(qb => {
qb
.where('user.updatedAt IS NULL')
.orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold });
}))
- .andWhere('user.isSuspended = FALSE');
-
- if (ps.origin === 'local') {
- nameQuery.andWhere('user.host IS NULL');
- } else if (ps.origin === 'remote') {
- nameQuery.andWhere('user.host IS NOT NULL');
- }
+ .andWhere('user.isSuspended = FALSE')
+ .setParameters(profQuery.getParameters());
- users = await nameQuery
+ users = users.concat(await query
.orderBy('user.updatedAt', 'DESC', 'NULLS LAST')
.limit(ps.limit)
.offset(ps.offset)
- .getMany();
-
- if (users.length < ps.limit) {
- const profQuery = this.userProfilesRepository.createQueryBuilder('prof')
- .select('prof.userId')
- .where('prof.description ILIKE :query', { query: '%' + sqlLikeEscape(ps.query) + '%' });
-
- if (ps.origin === 'local') {
- profQuery.andWhere('prof.userHost IS NULL');
- } else if (ps.origin === 'remote') {
- profQuery.andWhere('prof.userHost IS NOT NULL');
- }
-
- const query = this.usersRepository.createQueryBuilder('user')
- .where(`user.id IN (${ profQuery.getQuery() })`)
- .andWhere(new Brackets(qb => {
- qb
- .where('user.updatedAt IS NULL')
- .orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold });
- }))
- .andWhere('user.isSuspended = FALSE')
- .setParameters(profQuery.getParameters());
-
- users = users.concat(await query
- .orderBy('user.updatedAt', 'DESC', 'NULLS LAST')
- .limit(ps.limit)
- .offset(ps.offset)
- .getMany(),
- );
- }
+ .getMany(),
+ );
}
return await this.userEntityService.packMany(users, me, { schema: ps.detail ? 'UserDetailed' : 'UserLite' });
diff --git a/packages/backend/src/server/api/openapi/OpenApiServerService.ts b/packages/backend/src/server/api/openapi/OpenApiServerService.ts
index 5210e4d2bc..f124aa9f39 100644
--- a/packages/backend/src/server/api/openapi/OpenApiServerService.ts
+++ b/packages/backend/src/server/api/openapi/OpenApiServerService.ts
@@ -25,7 +25,7 @@ export class OpenApiServerService {
public createServer(fastify: FastifyInstance, _options: FastifyPluginOptions, done: (err?: Error) => void) {
fastify.get('/api-doc', async (_request, reply) => {
reply.header('Cache-Control', 'public, max-age=86400');
- return await reply.sendFile('/redoc.html', staticAssets);
+ return await reply.sendFile('/api-doc.html', staticAssets);
});
fastify.get('/api.json', (_request, reply) => {
reply.header('Cache-Control', 'public, max-age=600');
diff --git a/packages/backend/src/server/api/openapi/gen-spec.ts b/packages/backend/src/server/api/openapi/gen-spec.ts
index 2a14270a24..efa47a6986 100644
--- a/packages/backend/src/server/api/openapi/gen-spec.ts
+++ b/packages/backend/src/server/api/openapi/gen-spec.ts
@@ -15,7 +15,6 @@ export function genOpenapiSpec(config: Config, includeSelfRef = false) {
info: {
version: config.version,
title: 'Misskey API',
- 'x-logo': { url: '/static-assets/api-doc.png' },
},
externalDocs: {
diff --git a/packages/backend/src/server/api/stream/Connection.ts b/packages/backend/src/server/api/stream/Connection.ts
index 41c0feccc7..96082827f8 100644
--- a/packages/backend/src/server/api/stream/Connection.ts
+++ b/packages/backend/src/server/api/stream/Connection.ts
@@ -14,6 +14,7 @@ import { CacheService } from '@/core/CacheService.js';
import { MiFollowing, MiUserProfile } from '@/models/_.js';
import type { StreamEventEmitter, GlobalEvents } from '@/core/GlobalEventService.js';
import { ChannelFollowingService } from '@/core/ChannelFollowingService.js';
+import type { JsonObject } from '@/misc/json-value.js';
import type { ChannelsService } from './ChannelsService.js';
import type { EventEmitter } from 'events';
import type Channel from './channel.js';
@@ -28,7 +29,7 @@ export default class Connection {
private wsConnection: WebSocket.WebSocket;
public subscriber: StreamEventEmitter;
private channels: Channel[] = [];
- private subscribingNotes: any = {};
+ private subscribingNotes: Partial<Record<string, number>> = {};
private cachedNotes: Packed<'Note'>[] = [];
public userProfile: MiUserProfile | null = null;
public following: Record<string, Pick<MiFollowing, 'withReplies'> | undefined> = {};
@@ -101,7 +102,7 @@ export default class Connection {
*/
@bindThis
private async onWsConnectionMessage(data: WebSocket.RawData) {
- let obj: Record<string, any>;
+ let obj: JsonObject;
try {
obj = JSON.parse(data.toString());
@@ -111,6 +112,8 @@ export default class Connection {
const { type, body } = obj;
+ if (typeof body !== 'object' || body === null || Array.isArray(body)) return;
+
switch (type) {
case 'readNotification': this.onReadNotification(body); break;
case 'subNote': this.onSubscribeNote(body); break;
@@ -151,7 +154,7 @@ export default class Connection {
}
@bindThis
- private readNote(body: any) {
+ private readNote(body: JsonObject) {
const id = body.id;
const note = this.cachedNotes.find(n => n.id === id);
@@ -163,7 +166,7 @@ export default class Connection {
}
@bindThis
- private onReadNotification(payload: any) {
+ private onReadNotification(payload: JsonObject) {
this.notificationService.readAllNotification(this.user!.id);
}
@@ -171,16 +174,14 @@ export default class Connection {
* æŠ•ç¨¿è³¼èª­è¦æ±‚時
*/
@bindThis
- private onSubscribeNote(payload: any) {
- if (!payload.id) return;
-
- if (this.subscribingNotes[payload.id] == null) {
- this.subscribingNotes[payload.id] = 0;
- }
+ private onSubscribeNote(payload: JsonObject) {
+ if (!payload.id || typeof payload.id !== 'string') return;
- this.subscribingNotes[payload.id]++;
+ const current = this.subscribingNotes[payload.id] ?? 0;
+ const updated = current + 1;
+ this.subscribingNotes[payload.id] = updated;
- if (this.subscribingNotes[payload.id] === 1) {
+ if (updated === 1) {
this.subscriber.on(`noteStream:${payload.id}`, this.onNoteStreamMessage);
}
}
@@ -189,11 +190,14 @@ export default class Connection {
* æŠ•ç¨¿è³¼èª­è§£é™¤è¦æ±‚時
*/
@bindThis
- private onUnsubscribeNote(payload: any) {
- if (!payload.id) return;
+ private onUnsubscribeNote(payload: JsonObject) {
+ if (!payload.id || typeof payload.id !== 'string') return;
- this.subscribingNotes[payload.id]--;
- if (this.subscribingNotes[payload.id] <= 0) {
+ const current = this.subscribingNotes[payload.id];
+ if (current == null) return;
+ const updated = current - 1;
+ this.subscribingNotes[payload.id] = updated;
+ if (updated <= 0) {
delete this.subscribingNotes[payload.id];
this.subscriber.off(`noteStream:${payload.id}`, this.onNoteStreamMessage);
}
@@ -212,17 +216,22 @@ export default class Connection {
* ãƒãƒ£ãƒ³ãƒãƒ«æŽ¥ç¶šè¦æ±‚時
*/
@bindThis
- private onChannelConnectRequested(payload: any) {
+ private onChannelConnectRequested(payload: JsonObject) {
const { channel, id, params, pong } = payload;
- this.connectChannel(id, params, channel, pong);
+ if (typeof id !== 'string') return;
+ if (typeof channel !== 'string') return;
+ if (typeof pong !== 'boolean' && typeof pong !== 'undefined' && pong !== null) return;
+ if (typeof params !== 'undefined' && (typeof params !== 'object' || params === null || Array.isArray(params))) return;
+ this.connectChannel(id, params, channel, pong ?? undefined);
}
/**
* ãƒãƒ£ãƒ³ãƒãƒ«åˆ‡æ–­è¦æ±‚時
*/
@bindThis
- private onChannelDisconnectRequested(payload: any) {
+ private onChannelDisconnectRequested(payload: JsonObject) {
const { id } = payload;
+ if (typeof id !== 'string') return;
this.disconnectChannel(id);
}
@@ -230,7 +239,7 @@ export default class Connection {
* クライアントã«ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸é€ä¿¡
*/
@bindThis
- public sendMessageToWs(type: string, payload: any) {
+ public sendMessageToWs(type: string, payload: JsonObject) {
this.wsConnection.send(JSON.stringify({
type: type,
body: payload,
@@ -241,7 +250,7 @@ export default class Connection {
* ãƒãƒ£ãƒ³ãƒãƒ«ã«æŽ¥ç¶š
*/
@bindThis
- public connectChannel(id: string, params: any, channel: string, pong = false) {
+ public connectChannel(id: string, params: JsonObject | undefined, channel: string, pong = false) {
const channelService = this.channelsService.getChannelService(channel);
if (channelService.requireCredential && this.user == null) {
@@ -288,7 +297,11 @@ export default class Connection {
* @param data メッセージ
*/
@bindThis
- private onChannelMessageRequested(data: any) {
+ private onChannelMessageRequested(data: JsonObject) {
+ if (typeof data.id !== 'string') return;
+ if (typeof data.type !== 'string') return;
+ if (typeof data.body === 'undefined') return;
+
const channel = this.channels.find(c => c.id === data.id);
if (channel != null && channel.onMessage != null) {
channel.onMessage(data.type, data.body);
diff --git a/packages/backend/src/server/api/stream/channel.ts b/packages/backend/src/server/api/stream/channel.ts
index a267d27fba..84cb552369 100644
--- a/packages/backend/src/server/api/stream/channel.ts
+++ b/packages/backend/src/server/api/stream/channel.ts
@@ -8,6 +8,7 @@ import { isInstanceMuted } from '@/misc/is-instance-muted.js';
import { isUserRelated } from '@/misc/is-user-related.js';
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
import type { Packed } from '@/misc/json-schema.js';
+import type { JsonObject, JsonValue } from '@/misc/json-value.js';
import type Connection from './Connection.js';
/**
@@ -81,10 +82,12 @@ export default abstract class Channel {
this.connection = connection;
}
+ public send(payload: { type: string, body: JsonValue }): void
+ public send(type: string, payload: JsonValue): void
@bindThis
- public send(typeOrPayload: any, payload?: any) {
- const type = payload === undefined ? typeOrPayload.type : typeOrPayload;
- const body = payload === undefined ? typeOrPayload.body : payload;
+ public send(typeOrPayload: { type: string, body: JsonValue } | string, payload?: JsonValue) {
+ const type = payload === undefined ? (typeOrPayload as { type: string, body: JsonValue }).type : (typeOrPayload as string);
+ const body = payload === undefined ? (typeOrPayload as { type: string, body: JsonValue }).body : payload;
this.connection.sendMessageToWs('channel', {
id: this.id,
@@ -93,11 +96,11 @@ export default abstract class Channel {
});
}
- public abstract init(params: any): void;
+ public abstract init(params: JsonObject): void;
public dispose?(): void;
- public onMessage?(type: string, body: any): void;
+ public onMessage?(type: string, body: JsonValue): void;
}
export type MiChannelService<T extends boolean> = {
diff --git a/packages/backend/src/server/api/stream/channels/admin.ts b/packages/backend/src/server/api/stream/channels/admin.ts
index 92b6d2ac04..355d5dba21 100644
--- a/packages/backend/src/server/api/stream/channels/admin.ts
+++ b/packages/backend/src/server/api/stream/channels/admin.ts
@@ -5,6 +5,7 @@
import { Injectable } from '@nestjs/common';
import { bindThis } from '@/decorators.js';
+import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class AdminChannel extends Channel {
@@ -14,7 +15,7 @@ class AdminChannel extends Channel {
public static kind = 'read:admin:stream';
@bindThis
- public async init(params: any) {
+ public async init(params: JsonObject) {
// Subscribe admin stream
this.subscriber.on(`adminStream:${this.user!.id}`, data => {
this.send(data);
diff --git a/packages/backend/src/server/api/stream/channels/antenna.ts b/packages/backend/src/server/api/stream/channels/antenna.ts
index 4a1d2dd109..53dc7f18b6 100644
--- a/packages/backend/src/server/api/stream/channels/antenna.ts
+++ b/packages/backend/src/server/api/stream/channels/antenna.ts
@@ -7,6 +7,7 @@ import { Injectable } from '@nestjs/common';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { bindThis } from '@/decorators.js';
import type { GlobalEvents } from '@/core/GlobalEventService.js';
+import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class AntennaChannel extends Channel {
@@ -27,8 +28,9 @@ class AntennaChannel extends Channel {
}
@bindThis
- public async init(params: any) {
- this.antennaId = params.antennaId as string;
+ public async init(params: JsonObject) {
+ if (typeof params.antennaId !== 'string') return;
+ this.antennaId = params.antennaId;
// Subscribe stream
this.subscriber.on(`antennaStream:${this.antennaId}`, this.onEvent);
diff --git a/packages/backend/src/server/api/stream/channels/channel.ts b/packages/backend/src/server/api/stream/channels/channel.ts
index 140dd3dd9b..7108e0cd6e 100644
--- a/packages/backend/src/server/api/stream/channels/channel.ts
+++ b/packages/backend/src/server/api/stream/channels/channel.ts
@@ -8,6 +8,7 @@ import type { Packed } from '@/misc/json-schema.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { bindThis } from '@/decorators.js';
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
+import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class ChannelChannel extends Channel {
@@ -27,8 +28,9 @@ class ChannelChannel extends Channel {
}
@bindThis
- public async init(params: any) {
- this.channelId = params.channelId as string;
+ public async init(params: JsonObject) {
+ if (typeof params.channelId !== 'string') return;
+ this.channelId = params.channelId;
// Subscribe stream
this.subscriber.on('notesStream', this.onNote);
diff --git a/packages/backend/src/server/api/stream/channels/drive.ts b/packages/backend/src/server/api/stream/channels/drive.ts
index 0d9b486305..03768f3d23 100644
--- a/packages/backend/src/server/api/stream/channels/drive.ts
+++ b/packages/backend/src/server/api/stream/channels/drive.ts
@@ -5,6 +5,7 @@
import { Injectable } from '@nestjs/common';
import { bindThis } from '@/decorators.js';
+import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class DriveChannel extends Channel {
@@ -14,7 +15,7 @@ class DriveChannel extends Channel {
public static kind = 'read:account';
@bindThis
- public async init(params: any) {
+ public async init(params: JsonObject) {
// Subscribe drive stream
this.subscriber.on(`driveStream:${this.user!.id}`, data => {
this.send(data);
diff --git a/packages/backend/src/server/api/stream/channels/global-timeline.ts b/packages/backend/src/server/api/stream/channels/global-timeline.ts
index 17116258d8..ed56fe0d40 100644
--- a/packages/backend/src/server/api/stream/channels/global-timeline.ts
+++ b/packages/backend/src/server/api/stream/channels/global-timeline.ts
@@ -10,6 +10,7 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { bindThis } from '@/decorators.js';
import { RoleService } from '@/core/RoleService.js';
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
+import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class GlobalTimelineChannel extends Channel {
@@ -32,12 +33,12 @@ class GlobalTimelineChannel extends Channel {
}
@bindThis
- public async init(params: any) {
+ public async init(params: JsonObject) {
const policies = await this.roleService.getUserPolicies(this.user ? this.user.id : null);
if (!policies.gtlAvailable) return;
- this.withRenotes = params.withRenotes ?? true;
- this.withFiles = params.withFiles ?? false;
+ this.withRenotes = !!(params.withRenotes ?? true);
+ this.withFiles = !!(params.withFiles ?? false);
// Subscribe events
this.subscriber.on('notesStream', this.onNote);
diff --git a/packages/backend/src/server/api/stream/channels/hashtag.ts b/packages/backend/src/server/api/stream/channels/hashtag.ts
index 57bada5d9c..8105f15cb1 100644
--- a/packages/backend/src/server/api/stream/channels/hashtag.ts
+++ b/packages/backend/src/server/api/stream/channels/hashtag.ts
@@ -9,6 +9,7 @@ import type { Packed } from '@/misc/json-schema.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { bindThis } from '@/decorators.js';
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
+import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class HashtagChannel extends Channel {
@@ -28,11 +29,11 @@ class HashtagChannel extends Channel {
}
@bindThis
- public async init(params: any) {
+ public async init(params: JsonObject) {
+ if (!Array.isArray(params.q)) return;
+ if (!params.q.every(x => Array.isArray(x) && x.every(y => typeof y === 'string'))) return;
this.q = params.q;
- if (this.q == null) return;
-
// Subscribe stream
this.subscriber.on('notesStream', this.onNote);
}
diff --git a/packages/backend/src/server/api/stream/channels/home-timeline.ts b/packages/backend/src/server/api/stream/channels/home-timeline.ts
index 878a3180cb..66644ed58c 100644
--- a/packages/backend/src/server/api/stream/channels/home-timeline.ts
+++ b/packages/backend/src/server/api/stream/channels/home-timeline.ts
@@ -8,6 +8,7 @@ import type { Packed } from '@/misc/json-schema.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { bindThis } from '@/decorators.js';
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
+import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class HomeTimelineChannel extends Channel {
@@ -29,9 +30,9 @@ class HomeTimelineChannel extends Channel {
}
@bindThis
- public async init(params: any) {
- this.withRenotes = params.withRenotes ?? true;
- this.withFiles = params.withFiles ?? false;
+ public async init(params: JsonObject) {
+ this.withRenotes = !!(params.withRenotes ?? true);
+ this.withFiles = !!(params.withFiles ?? false);
this.subscriber.on('notesStream', this.onNote);
}
@@ -59,7 +60,7 @@ class HomeTimelineChannel extends Channel {
const reply = note.reply;
if (this.following[note.userId]?.withReplies) {
// 自分ã®ãƒ•ォローã—ã¦ã„ãªã„ユーザー㮠visibility: followers ãªæŠ•ç¨¿ã¸ã®è¿”ä¿¡ã¯å¼¾ã
- if (reply.visibility === 'followers' && !Object.hasOwn(this.following, reply.userId)) return;
+ if (reply.visibility === 'followers' && !Object.hasOwn(this.following, reply.userId) && reply.userId !== this.user!.id) return;
} else {
// 「ãƒãƒ£ãƒ³ãƒãƒ«æŽ¥ç¶šä¸»ã¸ã®è¿”ä¿¡ã€ã§ã‚‚ãªã‘れã°ã€ã€Œãƒãƒ£ãƒ³ãƒãƒ«æŽ¥ç¶šä¸»ãŒè¡Œã£ãŸè¿”ä¿¡ã€ã§ã‚‚ãªã‘れã°ã€ã€ŒæŠ•ç¨¿è€…ã®æŠ•ç¨¿è€…è‡ªèº«ã¸ã®è¿”ä¿¡ã€ã§ã‚‚ãªã„å ´åˆ
if (reply.userId !== this.user!.id && !isMe && reply.userId !== note.userId) return;
@@ -72,7 +73,7 @@ class HomeTimelineChannel extends Channel {
if (note.renote.reply) {
const reply = note.renote.reply;
// 自分ã®ãƒ•ォローã—ã¦ã„ãªã„ユーザー㮠visibility: followers ãªæŠ•ç¨¿ã¸ã®è¿”ä¿¡ã®ãƒªãƒŽãƒ¼ãƒˆã¯å¼¾ã
- if (reply.visibility === 'followers' && !Object.hasOwn(this.following, reply.userId)) return;
+ if (reply.visibility === 'followers' && !Object.hasOwn(this.following, reply.userId) && reply.userId !== this.user!.id) return;
}
}
diff --git a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts
index 575d23d53c..75bd13221f 100644
--- a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts
+++ b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts
@@ -10,6 +10,7 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { bindThis } from '@/decorators.js';
import { RoleService } from '@/core/RoleService.js';
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
+import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class HybridTimelineChannel extends Channel {
@@ -34,13 +35,13 @@ class HybridTimelineChannel extends Channel {
}
@bindThis
- public async init(params: any): Promise<void> {
+ public async init(params: JsonObject): Promise<void> {
const policies = await this.roleService.getUserPolicies(this.user ? this.user.id : null);
if (!policies.ltlAvailable) return;
- this.withRenotes = params.withRenotes ?? true;
- this.withReplies = params.withReplies ?? false;
- this.withFiles = params.withFiles ?? false;
+ this.withRenotes = !!(params.withRenotes ?? true);
+ this.withReplies = !!(params.withReplies ?? false);
+ this.withFiles = !!(params.withFiles ?? false);
// Subscribe events
this.subscriber.on('notesStream', this.onNote);
@@ -75,14 +76,22 @@ class HybridTimelineChannel extends Channel {
const reply = note.reply;
if ((this.following[note.userId]?.withReplies ?? false) || this.withReplies) {
// 自分ã®ãƒ•ォローã—ã¦ã„ãªã„ユーザー㮠visibility: followers ãªæŠ•ç¨¿ã¸ã®è¿”ä¿¡ã¯å¼¾ã
- if (reply.visibility === 'followers' && !Object.hasOwn(this.following, reply.userId)) return;
+ if (reply.visibility === 'followers' && !Object.hasOwn(this.following, reply.userId) && reply.userId !== this.user!.id) return;
} else {
// 「ãƒãƒ£ãƒ³ãƒãƒ«æŽ¥ç¶šä¸»ã¸ã®è¿”ä¿¡ã€ã§ã‚‚ãªã‘れã°ã€ã€Œãƒãƒ£ãƒ³ãƒãƒ«æŽ¥ç¶šä¸»ãŒè¡Œã£ãŸè¿”ä¿¡ã€ã§ã‚‚ãªã‘れã°ã€ã€ŒæŠ•ç¨¿è€…ã®æŠ•ç¨¿è€…è‡ªèº«ã¸ã®è¿”ä¿¡ã€ã§ã‚‚ãªã„å ´åˆ
if (reply.userId !== this.user!.id && !isMe && reply.userId !== note.userId) return;
}
}
- if (isRenotePacked(note) && !isQuotePacked(note) && !this.withRenotes) return;
+ // 純粋ãªãƒªãƒŽãƒ¼ãƒˆï¼ˆå¼•用リノートã§ãªã„リノート)ã®å ´åˆ
+ if (isRenotePacked(note) && !isQuotePacked(note) && note.renote) {
+ if (!this.withRenotes) return;
+ if (note.renote.reply) {
+ const reply = note.renote.reply;
+ // 自分ã®ãƒ•ォローã—ã¦ã„ãªã„ユーザー㮠visibility: followers ãªæŠ•ç¨¿ã¸ã®è¿”ä¿¡ã®ãƒªãƒŽãƒ¼ãƒˆã¯å¼¾ã
+ if (reply.visibility === 'followers' && !Object.hasOwn(this.following, reply.userId) && reply.userId !== this.user!.id) return;
+ }
+ }
if (this.user && note.renoteId && !note.text) {
if (note.renote && Object.keys(note.renote.reactions).length > 0) {
diff --git a/packages/backend/src/server/api/stream/channels/local-timeline.ts b/packages/backend/src/server/api/stream/channels/local-timeline.ts
index 442d08ae51..491029f5de 100644
--- a/packages/backend/src/server/api/stream/channels/local-timeline.ts
+++ b/packages/backend/src/server/api/stream/channels/local-timeline.ts
@@ -10,6 +10,7 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { bindThis } from '@/decorators.js';
import { RoleService } from '@/core/RoleService.js';
import { isQuotePacked, isRenotePacked } from '@/misc/is-renote.js';
+import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class LocalTimelineChannel extends Channel {
@@ -33,13 +34,13 @@ class LocalTimelineChannel extends Channel {
}
@bindThis
- public async init(params: any) {
+ public async init(params: JsonObject) {
const policies = await this.roleService.getUserPolicies(this.user ? this.user.id : null);
if (!policies.ltlAvailable) return;
- this.withRenotes = params.withRenotes ?? true;
- this.withReplies = params.withReplies ?? false;
- this.withFiles = params.withFiles ?? false;
+ this.withRenotes = !!(params.withRenotes ?? true);
+ this.withReplies = !!(params.withReplies ?? false);
+ this.withFiles = !!(params.withFiles ?? false);
// Subscribe events
this.subscriber.on('notesStream', this.onNote);
diff --git a/packages/backend/src/server/api/stream/channels/main.ts b/packages/backend/src/server/api/stream/channels/main.ts
index a12976d69d..863d7f4c4e 100644
--- a/packages/backend/src/server/api/stream/channels/main.ts
+++ b/packages/backend/src/server/api/stream/channels/main.ts
@@ -7,6 +7,7 @@ import { Injectable } from '@nestjs/common';
import { isInstanceMuted, isUserFromMutedInstance } from '@/misc/is-instance-muted.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { bindThis } from '@/decorators.js';
+import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class MainChannel extends Channel {
@@ -25,7 +26,7 @@ class MainChannel extends Channel {
}
@bindThis
- public async init(params: any) {
+ public async init(params: JsonObject) {
// Subscribe main stream channel
this.subscriber.on(`mainStream:${this.user!.id}`, async data => {
switch (data.type) {
diff --git a/packages/backend/src/server/api/stream/channels/queue-stats.ts b/packages/backend/src/server/api/stream/channels/queue-stats.ts
index 061aa76904..ff7e740226 100644
--- a/packages/backend/src/server/api/stream/channels/queue-stats.ts
+++ b/packages/backend/src/server/api/stream/channels/queue-stats.ts
@@ -6,6 +6,7 @@
import Xev from 'xev';
import { Injectable } from '@nestjs/common';
import { bindThis } from '@/decorators.js';
+import type { JsonObject, JsonValue } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
const ev = new Xev();
@@ -22,19 +23,22 @@ class QueueStatsChannel extends Channel {
}
@bindThis
- public async init(params: any) {
+ public async init(params: JsonObject) {
ev.addListener('queueStats', this.onStats);
}
@bindThis
- private onStats(stats: any) {
+ private onStats(stats: JsonObject) {
this.send('stats', stats);
}
@bindThis
- public onMessage(type: string, body: any) {
+ public onMessage(type: string, body: JsonValue) {
switch (type) {
case 'requestLog':
+ if (typeof body !== 'object' || body === null || Array.isArray(body)) return;
+ if (typeof body.id !== 'string') return;
+ if (typeof body.length !== 'number') return;
ev.once(`queueStatsLog:${body.id}`, statsLog => {
this.send('statsLog', statsLog);
});
diff --git a/packages/backend/src/server/api/stream/channels/reversi-game.ts b/packages/backend/src/server/api/stream/channels/reversi-game.ts
index f4a3a09367..17823a164a 100644
--- a/packages/backend/src/server/api/stream/channels/reversi-game.ts
+++ b/packages/backend/src/server/api/stream/channels/reversi-game.ts
@@ -9,6 +9,7 @@ import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';
import { ReversiService } from '@/core/ReversiService.js';
import { ReversiGameEntityService } from '@/core/entities/ReversiGameEntityService.js';
+import type { JsonObject, JsonValue } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class ReversiGameChannel extends Channel {
@@ -28,25 +29,41 @@ class ReversiGameChannel extends Channel {
}
@bindThis
- public async init(params: any) {
- this.gameId = params.gameId as string;
+ public async init(params: JsonObject) {
+ if (typeof params.gameId !== 'string') return;
+ this.gameId = params.gameId;
this.subscriber.on(`reversiGameStream:${this.gameId}`, this.send);
}
@bindThis
- public onMessage(type: string, body: any) {
+ public onMessage(type: string, body: JsonValue) {
switch (type) {
- case 'ready': this.ready(body); break;
- case 'updateSettings': this.updateSettings(body.key, body.value); break;
- case 'cancel': this.cancelGame(); break;
- case 'putStone': this.putStone(body.pos, body.id); break;
+ case 'ready':
+ if (typeof body !== 'boolean') return;
+ this.ready(body);
+ break;
+ case 'updateSettings':
+ if (typeof body !== 'object' || body === null || Array.isArray(body)) return;
+ if (typeof body.key !== 'string') return;
+ if (typeof body.value !== 'object' || body.value === null || Array.isArray(body.value)) return;
+ this.updateSettings(body.key, body.value);
+ break;
+ case 'cancel':
+ this.cancelGame();
+ break;
+ case 'putStone':
+ if (typeof body !== 'object' || body === null || Array.isArray(body)) return;
+ if (typeof body.pos !== 'number') return;
+ if (typeof body.id !== 'string') return;
+ this.putStone(body.pos, body.id);
+ break;
case 'claimTimeIsUp': this.claimTimeIsUp(); break;
}
}
@bindThis
- private async updateSettings(key: string, value: any) {
+ private async updateSettings(key: string, value: JsonObject) {
if (this.user == null) return;
this.reversiService.updateSettings(this.gameId!, this.user, key, value);
diff --git a/packages/backend/src/server/api/stream/channels/reversi.ts b/packages/backend/src/server/api/stream/channels/reversi.ts
index 3998a0fd36..6e88939724 100644
--- a/packages/backend/src/server/api/stream/channels/reversi.ts
+++ b/packages/backend/src/server/api/stream/channels/reversi.ts
@@ -5,6 +5,7 @@
import { Injectable } from '@nestjs/common';
import { bindThis } from '@/decorators.js';
+import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class ReversiChannel extends Channel {
@@ -21,7 +22,7 @@ class ReversiChannel extends Channel {
}
@bindThis
- public async init(params: any) {
+ public async init(params: JsonObject) {
this.subscriber.on(`reversiStream:${this.user!.id}`, this.send);
}
diff --git a/packages/backend/src/server/api/stream/channels/role-timeline.ts b/packages/backend/src/server/api/stream/channels/role-timeline.ts
index 6a4ad22460..fcfa26c38b 100644
--- a/packages/backend/src/server/api/stream/channels/role-timeline.ts
+++ b/packages/backend/src/server/api/stream/channels/role-timeline.ts
@@ -8,6 +8,7 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { bindThis } from '@/decorators.js';
import { RoleService } from '@/core/RoleService.js';
import type { GlobalEvents } from '@/core/GlobalEventService.js';
+import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class RoleTimelineChannel extends Channel {
@@ -28,8 +29,9 @@ class RoleTimelineChannel extends Channel {
}
@bindThis
- public async init(params: any) {
- this.roleId = params.roleId as string;
+ public async init(params: JsonObject) {
+ if (typeof params.roleId !== 'string') return;
+ this.roleId = params.roleId;
this.subscriber.on(`roleTimelineStream:${this.roleId}`, this.onEvent);
}
diff --git a/packages/backend/src/server/api/stream/channels/server-stats.ts b/packages/backend/src/server/api/stream/channels/server-stats.ts
index eb4d8c9992..6258afba35 100644
--- a/packages/backend/src/server/api/stream/channels/server-stats.ts
+++ b/packages/backend/src/server/api/stream/channels/server-stats.ts
@@ -6,6 +6,7 @@
import Xev from 'xev';
import { Injectable } from '@nestjs/common';
import { bindThis } from '@/decorators.js';
+import type { JsonObject, JsonValue } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
const ev = new Xev();
@@ -22,19 +23,20 @@ class ServerStatsChannel extends Channel {
}
@bindThis
- public async init(params: any) {
+ public async init(params: JsonObject) {
ev.addListener('serverStats', this.onStats);
}
@bindThis
- private onStats(stats: any) {
+ private onStats(stats: JsonObject) {
this.send('stats', stats);
}
@bindThis
- public onMessage(type: string, body: any) {
+ public onMessage(type: string, body: JsonValue) {
switch (type) {
case 'requestLog':
+ if (typeof body !== 'object' || body === null || Array.isArray(body)) return;
ev.once(`serverStatsLog:${body.id}`, statsLog => {
this.send('statsLog', statsLog);
});
diff --git a/packages/backend/src/server/api/stream/channels/user-list.ts b/packages/backend/src/server/api/stream/channels/user-list.ts
index 14b30a157c..4f38351e94 100644
--- a/packages/backend/src/server/api/stream/channels/user-list.ts
+++ b/packages/backend/src/server/api/stream/channels/user-list.ts
@@ -10,6 +10,7 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
+import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class UserListChannel extends Channel {
@@ -36,10 +37,11 @@ class UserListChannel extends Channel {
}
@bindThis
- public async init(params: any) {
- this.listId = params.listId as string;
- this.withFiles = params.withFiles ?? false;
- this.withRenotes = params.withRenotes ?? true;
+ public async init(params: JsonObject) {
+ if (typeof params.listId !== 'string') return;
+ this.listId = params.listId;
+ this.withFiles = !!(params.withFiles ?? false);
+ this.withRenotes = !!(params.withRenotes ?? true);
// Check existence and owner
const listExist = await this.userListsRepository.exists({
diff --git a/packages/backend/src/server/web/ClientServerService.ts b/packages/backend/src/server/web/ClientServerService.ts
index ab03489c0d..f55790b636 100644
--- a/packages/backend/src/server/web/ClientServerService.ts
+++ b/packages/backend/src/server/web/ClientServerService.ts
@@ -25,7 +25,16 @@ import { getNoteSummary } from '@/misc/get-note-summary.js';
import { DI } from '@/di-symbols.js';
import * as Acct from '@/misc/acct.js';
import { MetaService } from '@/core/MetaService.js';
-import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, ObjectStorageQueue, SystemQueue, WebhookDeliverQueue } from '@/core/QueueModule.js';
+import type {
+ DbQueue,
+ DeliverQueue,
+ EndedPollNotificationQueue,
+ InboxQueue,
+ ObjectStorageQueue,
+ SystemQueue,
+ UserWebhookDeliverQueue,
+ SystemWebhookDeliverQueue,
+} from '@/core/QueueModule.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { PageEntityService } from '@/core/entities/PageEntityService.js';
@@ -111,7 +120,8 @@ export class ClientServerService {
@Inject('queue:inbox') public inboxQueue: InboxQueue,
@Inject('queue:db') public dbQueue: DbQueue,
@Inject('queue:objectStorage') public objectStorageQueue: ObjectStorageQueue,
- @Inject('queue:webhookDeliver') public webhookDeliverQueue: WebhookDeliverQueue,
+ @Inject('queue:userWebhookDeliver') public userWebhookDeliverQueue: UserWebhookDeliverQueue,
+ @Inject('queue:systemWebhookDeliver') public systemWebhookDeliverQueue: SystemWebhookDeliverQueue,
) {
//this.createServer = this.createServer.bind(this);
}
@@ -239,7 +249,8 @@ export class ClientServerService {
this.inboxQueue,
this.dbQueue,
this.objectStorageQueue,
- this.webhookDeliverQueue,
+ this.userWebhookDeliverQueue,
+ this.systemWebhookDeliverQueue,
].map(q => new BullMQAdapter(q)),
serverAdapter,
});
diff --git a/packages/backend/src/server/web/FeedService.ts b/packages/backend/src/server/web/FeedService.ts
index 10e3ed2682..9d810ddc84 100644
--- a/packages/backend/src/server/web/FeedService.ts
+++ b/packages/backend/src/server/web/FeedService.ts
@@ -14,6 +14,8 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
import { bindThis } from '@/decorators.js';
import { IdService } from '@/core/IdService.js';
+import { MfmService } from "@/core/MfmService.js";
+import { parse as mfmParse } from 'mfm-js';
@Injectable()
export class FeedService {
@@ -33,6 +35,7 @@ export class FeedService {
private userEntityService: UserEntityService,
private driveFileEntityService: DriveFileEntityService,
private idService: IdService,
+ private mfmService: MfmService,
) {
}
@@ -76,13 +79,14 @@ export class FeedService {
id: In(note.fileIds),
}) : [];
const file = files.find(file => file.type.startsWith('image/'));
+ const text = note.text;
feed.addItem({
title: `New note by ${author.name}`,
link: `${this.config.url}/notes/${note.id}`,
date: this.idService.parse(note.id).date,
description: note.cw ?? undefined,
- content: note.text ?? undefined,
+ content: text ? this.mfmService.toHtml(mfmParse(text), JSON.parse(note.mentionedRemoteUsers)) ?? undefined : undefined,
image: file ? this.driveFileEntityService.getPublicUrl(file) : undefined,
});
}
diff --git a/packages/backend/src/server/web/boot.js b/packages/backend/src/server/web/boot.js
index 396536948e..4275dc9527 100644
--- a/packages/backend/src/server/web/boot.js
+++ b/packages/backend/src/server/web/boot.js
@@ -29,7 +29,8 @@
let forceError = localStorage.getItem('forceError');
if (forceError != null) {
- renderError('FORCED_ERROR', 'This error is forced by having forceError in local storage.')
+ renderError('FORCED_ERROR', 'This error is forced by having forceError in local storage.');
+ return;
}
//#region Detect language & fetch translations
@@ -155,7 +156,12 @@
document.head.appendChild(css);
}
- function renderError(code, details) {
+ async function renderError(code, details) {
+ // Cannot set property 'innerHTML' of null を回é¿
+ if (document.readyState === 'loading') {
+ await new Promise(resolve => window.addEventListener('DOMContentLoaded', resolve));
+ }
+
let errorsElement = document.getElementById('errors');
if (!errorsElement) {
@@ -314,6 +320,6 @@
#errorInfo {
width: 50%;
}
- `)
+ }`)
}
})();
diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts
index 929070d0d2..ecbbee4eff 100644
--- a/packages/backend/src/types.ts
+++ b/packages/backend/src/types.ts
@@ -90,6 +90,12 @@ export const moderationLogTypes = [
'deleteAvatarDecoration',
'unsetUserAvatar',
'unsetUserBanner',
+ 'createSystemWebhook',
+ 'updateSystemWebhook',
+ 'deleteSystemWebhook',
+ 'createAbuseReportNotificationRecipient',
+ 'updateAbuseReportNotificationRecipient',
+ 'deleteAbuseReportNotificationRecipient',
] as const;
export type ModerationLogPayloads = {
@@ -282,6 +288,32 @@ export type ModerationLogPayloads = {
userHost: string | null;
fileId: string;
};
+ createSystemWebhook: {
+ systemWebhookId: string;
+ webhook: any;
+ };
+ updateSystemWebhook: {
+ systemWebhookId: string;
+ before: any;
+ after: any;
+ };
+ deleteSystemWebhook: {
+ systemWebhookId: string;
+ webhook: any;
+ };
+ createAbuseReportNotificationRecipient: {
+ recipientId: string;
+ recipient: any;
+ };
+ updateAbuseReportNotificationRecipient: {
+ recipientId: string;
+ before: any;
+ after: any;
+ };
+ deleteAbuseReportNotificationRecipient: {
+ recipientId: string;
+ recipient: any;
+ };
};
export type Serialized<T> = {
diff --git a/packages/backend/test-server/.eslintrc.cjs b/packages/backend/test-server/.eslintrc.cjs
deleted file mode 100644
index c261741a36..0000000000
--- a/packages/backend/test-server/.eslintrc.cjs
+++ /dev/null
@@ -1,32 +0,0 @@
-module.exports = {
- parserOptions: {
- tsconfigRootDir: __dirname,
- project: ['./tsconfig.json'],
- },
- extends: [
- '../../shared/.eslintrc.js',
- ],
- rules: {
- 'import/order': ['warn', {
- 'groups': ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],
- 'pathGroups': [
- {
- 'pattern': '@/**',
- 'group': 'external',
- 'position': 'after'
- }
- ],
- }],
- 'no-restricted-globals': [
- 'error',
- {
- 'name': '__dirname',
- 'message': 'Not in ESModule. Use `import.meta.url` instead.'
- },
- {
- 'name': '__filename',
- 'message': 'Not in ESModule. Use `import.meta.url` instead.'
- }
- ]
- },
-};
diff --git a/packages/backend/test-server/eslint.config.js b/packages/backend/test-server/eslint.config.js
new file mode 100644
index 0000000000..b9c16d469f
--- /dev/null
+++ b/packages/backend/test-server/eslint.config.js
@@ -0,0 +1,43 @@
+import tsParser from '@typescript-eslint/parser';
+import sharedConfig from '../../shared/eslint.config.js';
+
+export default [
+ ...sharedConfig,
+ {
+ files: ['**/*.ts', '**/*.tsx'],
+ languageOptions: {
+ parserOptions: {
+ parser: tsParser,
+ project: ['./tsconfig.json'],
+ sourceType: 'module',
+ tsconfigRootDir: import.meta.dirname,
+ },
+ },
+ rules: {
+ 'import/order': ['warn', {
+ groups: [
+ 'builtin',
+ 'external',
+ 'internal',
+ 'parent',
+ 'sibling',
+ 'index',
+ 'object',
+ 'type',
+ ],
+ pathGroups: [{
+ pattern: '@/**',
+ group: 'external',
+ position: 'after',
+ }],
+ }],
+ 'no-restricted-globals': ['error', {
+ name: '__dirname',
+ message: 'Not in ESModule. Use `import.meta.url` instead.',
+ }, {
+ name: '__filename',
+ message: 'Not in ESModule. Use `import.meta.url` instead.',
+ }],
+ },
+ },
+];
diff --git a/packages/backend/test/.eslintrc.cjs b/packages/backend/test/.eslintrc.cjs
deleted file mode 100644
index 41ecea0c3f..0000000000
--- a/packages/backend/test/.eslintrc.cjs
+++ /dev/null
@@ -1,11 +0,0 @@
-module.exports = {
- parserOptions: {
- tsconfigRootDir: __dirname,
- project: ['./tsconfig.json'],
- },
- extends: ['../.eslintrc.cjs'],
- env: {
- node: true,
- jest: true,
- },
-};
diff --git a/packages/backend/test/docker-compose.yml b/packages/backend/test/compose.yml
index f2d8990758..6593fc33dd 100644
--- a/packages/backend/test/docker-compose.yml
+++ b/packages/backend/test/compose.yml
@@ -1,5 +1,3 @@
-version: "3"
-
services:
redistest:
image: redis:7
diff --git a/packages/backend/test/e2e/2fa.ts b/packages/backend/test/e2e/2fa.ts
index 13c56b88a6..06548fa7da 100644
--- a/packages/backend/test/e2e/2fa.ts
+++ b/packages/backend/test/e2e/2fa.ts
@@ -206,7 +206,7 @@ describe('2è¦ç´ èªè¨¼', () => {
username,
}, alice);
assert.strictEqual(usersShowResponse.status, 200);
- assert.strictEqual(usersShowResponse.body.twoFactorEnabled, true);
+ assert.strictEqual((usersShowResponse.body as unknown as { twoFactorEnabled: boolean }).twoFactorEnabled, true);
const signinResponse = await api('signin', {
...signinParam(),
@@ -248,7 +248,7 @@ describe('2è¦ç´ èªè¨¼', () => {
keyName,
credentialId,
creationOptions: registerKeyResponse.body,
- }) as any, alice);
+ } as any) as any, alice);
assert.strictEqual(keyDoneResponse.status, 200);
assert.strictEqual(keyDoneResponse.body.id, credentialId.toString('base64url'));
assert.strictEqual(keyDoneResponse.body.name, keyName);
@@ -257,22 +257,22 @@ describe('2è¦ç´ èªè¨¼', () => {
username,
});
assert.strictEqual(usersShowResponse.status, 200);
- assert.strictEqual(usersShowResponse.body.securityKeys, true);
+ assert.strictEqual((usersShowResponse.body as unknown as { securityKeys: boolean }).securityKeys, true);
const signinResponse = await api('signin', {
...signinParam(),
});
assert.strictEqual(signinResponse.status, 200);
assert.strictEqual(signinResponse.body.i, undefined);
- assert.notEqual(signinResponse.body.challenge, undefined);
- assert.notEqual(signinResponse.body.allowCredentials, undefined);
- assert.strictEqual(signinResponse.body.allowCredentials[0].id, credentialId.toString('base64url'));
+ assert.notEqual((signinResponse.body as unknown as { challenge: unknown | undefined }).challenge, undefined);
+ assert.notEqual((signinResponse.body as unknown as { allowCredentials: unknown | undefined }).allowCredentials, undefined);
+ assert.strictEqual((signinResponse.body as unknown as { allowCredentials: {id: string}[] }).allowCredentials[0].id, credentialId.toString('base64url'));
const signinResponse2 = await api('signin', signinWithSecurityKeyParam({
keyName,
credentialId,
requestOptions: signinResponse.body,
- }));
+ } as any));
assert.strictEqual(signinResponse2.status, 200);
assert.notEqual(signinResponse2.body.i, undefined);
@@ -307,7 +307,7 @@ describe('2è¦ç´ èªè¨¼', () => {
keyName,
credentialId,
creationOptions: registerKeyResponse.body,
- }) as any, alice);
+ } as any) as any, alice);
assert.strictEqual(keyDoneResponse.status, 200);
const passwordLessResponse = await api('i/2fa/password-less', {
@@ -319,7 +319,7 @@ describe('2è¦ç´ èªè¨¼', () => {
username,
});
assert.strictEqual(usersShowResponse.status, 200);
- assert.strictEqual(usersShowResponse.body.usePasswordLessLogin, true);
+ assert.strictEqual((usersShowResponse.body as unknown as { usePasswordLessLogin: boolean }).usePasswordLessLogin, true);
const signinResponse = await api('signin', {
...signinParam(),
@@ -333,7 +333,7 @@ describe('2è¦ç´ èªè¨¼', () => {
keyName,
credentialId,
requestOptions: signinResponse.body,
- }),
+ } as any),
password: '',
});
assert.strictEqual(signinResponse2.status, 200);
@@ -370,7 +370,7 @@ describe('2è¦ç´ èªè¨¼', () => {
keyName,
credentialId,
creationOptions: registerKeyResponse.body,
- }) as any, alice);
+ } as any) as any, alice);
assert.strictEqual(keyDoneResponse.status, 200);
const renamedKey = 'other-key';
@@ -383,6 +383,7 @@ describe('2è¦ç´ èªè¨¼', () => {
const iResponse = await api('i', {
}, alice);
assert.strictEqual(iResponse.status, 200);
+ assert.ok(iResponse.body.securityKeysList);
const securityKeys = iResponse.body.securityKeysList.filter((s: { id: string; }) => s.id === credentialId.toString('base64url'));
assert.strictEqual(securityKeys.length, 1);
assert.strictEqual(securityKeys[0].name, renamedKey);
@@ -419,13 +420,14 @@ describe('2è¦ç´ èªè¨¼', () => {
keyName,
credentialId,
creationOptions: registerKeyResponse.body,
- }) as any, alice);
+ } as any) as any, alice);
assert.strictEqual(keyDoneResponse.status, 200);
// テストã®å®Ÿè¡Œé †ã«ã‚ˆã£ã¦ã¯è¤‡æ•°æ®‹ã£ã¦ã‚‹ã®ã§å…¨éƒ¨æ¶ˆã™
const iResponse = await api('i', {
}, alice);
assert.strictEqual(iResponse.status, 200);
+ assert.ok(iResponse.body.securityKeysList);
for (const key of iResponse.body.securityKeysList) {
const removeKeyResponse = await api('i/2fa/remove-key', {
token: otpToken(registerResponse.body.secret),
@@ -439,7 +441,7 @@ describe('2è¦ç´ èªè¨¼', () => {
username,
});
assert.strictEqual(usersShowResponse.status, 200);
- assert.strictEqual(usersShowResponse.body.securityKeys, false);
+ assert.strictEqual((usersShowResponse.body as unknown as { securityKeys: boolean }).securityKeys, false);
const signinResponse = await api('signin', {
...signinParam(),
@@ -470,7 +472,7 @@ describe('2è¦ç´ èªè¨¼', () => {
username,
});
assert.strictEqual(usersShowResponse.status, 200);
- assert.strictEqual(usersShowResponse.body.twoFactorEnabled, true);
+ assert.strictEqual((usersShowResponse.body as unknown as { twoFactorEnabled: boolean }).twoFactorEnabled, true);
const unregisterResponse = await api('i/2fa/unregister', {
token: otpToken(registerResponse.body.secret),
diff --git a/packages/backend/test/e2e/antennas.ts b/packages/backend/test/e2e/antennas.ts
index 101238b601..6ac14cd8dc 100644
--- a/packages/backend/test/e2e/antennas.ts
+++ b/packages/backend/test/e2e/antennas.ts
@@ -163,8 +163,7 @@ describe('アンテナ', () => {
});
test('ãŒä¸Šé™ã„ã£ã±ã„ã¾ã§ä½œæˆã§ãã‚‹ã“ã¨', async () => {
- // antennaLimit + 1ã¾ã§ä½œã‚Œã‚‹ã®ãŒã‚­ãƒ¢
- const response = await Promise.all([...Array(DEFAULT_POLICIES.antennaLimit + 1)].map(() => successfulApiCall({
+ const response = await Promise.all([...Array(DEFAULT_POLICIES.antennaLimit)].map(() => successfulApiCall({
endpoint: 'antennas/create',
parameters: { ...defaultParam },
user: alice,
diff --git a/packages/backend/test/e2e/api-visibility.ts b/packages/backend/test/e2e/api-visibility.ts
index c61b0c2a86..2dd645d97a 100644
--- a/packages/backend/test/e2e/api-visibility.ts
+++ b/packages/backend/test/e2e/api-visibility.ts
@@ -410,21 +410,21 @@ describe('API visibility', () => {
test('[HTL] public-post ㌠自分ãŒè¦‹ã‚Œã‚‹', async () => {
const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.status, 200);
- const notes = res.body.filter((n: any) => n.id === pub.id);
+ const notes = res.body.filter(n => n.id === pub.id);
assert.strictEqual(notes[0].text, 'x');
});
test('[HTL] public-post ㌠éžãƒ•ォロワーã‹ã‚‰è¦‹ã‚Œãªã„', async () => {
const res = await api('notes/timeline', { limit: 100 }, other);
assert.strictEqual(res.status, 200);
- const notes = res.body.filter((n: any) => n.id === pub.id);
+ const notes = res.body.filter(n => n.id === pub.id);
assert.strictEqual(notes.length, 0);
});
test('[HTL] followers-post ㌠フォロワーã‹ã‚‰è¦‹ã‚Œã‚‹', async () => {
const res = await api('notes/timeline', { limit: 100 }, follower);
assert.strictEqual(res.status, 200);
- const notes = res.body.filter((n: any) => n.id === fol.id);
+ const notes = res.body.filter(n => n.id === fol.id);
assert.strictEqual(notes[0].text, 'x');
});
//#endregion
@@ -433,21 +433,21 @@ describe('API visibility', () => {
test('[replies] followers-reply ㌠フォロワーã‹ã‚‰è¦‹ã‚Œã‚‹', async () => {
const res = await api('notes/replies', { noteId: tgt.id, limit: 100 }, follower);
assert.strictEqual(res.status, 200);
- const notes = res.body.filter((n: any) => n.id === folR.id);
+ const notes = res.body.filter(n => n.id === folR.id);
assert.strictEqual(notes[0].text, 'x');
});
test('[replies] followers-reply ㌠éžãƒ•ォロワー (リプライ先ã§ã¯ãªã„) ã‹ã‚‰è¦‹ã‚Œãªã„', async () => {
const res = await api('notes/replies', { noteId: tgt.id, limit: 100 }, other);
assert.strictEqual(res.status, 200);
- const notes = res.body.filter((n: any) => n.id === folR.id);
+ const notes = res.body.filter(n => n.id === folR.id);
assert.strictEqual(notes.length, 0);
});
test('[replies] followers-reply ㌠éžãƒ•ォロワー (リプライ先ã§ã‚ã‚‹) ã‹ã‚‰è¦‹ã‚Œã‚‹', async () => {
const res = await api('notes/replies', { noteId: tgt.id, limit: 100 }, target);
assert.strictEqual(res.status, 200);
- const notes = res.body.filter((n: any) => n.id === folR.id);
+ const notes = res.body.filter(n => n.id === folR.id);
assert.strictEqual(notes[0].text, 'x');
});
//#endregion
@@ -456,14 +456,14 @@ describe('API visibility', () => {
test('[mentions] followers-reply ㌠éžãƒ•ォロワー (リプライ先ã§ã‚ã‚‹) ã‹ã‚‰è¦‹ã‚Œã‚‹', async () => {
const res = await api('notes/mentions', { limit: 100 }, target);
assert.strictEqual(res.status, 200);
- const notes = res.body.filter((n: any) => n.id === folR.id);
+ const notes = res.body.filter(n => n.id === folR.id);
assert.strictEqual(notes[0].text, 'x');
});
test('[mentions] followers-mention ㌠éžãƒ•ォロワー (メンション先ã§ã‚ã‚‹) ã‹ã‚‰è¦‹ã‚Œã‚‹', async () => {
const res = await api('notes/mentions', { limit: 100 }, target);
assert.strictEqual(res.status, 200);
- const notes = res.body.filter((n: any) => n.id === folM.id);
+ const notes = res.body.filter(n => n.id === folM.id);
assert.strictEqual(notes[0].text, '@target x');
});
//#endregion
diff --git a/packages/backend/test/e2e/block.ts b/packages/backend/test/e2e/block.ts
index e4f798498f..35b0e59383 100644
--- a/packages/backend/test/e2e/block.ts
+++ b/packages/backend/test/e2e/block.ts
@@ -6,7 +6,7 @@
process.env.NODE_ENV = 'test';
import * as assert from 'assert';
-import { api, post, signup } from '../utils.js';
+import { api, castAsError, post, signup } from '../utils.js';
import type * as misskey from 'misskey-js';
describe('Block', () => {
@@ -33,7 +33,7 @@ describe('Block', () => {
const res = await api('following/create', { userId: alice.id }, bob);
assert.strictEqual(res.status, 400);
- assert.strictEqual(res.body.error.id, 'c4ab57cc-4e41-45e9-bfd9-584f61e35ce0');
+ assert.strictEqual(castAsError(res.body).error.id, 'c4ab57cc-4e41-45e9-bfd9-584f61e35ce0');
});
test('ブロックã•れã¦ã„るユーザーã«ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã§ããªã„', async () => {
@@ -42,7 +42,8 @@ describe('Block', () => {
const res = await api('notes/reactions/create', { noteId: note.id, reaction: 'ðŸ‘' }, bob);
assert.strictEqual(res.status, 400);
- assert.strictEqual(res.body.error.id, '20ef5475-9f38-4e4c-bd33-de6d979498ec');
+ assert.ok(res.body);
+ assert.strictEqual(castAsError(res.body).error.id, '20ef5475-9f38-4e4c-bd33-de6d979498ec');
});
test('ブロックã•れã¦ã„るユーザーã«è¿”ä¿¡ã§ããªã„', async () => {
@@ -51,7 +52,8 @@ describe('Block', () => {
const res = await api('notes/create', { replyId: note.id, text: 'yo' }, bob);
assert.strictEqual(res.status, 400);
- assert.strictEqual(res.body.error.id, 'b390d7e1-8a5e-46ed-b625-06271cafd3d3');
+ assert.ok(res.body);
+ assert.strictEqual(castAsError(res.body).error.id, 'b390d7e1-8a5e-46ed-b625-06271cafd3d3');
});
test('ブロックã•れã¦ã„るユーザーã®ãƒŽãƒ¼ãƒˆã‚’Renoteã§ããªã„', async () => {
@@ -60,7 +62,7 @@ describe('Block', () => {
const res = await api('notes/create', { renoteId: note.id, text: 'yo' }, bob);
assert.strictEqual(res.status, 400);
- assert.strictEqual(res.body.error.id, 'b390d7e1-8a5e-46ed-b625-06271cafd3d3');
+ assert.strictEqual(castAsError(res.body).error.id, 'b390d7e1-8a5e-46ed-b625-06271cafd3d3');
});
// TODO: ユーザーリストã«å…¥ã‚Œã‚‰ã‚Œãªã„テスト
diff --git a/packages/backend/test/e2e/clips.ts b/packages/backend/test/e2e/clips.ts
index ba6f9d6a65..a130c3698d 100644
--- a/packages/backend/test/e2e/clips.ts
+++ b/packages/backend/test/e2e/clips.ts
@@ -79,14 +79,14 @@ describe('クリップ', () => {
};
const deleteClip = async (parameters: Misskey.entities.ClipsDeleteRequest, request: Partial<ApiRequest<'clips/delete'>> = {}): Promise<void> => {
- return await successfulApiCall({
+ await successfulApiCall({
endpoint: 'clips/delete',
parameters,
user: alice,
...request,
}, {
status: 204,
- }) as any as void;
+ });
};
const show = async (parameters: Misskey.entities.ClipsShowRequest, request: Partial<ApiRequest<'clips/show'>> = {}): Promise<Misskey.entities.Clip> => {
@@ -153,8 +153,7 @@ describe('クリップ', () => {
});
test('ã®ä½œæˆã¯ãƒãƒªã‚·ãƒ¼ã§å®šã‚ã‚‰ã‚ŒãŸæ•°ä»¥ä¸Šã¯ã§ããªã„。', async () => {
- // ãƒãƒªã‚·ãƒ¼ + 1ã¾ã§ä½œã‚Œã‚‹ã¨ã„ã†æ‰€ãŒãƒŸã‚½
- const clipLimit = DEFAULT_POLICIES.clipLimit + 1;
+ const clipLimit = DEFAULT_POLICIES.clipLimit;
for (let i = 0; i < clipLimit; i++) {
await create();
}
@@ -327,7 +326,7 @@ describe('クリップ', () => {
});
test('ã®ä¸€è¦§(clips/list)ãŒå–å¾—ã§ãã‚‹(上é™ã„ã£ã±ã„)', async () => {
- const clipLimit = DEFAULT_POLICIES.clipLimit + 1;
+ const clipLimit = DEFAULT_POLICIES.clipLimit;
const clips = await createMany({}, clipLimit);
const res = await list({
parameters: { limit: 1 }, // FIXME: 無視ã•れã¦11全部返ã£ã¦ãã‚‹
@@ -455,25 +454,25 @@ describe('クリップ', () => {
let aliceClip: Misskey.entities.Clip;
const favorite = async (parameters: Misskey.entities.ClipsFavoriteRequest, request: Partial<ApiRequest<'clips/favorite'>> = {}): Promise<void> => {
- return successfulApiCall({
+ await successfulApiCall({
endpoint: 'clips/favorite',
parameters,
user: alice,
...request,
}, {
status: 204,
- }) as any as void;
+ });
};
const unfavorite = async (parameters: Misskey.entities.ClipsUnfavoriteRequest, request: Partial<ApiRequest<'clips/unfavorite'>> = {}): Promise<void> => {
- return successfulApiCall({
+ await successfulApiCall({
endpoint: 'clips/unfavorite',
parameters,
user: alice,
...request,
}, {
status: 204,
- }) as any as void;
+ });
};
const myFavorites = async (request: Partial<ApiRequest<'clips/my-favorites'>> = {}): Promise<Misskey.entities.Clip[]> => {
@@ -705,7 +704,7 @@ describe('クリップ', () => {
// TODO: 17000msãらã„ã‹ã‹ã‚‹...
test('ã‚’ãƒãƒªã‚·ãƒ¼ã§å®šã‚られãŸä¸Šé™ã„ã£ã±ã„(200)ã‚’è¶…ãˆã¦è¿½åŠ ã¯ã§ããªã„。', async () => {
- const noteLimit = DEFAULT_POLICIES.noteEachClipsLimit + 1;
+ const noteLimit = DEFAULT_POLICIES.noteEachClipsLimit;
const noteList = await Promise.all([...Array(noteLimit)].map((_, i) => post(alice, {
text: `test ${i}`,
}) as unknown)) as Misskey.entities.Note[];
diff --git a/packages/backend/test/e2e/drive.ts b/packages/backend/test/e2e/drive.ts
index 828c5200ef..43a73163eb 100644
--- a/packages/backend/test/e2e/drive.ts
+++ b/packages/backend/test/e2e/drive.ts
@@ -23,7 +23,7 @@ describe('Drive', () => {
const marker = Math.random().toString();
- const url = 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg';
+ const url = 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/192.jpg';
const catcher = makeStreamCatcher(
alice,
@@ -41,14 +41,14 @@ describe('Drive', () => {
const file = await catcher;
assert.strictEqual(res.status, 204);
- assert.strictEqual(file.name, 'Lenna.jpg');
+ assert.strictEqual(file.name, '192.jpg');
assert.strictEqual(file.type, 'image/jpeg');
});
test('ローカルã‹ã‚‰ã‚¢ãƒƒãƒ—ロードã§ãã‚‹', async () => {
// APIレスãƒãƒ³ã‚¹ã‚’直接使用ã™ã‚‹ã®ã§ utils.js uploadFile ãŒé€šéŽã™ã‚‹ã“ã¨ã§æˆåŠŸã¨ã™ã‚‹
- const res = await uploadFile(alice, { path: 'Lenna.jpg', name: 'テスト画åƒ' });
+ const res = await uploadFile(alice, { path: '192.jpg', name: 'テスト画åƒ' });
assert.strictEqual(res.body?.name, 'テスト画åƒ.jpg');
assert.strictEqual(res.body.type, 'image/jpeg');
diff --git a/packages/backend/test/e2e/endpoints.ts b/packages/backend/test/e2e/endpoints.ts
index bc89dc37f4..5aaec7f6f9 100644
--- a/packages/backend/test/e2e/endpoints.ts
+++ b/packages/backend/test/e2e/endpoints.ts
@@ -10,7 +10,7 @@ import * as assert from 'assert';
// https://github.com/node-fetch/node-fetch/pull/1664
import { Blob } from 'node-fetch';
import { MiUser } from '@/models/_.js';
-import { api, initTestDb, post, signup, simpleGet, uploadFile } from '../utils.js';
+import { api, castAsError, initTestDb, post, signup, simpleGet, uploadFile } from '../utils.js';
import type * as misskey from 'misskey-js';
describe('Endpoints', () => {
@@ -117,12 +117,21 @@ describe('Endpoints', () => {
assert.strictEqual(res.body.birthday, myBirthday);
});
- test('åå‰ã‚’空白ã«ã§ãã‚‹', async () => {
+ test('åå‰ã‚’空白ã®ã¿ã«ã—ãŸå ´åˆnullã«ãªã‚‹', async () => {
const res = await api('i/update', {
name: ' ',
}, alice);
assert.strictEqual(res.status, 200);
- assert.strictEqual(res.body.name, ' ');
+ assert.strictEqual(res.body.name, null);
+ });
+
+ test('åå‰ã®å‰å¾Œã«ç©ºç™½ï¼ˆãƒ›ãƒ¯ã‚¤ãƒˆã‚¹ãƒšãƒ¼ã‚¹ï¼‰ã‚’入れã¦ã‚‚トリムã•れる', async () => {
+ const res = await api('i/update', {
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#white_space
+ name: ' ゠ㄠㆠ\u0009\u000b\u000c\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\ufeff',
+ }, alice);
+ assert.strictEqual(res.status, 200);
+ assert.strictEqual(res.body.name, 'ã‚ ã„ ã†');
});
test('誕生日ã®è¨­å®šã‚’削除ã§ãã‚‹', async () => {
@@ -155,7 +164,7 @@ describe('Endpoints', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
- assert.strictEqual(res.body.id, alice.id);
+ assert.strictEqual((res.body as unknown as { id: string }).id, alice.id);
});
test('ユーザーãŒå­˜åœ¨ã—ãªã‹ã£ãŸã‚‰æ€’ã‚‹', async () => {
@@ -266,6 +275,68 @@ describe('Endpoints', () => {
assert.strictEqual(res.status, 400);
});
+ test('リノートã«ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã§ããªã„', async () => {
+ const bobNote = await post(bob, { text: 'hi' });
+ const bobRenote = await post(bob, { renoteId: bobNote.id });
+
+ const res = await api('notes/reactions/create', {
+ noteId: bobRenote.id,
+ reaction: '🚀',
+ }, alice);
+
+ assert.strictEqual(res.status, 400);
+ assert.ok(res.body);
+ assert.strictEqual(castAsError(res.body).error.code, 'CANNOT_REACT_TO_RENOTE');
+ });
+
+ test('引用ã«ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã§ãã‚‹', async () => {
+ const bobNote = await post(bob, { text: 'hi' });
+ const bobRenote = await post(bob, { text: 'hi again', renoteId: bobNote.id });
+
+ const res = await api('notes/reactions/create', {
+ noteId: bobRenote.id,
+ reaction: '🚀',
+ }, alice);
+
+ assert.strictEqual(res.status, 204);
+ });
+
+ test('空文字列ã®ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã¯\u2764ã«ãƒ•ォールãƒãƒƒã‚¯ã•れる', async () => {
+ const bobNote = await post(bob, { text: 'hi' });
+
+ const res = await api('notes/reactions/create', {
+ noteId: bobNote.id,
+ reaction: '',
+ }, alice);
+
+ assert.strictEqual(res.status, 204);
+
+ const reaction = await api('notes/reactions', {
+ noteId: bobNote.id,
+ });
+
+ assert.strictEqual(reaction.body.length, 1);
+ assert.strictEqual(reaction.body[0].type, '\u2764');
+ });
+
+ test('絵文字ã§ã¯ãªã„文字列ã®ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã¯\u2764ã«ãƒ•ォールãƒãƒƒã‚¯ã•れる', async () => {
+ const bobNote = await post(bob, { text: 'hi' });
+
+ const res = await api('notes/reactions/create', {
+ noteId: bobNote.id,
+ reaction: 'Hello!',
+ }, alice);
+
+ assert.strictEqual(res.status, 204);
+
+ const reaction = await api('notes/reactions', {
+ noteId: bobNote.id,
+ });
+
+ assert.strictEqual(reaction.body.length, 1);
+ assert.strictEqual(reaction.body[0].type, '\u2764');
+ });
+
test('空ã®ãƒ‘ãƒ©ãƒ¡ãƒ¼ã‚¿ã§æ€’られる', async () => {
// @ts-expect-error param must not be empty
const res = await api('notes/reactions/create', {}, alice);
@@ -523,7 +594,7 @@ describe('Endpoints', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
- assert.strictEqual(res.body!.name, 'Lenna.jpg');
+ assert.strictEqual(res.body!.name, '192.jpg');
});
test('ファイルã«åå‰ã‚’付ã‘られる', async () => {
@@ -993,7 +1064,7 @@ describe('Endpoints', () => {
userId: bob.id,
}, alice);
assert.strictEqual(res1.status, 204);
- assert.strictEqual(res2.body?.memo, memo);
+ assert.strictEqual((res2.body as unknown as { memo: string })?.memo, memo);
});
test('自分ã«é–¢ã™ã‚‹ãƒ¡ãƒ¢ã‚’æ›´æ–°ã§ãã‚‹', async () => {
@@ -1008,7 +1079,7 @@ describe('Endpoints', () => {
userId: alice.id,
}, alice);
assert.strictEqual(res1.status, 204);
- assert.strictEqual(res2.body?.memo, memo);
+ assert.strictEqual((res2.body as unknown as { memo: string })?.memo, memo);
});
test('メモを削除ã§ãã‚‹', async () => {
@@ -1029,7 +1100,7 @@ describe('Endpoints', () => {
}, alice);
// memoã«ã¯å¸¸ã«æ–‡å­—列ã‹nullãŒå…¥ã£ã¦ã„ã‚‹(5cac151)
- assert.strictEqual(res.body.memo, null);
+ assert.strictEqual((res.body as unknown as { memo: string | null }).memo, null);
});
test('メモã¯å€‹äººã”ã¨ã«ç‹¬ç«‹ã—ã¦ä¿å­˜ã•れる', async () => {
@@ -1056,8 +1127,8 @@ describe('Endpoints', () => {
}, carol),
]);
- assert.strictEqual(resAlice.body.memo, memoAliceToBob);
- assert.strictEqual(resCarol.body.memo, memoCarolToBob);
+ assert.strictEqual((resAlice.body as unknown as { memo: string }).memo, memoAliceToBob);
+ assert.strictEqual((resCarol.body as unknown as { memo: string }).memo, memoCarolToBob);
});
});
});
diff --git a/packages/backend/test/e2e/exports.ts b/packages/backend/test/e2e/exports.ts
index 80a5331a6d..4bcecc9716 100644
--- a/packages/backend/test/e2e/exports.ts
+++ b/packages/backend/test/e2e/exports.ts
@@ -61,14 +61,14 @@ describe('export-clips', () => {
});
test('basic export', async () => {
- let res = await api('clips/create', {
+ const res1 = await api('clips/create', {
name: 'foo',
description: 'bar',
}, alice);
- assert.strictEqual(res.status, 200);
+ assert.strictEqual(res1.status, 200);
- res = await api('i/export-clips', {}, alice);
- assert.strictEqual(res.status, 204);
+ const res2 = await api('i/export-clips', {}, alice);
+ assert.strictEqual(res2.status, 204);
const exported = await pollFirstDriveFile();
assert.strictEqual(exported[0].name, 'foo');
@@ -77,7 +77,7 @@ describe('export-clips', () => {
});
test('export with notes', async () => {
- let res = await api('clips/create', {
+ const res = await api('clips/create', {
name: 'foo',
description: 'bar',
}, alice);
@@ -96,15 +96,15 @@ describe('export-clips', () => {
});
for (const note of [note1, note2]) {
- res = await api('clips/add-note', {
+ const res2 = await api('clips/add-note', {
clipId: clip.id,
noteId: note.id,
}, alice);
- assert.strictEqual(res.status, 204);
+ assert.strictEqual(res2.status, 204);
}
- res = await api('i/export-clips', {}, alice);
- assert.strictEqual(res.status, 204);
+ const res3 = await api('i/export-clips', {}, alice);
+ assert.strictEqual(res3.status, 204);
const exported = await pollFirstDriveFile();
assert.strictEqual(exported[0].name, 'foo');
@@ -116,19 +116,19 @@ describe('export-clips', () => {
});
test('multiple clips', async () => {
- let res = await api('clips/create', {
+ const res1 = await api('clips/create', {
name: 'kawaii',
description: 'kawaii',
}, alice);
- assert.strictEqual(res.status, 200);
- const clip1 = res.body;
+ assert.strictEqual(res1.status, 200);
+ const clip1 = res1.body;
- res = await api('clips/create', {
+ const res2 = await api('clips/create', {
name: 'yuri',
description: 'yuri',
}, alice);
- assert.strictEqual(res.status, 200);
- const clip2 = res.body;
+ assert.strictEqual(res2.status, 200);
+ const clip2 = res2.body;
const note1 = await post(alice, {
text: 'baz1',
@@ -138,20 +138,26 @@ describe('export-clips', () => {
text: 'baz2',
});
- res = await api('clips/add-note', {
- clipId: clip1.id,
- noteId: note1.id,
- }, alice);
- assert.strictEqual(res.status, 204);
+ {
+ const res = await api('clips/add-note', {
+ clipId: clip1.id,
+ noteId: note1.id,
+ }, alice);
+ assert.strictEqual(res.status, 204);
+ }
- res = await api('clips/add-note', {
- clipId: clip2.id,
- noteId: note2.id,
- }, alice);
- assert.strictEqual(res.status, 204);
+ {
+ const res = await api('clips/add-note', {
+ clipId: clip2.id,
+ noteId: note2.id,
+ }, alice);
+ assert.strictEqual(res.status, 204);
+ }
- res = await api('i/export-clips', {}, alice);
- assert.strictEqual(res.status, 204);
+ {
+ const res = await api('i/export-clips', {}, alice);
+ assert.strictEqual(res.status, 204);
+ }
const exported = await pollFirstDriveFile();
assert.strictEqual(exported[0].name, 'kawaii');
@@ -163,7 +169,7 @@ describe('export-clips', () => {
});
test('Clipping other user\'s note', async () => {
- let res = await api('clips/create', {
+ const res = await api('clips/create', {
name: 'kawaii',
description: 'kawaii',
}, alice);
@@ -175,14 +181,14 @@ describe('export-clips', () => {
visibility: 'followers',
});
- res = await api('clips/add-note', {
+ const res2 = await api('clips/add-note', {
clipId: clip.id,
noteId: note.id,
}, alice);
- assert.strictEqual(res.status, 204);
+ assert.strictEqual(res2.status, 204);
- res = await api('i/export-clips', {}, alice);
- assert.strictEqual(res.status, 204);
+ const res3 = await api('i/export-clips', {}, alice);
+ assert.strictEqual(res3.status, 204);
const exported = await pollFirstDriveFile();
assert.strictEqual(exported[0].name, 'kawaii');
diff --git a/packages/backend/test/e2e/fetch-resource.ts b/packages/backend/test/e2e/fetch-resource.ts
index 4851ed14be..7efd688ec2 100644
--- a/packages/backend/test/e2e/fetch-resource.ts
+++ b/packages/backend/test/e2e/fetch-resource.ts
@@ -153,6 +153,23 @@ describe('Webリソース', () => {
path: path('nonexisting'),
status: 404,
}));
+
+ describe(' has entry such ', () => {
+ beforeEach(() => {
+ post(alice, { text: "**a**" })
+ });
+
+ test('MFMã‚’å«ã¾ãªã„。', async () => {
+ const content = await simpleGet(path(alice.username), "*/*", undefined, res => res.text());
+ const _body: unknown = content.body;
+ // JSONフィードã®ã¨ãã¯æ”¹ã‚ã¦æ–‡å­—列化ã™ã‚‹
+ const body: string = typeof (_body) === "object" ? JSON.stringify(_body) : _body as string;
+
+ if (body.includes("**a**")) {
+ throw new Error("MFM shouldn't be included");
+ }
+ });
+ })
});
describe.each([{ path: '/api/foo' }])('$path', ({ path }) => {
diff --git a/packages/backend/test/e2e/move.ts b/packages/backend/test/e2e/move.ts
index 74cf61a785..fd798bdb25 100644
--- a/packages/backend/test/e2e/move.ts
+++ b/packages/backend/test/e2e/move.ts
@@ -7,19 +7,20 @@ import { INestApplicationContext } from '@nestjs/common';
process.env.NODE_ENV = 'test';
+import { setTimeout } from 'node:timers/promises';
import * as assert from 'assert';
import { loadConfig } from '@/config.js';
import { MiRepository, MiUser, UsersRepository, miRepository } from '@/models/_.js';
import { secureRndstr } from '@/misc/secure-rndstr.js';
import { jobQueue } from '@/boot/common.js';
-import { api, initTestDb, signup, sleep, successfulApiCall, uploadFile } from '../utils.js';
+import { api, castAsError, initTestDb, signup, successfulApiCall, uploadFile } from '../utils.js';
import type * as misskey from 'misskey-js';
describe('Account Move', () => {
let jq: INestApplicationContext;
let url: URL;
- let root: any;
+ let root: misskey.entities.SignupResponse;
let alice: misskey.entities.SignupResponse;
let bob: misskey.entities.SignupResponse;
let carol: misskey.entities.SignupResponse;
@@ -92,8 +93,8 @@ describe('Account Move', () => {
}, bob);
assert.strictEqual(res.status, 400);
- assert.strictEqual(res.body.error.code, 'NO_SUCH_USER');
- assert.strictEqual(res.body.error.id, 'fcd2eef9-a9b2-4c4f-8624-038099e90aa5');
+ assert.strictEqual(castAsError(res.body).error.code, 'NO_SUCH_USER');
+ assert.strictEqual(castAsError(res.body).error.id, 'fcd2eef9-a9b2-4c4f-8624-038099e90aa5');
});
test('Unable to add duplicated aliases to alsoKnownAs', async () => {
@@ -102,8 +103,8 @@ describe('Account Move', () => {
}, bob);
assert.strictEqual(res.status, 400);
- assert.strictEqual(res.body.error.code, 'INVALID_PARAM');
- assert.strictEqual(res.body.error.id, '3d81ceae-475f-4600-b2a8-2bc116157532');
+ assert.strictEqual(castAsError(res.body).error.code, 'INVALID_PARAM');
+ assert.strictEqual(castAsError(res.body).error.id, '3d81ceae-475f-4600-b2a8-2bc116157532');
});
test('Unable to add itself', async () => {
@@ -112,8 +113,8 @@ describe('Account Move', () => {
}, bob);
assert.strictEqual(res.status, 400);
- assert.strictEqual(res.body.error.code, 'FORBIDDEN_TO_SET_YOURSELF');
- assert.strictEqual(res.body.error.id, '25c90186-4ab0-49c8-9bba-a1fa6c202ba4');
+ assert.strictEqual(castAsError(res.body).error.code, 'FORBIDDEN_TO_SET_YOURSELF');
+ assert.strictEqual(castAsError(res.body).error.id, '25c90186-4ab0-49c8-9bba-a1fa6c202ba4');
});
test('Unable to add a nonexisting local account to alsoKnownAs', async () => {
@@ -122,16 +123,16 @@ describe('Account Move', () => {
}, bob);
assert.strictEqual(res1.status, 400);
- assert.strictEqual(res1.body.error.code, 'NO_SUCH_USER');
- assert.strictEqual(res1.body.error.id, 'fcd2eef9-a9b2-4c4f-8624-038099e90aa5');
+ assert.strictEqual(castAsError(res1.body).error.code, 'NO_SUCH_USER');
+ assert.strictEqual(castAsError(res1.body).error.id, 'fcd2eef9-a9b2-4c4f-8624-038099e90aa5');
const res2 = await api('i/update', {
alsoKnownAs: ['@alice', 'nonexist'],
}, bob);
assert.strictEqual(res2.status, 400);
- assert.strictEqual(res2.body.error.code, 'NO_SUCH_USER');
- assert.strictEqual(res2.body.error.id, 'fcd2eef9-a9b2-4c4f-8624-038099e90aa5');
+ assert.strictEqual(castAsError(res2.body).error.code, 'NO_SUCH_USER');
+ assert.strictEqual(castAsError(res2.body).error.id, 'fcd2eef9-a9b2-4c4f-8624-038099e90aa5');
});
test('Able to add two existing local account to alsoKnownAs', async () => {
@@ -240,8 +241,8 @@ describe('Account Move', () => {
}, root);
assert.strictEqual(res.status, 400);
- assert.strictEqual(res.body.error.code, 'NOT_ROOT_FORBIDDEN');
- assert.strictEqual(res.body.error.id, '4362e8dc-731f-4ad8-a694-be2a88922a24');
+ assert.strictEqual(castAsError(res.body).error.code, 'NOT_ROOT_FORBIDDEN');
+ assert.strictEqual(castAsError(res.body).error.id, '4362e8dc-731f-4ad8-a694-be2a88922a24');
});
test('Unable to move to a nonexisting local account', async () => {
@@ -250,8 +251,8 @@ describe('Account Move', () => {
}, alice);
assert.strictEqual(res.status, 400);
- assert.strictEqual(res.body.error.code, 'NO_SUCH_USER');
- assert.strictEqual(res.body.error.id, 'fcd2eef9-a9b2-4c4f-8624-038099e90aa5');
+ assert.strictEqual(castAsError(res.body).error.code, 'NO_SUCH_USER');
+ assert.strictEqual(castAsError(res.body).error.id, 'fcd2eef9-a9b2-4c4f-8624-038099e90aa5');
});
test('Unable to move if alsoKnownAs is invalid', async () => {
@@ -260,8 +261,8 @@ describe('Account Move', () => {
}, alice);
assert.strictEqual(res.status, 400);
- assert.strictEqual(res.body.error.code, 'DESTINATION_ACCOUNT_FORBIDS');
- assert.strictEqual(res.body.error.id, 'b5c90186-4ab0-49c8-9bba-a1f766282ba4');
+ assert.strictEqual(castAsError(res.body).error.code, 'DESTINATION_ACCOUNT_FORBIDS');
+ assert.strictEqual(castAsError(res.body).error.id, 'b5c90186-4ab0-49c8-9bba-a1f766282ba4');
});
test('Relationships have been properly migrated', async () => {
@@ -271,43 +272,51 @@ describe('Account Move', () => {
assert.strictEqual(move.status, 200);
- await sleep(1000 * 3); // wait for jobs to finish
+ await setTimeout(1000 * 3); // wait for jobs to finish
// Unfollow delayed?
const aliceFollowings = await api('users/following', {
userId: alice.id,
}, alice);
assert.strictEqual(aliceFollowings.status, 200);
+ assert.ok(aliceFollowings);
assert.strictEqual(aliceFollowings.body.length, 3);
const carolFollowings = await api('users/following', {
userId: carol.id,
}, carol);
assert.strictEqual(carolFollowings.status, 200);
+ assert.ok(carolFollowings);
assert.strictEqual(carolFollowings.body.length, 2);
assert.strictEqual(carolFollowings.body[0].followeeId, bob.id);
assert.strictEqual(carolFollowings.body[1].followeeId, alice.id);
const blockings = await api('blocking/list', {}, dave);
assert.strictEqual(blockings.status, 200);
+ assert.ok(blockings);
assert.strictEqual(blockings.body.length, 2);
assert.strictEqual(blockings.body[0].blockeeId, bob.id);
assert.strictEqual(blockings.body[1].blockeeId, alice.id);
const mutings = await api('mute/list', {}, dave);
assert.strictEqual(mutings.status, 200);
+ assert.ok(mutings);
assert.strictEqual(mutings.body.length, 2);
assert.strictEqual(mutings.body[0].muteeId, bob.id);
assert.strictEqual(mutings.body[1].muteeId, alice.id);
const rootLists = await api('users/lists/list', {}, root);
assert.strictEqual(rootLists.status, 200);
+ assert.ok(rootLists);
+ assert.ok(rootLists.body[0].userIds);
assert.strictEqual(rootLists.body[0].userIds.length, 2);
assert.ok(rootLists.body[0].userIds.find((id: string) => id === bob.id));
assert.ok(rootLists.body[0].userIds.find((id: string) => id === alice.id));
const eveLists = await api('users/lists/list', {}, eve);
assert.strictEqual(eveLists.status, 200);
+ assert.ok(eveLists);
+ assert.ok(eveLists.body[0].userIds);
assert.strictEqual(eveLists.body[0].userIds.length, 1);
assert.ok(eveLists.body[0].userIds.find((id: string) => id === bob.id));
});
@@ -330,7 +339,7 @@ describe('Account Move', () => {
});
test('Unfollowed after 10 sec (24 hours in production).', async () => {
- await sleep(1000 * 8);
+ await setTimeout(1000 * 8);
const following = await api('users/following', {
userId: alice.id,
@@ -346,8 +355,8 @@ describe('Account Move', () => {
}, bob);
assert.strictEqual(res.status, 400);
- assert.strictEqual(res.body.error.code, 'DESTINATION_ACCOUNT_FORBIDS');
- assert.strictEqual(res.body.error.id, 'b5c90186-4ab0-49c8-9bba-a1f766282ba4');
+ assert.strictEqual(castAsError(res.body).error.code, 'DESTINATION_ACCOUNT_FORBIDS');
+ assert.strictEqual(castAsError(res.body).error.id, 'b5c90186-4ab0-49c8-9bba-a1f766282ba4');
});
test('Follow and follower counts are properly adjusted', async () => {
@@ -418,8 +427,9 @@ describe('Account Move', () => {
] as const)('Prohibit access after moving: %s', async (endpoint) => {
const res = await api(endpoint, {}, alice);
assert.strictEqual(res.status, 403);
- assert.strictEqual(res.body.error.code, 'YOUR_ACCOUNT_MOVED');
- assert.strictEqual(res.body.error.id, '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31');
+ assert.ok(res.body);
+ assert.strictEqual(castAsError(res.body).error.code, 'YOUR_ACCOUNT_MOVED');
+ assert.strictEqual(castAsError(res.body).error.id, '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31');
});
test('Prohibit access after moving: /antennas/update', async () => {
@@ -437,16 +447,19 @@ describe('Account Move', () => {
}, alice);
assert.strictEqual(res.status, 403);
- assert.strictEqual(res.body.error.code, 'YOUR_ACCOUNT_MOVED');
- assert.strictEqual(res.body.error.id, '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31');
+ assert.ok(res.body);
+ assert.strictEqual(castAsError(res.body).error.code, 'YOUR_ACCOUNT_MOVED');
+ assert.strictEqual(castAsError(res.body).error.id, '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31');
});
test('Prohibit access after moving: /drive/files/create', async () => {
+ // FIXME: 一旦逃ã’ã¦ãŠã
const res = await uploadFile(alice);
assert.strictEqual(res.status, 403);
- assert.strictEqual((res.body! as any as { error: misskey.api.APIError }).error.code, 'YOUR_ACCOUNT_MOVED');
- assert.strictEqual((res.body! as any as { error: misskey.api.APIError }).error.id, '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31');
+ assert.ok(res.body);
+ assert.strictEqual(castAsError(res.body).error.code, 'YOUR_ACCOUNT_MOVED');
+ assert.strictEqual(castAsError(res.body).error.id, '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31');
});
test('Prohibit updating alsoKnownAs after moving', async () => {
@@ -455,8 +468,8 @@ describe('Account Move', () => {
}, alice);
assert.strictEqual(res.status, 403);
- assert.strictEqual(res.body.error.code, 'YOUR_ACCOUNT_MOVED');
- assert.strictEqual(res.body.error.id, '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31');
+ assert.strictEqual(castAsError(res.body).error.code, 'YOUR_ACCOUNT_MOVED');
+ assert.strictEqual(castAsError(res.body).error.id, '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31');
});
});
});
diff --git a/packages/backend/test/e2e/mute.ts b/packages/backend/test/e2e/mute.ts
index 0e52c5decc..f37da288b7 100644
--- a/packages/backend/test/e2e/mute.ts
+++ b/packages/backend/test/e2e/mute.ts
@@ -47,8 +47,8 @@ describe('Mute', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), false);
});
test('ミュートã—ã¦ã„るユーザーã‹ã‚‰ãƒ¡ãƒ³ã‚·ãƒ§ãƒ³ã•れã¦ã‚‚ã€hasUnreadMentions ㌠true ã«ãªã‚‰ãªã„', async () => {
@@ -92,9 +92,9 @@ describe('Mute', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
- assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), false);
});
test('タイムラインã«ãƒŸãƒ¥ãƒ¼ãƒˆã—ã¦ã„ã‚‹ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®æŠ•ç¨¿ã®RenoteãŒå«ã¾ã‚Œãªã„', async () => {
@@ -108,9 +108,9 @@ describe('Mute', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
- assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), false);
});
});
@@ -124,8 +124,8 @@ describe('Mute', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false);
});
test('通知ã«ãƒŸãƒ¥ãƒ¼ãƒˆã—ã¦ã„るユーザーã‹ã‚‰ã®ãƒªãƒ—ライãŒå«ã¾ã‚Œãªã„', async () => {
@@ -138,8 +138,8 @@ describe('Mute', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false);
});
test('通知ã«ãƒŸãƒ¥ãƒ¼ãƒˆã—ã¦ã„るユーザーã‹ã‚‰ã®ãƒªãƒ—ライãŒå«ã¾ã‚Œãªã„', async () => {
@@ -152,8 +152,8 @@ describe('Mute', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false);
});
test('通知ã«ãƒŸãƒ¥ãƒ¼ãƒˆã—ã¦ã„るユーザーã‹ã‚‰ã®å¼•用リノートãŒå«ã¾ã‚Œãªã„', async () => {
@@ -166,8 +166,8 @@ describe('Mute', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false);
});
test('通知ã«ãƒŸãƒ¥ãƒ¼ãƒˆã—ã¦ã„るユーザーã‹ã‚‰ã®ãƒªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œãªã„', async () => {
@@ -180,8 +180,8 @@ describe('Mute', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false);
});
test('通知ã«ãƒŸãƒ¥ãƒ¼ãƒˆã—ã¦ã„るユーザーã‹ã‚‰ã®ãƒ•ォロー通知ãŒå«ã¾ã‚Œãªã„', async () => {
@@ -193,8 +193,8 @@ describe('Mute', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false);
await api('following/delete', { userId: alice.id }, bob);
await api('following/delete', { userId: alice.id }, carol);
@@ -210,8 +210,8 @@ describe('Mute', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false);
await api('following/delete', { userId: alice.id }, bob);
await api('following/delete', { userId: alice.id }, carol);
@@ -228,8 +228,8 @@ describe('Mute', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false);
});
test('通知ã«ãƒŸãƒ¥ãƒ¼ãƒˆã—ã¦ã„るユーザーã‹ã‚‰ã®ãƒªãƒ—ライãŒå«ã¾ã‚Œãªã„', async () => {
const aliceNote = await post(alice, { text: 'hi' });
@@ -241,8 +241,8 @@ describe('Mute', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false);
});
test('通知ã«ãƒŸãƒ¥ãƒ¼ãƒˆã—ã¦ã„るユーザーã‹ã‚‰ã®ãƒªãƒ—ライãŒå«ã¾ã‚Œãªã„', async () => {
@@ -255,8 +255,8 @@ describe('Mute', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false);
});
test('通知ã«ãƒŸãƒ¥ãƒ¼ãƒˆã—ã¦ã„るユーザーã‹ã‚‰ã®å¼•用リノートãŒå«ã¾ã‚Œãªã„', async () => {
@@ -269,8 +269,8 @@ describe('Mute', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false);
});
test('通知ã«ãƒŸãƒ¥ãƒ¼ãƒˆã—ã¦ã„るユーザーã‹ã‚‰ã®ãƒªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œãªã„', async () => {
@@ -283,8 +283,8 @@ describe('Mute', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false);
});
test('通知ã«ãƒŸãƒ¥ãƒ¼ãƒˆã—ã¦ã„るユーザーã‹ã‚‰ã®ãƒ•ォロー通知ãŒå«ã¾ã‚Œãªã„', async () => {
@@ -296,8 +296,8 @@ describe('Mute', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false);
await api('following/delete', { userId: alice.id }, bob);
await api('following/delete', { userId: alice.id }, carol);
@@ -313,8 +313,8 @@ describe('Mute', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
- assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true);
+ assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false);
});
});
});
diff --git a/packages/backend/test/e2e/note.ts b/packages/backend/test/e2e/note.ts
index bda31d9640..5937eb9b49 100644
--- a/packages/backend/test/e2e/note.ts
+++ b/packages/backend/test/e2e/note.ts
@@ -3,16 +3,18 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
+import type { Repository } from "typeorm";
+
process.env.NODE_ENV = 'test';
import * as assert from 'assert';
import { MiNote } from '@/models/Note.js';
import { MAX_NOTE_TEXT_LENGTH } from '@/const.js';
-import { api, initTestDb, post, role, signup, uploadFile, uploadUrl } from '../utils.js';
+import { api, castAsError, initTestDb, post, role, signup, uploadFile, uploadUrl } from '../utils.js';
import type * as misskey from 'misskey-js';
describe('Note', () => {
- let Notes: any;
+ let Notes: Repository<MiNote>;
let root: misskey.entities.SignupResponse;
let alice: misskey.entities.SignupResponse;
@@ -41,7 +43,7 @@ describe('Note', () => {
});
test('ファイルを添付ã§ãã‚‹', async () => {
- const file = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg');
+ const file = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/192.jpg');
const res = await api('notes/create', {
fileIds: [file.id],
@@ -53,7 +55,7 @@ describe('Note', () => {
}, 1000 * 10);
test('他人ã®ãƒ•ã‚¡ã‚¤ãƒ«ã§æ€’られる', async () => {
- const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg');
+ const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/192.jpg');
const res = await api('notes/create', {
text: 'test',
@@ -61,8 +63,8 @@ describe('Note', () => {
}, alice);
assert.strictEqual(res.status, 400);
- assert.strictEqual(res.body.error.code, 'NO_SUCH_FILE');
- assert.strictEqual(res.body.error.id, 'b6992544-63e7-67f0-fa7f-32444b1b5306');
+ assert.strictEqual(castAsError(res.body).error.code, 'NO_SUCH_FILE');
+ assert.strictEqual(castAsError(res.body).error.id, 'b6992544-63e7-67f0-fa7f-32444b1b5306');
}, 1000 * 10);
test('存在ã—ãªã„ãƒ•ã‚¡ã‚¤ãƒ«ã§æ€’られる', async () => {
@@ -72,8 +74,8 @@ describe('Note', () => {
}, alice);
assert.strictEqual(res.status, 400);
- assert.strictEqual(res.body.error.code, 'NO_SUCH_FILE');
- assert.strictEqual(res.body.error.id, 'b6992544-63e7-67f0-fa7f-32444b1b5306');
+ assert.strictEqual(castAsError(res.body).error.code, 'NO_SUCH_FILE');
+ assert.strictEqual(castAsError(res.body).error.id, 'b6992544-63e7-67f0-fa7f-32444b1b5306');
});
test('䏿­£ãªãƒ•ァイルIDã§æ€’られる', async () => {
@@ -81,8 +83,8 @@ describe('Note', () => {
fileIds: ['kyoppie'],
}, alice);
assert.strictEqual(res.status, 400);
- assert.strictEqual(res.body.error.code, 'NO_SUCH_FILE');
- assert.strictEqual(res.body.error.id, 'b6992544-63e7-67f0-fa7f-32444b1b5306');
+ assert.strictEqual(castAsError(res.body).error.code, 'NO_SUCH_FILE');
+ assert.strictEqual(castAsError(res.body).error.id, 'b6992544-63e7-67f0-fa7f-32444b1b5306');
});
test('返信ã§ãã‚‹', async () => {
@@ -101,6 +103,7 @@ describe('Note', () => {
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
assert.strictEqual(res.body.createdNote.text, alicePost.text);
assert.strictEqual(res.body.createdNote.replyId, alicePost.replyId);
+ assert.ok(res.body.createdNote.reply);
assert.strictEqual(res.body.createdNote.reply.text, bobPost.text);
});
@@ -118,6 +121,7 @@ describe('Note', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
assert.strictEqual(res.body.createdNote.renoteId, alicePost.renoteId);
+ assert.ok(res.body.createdNote.renote);
assert.strictEqual(res.body.createdNote.renote.text, bobPost.text);
});
@@ -137,6 +141,7 @@ describe('Note', () => {
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
assert.strictEqual(res.body.createdNote.text, alicePost.text);
assert.strictEqual(res.body.createdNote.renoteId, alicePost.renoteId);
+ assert.ok(res.body.createdNote.renote);
assert.strictEqual(res.body.createdNote.renote.text, bobPost.text);
});
@@ -218,7 +223,7 @@ describe('Note', () => {
}, bob);
assert.strictEqual(bobReply.status, 400);
- assert.strictEqual(bobReply.body.error.code, 'CANNOT_REPLY_TO_AN_INVISIBLE_NOTE');
+ assert.strictEqual(castAsError(bobReply.body).error.code, 'CANNOT_REPLY_TO_AN_INVISIBLE_NOTE');
});
test('visibility: specifiedãªãƒŽãƒ¼ãƒˆã«å¯¾ã—ã¦visibility: specifiedã§è¿”ä¿¡ã§ãã‚‹', async () => {
@@ -256,7 +261,7 @@ describe('Note', () => {
}, bob);
assert.strictEqual(bobReply.status, 400);
- assert.strictEqual(bobReply.body.error.code, 'CANNOT_REPLY_TO_SPECIFIED_VISIBILITY_NOTE_WITH_EXTENDED_VISIBILITY');
+ assert.strictEqual(castAsError(bobReply.body).error.code, 'CANNOT_REPLY_TO_SPECIFIED_VISIBILITY_NOTE_WITH_EXTENDED_VISIBILITY');
});
test('文字数ãŽã‚ŠãŽã‚Šã§æ€’られãªã„', async () => {
@@ -333,6 +338,7 @@ describe('Note', () => {
assert.strictEqual(res.body.createdNote.text, post.text);
const noteDoc = await Notes.findOneBy({ id: res.body.createdNote.id });
+ assert.ok(noteDoc);
assert.deepStrictEqual(noteDoc.mentions, [bob.id]);
});
@@ -345,6 +351,7 @@ describe('Note', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
+ assert.ok(res.body.createdNote.files);
assert.strictEqual(res.body.createdNote.files.length, 1);
assert.strictEqual(res.body.createdNote.files[0].id, file.body!.id);
});
@@ -363,8 +370,9 @@ describe('Note', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
- const myNote = res.body.find((note: { id: string; files: { id: string }[] }) => note.id === createdNote.body.createdNote.id);
- assert.notEqual(myNote, null);
+ const myNote = res.body.find(note => note.id === createdNote.body.createdNote.id);
+ assert.ok(myNote);
+ assert.ok(myNote.files);
assert.strictEqual(myNote.files.length, 1);
assert.strictEqual(myNote.files[0].id, file.body!.id);
});
@@ -389,7 +397,9 @@ describe('Note', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
const myNote = res.body.find((note: { id: string }) => note.id === renoted.body.createdNote.id);
- assert.notEqual(myNote, null);
+ assert.ok(myNote);
+ assert.ok(myNote.renote);
+ assert.ok(myNote.renote.files);
assert.strictEqual(myNote.renote.files.length, 1);
assert.strictEqual(myNote.renote.files[0].id, file.body!.id);
});
@@ -415,7 +425,9 @@ describe('Note', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
const myNote = res.body.find((note: { id: string }) => note.id === reply.body.createdNote.id);
- assert.notEqual(myNote, null);
+ assert.ok(myNote);
+ assert.ok(myNote.reply);
+ assert.ok(myNote.reply.files);
assert.strictEqual(myNote.reply.files.length, 1);
assert.strictEqual(myNote.reply.files[0].id, file.body!.id);
});
@@ -446,7 +458,10 @@ describe('Note', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
const myNote = res.body.find((note: { id: string }) => note.id === renoted.body.createdNote.id);
- assert.notEqual(myNote, null);
+ assert.ok(myNote);
+ assert.ok(myNote.renote);
+ assert.ok(myNote.renote.reply);
+ assert.ok(myNote.renote.reply.files);
assert.strictEqual(myNote.renote.reply.files.length, 1);
assert.strictEqual(myNote.renote.reply.files[0].id, file.body!.id);
});
@@ -474,7 +489,7 @@ describe('Note', () => {
priority: 0,
value: true,
},
- } as any,
+ },
}, root);
assert.strictEqual(res.status, 200);
@@ -498,7 +513,7 @@ describe('Note', () => {
}, alice);
assert.strictEqual(liftnsfw.status, 400);
- assert.strictEqual(liftnsfw.body.error.code, 'RESTRICTED_BY_ROLE');
+ assert.strictEqual(castAsError(liftnsfw.body).error.code, 'RESTRICTED_BY_ROLE');
const oldaddnsfw = await api('drive/files/update', {
fileId: file.body!.id,
@@ -710,7 +725,7 @@ describe('Note', () => {
}, alice);
assert.strictEqual(note1.status, 400);
- assert.strictEqual(note1.body.error.code, 'CONTAINS_PROHIBITED_WORDS');
+ assert.strictEqual(castAsError(note1.body).error.code, 'CONTAINS_PROHIBITED_WORDS');
});
test('ç¦æ­¢ãƒ¯ãƒ¼ãƒ‰ã‚’å«ã‚€æŠ•稿ã¯ã‚¨ãƒ©ãƒ¼ã«ãªã‚‹ (æ­£è¦è¡¨ç¾)', async () => {
@@ -727,7 +742,7 @@ describe('Note', () => {
}, alice);
assert.strictEqual(note2.status, 400);
- assert.strictEqual(note2.body.error.code, 'CONTAINS_PROHIBITED_WORDS');
+ assert.strictEqual(castAsError(note2.body).error.code, 'CONTAINS_PROHIBITED_WORDS');
});
test('ç¦æ­¢ãƒ¯ãƒ¼ãƒ‰ã‚’å«ã‚€æŠ•稿ã¯ã‚¨ãƒ©ãƒ¼ã«ãªã‚‹ (スペースアンド)', async () => {
@@ -744,7 +759,7 @@ describe('Note', () => {
}, alice);
assert.strictEqual(note2.status, 400);
- assert.strictEqual(note2.body.error.code, 'CONTAINS_PROHIBITED_WORDS');
+ assert.strictEqual(castAsError(note2.body).error.code, 'CONTAINS_PROHIBITED_WORDS');
});
test('ç¦æ­¢ãƒ¯ãƒ¼ãƒ‰ã‚’å«ã‚“ã§ã‚‹ãƒªãƒ¢ãƒ¼ãƒˆãƒŽãƒ¼ãƒˆã‚‚エラーã«ãªã‚‹', async () => {
@@ -786,7 +801,7 @@ describe('Note', () => {
priority: 1,
value: 0,
},
- } as any,
+ },
}, root);
assert.strictEqual(res.status, 200);
@@ -807,7 +822,7 @@ describe('Note', () => {
}, alice);
assert.strictEqual(note.status, 400);
- assert.strictEqual(note.body.error.code, 'CONTAINS_TOO_MANY_MENTIONS');
+ assert.strictEqual(castAsError(note.body).error.code, 'CONTAINS_TOO_MANY_MENTIONS');
await api('admin/roles/unassign', {
userId: alice.id,
@@ -840,7 +855,7 @@ describe('Note', () => {
priority: 1,
value: 0,
},
- } as any,
+ },
}, root);
assert.strictEqual(res.status, 200);
@@ -863,7 +878,7 @@ describe('Note', () => {
}, alice);
assert.strictEqual(note.status, 400);
- assert.strictEqual(note.body.error.code, 'CONTAINS_TOO_MANY_MENTIONS');
+ assert.strictEqual(castAsError(note.body).error.code, 'CONTAINS_TOO_MANY_MENTIONS');
await api('admin/roles/unassign', {
userId: alice.id,
@@ -896,7 +911,7 @@ describe('Note', () => {
priority: 1,
value: 1,
},
- } as any,
+ },
}, root);
assert.strictEqual(res.status, 200);
@@ -951,6 +966,7 @@ describe('Note', () => {
assert.strictEqual(deleteOneRes.status, 204);
let mainNote = await Notes.findOneBy({ id: mainNoteRes.body.createdNote.id });
+ assert.ok(mainNote);
assert.strictEqual(mainNote.repliesCount, 1);
const deleteTwoRes = await api('notes/delete', {
@@ -959,6 +975,7 @@ describe('Note', () => {
assert.strictEqual(deleteTwoRes.status, 204);
mainNote = await Notes.findOneBy({ id: mainNoteRes.body.createdNote.id });
+ assert.ok(mainNote);
assert.strictEqual(mainNote.repliesCount, 0);
});
});
@@ -980,7 +997,7 @@ describe('Note', () => {
}, alice);
assert.strictEqual(res.status, 400);
- assert.strictEqual(res.body.error.code, 'UNAVAILABLE');
+ assert.strictEqual(castAsError(res.body).error.code, 'UNAVAILABLE');
});
afterAll(async () => {
@@ -992,7 +1009,7 @@ describe('Note', () => {
const res = await api('notes/translate', { noteId: 'foo', targetLang: 'ja' }, alice);
assert.strictEqual(res.status, 400);
- assert.strictEqual(res.body.error.code, 'NO_SUCH_NOTE');
+ assert.strictEqual(castAsError(res.body).error.code, 'NO_SUCH_NOTE');
});
test('ä¸å¯è¦–ãªãƒŽãƒ¼ãƒˆã¯ç¿»è¨³ã§ããªã„', async () => {
@@ -1000,7 +1017,7 @@ describe('Note', () => {
const bobTranslateAttempt = await api('notes/translate', { noteId: aliceNote.id, targetLang: 'ja' }, bob);
assert.strictEqual(bobTranslateAttempt.status, 400);
- assert.strictEqual(bobTranslateAttempt.body.error.code, 'CANNOT_TRANSLATE_INVISIBLE_NOTE');
+ assert.strictEqual(castAsError(bobTranslateAttempt.body).error.code, 'CANNOT_TRANSLATE_INVISIBLE_NOTE');
});
test('text: null ãªãƒŽãƒ¼ãƒˆã‚’翻訳ã™ã‚‹ã¨ç©ºã®ãƒ¬ã‚¹ãƒãƒ³ã‚¹ãŒè¿”ã£ã¦ãã‚‹', async () => {
@@ -1016,7 +1033,7 @@ describe('Note', () => {
// NOTE: デフォルトã§ã¯ç™»éŒ²ã•れã¦ã„ãªã„ã®ã§è½ã¡ã‚‹
assert.strictEqual(res.status, 400);
- assert.strictEqual(res.body.error.code, 'UNAVAILABLE');
+ assert.strictEqual(castAsError(res.body).error.code, 'UNAVAILABLE');
});
});
});
diff --git a/packages/backend/test/e2e/renote-mute.ts b/packages/backend/test/e2e/renote-mute.ts
index 1abbb4f044..0f636b9ae2 100644
--- a/packages/backend/test/e2e/renote-mute.ts
+++ b/packages/backend/test/e2e/renote-mute.ts
@@ -6,7 +6,8 @@
process.env.NODE_ENV = 'test';
import * as assert from 'assert';
-import { api, post, signup, sleep, waitFire } from '../utils.js';
+import { setTimeout } from 'node:timers/promises';
+import { api, post, signup, waitFire } from '../utils.js';
import type * as misskey from 'misskey-js';
describe('Renote Mute', () => {
@@ -35,15 +36,15 @@ describe('Renote Mute', () => {
const carolNote = await post(carol, { text: 'hi' });
// redisã«è¿½åŠ ã•れるã®ã‚’å¾…ã¤
- await sleep(100);
+ await setTimeout(100);
const res = await api('notes/local-timeline', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === carolRenote.id), false);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === carolRenote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), true);
});
test('タイムラインã«ãƒªãƒŽãƒ¼ãƒˆãƒŸãƒ¥ãƒ¼ãƒˆã—ã¦ã„るユーザーã®å¼•用ãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -52,15 +53,15 @@ describe('Renote Mute', () => {
const carolNote = await post(carol, { text: 'hi' });
// redisã«è¿½åŠ ã•れるã®ã‚’å¾…ã¤
- await sleep(100);
+ await setTimeout(100);
const res = await api('notes/local-timeline', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === carolRenote.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === carolRenote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), true);
});
// #12956
@@ -69,14 +70,14 @@ describe('Renote Mute', () => {
const bobRenote = await post(bob, { renoteId: carolNote.id });
// redisã«è¿½åŠ ã•れるã®ã‚’å¾…ã¤
- await sleep(100);
+ await setTimeout(100);
const res = await api('notes/local-timeline', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === bobRenote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobRenote.id), true);
});
test('ストリームã«ãƒªãƒŽãƒ¼ãƒˆãƒŸãƒ¥ãƒ¼ãƒˆã—ã¦ã„るユーザーã®ãƒªãƒŽãƒ¼ãƒˆãŒæµã‚Œãªã„', async () => {
diff --git a/packages/backend/test/e2e/streaming.ts b/packages/backend/test/e2e/streaming.ts
index b0a70074c6..72f26a38e0 100644
--- a/packages/backend/test/e2e/streaming.ts
+++ b/packages/backend/test/e2e/streaming.ts
@@ -34,6 +34,7 @@ describe('Streaming', () => {
let kyoko: misskey.entities.SignupResponse;
let chitose: misskey.entities.SignupResponse;
let kanako: misskey.entities.SignupResponse;
+ let erin: misskey.entities.SignupResponse;
// Remote users
let akari: misskey.entities.SignupResponse;
@@ -53,6 +54,7 @@ describe('Streaming', () => {
kyoko = await signup({ username: 'kyoko' });
chitose = await signup({ username: 'chitose' });
kanako = await signup({ username: 'kanako' });
+ erin = await signup({ username: 'erin' }); // erin: A generic fifth participant
akari = await signup({ username: 'akari', host: 'example.com' });
chinatsu = await signup({ username: 'chinatsu', host: 'example.com' });
@@ -71,6 +73,12 @@ describe('Streaming', () => {
// Follow: kyoko => chitose
await api('following/create', { userId: chitose.id }, kyoko);
+ // Follow: erin <=> ayano each other.
+ // erin => ayano: withReplies: true
+ await api('following/create', { userId: ayano.id, withReplies: true }, erin);
+ // ayano => erin: withReplies: false
+ await api('following/create', { userId: erin.id, withReplies: false }, ayano);
+
// Mute: chitose => kanako
await api('mute/create', { userId: kanako.id }, chitose);
@@ -297,6 +305,28 @@ describe('Streaming', () => {
assert.strictEqual(fired, true);
});
+
+ test('withReplies: true ã®ã¨ã自分ã®followers投稿ã«å¯¾ã™ã‚‹ãƒªãƒ—ãƒ©ã‚¤ãŒæµã‚Œã‚‹', async () => {
+ const erinNote = await post(erin, { text: 'hi', visibility: 'followers' });
+ const fired = await waitFire(
+ erin, 'homeTimeline', // erin:home
+ () => api('notes/create', { text: 'hello', replyId: erinNote.id }, ayano), // ayano reply to erin's followers post
+ msg => msg.type === 'note' && msg.body.userId === ayano.id, // wait ayano
+ );
+
+ assert.strictEqual(fired, true);
+ });
+
+ test('withReplies: false ã§ã‚‚è‡ªåˆ†ã®æŠ•ç¨¿ã«å¯¾ã™ã‚‹ãƒªãƒ—ãƒ©ã‚¤ãŒæµã‚Œã‚‹', async () => {
+ const ayanoNote = await post(ayano, { text: 'hi', visibility: 'followers' });
+ const fired = await waitFire(
+ ayano, 'homeTimeline', // ayano:home
+ () => api('notes/create', { text: 'hello', replyId: ayanoNote.id }, erin), // erin reply to ayano's followers post
+ msg => msg.type === 'note' && msg.body.userId === erin.id, // wait erin
+ );
+
+ assert.strictEqual(fired, true);
+ });
}); // Home
describe('Local Timeline', () => {
@@ -475,6 +505,38 @@ describe('Streaming', () => {
assert.strictEqual(fired, false);
});
+
+ test('withReplies: true ã®ã¨ã自分ã®followers投稿ã«å¯¾ã™ã‚‹ãƒªãƒ—ãƒ©ã‚¤ãŒæµã‚Œã‚‹', async () => {
+ const erinNote = await post(erin, { text: 'hi', visibility: 'followers' });
+ const fired = await waitFire(
+ erin, 'homeTimeline', // erin:home
+ () => api('notes/create', { text: 'hello', replyId: erinNote.id }, ayano), // ayano reply to erin's followers post
+ msg => msg.type === 'note' && msg.body.userId === ayano.id, // wait ayano
+ );
+
+ assert.strictEqual(fired, true);
+ });
+
+ test('withReplies: false ã§ã‚‚è‡ªåˆ†ã®æŠ•ç¨¿ã«å¯¾ã™ã‚‹ãƒªãƒ—ãƒ©ã‚¤ãŒæµã‚Œã‚‹', async () => {
+ const ayanoNote = await post(ayano, { text: 'hi', visibility: 'followers' });
+ const fired = await waitFire(
+ ayano, 'homeTimeline', // ayano:home
+ () => api('notes/create', { text: 'hello', replyId: ayanoNote.id }, erin), // erin reply to ayano's followers post
+ msg => msg.type === 'note' && msg.body.userId === erin.id, // wait erin
+ );
+
+ assert.strictEqual(fired, true);
+ });
+
+ test('withReplies: true ã®ãƒ•ォローã—ã¦ã„ãªã„人ã®followersノートã«å¯¾ã™ã‚‹ãƒªãƒ—ãƒ©ã‚¤ãŒæµã‚Œãªã„', async () => {
+ const fired = await waitFire(
+ erin, 'homeTimeline', // erin:home
+ () => api('notes/create', { text: 'hello', replyId: chitose.id }, ayano), // ayano reply to chitose's post
+ msg => msg.type === 'note' && msg.body.userId === ayano.id, // wait ayano
+ );
+
+ assert.strictEqual(fired, false);
+ });
});
describe('Global Timeline', () => {
diff --git a/packages/backend/test/e2e/synalio/abuse-report.ts b/packages/backend/test/e2e/synalio/abuse-report.ts
new file mode 100644
index 0000000000..6ce6e47781
--- /dev/null
+++ b/packages/backend/test/e2e/synalio/abuse-report.ts
@@ -0,0 +1,360 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { entities } from 'misskey-js';
+import { beforeEach, describe, test } from '@jest/globals';
+import {
+ api,
+ captureWebhook,
+ randomString,
+ role,
+ signup,
+ startJobQueue,
+ UserToken,
+ WEBHOOK_HOST,
+} from '../../utils.js';
+import type { INestApplicationContext } from '@nestjs/common';
+
+describe('[シナリオ] ユーザ通報', () => {
+ let queue: INestApplicationContext;
+ let admin: entities.SignupResponse;
+ let alice: entities.SignupResponse;
+ let bob: entities.SignupResponse;
+
+ async function createSystemWebhook(args?: Partial<entities.AdminSystemWebhookCreateRequest>, credential?: UserToken): Promise<entities.AdminSystemWebhookCreateResponse> {
+ const res = await api(
+ 'admin/system-webhook/create',
+ {
+ isActive: true,
+ name: randomString(),
+ on: ['abuseReport'],
+ url: WEBHOOK_HOST,
+ secret: randomString(),
+ ...args,
+ },
+ credential ?? admin,
+ );
+ return res.body;
+ }
+
+ async function createAbuseReportNotificationRecipient(args?: Partial<entities.AdminAbuseReportNotificationRecipientCreateRequest>, credential?: UserToken): Promise<entities.AdminAbuseReportNotificationRecipientCreateResponse> {
+ const res = await api(
+ 'admin/abuse-report/notification-recipient/create',
+ {
+ isActive: true,
+ name: randomString(),
+ method: 'webhook',
+ ...args,
+ },
+ credential ?? admin,
+ );
+ return res.body;
+ }
+
+ async function createAbuseReport(args?: Partial<entities.UsersReportAbuseRequest>, credential?: UserToken): Promise<entities.EmptyResponse> {
+ const res = await api(
+ 'users/report-abuse',
+ {
+ userId: alice.id,
+ comment: randomString(),
+ ...args,
+ },
+ credential ?? admin,
+ );
+ return res.body;
+ }
+
+ async function resolveAbuseReport(args?: Partial<entities.AdminResolveAbuseUserReportRequest>, credential?: UserToken): Promise<entities.EmptyResponse> {
+ const res = await api(
+ 'admin/resolve-abuse-user-report',
+ {
+ reportId: admin.id,
+ ...args,
+ },
+ credential ?? admin,
+ );
+ return res.body;
+ }
+
+ // -------------------------------------------------------------------------------------------
+
+ beforeAll(async () => {
+ queue = await startJobQueue();
+ admin = await signup({ username: 'admin' });
+ alice = await signup({ username: 'alice' });
+ bob = await signup({ username: 'bob' });
+
+ await role(admin, { isAdministrator: true });
+ }, 1000 * 60 * 2);
+
+ afterAll(async () => {
+ await queue.close();
+ });
+
+ // -------------------------------------------------------------------------------------------
+
+ describe('SystemWebhook', () => {
+ beforeEach(async () => {
+ const webhooks = await api('admin/system-webhook/list', {}, admin);
+ for (const webhook of webhooks.body) {
+ await api('admin/system-webhook/delete', { id: webhook.id }, admin);
+ }
+ });
+
+ test('通報をå—ã‘㟠-> abuseReportãŒé€å‡ºã•れる', async () => {
+ const webhook = await createSystemWebhook({
+ on: ['abuseReport'],
+ isActive: true,
+ });
+ await createAbuseReportNotificationRecipient({ systemWebhookId: webhook.id });
+
+ // 通報(bob -> alice)
+ const abuse = {
+ userId: alice.id,
+ comment: randomString(),
+ };
+ const webhookBody = await captureWebhook(async () => {
+ await createAbuseReport(abuse, bob);
+ });
+
+ console.log(JSON.stringify(webhookBody, null, 2));
+
+ expect(webhookBody.hookId).toBe(webhook.id);
+ expect(webhookBody.type).toBe('abuseReport');
+ expect(webhookBody.body.targetUserId).toBe(alice.id);
+ expect(webhookBody.body.reporterId).toBe(bob.id);
+ expect(webhookBody.body.comment).toBe(abuse.comment);
+ });
+
+ test('通報をå—ã‘㟠-> abuseReportãŒé€å‡ºã•れる -> 解決 -> abuseReportResolvedãŒé€å‡ºã•れる', async () => {
+ const webhook = await createSystemWebhook({
+ on: ['abuseReport', 'abuseReportResolved'],
+ isActive: true,
+ });
+ await createAbuseReportNotificationRecipient({ systemWebhookId: webhook.id });
+
+ // 通報(bob -> alice)
+ const abuse = {
+ userId: alice.id,
+ comment: randomString(),
+ };
+ const webhookBody1 = await captureWebhook(async () => {
+ await createAbuseReport(abuse, bob);
+ });
+
+ console.log(JSON.stringify(webhookBody1, null, 2));
+ expect(webhookBody1.hookId).toBe(webhook.id);
+ expect(webhookBody1.type).toBe('abuseReport');
+ expect(webhookBody1.body.targetUserId).toBe(alice.id);
+ expect(webhookBody1.body.reporterId).toBe(bob.id);
+ expect(webhookBody1.body.assigneeId).toBeNull();
+ expect(webhookBody1.body.resolved).toBe(false);
+ expect(webhookBody1.body.comment).toBe(abuse.comment);
+
+ // 解決
+ const webhookBody2 = await captureWebhook(async () => {
+ await resolveAbuseReport({
+ reportId: webhookBody1.body.id,
+ forward: false,
+ }, admin);
+ });
+
+ console.log(JSON.stringify(webhookBody2, null, 2));
+ expect(webhookBody2.hookId).toBe(webhook.id);
+ expect(webhookBody2.type).toBe('abuseReportResolved');
+ expect(webhookBody2.body.targetUserId).toBe(alice.id);
+ expect(webhookBody2.body.reporterId).toBe(bob.id);
+ expect(webhookBody2.body.assigneeId).toBe(admin.id);
+ expect(webhookBody2.body.resolved).toBe(true);
+ expect(webhookBody2.body.comment).toBe(abuse.comment);
+ });
+
+ test('通報をå—ã‘㟠-> abuseReportãŒæœªè¨±å¯ã®å ´åˆã¯é€å‡ºã•れãªã„', async () => {
+ const webhook = await createSystemWebhook({
+ on: [],
+ isActive: true,
+ });
+ await createAbuseReportNotificationRecipient({ systemWebhookId: webhook.id });
+
+ // 通報(bob -> alice)
+ const abuse = {
+ userId: alice.id,
+ comment: randomString(),
+ };
+ const webhookBody = await captureWebhook(async () => {
+ await createAbuseReport(abuse, bob);
+ }).catch(e => e.message);
+
+ expect(webhookBody).toBe('timeout');
+ });
+
+ test('通報をå—ã‘㟠-> abuseReportãŒæœªè¨±å¯ã®å ´åˆã¯é€å‡ºã•れãªã„ -> 解決 -> abuseReportResolvedãŒé€å‡ºã•れる', async () => {
+ const webhook = await createSystemWebhook({
+ on: ['abuseReportResolved'],
+ isActive: true,
+ });
+ await createAbuseReportNotificationRecipient({ systemWebhookId: webhook.id });
+
+ // 通報(bob -> alice)
+ const abuse = {
+ userId: alice.id,
+ comment: randomString(),
+ };
+ const webhookBody1 = await captureWebhook(async () => {
+ await createAbuseReport(abuse, bob);
+ }).catch(e => e.message);
+
+ expect(webhookBody1).toBe('timeout');
+
+ const abuseReportId = (await api('admin/abuse-user-reports', {}, admin)).body[0].id;
+
+ // 解決
+ const webhookBody2 = await captureWebhook(async () => {
+ await resolveAbuseReport({
+ reportId: abuseReportId,
+ forward: false,
+ }, admin);
+ });
+
+ console.log(JSON.stringify(webhookBody2, null, 2));
+ expect(webhookBody2.hookId).toBe(webhook.id);
+ expect(webhookBody2.type).toBe('abuseReportResolved');
+ expect(webhookBody2.body.targetUserId).toBe(alice.id);
+ expect(webhookBody2.body.reporterId).toBe(bob.id);
+ expect(webhookBody2.body.assigneeId).toBe(admin.id);
+ expect(webhookBody2.body.resolved).toBe(true);
+ expect(webhookBody2.body.comment).toBe(abuse.comment);
+ });
+
+ test('通報をå—ã‘㟠-> abuseReportãŒé€å‡ºã•れる -> 解決 -> abuseReportResolvedãŒæœªè¨±å¯ã®å ´åˆã¯é€å‡ºã•れãªã„', async () => {
+ const webhook = await createSystemWebhook({
+ on: ['abuseReport'],
+ isActive: true,
+ });
+ await createAbuseReportNotificationRecipient({ systemWebhookId: webhook.id });
+
+ // 通報(bob -> alice)
+ const abuse = {
+ userId: alice.id,
+ comment: randomString(),
+ };
+ const webhookBody1 = await captureWebhook(async () => {
+ await createAbuseReport(abuse, bob);
+ });
+
+ console.log(JSON.stringify(webhookBody1, null, 2));
+ expect(webhookBody1.hookId).toBe(webhook.id);
+ expect(webhookBody1.type).toBe('abuseReport');
+ expect(webhookBody1.body.targetUserId).toBe(alice.id);
+ expect(webhookBody1.body.reporterId).toBe(bob.id);
+ expect(webhookBody1.body.assigneeId).toBeNull();
+ expect(webhookBody1.body.resolved).toBe(false);
+ expect(webhookBody1.body.comment).toBe(abuse.comment);
+
+ // 解決
+ const webhookBody2 = await captureWebhook(async () => {
+ await resolveAbuseReport({
+ reportId: webhookBody1.body.id,
+ forward: false,
+ }, admin);
+ }).catch(e => e.message);
+
+ expect(webhookBody2).toBe('timeout');
+ });
+
+ test('通報をå—ã‘㟠-> abuseReportãŒæœªè¨±å¯ã®å ´åˆã¯é€å‡ºã•れãªã„ -> 解決 -> abuseReportResolvedãŒæœªè¨±å¯ã®å ´åˆã¯é€å‡ºã•れãªã„', async () => {
+ const webhook = await createSystemWebhook({
+ on: [],
+ isActive: true,
+ });
+ await createAbuseReportNotificationRecipient({ systemWebhookId: webhook.id });
+
+ // 通報(bob -> alice)
+ const abuse = {
+ userId: alice.id,
+ comment: randomString(),
+ };
+ const webhookBody1 = await captureWebhook(async () => {
+ await createAbuseReport(abuse, bob);
+ }).catch(e => e.message);
+
+ expect(webhookBody1).toBe('timeout');
+
+ const abuseReportId = (await api('admin/abuse-user-reports', {}, admin)).body[0].id;
+
+ // 解決
+ const webhookBody2 = await captureWebhook(async () => {
+ await resolveAbuseReport({
+ reportId: abuseReportId,
+ forward: false,
+ }, admin);
+ }).catch(e => e.message);
+
+ expect(webhookBody2).toBe('timeout');
+ });
+
+ test('通報をå—ã‘㟠-> WebhookãŒç„¡åйã®å ´åˆã¯é€å‡ºã•れãªã„', async () => {
+ const webhook = await createSystemWebhook({
+ on: ['abuseReport', 'abuseReportResolved'],
+ isActive: false,
+ });
+ await createAbuseReportNotificationRecipient({ systemWebhookId: webhook.id });
+
+ // 通報(bob -> alice)
+ const abuse = {
+ userId: alice.id,
+ comment: randomString(),
+ };
+ const webhookBody1 = await captureWebhook(async () => {
+ await createAbuseReport(abuse, bob);
+ }).catch(e => e.message);
+
+ expect(webhookBody1).toBe('timeout');
+
+ const abuseReportId = (await api('admin/abuse-user-reports', {}, admin)).body[0].id;
+
+ // 解決
+ const webhookBody2 = await captureWebhook(async () => {
+ await resolveAbuseReport({
+ reportId: abuseReportId,
+ forward: false,
+ }, admin);
+ }).catch(e => e.message);
+
+ expect(webhookBody2).toBe('timeout');
+ });
+
+ test('通報をå—ã‘㟠-> 通知設定ãŒç„¡åйã®å ´åˆã¯é€å‡ºã•れãªã„', async () => {
+ const webhook = await createSystemWebhook({
+ on: ['abuseReport', 'abuseReportResolved'],
+ isActive: true,
+ });
+ await createAbuseReportNotificationRecipient({ systemWebhookId: webhook.id, isActive: false });
+
+ // 通報(bob -> alice)
+ const abuse = {
+ userId: alice.id,
+ comment: randomString(),
+ };
+ const webhookBody1 = await captureWebhook(async () => {
+ await createAbuseReport(abuse, bob);
+ }).catch(e => e.message);
+
+ expect(webhookBody1).toBe('timeout');
+
+ const abuseReportId = (await api('admin/abuse-user-reports', {}, admin)).body[0].id;
+
+ // 解決
+ const webhookBody2 = await captureWebhook(async () => {
+ await resolveAbuseReport({
+ reportId: abuseReportId,
+ forward: false,
+ }, admin);
+ }).catch(e => e.message);
+
+ expect(webhookBody2).toBe('timeout');
+ });
+ });
+});
diff --git a/packages/backend/test/e2e/synalio/user-create.ts b/packages/backend/test/e2e/synalio/user-create.ts
new file mode 100644
index 0000000000..cb0f68dfea
--- /dev/null
+++ b/packages/backend/test/e2e/synalio/user-create.ts
@@ -0,0 +1,130 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { setTimeout } from 'node:timers/promises';
+import { entities } from 'misskey-js';
+import { beforeEach, describe, test } from '@jest/globals';
+import {
+ api,
+ captureWebhook,
+ randomString,
+ role,
+ signup,
+ startJobQueue,
+ UserToken,
+ WEBHOOK_HOST,
+} from '../../utils.js';
+import type { INestApplicationContext } from '@nestjs/common';
+
+describe('[シナリオ] ユーザ作æˆ', () => {
+ let queue: INestApplicationContext;
+ let admin: entities.SignupResponse;
+
+ async function createSystemWebhook(args?: Partial<entities.AdminSystemWebhookCreateRequest>, credential?: UserToken): Promise<entities.AdminSystemWebhookCreateResponse> {
+ const res = await api(
+ 'admin/system-webhook/create',
+ {
+ isActive: true,
+ name: randomString(),
+ on: ['userCreated'],
+ url: WEBHOOK_HOST,
+ secret: randomString(),
+ ...args,
+ },
+ credential ?? admin,
+ );
+ return res.body;
+ }
+
+ // -------------------------------------------------------------------------------------------
+
+ beforeAll(async () => {
+ queue = await startJobQueue();
+ admin = await signup({ username: 'admin' });
+
+ await role(admin, { isAdministrator: true });
+ }, 1000 * 60 * 2);
+
+ afterAll(async () => {
+ await queue.close();
+ });
+
+ // -------------------------------------------------------------------------------------------
+
+ describe('SystemWebhook', () => {
+ beforeEach(async () => {
+ const webhooks = await api('admin/system-webhook/list', {}, admin);
+ for (const webhook of webhooks.body) {
+ await api('admin/system-webhook/delete', { id: webhook.id }, admin);
+ }
+ });
+
+ test('ユーザãŒä½œæˆã•れ㟠-> userCreatedãŒé€å‡ºã•れる', async () => {
+ const webhook = await createSystemWebhook({
+ on: ['userCreated'],
+ isActive: true,
+ });
+
+ let alice: any = null;
+ const webhookBody = await captureWebhook(async () => {
+ alice = await signup({ username: 'alice' });
+ });
+
+ // webhookã®é€å‡ºå¾Œã«ã„ã‚ã„ã‚ã‚„ã£ã¦ã‚‹ã®ã§ã¡ã‚‡ã£ã¨å¾…ã¤å¿…è¦ãŒã‚ã‚‹
+ await setTimeout(2000);
+
+ console.log(alice);
+ console.log(JSON.stringify(webhookBody, null, 2));
+
+ expect(webhookBody.hookId).toBe(webhook.id);
+ expect(webhookBody.type).toBe('userCreated');
+
+ const body = webhookBody.body as entities.UserLite;
+ expect(alice.id).toBe(body.id);
+ expect(alice.name).toBe(body.name);
+ expect(alice.username).toBe(body.username);
+ expect(alice.host).toBe(body.host);
+ expect(alice.avatarUrl).toBe(body.avatarUrl);
+ expect(alice.avatarBlurhash).toBe(body.avatarBlurhash);
+ expect(alice.avatarDecorations).toEqual(body.avatarDecorations);
+ expect(alice.isBot).toBe(body.isBot);
+ expect(alice.isCat).toBe(body.isCat);
+ expect(alice.instance).toEqual(body.instance);
+ expect(alice.emojis).toEqual(body.emojis);
+ expect(alice.onlineStatus).toBe(body.onlineStatus);
+ expect(alice.badgeRoles).toEqual(body.badgeRoles);
+ });
+
+ test('ãƒ¦ãƒ¼ã‚¶ä½œæˆ -> userCreatedãŒæœªè¨±å¯ã®å ´åˆã¯é€å‡ºã•れãªã„', async () => {
+ await createSystemWebhook({
+ on: [],
+ isActive: true,
+ });
+
+ let alice: any = null;
+ const webhookBody = await captureWebhook(async () => {
+ alice = await signup({ username: 'alice' });
+ }).catch(e => e.message);
+
+ expect(webhookBody).toBe('timeout');
+ expect(alice.id).not.toBeNull();
+ });
+
+ test('ãƒ¦ãƒ¼ã‚¶ä½œæˆ -> WebhookãŒç„¡åйã®å ´åˆã¯é€å‡ºã•れãªã„', async () => {
+ await createSystemWebhook({
+ on: ['userCreated'],
+ isActive: false,
+ });
+
+ let alice: any = null;
+ const webhookBody = await captureWebhook(async () => {
+ alice = await signup({ username: 'alice' });
+ }).catch(e => e.message);
+
+ expect(webhookBody).toBe('timeout');
+ expect(alice.id).not.toBeNull();
+ });
+ });
+});
diff --git a/packages/backend/test/e2e/thread-mute.ts b/packages/backend/test/e2e/thread-mute.ts
index 53bb6eb765..1ac99df884 100644
--- a/packages/backend/test/e2e/thread-mute.ts
+++ b/packages/backend/test/e2e/thread-mute.ts
@@ -33,9 +33,9 @@ describe('Note thread mute', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
- assert.strictEqual(res.body.some((note: any) => note.id === carolReply.id), false);
- assert.strictEqual(res.body.some((note: any) => note.id === carolReplyWithoutMention.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === carolReply.id), false);
+ assert.strictEqual(res.body.some(note => note.id === carolReplyWithoutMention.id), false);
});
test('ミュートã—ã¦ã„るスレッドã‹ã‚‰ãƒ¡ãƒ³ã‚·ãƒ§ãƒ³ã•れã¦ã‚‚ã€hasUnreadMentions ㌠true ã«ãªã‚‰ãªã„', async () => {
@@ -93,8 +93,8 @@ describe('Note thread mute', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
- assert.strictEqual(res.body.some((notification: any) => notification.note.id === carolReply.id), false);
- assert.strictEqual(res.body.some((notification: any) => notification.note.id === carolReplyWithoutMention.id), false);
+ assert.strictEqual(res.body.some(notification => 'note' in notification && notification.note.id === carolReply.id), false);
+ assert.strictEqual(res.body.some(notification => 'note' in notification && notification.note.id === carolReplyWithoutMention.id), false);
// NOTE: bobã®æŠ•ç¨¿ã¯ã‚¹ãƒ¬ãƒƒãƒ‰ãƒŸãƒ¥ãƒ¼ãƒˆå‰ã«è¡Œã‚れãŸãŸã‚通知ã«å«ã¾ã‚Œã¦ã„ã¦ã‚‚よã„
});
diff --git a/packages/backend/test/e2e/timelines.ts b/packages/backend/test/e2e/timelines.ts
index 5487292afc..d12be2a9ac 100644
--- a/packages/backend/test/e2e/timelines.ts
+++ b/packages/backend/test/e2e/timelines.ts
@@ -7,17 +7,26 @@
// pnpm jest -- e2e/timelines.ts
import * as assert from 'assert';
-import { api, post, randomString, sendEnvUpdateRequest, signup, sleep, uploadUrl } from '../utils.js';
+import { setTimeout } from 'node:timers/promises';
+import { Redis } from 'ioredis';
+import { api, post, randomString, sendEnvUpdateRequest, signup, uploadUrl } from '../utils.js';
+import { loadConfig } from '@/config.js';
function genHost() {
return randomString() + '.example.com';
}
function waitForPushToTl() {
- return sleep(500);
+ return setTimeout(500);
}
+let redisForTimelines: Redis;
+
describe('Timelines', () => {
+ beforeAll(() => {
+ redisForTimelines = new Redis(loadConfig().redisForTimelines);
+ });
+
describe('Home TL', () => {
test.concurrent('自分㮠visibility: followers ãªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œã‚‹', async () => {
const [alice] = await Promise.all([signup()]);
@@ -28,15 +37,15 @@ describe('Timelines', () => {
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
- assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'hi');
+ assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true);
+ assert.strictEqual(res.body.find(note => note.id === aliceNote.id)?.text, 'hi');
});
test.concurrent('フォローã—ã¦ã„るユーザーã®ãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œã‚‹', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
await api('following/create', { userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const bobNote = await post(bob, { text: 'hi' });
const carolNote = await post(carol, { text: 'hi' });
@@ -44,15 +53,15 @@ describe('Timelines', () => {
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), false);
});
test.concurrent('フォローã—ã¦ã„るユーザー㮠visibility: followers ãªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œã‚‹', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
await api('following/create', { userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const bobNote = await post(bob, { text: 'hi', visibility: 'followers' });
const carolNote = await post(carol, { text: 'hi' });
@@ -60,16 +69,16 @@ describe('Timelines', () => {
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
- assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi');
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.find(note => note.id === bobNote.id)?.text, 'hi');
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), false);
});
test.concurrent('withReplies: false ã§ãƒ•ォローã—ã¦ã„るユーザーã®ä»–人ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œãªã„', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
await api('following/create', { userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
@@ -77,8 +86,8 @@ describe('Timelines', () => {
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), false);
});
test.concurrent('withReplies: true ã§ãƒ•ォローã—ã¦ã„るユーザーã®ä»–人ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -86,7 +95,7 @@ describe('Timelines', () => {
await api('following/create', { userId: bob.id }, alice);
await api('following/update', { userId: bob.id, withReplies: true }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
@@ -94,8 +103,8 @@ describe('Timelines', () => {
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), false);
});
test.concurrent('withReplies: true ã§ãƒ•ォローã—ã¦ã„るユーザーã®ä»–人ã¸ã®DM返信ãŒå«ã¾ã‚Œãªã„', async () => {
@@ -103,7 +112,7 @@ describe('Timelines', () => {
await api('following/create', { userId: bob.id }, alice);
await api('following/update', { userId: bob.id, withReplies: true }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id, visibility: 'specified', visibleUserIds: [carolNote.id] });
@@ -111,16 +120,17 @@ describe('Timelines', () => {
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), false);
});
test.concurrent('withReplies: true ã§ãƒ•ォローã—ã¦ã„るユーザーã®ä»–人㮠visibility: followers ãªæŠ•ç¨¿ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œãªã„', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
+ await api('following/create', { userId: carol.id }, bob);
await api('following/create', { userId: bob.id }, alice);
await api('following/update', { userId: bob.id, withReplies: true }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const carolNote = await post(carol, { text: 'hi', visibility: 'followers' });
const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
@@ -128,8 +138,8 @@ describe('Timelines', () => {
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), false);
});
test.concurrent('withReplies: true ã§ãƒ•ォローã—ã¦ã„るユーザーã®è¡Œã£ãŸåˆ¥ã®ãƒ•ォローã—ã¦ã„るユーザー㮠visibility: followers ãªæŠ•ç¨¿ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -139,7 +149,7 @@ describe('Timelines', () => {
await api('following/create', { userId: carol.id }, alice);
await api('following/create', { userId: carol.id }, bob);
await api('following/update', { userId: bob.id, withReplies: true }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const carolNote = await post(carol, { text: 'hi', visibility: 'followers' });
const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
@@ -147,9 +157,27 @@ describe('Timelines', () => {
const res = await api('notes/timeline', { limit: 100 }, alice);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), true);
+ assert.strictEqual(res.body.find(note => note.id === carolNote.id)?.text, 'hi');
+ });
+
+ test.concurrent('withReplies: true ã§ãƒ•ォローã—ã¦ã„るユーザーã®è‡ªåˆ†ã® visibility: followers ãªæŠ•ç¨¿ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œã‚‹', async () => {
+ const [alice, bob] = await Promise.all([signup(), signup()]);
+
+ await api('following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: alice.id }, bob);
+ await api('following/update', { userId: bob.id, withReplies: true }, alice);
+ await setTimeout(1000);
+ const aliceNote = await post(alice, { text: 'hi', visibility: 'followers' });
+ const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id });
+
+ await waitForPushToTl();
+
+ const res = await api('notes/timeline', { limit: 100 }, alice);
+
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true);
- assert.strictEqual(res.body.find((note: any) => note.id === carolNote.id).text, 'hi');
+ assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
});
test.concurrent('withReplies: true ã§ãƒ•ォローã—ã¦ã„るユーザーã®è¡Œã£ãŸåˆ¥ã®ãƒ•ォローã—ã¦ã„ã‚‹ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®æŠ•ç¨¿ã¸ã® visibility: specified ãªè¿”ä¿¡ãŒå«ã¾ã‚Œãªã„', async () => {
@@ -158,7 +186,7 @@ describe('Timelines', () => {
await api('following/create', { userId: bob.id }, alice);
await api('following/create', { userId: carol.id }, alice);
await api('following/update', { userId: bob.id, withReplies: true }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id, visibility: 'specified', visibleUserIds: [carolNote.id] });
@@ -166,15 +194,15 @@ describe('Timelines', () => {
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), true);
});
test.concurrent('withReplies: false ã§ãƒ•ォローã—ã¦ã„るユーザーã®ãã®ãƒ¦ãƒ¼ã‚¶ãƒ¼è‡ªèº«ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œã‚‹', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
await api('following/create', { userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const bobNote1 = await post(bob, { text: 'hi' });
const bobNote2 = await post(bob, { text: 'hi', replyId: bobNote1.id });
@@ -182,15 +210,15 @@ describe('Timelines', () => {
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote1.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote2.id), true);
});
test.concurrent('withReplies: false ã§ãƒ•ォローã—ã¦ã„るユーザーã‹ã‚‰ã®è‡ªåˆ†ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œã‚‹', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
await api('following/create', { userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const aliceNote = await post(alice, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id });
@@ -198,8 +226,8 @@ describe('Timelines', () => {
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
});
test.concurrent('自分ã®ä»–人ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -212,15 +240,15 @@ describe('Timelines', () => {
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
- assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true);
});
test.concurrent('フォローã—ã¦ã„るユーザーã®ä»–äººã®æŠ•ç¨¿ã®ãƒªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œã‚‹', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
await api('following/create', { userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { renoteId: carolNote.id });
@@ -228,15 +256,15 @@ describe('Timelines', () => {
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), false);
});
test.concurrent('[withRenotes: false] フォローã—ã¦ã„るユーザーã®ä»–äººã®æŠ•ç¨¿ã®ãƒªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œãªã„', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
await api('following/create', { userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { renoteId: carolNote.id });
@@ -246,15 +274,15 @@ describe('Timelines', () => {
withRenotes: false,
}, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), false);
});
test.concurrent('[withRenotes: false] フォローã—ã¦ã„るユーザーã®ä»–äººã®æŠ•ç¨¿ã®å¼•用ãŒå«ã¾ã‚Œã‚‹', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
await api('following/create', { userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id });
@@ -264,22 +292,22 @@ describe('Timelines', () => {
withRenotes: false,
}, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), false);
});
test.concurrent('フォローã—ã¦ã„るユーザーã®ä»–人ã¸ã® visibility: specified ãªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œãªã„', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
await api('following/create', { userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [carol.id] });
await waitForPushToTl();
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
});
test.concurrent('フォローã—ã¦ã„るユーザーãŒè¡Œã£ãŸãƒŸãƒ¥ãƒ¼ãƒˆã—ã¦ã„るユーザーã®ãƒªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œãªã„', async () => {
@@ -287,7 +315,7 @@ describe('Timelines', () => {
await api('following/create', { userId: bob.id }, alice);
await api('mute/create', { userId: carol.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id });
@@ -295,8 +323,8 @@ describe('Timelines', () => {
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), false);
});
test.concurrent('withReplies: true ã§ãƒ•ォローã—ã¦ã„るユーザーãŒè¡Œã£ãŸãƒŸãƒ¥ãƒ¼ãƒˆã—ã¦ã„ã‚‹ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®æŠ•ç¨¿ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œãªã„', async () => {
@@ -305,7 +333,7 @@ describe('Timelines', () => {
await api('following/create', { userId: bob.id }, alice);
await api('following/update', { userId: bob.id, withReplies: true }, alice);
await api('mute/create', { userId: carol.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
@@ -313,8 +341,8 @@ describe('Timelines', () => {
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), false);
});
test.concurrent('フォローã—ã¦ã„るリモートユーザーã®ãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -329,7 +357,7 @@ describe('Timelines', () => {
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
});
test.concurrent('フォローã—ã¦ã„るリモートユーザー㮠visibility: home ãªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -344,14 +372,14 @@ describe('Timelines', () => {
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
});
test.concurrent('[withFiles: true] フォローã—ã¦ã„るユーザーã®ãƒ•ァイル付ãノートã®ã¿å«ã¾ã‚Œã‚‹', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
await api('following/create', { userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const [bobFile, carolFile] = await Promise.all([
uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png'),
uploadUrl(carol, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png'),
@@ -365,10 +393,10 @@ describe('Timelines', () => {
const res = await api('notes/timeline', { limit: 100, withFiles: true }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote1.id), false);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote2.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote1.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote2.id), true);
+ assert.strictEqual(res.body.some(note => note.id === carolNote1.id), false);
+ assert.strictEqual(res.body.some(note => note.id === carolNote2.id), false);
}, 1000 * 10);
test.concurrent('フォローã—ã¦ã„るユーザーã®ãƒãƒ£ãƒ³ãƒãƒ«æŠ•稿ãŒå«ã¾ã‚Œãªã„', async () => {
@@ -376,14 +404,14 @@ describe('Timelines', () => {
const channel = await api('channels/create', { name: 'channel' }, bob).then(x => x.body);
await api('following/create', { userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const bobNote = await post(bob, { text: 'hi', channelId: channel.id });
await waitForPushToTl();
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
});
test.concurrent('自分㮠visibility: specified ãªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -395,23 +423,23 @@ describe('Timelines', () => {
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
- assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'hi');
+ assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true);
+ assert.strictEqual(res.body.find(note => note.id === aliceNote.id)?.text, 'hi');
});
test.concurrent('フォローã—ã¦ã„るユーザーã®è‡ªèº«ã‚’ visibleUserIds ã«æŒ‡å®šã—㟠visibility: specified ãªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œã‚‹', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
await api('following/create', { userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [alice.id] });
await waitForPushToTl();
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
- assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi');
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.find(note => note.id === bobNote.id)?.text, 'hi');
});
test.concurrent('フォローã—ã¦ã„ãªã„ユーザーã®è‡ªèº«ã‚’ visibleUserIds ã«æŒ‡å®šã—㟠visibility: specified ãªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œãªã„', async () => {
@@ -423,21 +451,21 @@ describe('Timelines', () => {
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
});
test.concurrent('フォローã—ã¦ã„るユーザーã®è‡ªèº«ã‚’ visibleUserIds ã«æŒ‡å®šã—ã¦ã„ãªã„ visibility: specified ãªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œãªã„', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
await api('following/create', { userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [carol.id] });
await waitForPushToTl();
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
});
test.concurrent('フォローã—ã¦ã„ãªã„ユーザーã‹ã‚‰ã® visibility: specified ãªãƒŽãƒ¼ãƒˆã«è¿”ä¿¡ã—ãŸã¨ãã®è‡ªèº«ã®ãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -450,8 +478,8 @@ describe('Timelines', () => {
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
- assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'ok');
+ assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true);
+ assert.strictEqual(res.body.find(note => note.id === aliceNote.id)?.text, 'ok');
});
/* TODO
@@ -465,8 +493,8 @@ describe('Timelines', () => {
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
- assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'ok');
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.find(note => note.id === bobNote.id).text, 'ok');
});
*/
@@ -481,7 +509,45 @@ describe('Timelines', () => {
const res = await api('notes/timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
+ });
+
+ test.concurrent('FTT: ローカルユーザー㮠HTL ã«ã¯ãƒ—ッシュã•れる', async () => {
+ const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
+
+ await api('following/create', {
+ userId: alice.id,
+ }, bob);
+
+ const aliceNote = await post(alice, { text: 'I\'m Alice.' });
+ const bobNote = await post(bob, { text: 'I\'m Bob.' });
+ const carolNote = await post(carol, { text: 'I\'m Carol.' });
+
+ await waitForPushToTl();
+
+ // NOTE: notes/timeline ã ã¨ DB ã¸ã®ãƒ•ォールãƒãƒƒã‚¯ãŒåйãã®ã§ Redis を直接見ã¦ç¢ºã‹ã‚ã‚‹
+ assert.strictEqual(await redisForTimelines.exists(`list:homeTimeline:${bob.id}`), 1);
+
+ const bobHTL = await redisForTimelines.lrange(`list:homeTimeline:${bob.id}`, 0, -1);
+ assert.strictEqual(bobHTL.includes(aliceNote.id), true);
+ assert.strictEqual(bobHTL.includes(bobNote.id), true);
+ assert.strictEqual(bobHTL.includes(carolNote.id), false);
+ });
+
+ test.concurrent('FTT: リモートユーザー㮠HTL ã«ã¯ãƒ—ッシュã•れãªã„', async () => {
+ const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]);
+
+ await api('following/create', {
+ userId: alice.id,
+ }, bob);
+
+ await post(alice, { text: 'I\'m Alice.' });
+ await post(bob, { text: 'I\'m Bob.' });
+
+ await waitForPushToTl();
+
+ // NOTE: notes/timeline ã ã¨ DB ã¸ã®ãƒ•ォールãƒãƒƒã‚¯ãŒåйãã®ã§ Redis を直接見ã¦ç¢ºã‹ã‚ã‚‹
+ assert.strictEqual(await redisForTimelines.exists(`list:homeTimeline:${bob.id}`), 0);
});
});
@@ -496,8 +562,8 @@ describe('Timelines', () => {
const res = await api('notes/local-timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), false);
});
test.concurrent('他人ã®ä»–人ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œãªã„', async () => {
@@ -510,8 +576,8 @@ describe('Timelines', () => {
const res = await api('notes/local-timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), true);
});
test.concurrent('他人ã®ãã®äººè‡ªèº«ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -524,8 +590,8 @@ describe('Timelines', () => {
const res = await api('notes/local-timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote1.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote2.id), true);
});
test.concurrent('ãƒãƒ£ãƒ³ãƒãƒ«æŠ•稿ãŒå«ã¾ã‚Œãªã„', async () => {
@@ -538,7 +604,7 @@ describe('Timelines', () => {
const res = await api('notes/local-timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
});
test.concurrent('リモートユーザーã®ãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œãªã„', async () => {
@@ -550,7 +616,7 @@ describe('Timelines', () => {
const res = await api('notes/local-timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
});
// å«ã¾ã‚Œã¦ã‚‚良ã„ã¨æ€ã†ã‘ã©å®Ÿè£…ãŒé¢å€’ãªã®ã§å«ã¾ã‚Œãªã„
@@ -558,7 +624,7 @@ describe('Timelines', () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
await api('following/create', { userId: carol.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const carolNote = await post(carol, { text: 'hi', visibility: 'home' });
const bobNote = await post(bob, { text: 'hi' });
@@ -566,15 +632,15 @@ describe('Timelines', () => {
const res = await api('notes/local-timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), false);
});
test.concurrent('ミュートã—ã¦ã„るユーザーã®ãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œãªã„', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
await api('mute/create', { userId: carol.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi' });
@@ -582,8 +648,8 @@ describe('Timelines', () => {
const res = await api('notes/local-timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), false);
});
test.concurrent('フォローã—ã¦ã„るユーザーãŒè¡Œã£ãŸãƒŸãƒ¥ãƒ¼ãƒˆã—ã¦ã„るユーザーã®ãƒªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œãªã„', async () => {
@@ -591,7 +657,7 @@ describe('Timelines', () => {
await api('following/create', { userId: bob.id }, alice);
await api('mute/create', { userId: carol.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id });
@@ -599,8 +665,8 @@ describe('Timelines', () => {
const res = await api('notes/local-timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), false);
});
test.concurrent('withReplies: true ã§ãƒ•ォローã—ã¦ã„るユーザーãŒè¡Œã£ãŸãƒŸãƒ¥ãƒ¼ãƒˆã—ã¦ã„ã‚‹ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®æŠ•ç¨¿ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œãªã„', async () => {
@@ -609,7 +675,7 @@ describe('Timelines', () => {
await api('following/create', { userId: bob.id }, alice);
await api('following/update', { userId: bob.id, withReplies: true }, alice);
await api('mute/create', { userId: carol.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
@@ -617,15 +683,15 @@ describe('Timelines', () => {
const res = await api('notes/local-timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), false);
});
test.concurrent('withReplies: false ã§ãƒ•ォローã—ã¦ã„るユーザーã‹ã‚‰ã®è‡ªåˆ†ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œã‚‹', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
await api('following/create', { userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const aliceNote = await post(alice, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id });
@@ -633,8 +699,23 @@ describe('Timelines', () => {
const res = await api('notes/local-timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
+ });
+
+ test.concurrent('withReplies: false ã§ãƒ•ォローã—ã¦ã„ãªã„ユーザーã‹ã‚‰ã®è‡ªåˆ†ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œã‚‹', async () => {
+ const [alice, bob] = await Promise.all([signup(), signup()]);
+
+ await setTimeout(1000);
+ const aliceNote = await post(alice, { text: 'hi' });
+ const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id });
+
+ await waitForPushToTl();
+
+ const res = await api('notes/local-timeline', { limit: 100 }, alice);
+
+ assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
});
test.concurrent('[withReplies: true] 他人ã®ä»–人ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -647,7 +728,7 @@ describe('Timelines', () => {
const res = await api('notes/local-timeline', { limit: 100, withReplies: true }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
});
test.concurrent('[withFiles: true] ファイル付ãノートã®ã¿å«ã¾ã‚Œã‚‹', async () => {
@@ -661,8 +742,8 @@ describe('Timelines', () => {
const res = await api('notes/local-timeline', { limit: 100, withFiles: true }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote1.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote2.id), true);
}, 1000 * 10);
});
@@ -676,7 +757,7 @@ describe('Timelines', () => {
const res = await api('notes/hybrid-timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
});
test.concurrent('ローカルユーザー㮠visibility: home ãªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œãªã„', async () => {
@@ -688,28 +769,28 @@ describe('Timelines', () => {
const res = await api('notes/hybrid-timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
});
test.concurrent('フォローã—ã¦ã„るローカルユーザー㮠visibility: home ãªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œã‚‹', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
await api('following/create', { userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const bobNote = await post(bob, { text: 'hi', visibility: 'home' });
await waitForPushToTl();
const res = await api('notes/hybrid-timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
});
test.concurrent('withReplies: false ã§ãƒ•ォローã—ã¦ã„るユーザーã‹ã‚‰ã®è‡ªåˆ†ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œã‚‹', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
await api('following/create', { userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const aliceNote = await post(alice, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id });
@@ -717,8 +798,64 @@ describe('Timelines', () => {
const res = await api('notes/hybrid-timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
+ });
+
+ test.concurrent('withReplies: true ã§ãƒ•ォローã—ã¦ã„るユーザーã®ä»–人㮠visibility: followers ãªæŠ•ç¨¿ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œãªã„', async () => {
+ const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
+
+ await api('following/create', { userId: carol.id }, bob);
+ await api('following/create', { userId: bob.id }, alice);
+ await api('following/update', { userId: bob.id, withReplies: true }, alice);
+ await setTimeout(1000);
+ const carolNote = await post(carol, { text: 'hi', visibility: 'followers' });
+ const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
+
+ await waitForPushToTl();
+
+ const res = await api('notes/hybrid-timeline', { limit: 100 }, alice);
+
+ assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
+ });
+
+ test.concurrent('withReplies: true ã§ãƒ•ォローã—ã¦ã„るユーザーã®è¡Œã£ãŸåˆ¥ã®ãƒ•ォローã—ã¦ã„るユーザー㮠visibility: followers ãªæŠ•ç¨¿ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œã‚‹', async () => {
+ const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
+
+ await api('following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: carol.id }, alice);
+ await api('following/create', { userId: carol.id }, bob);
+ await api('following/update', { userId: bob.id, withReplies: true }, alice);
+ await setTimeout(1000);
+ const carolNote = await post(carol, { text: 'hi', visibility: 'followers' });
+ const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
+
+ await waitForPushToTl();
+
+ const res = await api('notes/hybrid-timeline', { limit: 100 }, alice);
+
+ assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true);
+ assert.strictEqual(res.body.find((note: any) => note.id === carolNote.id)?.text, 'hi');
+ });
+
+ test.concurrent('withReplies: true ã§ãƒ•ォローã—ã¦ã„るユーザーã®è‡ªåˆ†ã® visibility: followers ãªæŠ•ç¨¿ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œã‚‹', async () => {
+ const [alice, bob] = await Promise.all([signup(), signup()]);
+
+ await api('following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: alice.id }, bob);
+ await api('following/update', { userId: bob.id, withReplies: true }, alice);
+ await setTimeout(1000);
+ const aliceNote = await post(alice, { text: 'hi', visibility: 'followers' });
+ const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id });
+
+ await waitForPushToTl();
+
+ const res = await api('notes/hybrid-timeline', { limit: 100 }, alice);
+
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
});
test.concurrent('他人ã®ä»–人ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œãªã„', async () => {
@@ -731,8 +868,8 @@ describe('Timelines', () => {
const res = await api('notes/hybrid-timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === carolNote.id), true);
});
test.concurrent('リモートユーザーã®ãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œãªã„', async () => {
@@ -744,7 +881,7 @@ describe('Timelines', () => {
const res = await api('notes/local-timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
});
test.concurrent('フォローã—ã¦ã„るリモートユーザーã®ãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -759,7 +896,7 @@ describe('Timelines', () => {
const res = await api('notes/hybrid-timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
});
test.concurrent('フォローã—ã¦ã„るリモートユーザー㮠visibility: home ãªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -774,7 +911,22 @@ describe('Timelines', () => {
const res = await api('notes/hybrid-timeline', { limit: 100 }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
+ });
+
+ test.concurrent('withReplies: false ã§ãƒ•ォローã—ã¦ã„ãªã„ユーザーã‹ã‚‰ã®è‡ªåˆ†ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œã‚‹', async () => {
+ const [alice, bob] = await Promise.all([signup(), signup()]);
+
+ await setTimeout(1000);
+ const aliceNote = await post(alice, { text: 'hi' });
+ const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id });
+
+ await waitForPushToTl();
+
+ const res = await api('notes/local-timeline', { limit: 100 }, alice);
+
+ assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
});
test.concurrent('[withReplies: true] 他人ã®ä»–人ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -787,7 +939,7 @@ describe('Timelines', () => {
const res = await api('notes/hybrid-timeline', { limit: 100, withReplies: true }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
});
test.concurrent('[withFiles: true] ファイル付ãノートã®ã¿å«ã¾ã‚Œã‚‹', async () => {
@@ -801,8 +953,8 @@ describe('Timelines', () => {
const res = await api('notes/hybrid-timeline', { limit: 100, withFiles: true }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote1.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote2.id), true);
}, 1000 * 10);
});
@@ -812,14 +964,14 @@ describe('Timelines', () => {
const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const bobNote = await post(bob, { text: 'hi' });
await waitForPushToTl();
const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
});
test.concurrent('リスインã—ã¦ã„るフォローã—ã¦ã„ãªã„ユーザー㮠visibility: home ãªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -827,14 +979,14 @@ describe('Timelines', () => {
const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const bobNote = await post(bob, { text: 'hi', visibility: 'home' });
await waitForPushToTl();
const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
});
test.concurrent('リスインã—ã¦ã„るフォローã—ã¦ã„ãªã„ユーザー㮠visibility: followers ãªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œãªã„', async () => {
@@ -842,14 +994,14 @@ describe('Timelines', () => {
const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const bobNote = await post(bob, { text: 'hi', visibility: 'followers' });
await waitForPushToTl();
const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
});
test.concurrent('リスインã—ã¦ã„るフォローã—ã¦ã„ãªã„ユーザーã®ä»–人ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œãªã„', async () => {
@@ -857,7 +1009,7 @@ describe('Timelines', () => {
const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
@@ -865,7 +1017,7 @@ describe('Timelines', () => {
const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
});
test.concurrent('リスインã—ã¦ã„るフォローã—ã¦ã„ãªã„ユーザーã®ãƒ¦ãƒ¼ã‚¶ãƒ¼è‡ªèº«ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -873,7 +1025,7 @@ describe('Timelines', () => {
const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const bobNote1 = await post(bob, { text: 'hi' });
const bobNote2 = await post(bob, { text: 'hi', replyId: bobNote1.id });
@@ -881,8 +1033,8 @@ describe('Timelines', () => {
const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote1.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote2.id), true);
});
test.concurrent('withReplies: false ã§ãƒªã‚¹ã‚¤ãƒ³ã—ã¦ã„るフォローã—ã¦ã„ãªã„ユーザーã‹ã‚‰ã®è‡ªåˆ†ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -891,7 +1043,7 @@ describe('Timelines', () => {
const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
await api('users/lists/update-membership', { listId: list.id, userId: bob.id, withReplies: false }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const aliceNote = await post(alice, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id });
@@ -899,7 +1051,7 @@ describe('Timelines', () => {
const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
});
test.concurrent('withReplies: false ã§ãƒªã‚¹ã‚¤ãƒ³ã—ã¦ã„るフォローã—ã¦ã„ãªã„ユーザーã®ä»–人ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œãªã„', async () => {
@@ -908,7 +1060,7 @@ describe('Timelines', () => {
const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
await api('users/lists/update-membership', { listId: list.id, userId: bob.id, withReplies: false }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
@@ -916,7 +1068,7 @@ describe('Timelines', () => {
const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
});
test.concurrent('withReplies: true ã§ãƒªã‚¹ã‚¤ãƒ³ã—ã¦ã„るフォローã—ã¦ã„ãªã„ユーザーã®ä»–人ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -925,7 +1077,7 @@ describe('Timelines', () => {
const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
await api('users/lists/update-membership', { listId: list.id, userId: bob.id, withReplies: true }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
@@ -933,7 +1085,7 @@ describe('Timelines', () => {
const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
});
test.concurrent('リスインã—ã¦ã„るフォローã—ã¦ã„るユーザー㮠visibility: home ãªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -942,14 +1094,14 @@ describe('Timelines', () => {
await api('following/create', { userId: bob.id }, alice);
const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const bobNote = await post(bob, { text: 'hi', visibility: 'home' });
await waitForPushToTl();
const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
});
test.concurrent('リスインã—ã¦ã„るフォローã—ã¦ã„るユーザー㮠visibility: followers ãªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -958,15 +1110,15 @@ describe('Timelines', () => {
await api('following/create', { userId: bob.id }, alice);
const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const bobNote = await post(bob, { text: 'hi', visibility: 'followers' });
await waitForPushToTl();
const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
- assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi');
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.find(note => note.id === bobNote.id)?.text, 'hi');
});
test.concurrent('リスインã—ã¦ã„る自分㮠visibility: followers ãªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -974,15 +1126,15 @@ describe('Timelines', () => {
const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
await api('users/lists/push', { listId: list.id, userId: alice.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const aliceNote = await post(alice, { text: 'hi', visibility: 'followers' });
await waitForPushToTl();
const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
- assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'hi');
+ assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true);
+ assert.strictEqual(res.body.find(note => note.id === aliceNote.id)?.text, 'hi');
});
test.concurrent('リスインã—ã¦ã„るユーザーã®ãƒãƒ£ãƒ³ãƒãƒ«ãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œãªã„', async () => {
@@ -991,14 +1143,14 @@ describe('Timelines', () => {
const channel = await api('channels/create', { name: 'channel' }, bob).then(x => x.body);
const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const bobNote = await post(bob, { text: 'hi', channelId: channel.id });
await waitForPushToTl();
const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
});
test.concurrent('[withFiles: true] リスインã—ã¦ã„るユーザーã®ãƒ•ァイル付ãノートã®ã¿å«ã¾ã‚Œã‚‹', async () => {
@@ -1014,8 +1166,8 @@ describe('Timelines', () => {
const res = await api('notes/user-list-timeline', { listId: list.id, withFiles: true }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote1.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote2.id), true);
}, 1000 * 10);
test.concurrent('リスインã—ã¦ã„るユーザーã®è‡ªèº«å®›ã¦ã® visibility: specified ãªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -1023,15 +1175,15 @@ describe('Timelines', () => {
const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [alice.id] });
await waitForPushToTl();
const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
- assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi');
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.find(note => note.id === bobNote.id)?.text, 'hi');
});
test.concurrent('リスインã—ã¦ã„るユーザーã®è‡ªèº«å®›ã¦ã§ã¯ãªã„ visibility: specified ãªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œãªã„', async () => {
@@ -1040,14 +1192,14 @@ describe('Timelines', () => {
const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
await api('users/lists/push', { listId: list.id, userId: carol.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [carol.id] });
await waitForPushToTl();
const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
});
});
@@ -1061,7 +1213,7 @@ describe('Timelines', () => {
const res = await api('users/notes', { userId: bob.id }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
});
test.concurrent('フォローã—ã¦ã„ãªã„ユーザー㮠visibility: followers ãªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œãªã„', async () => {
@@ -1073,22 +1225,22 @@ describe('Timelines', () => {
const res = await api('users/notes', { userId: bob.id }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
});
test.concurrent('フォローã—ã¦ã„るユーザー㮠visibility: followers ãªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œã‚‹', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
await api('following/create', { userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const bobNote = await post(bob, { text: 'hi', visibility: 'followers' });
await waitForPushToTl();
const res = await api('users/notes', { userId: bob.id }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
- assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi');
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.find(note => note.id === bobNote.id)?.text, 'hi');
});
test.concurrent('自身㮠visibility: followers ãªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -1100,8 +1252,8 @@ describe('Timelines', () => {
const res = await api('users/notes', { userId: alice.id }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
- assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'hi');
+ assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true);
+ assert.strictEqual(res.body.find(note => note.id === aliceNote.id)?.text, 'hi');
});
test.concurrent('ãƒãƒ£ãƒ³ãƒãƒ«æŠ•稿ãŒå«ã¾ã‚Œãªã„', async () => {
@@ -1114,7 +1266,7 @@ describe('Timelines', () => {
const res = await api('users/notes', { userId: bob.id }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
});
test.concurrent('[withReplies: false] 他人ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œãªã„', async () => {
@@ -1128,8 +1280,8 @@ describe('Timelines', () => {
const res = await api('users/notes', { userId: bob.id }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote1.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote2.id), false);
});
test.concurrent('[withReplies: true] 他人ã¸ã®è¿”ä¿¡ãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -1143,8 +1295,8 @@ describe('Timelines', () => {
const res = await api('users/notes', { userId: bob.id, withReplies: true }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote1.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote2.id), true);
});
test.concurrent('[withReplies: true] 他人ã¸ã® visibility: specified ãªè¿”ä¿¡ãŒå«ã¾ã‚Œãªã„', async () => {
@@ -1158,8 +1310,8 @@ describe('Timelines', () => {
const res = await api('users/notes', { userId: bob.id, withReplies: true }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote1.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote2.id), false);
});
test.concurrent('[withFiles: true] ファイル付ãノートã®ã¿å«ã¾ã‚Œã‚‹', async () => {
@@ -1173,8 +1325,8 @@ describe('Timelines', () => {
const res = await api('users/notes', { userId: bob.id, withFiles: true }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote1.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote2.id), true);
}, 1000 * 10);
test.concurrent('[withChannelNotes: true] ãƒãƒ£ãƒ³ãƒãƒ«æŠ•稿ãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -1187,7 +1339,7 @@ describe('Timelines', () => {
const res = await api('users/notes', { userId: bob.id, withChannelNotes: true }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
});
test.concurrent('[withChannelNotes: true] 他人ãŒå–å¾—ã—ãŸå ´åˆã‚»ãƒ³ã‚·ãƒ†ã‚£ãƒ–ãƒãƒ£ãƒ³ãƒãƒ«æŠ•稿ãŒå«ã¾ã‚Œãªã„', async () => {
@@ -1200,7 +1352,7 @@ describe('Timelines', () => {
const res = await api('users/notes', { userId: bob.id, withChannelNotes: true }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
});
test.concurrent('[withChannelNotes: true] 自分ãŒå–å¾—ã—ãŸå ´åˆã‚»ãƒ³ã‚·ãƒ†ã‚£ãƒ–ãƒãƒ£ãƒ³ãƒãƒ«æŠ•稿ãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -1213,14 +1365,14 @@ describe('Timelines', () => {
const res = await api('users/notes', { userId: bob.id, withChannelNotes: true }, bob);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), true);
});
test.concurrent('ミュートã—ã¦ã„るユーザーã«é–¢é€£ã™ã‚‹æŠ•稿ãŒå«ã¾ã‚Œãªã„', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
await api('mute/create', { userId: carol.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id });
@@ -1228,14 +1380,14 @@ describe('Timelines', () => {
const res = await api('users/notes', { userId: bob.id }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
});
test.concurrent('ミュートã—ã¦ã„ã¦ã‚‚ userId ã«æŒ‡å®šã—ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ã®æŠ•稿ãŒå«ã¾ã‚Œã‚‹', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
await api('mute/create', { userId: bob.id }, alice);
- await sleep(1000);
+ await setTimeout(1000);
const bobNote1 = await post(bob, { text: 'hi' });
const bobNote2 = await post(bob, { text: 'hi', replyId: bobNote1.id });
const bobNote3 = await post(bob, { text: 'hi', renoteId: bobNote1.id });
@@ -1244,9 +1396,9 @@ describe('Timelines', () => {
const res = await api('users/notes', { userId: bob.id }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote3.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote1.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote2.id), true);
+ assert.strictEqual(res.body.some(note => note.id === bobNote3.id), true);
});
test.concurrent('自身㮠visibility: specified ãªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œã‚‹', async () => {
@@ -1258,7 +1410,7 @@ describe('Timelines', () => {
const res = await api('users/notes', { userId: alice.id, withReplies: true }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
+ assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true);
});
test.concurrent('visibleUserIds ã«æŒ‡å®šã•れã¦ãªã„ visibility: specified ãªãƒŽãƒ¼ãƒˆãŒå«ã¾ã‚Œãªã„', async () => {
@@ -1270,7 +1422,34 @@ describe('Timelines', () => {
const res = await api('users/notes', { userId: bob.id, withReplies: true }, alice);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
+ assert.strictEqual(res.body.some(note => note.id === bobNote.id), false);
+ });
+
+ /** @see https://github.com/misskey-dev/misskey/issues/14000 */
+ test.concurrent('FTT: sinceId ã«ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã‚ˆã‚Šå¤ã„ノートを指定ã—ã¦ã‚‚ã€sinceId ã«ã‚ˆã‚‹çµžã‚Šè¾¼ã¿ãŒæ­£ã—ã動作ã™ã‚‹', async () => {
+ const alice = await signup();
+ const noteSince = await post(alice, { text: 'Note where id will be `sinceId`.' });
+ const note1 = await post(alice, { text: '1' });
+ const note2 = await post(alice, { text: '2' });
+ await redisForTimelines.del('list:userTimeline:' + alice.id);
+ const note3 = await post(alice, { text: '3' });
+
+ const res = await api('users/notes', { userId: alice.id, sinceId: noteSince.id });
+ assert.deepStrictEqual(res.body, [note1, note2, note3]);
+ });
+
+ test.concurrent('FTT: sinceId ã«ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã‚ˆã‚Šå¤ã„ノートを指定ã—ã¦ã‚‚ã€sinceId 㨠untilId ã«ã‚ˆã‚‹çµžã‚Šè¾¼ã¿ãŒæ­£ã—ã動作ã™ã‚‹', async () => {
+ const alice = await signup();
+ const noteSince = await post(alice, { text: 'Note where id will be `sinceId`.' });
+ const note1 = await post(alice, { text: '1' });
+ const note2 = await post(alice, { text: '2' });
+ await redisForTimelines.del('list:userTimeline:' + alice.id);
+ const note3 = await post(alice, { text: '3' });
+ const noteUntil = await post(alice, { text: 'Note where id will be `untilId`.' });
+ await post(alice, { text: '4' });
+
+ const res = await api('users/notes', { userId: alice.id, sinceId: noteSince.id, untilId: noteUntil.id });
+ assert.deepStrictEqual(res.body, [note3, note2, note1]);
});
});
diff --git a/packages/backend/test/e2e/user-notes.ts b/packages/backend/test/e2e/user-notes.ts
index 331e053935..cc07c5ae71 100644
--- a/packages/backend/test/e2e/user-notes.ts
+++ b/packages/backend/test/e2e/user-notes.ts
@@ -17,8 +17,8 @@ describe('users/notes', () => {
beforeAll(async () => {
alice = await signup({ username: 'alice' });
- const jpg = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg');
- const png = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.png');
+ const jpg = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/192.jpg');
+ const png = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/192.png');
jpgNote = await post(alice, {
fileIds: [jpg.id],
});
diff --git a/packages/backend/test/e2e/users.ts b/packages/backend/test/e2e/users.ts
index 3458e06384..61fd759932 100644
--- a/packages/backend/test/e2e/users.ts
+++ b/packages/backend/test/e2e/users.ts
@@ -231,7 +231,7 @@ describe('ユーザー', () => {
rolePublic = await role(root, { isPublic: true, name: 'Public Role' });
await api('admin/roles/assign', { userId: userRolePublic.id, roleId: rolePublic.id }, root);
userRoleBadge = await signup({ username: 'userRoleBadge' });
- roleBadge = await role(root, { asBadge: true, name: 'Badge Role' });
+ roleBadge = await role(root, { asBadge: true, name: 'Badge Role', isPublic: true });
await api('admin/roles/assign', { userId: userRoleBadge.id, roleId: roleBadge.id }, root);
userSilenced = await signup({ username: 'userSilenced' });
await post(userSilenced, { text: 'test' });
@@ -655,7 +655,16 @@ describe('ユーザー', () => {
iconUrl: roleBadge.iconUrl,
displayOrder: roleBadge.displayOrder,
}]);
- assert.deepStrictEqual(response.roles, []); // ãƒãƒƒãƒ‚ã ã‹ã‚‰ã¨ã„ã£ã¦rolesãŒå–れるã¨ã¯é™ã‚‰ãªã„
+ assert.deepStrictEqual(response.roles, [{
+ id: roleBadge.id,
+ name: roleBadge.name,
+ color: roleBadge.color,
+ iconUrl: roleBadge.iconUrl,
+ description: roleBadge.description,
+ isModerator: roleBadge.isModerator,
+ isAdministrator: roleBadge.isAdministrator,
+ displayOrder: roleBadge.displayOrder,
+ }]);
});
test('ã‚’ID指定ã®ãƒªã‚¹ãƒˆå½¢å¼ã§å–å¾—ã™ã‚‹ã“ã¨ãŒã§ãる(空)', async () => {
const parameters = { userIds: [] };
diff --git a/packages/backend/test/eslint.config.js b/packages/backend/test/eslint.config.js
new file mode 100644
index 0000000000..a0f43babad
--- /dev/null
+++ b/packages/backend/test/eslint.config.js
@@ -0,0 +1,22 @@
+import globals from 'globals';
+import tsParser from '@typescript-eslint/parser';
+import sharedConfig from '../../shared/eslint.config.js';
+
+export default [
+ ...sharedConfig,
+ {
+ files: ['**/*.ts', '**/*.tsx'],
+ languageOptions: {
+ globals: {
+ ...globals.node,
+ ...globals.jest,
+ },
+ parserOptions: {
+ parser: tsParser,
+ project: ['./tsconfig.json'],
+ sourceType: 'module',
+ tsconfigRootDir: import.meta.dirname,
+ },
+ },
+ },
+];
diff --git a/packages/backend/test/prelude/maybe.ts b/packages/backend/test/prelude/maybe.ts
deleted file mode 100644
index 16e92216d4..0000000000
--- a/packages/backend/test/prelude/maybe.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import * as assert from 'assert';
-import { just, nothing } from '../../src/misc/prelude/maybe.js';
-
-describe('just', () => {
- test('has a value', () => {
- assert.deepStrictEqual(just(3).isJust(), true);
- });
-
- test('has the inverse called get', () => {
- assert.deepStrictEqual(just(3).get(), 3);
- });
-});
-
-describe('nothing', () => {
- test('has no value', () => {
- assert.deepStrictEqual(nothing().isJust(), false);
- });
-});
diff --git a/packages/backend/test/resources/192.jpg b/packages/backend/test/resources/192.jpg
new file mode 100644
index 0000000000..76374628e0
--- /dev/null
+++ b/packages/backend/test/resources/192.jpg
Binary files differ
diff --git a/packages/backend/test/resources/192.png b/packages/backend/test/resources/192.png
new file mode 100644
index 0000000000..15fd1e3731
--- /dev/null
+++ b/packages/backend/test/resources/192.png
Binary files differ
diff --git a/packages/backend/test/resources/Lenna.jpg b/packages/backend/test/resources/Lenna.jpg
deleted file mode 100644
index 6b5b32281c..0000000000
--- a/packages/backend/test/resources/Lenna.jpg
+++ /dev/null
Binary files differ
diff --git a/packages/backend/test/resources/Lenna.png b/packages/backend/test/resources/Lenna.png
deleted file mode 100644
index 59ef68aabd..0000000000
--- a/packages/backend/test/resources/Lenna.png
+++ /dev/null
Binary files differ
diff --git a/packages/backend/test/unit/AbuseReportNotificationService.ts b/packages/backend/test/unit/AbuseReportNotificationService.ts
new file mode 100644
index 0000000000..e971659070
--- /dev/null
+++ b/packages/backend/test/unit/AbuseReportNotificationService.ts
@@ -0,0 +1,343 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { jest } from '@jest/globals';
+import { Test, TestingModule } from '@nestjs/testing';
+import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js';
+import {
+ AbuseReportNotificationRecipientRepository,
+ MiAbuseReportNotificationRecipient,
+ MiSystemWebhook,
+ MiUser,
+ SystemWebhooksRepository,
+ UserProfilesRepository,
+ UsersRepository,
+} from '@/models/_.js';
+import { DI } from '@/di-symbols.js';
+import { GlobalModule } from '@/GlobalModule.js';
+import { IdService } from '@/core/IdService.js';
+import { EmailService } from '@/core/EmailService.js';
+import { RoleService } from '@/core/RoleService.js';
+import { MetaService } from '@/core/MetaService.js';
+import { ModerationLogService } from '@/core/ModerationLogService.js';
+import { GlobalEventService } from '@/core/GlobalEventService.js';
+import { RecipientMethod } from '@/models/AbuseReportNotificationRecipient.js';
+import { SystemWebhookService } from '@/core/SystemWebhookService.js';
+import { randomString } from '../utils.js';
+
+process.env.NODE_ENV = 'test';
+
+describe('AbuseReportNotificationService', () => {
+ let app: TestingModule;
+ let service: AbuseReportNotificationService;
+
+ // --------------------------------------------------------------------------------------
+
+ let usersRepository: UsersRepository;
+ let userProfilesRepository: UserProfilesRepository;
+ let systemWebhooksRepository: SystemWebhooksRepository;
+ let abuseReportNotificationRecipientRepository: AbuseReportNotificationRecipientRepository;
+ let idService: IdService;
+ let roleService: jest.Mocked<RoleService>;
+ let emailService: jest.Mocked<EmailService>;
+ let webhookService: jest.Mocked<SystemWebhookService>;
+
+ // --------------------------------------------------------------------------------------
+
+ let root: MiUser;
+ let alice: MiUser;
+ let bob: MiUser;
+ let systemWebhook1: MiSystemWebhook;
+ let systemWebhook2: MiSystemWebhook;
+
+ // --------------------------------------------------------------------------------------
+
+ async function createUser(data: Partial<MiUser> = {}) {
+ const user = await usersRepository
+ .insert({
+ id: idService.gen(),
+ ...data,
+ })
+ .then(x => usersRepository.findOneByOrFail(x.identifiers[0]));
+
+ await userProfilesRepository.insert({
+ userId: user.id,
+ });
+
+ return user;
+ }
+
+ async function createWebhook(data: Partial<MiSystemWebhook> = {}) {
+ return systemWebhooksRepository
+ .insert({
+ id: idService.gen(),
+ name: randomString(),
+ on: ['abuseReport'],
+ url: 'https://example.com',
+ secret: randomString(),
+ ...data,
+ })
+ .then(x => systemWebhooksRepository.findOneByOrFail(x.identifiers[0]));
+ }
+
+ async function createRecipient(data: Partial<MiAbuseReportNotificationRecipient> = {}) {
+ return abuseReportNotificationRecipientRepository
+ .insert({
+ id: idService.gen(),
+ isActive: true,
+ name: randomString(),
+ ...data,
+ })
+ .then(x => abuseReportNotificationRecipientRepository.findOneByOrFail(x.identifiers[0]));
+ }
+
+ // --------------------------------------------------------------------------------------
+
+ beforeAll(async () => {
+ app = await Test
+ .createTestingModule({
+ imports: [
+ GlobalModule,
+ ],
+ providers: [
+ AbuseReportNotificationService,
+ IdService,
+ {
+ provide: RoleService, useFactory: () => ({ getModeratorIds: jest.fn() }),
+ },
+ {
+ provide: SystemWebhookService, useFactory: () => ({ enqueueSystemWebhook: jest.fn() }),
+ },
+ {
+ provide: EmailService, useFactory: () => ({ sendEmail: jest.fn() }),
+ },
+ {
+ provide: MetaService, useFactory: () => ({ fetch: jest.fn() }),
+ },
+ {
+ provide: ModerationLogService, useFactory: () => ({ log: () => Promise.resolve() }),
+ },
+ {
+ provide: GlobalEventService, useFactory: () => ({ publishAdminStream: jest.fn() }),
+ },
+ ],
+ })
+ .compile();
+
+ usersRepository = app.get(DI.usersRepository);
+ userProfilesRepository = app.get(DI.userProfilesRepository);
+ systemWebhooksRepository = app.get(DI.systemWebhooksRepository);
+ abuseReportNotificationRecipientRepository = app.get(DI.abuseReportNotificationRecipientRepository);
+
+ service = app.get(AbuseReportNotificationService);
+ idService = app.get(IdService);
+ roleService = app.get(RoleService) as jest.Mocked<RoleService>;
+ emailService = app.get<EmailService>(EmailService) as jest.Mocked<EmailService>;
+ webhookService = app.get<SystemWebhookService>(SystemWebhookService) as jest.Mocked<SystemWebhookService>;
+
+ app.enableShutdownHooks();
+ });
+
+ beforeEach(async () => {
+ root = await createUser({ username: 'root', usernameLower: 'root', isRoot: true });
+ alice = await createUser({ username: 'alice', usernameLower: 'alice', isRoot: false });
+ bob = await createUser({ username: 'bob', usernameLower: 'bob', isRoot: false });
+ systemWebhook1 = await createWebhook();
+ systemWebhook2 = await createWebhook();
+
+ roleService.getModeratorIds.mockResolvedValue([root.id, alice.id, bob.id]);
+ });
+
+ afterEach(async () => {
+ emailService.sendEmail.mockClear();
+ webhookService.enqueueSystemWebhook.mockClear();
+
+ await usersRepository.delete({});
+ await userProfilesRepository.delete({});
+ await systemWebhooksRepository.delete({});
+ await abuseReportNotificationRecipientRepository.delete({});
+ });
+
+ afterAll(async () => {
+ await app.close();
+ });
+
+ // --------------------------------------------------------------------------------------
+
+ describe('createRecipient', () => {
+ test('ä½œæˆæˆåŠŸ1', async () => {
+ const params = {
+ isActive: true,
+ name: randomString(),
+ method: 'email' as RecipientMethod,
+ userId: alice.id,
+ systemWebhookId: null,
+ };
+
+ const recipient1 = await service.createRecipient(params, root);
+ expect(recipient1).toMatchObject(params);
+ });
+
+ test('ä½œæˆæˆåŠŸ2', async () => {
+ const params = {
+ isActive: true,
+ name: randomString(),
+ method: 'webhook' as RecipientMethod,
+ userId: null,
+ systemWebhookId: systemWebhook1.id,
+ };
+
+ const recipient1 = await service.createRecipient(params, root);
+ expect(recipient1).toMatchObject(params);
+ });
+ });
+
+ describe('updateRecipient', () => {
+ test('æ›´æ–°æˆåŠŸ1', async () => {
+ const recipient1 = await createRecipient({
+ method: 'email',
+ userId: alice.id,
+ });
+
+ const params = {
+ id: recipient1.id,
+ isActive: false,
+ name: randomString(),
+ method: 'email' as RecipientMethod,
+ userId: bob.id,
+ systemWebhookId: null,
+ };
+
+ const recipient2 = await service.updateRecipient(params, root);
+ expect(recipient2).toMatchObject(params);
+ });
+
+ test('æ›´æ–°æˆåŠŸ2', async () => {
+ const recipient1 = await createRecipient({
+ method: 'webhook',
+ systemWebhookId: systemWebhook1.id,
+ });
+
+ const params = {
+ id: recipient1.id,
+ isActive: false,
+ name: randomString(),
+ method: 'webhook' as RecipientMethod,
+ userId: null,
+ systemWebhookId: systemWebhook2.id,
+ };
+
+ const recipient2 = await service.updateRecipient(params, root);
+ expect(recipient2).toMatchObject(params);
+ });
+ });
+
+ describe('deleteRecipient', () => {
+ test('削除æˆåŠŸ1', async () => {
+ const recipient1 = await createRecipient({
+ method: 'email',
+ userId: alice.id,
+ });
+
+ await service.deleteRecipient(recipient1.id, root);
+
+ await expect(abuseReportNotificationRecipientRepository.findOneBy({ id: recipient1.id })).resolves.toBeNull();
+ });
+ });
+
+ describe('fetchRecipients', () => {
+ async function create() {
+ const recipient1 = await createRecipient({
+ method: 'email',
+ userId: alice.id,
+ });
+ const recipient2 = await createRecipient({
+ method: 'email',
+ userId: bob.id,
+ });
+
+ const recipient3 = await createRecipient({
+ method: 'webhook',
+ systemWebhookId: systemWebhook1.id,
+ });
+ const recipient4 = await createRecipient({
+ method: 'webhook',
+ systemWebhookId: systemWebhook2.id,
+ });
+
+ return [recipient1, recipient2, recipient3, recipient4];
+ }
+
+ test('フィルタãªã—', async () => {
+ const [recipient1, recipient2, recipient3, recipient4] = await create();
+
+ const recipients = await service.fetchRecipients({});
+ expect(recipients).toEqual([recipient1, recipient2, recipient3, recipient4]);
+ });
+
+ test('フィルタãªã—(éžãƒ¢ãƒ‡ãƒ¬ãƒ¼ã‚¿ã¯é™¤å¤–ã•れる)', async () => {
+ roleService.getModeratorIds.mockClear();
+ roleService.getModeratorIds.mockResolvedValue([root.id, bob.id]);
+
+ const [recipient1, recipient2, recipient3, recipient4] = await create();
+
+ const recipients = await service.fetchRecipients({});
+ // aliceã¯ãƒ¢ãƒ‡ãƒ¬ãƒ¼ã‚¿ã§ã¯ãªã„ã®ã§é™¤å¤–ã•れる
+ expect(recipients).toEqual([recipient2, recipient3, recipient4]);
+ });
+
+ test('フィルタãªã—(éžãƒ¢ãƒ‡ãƒ¬ãƒ¼ã‚¿ã§ã‚‚除外ã•れãªã„オプション設定)', async () => {
+ roleService.getModeratorIds.mockClear();
+ roleService.getModeratorIds.mockResolvedValue([root.id, bob.id]);
+
+ const [recipient1, recipient2, recipient3, recipient4] = await create();
+
+ const recipients = await service.fetchRecipients({}, { removeUnauthorized: false });
+ expect(recipients).toEqual([recipient1, recipient2, recipient3, recipient4]);
+ });
+
+ test('emailã®ã¿', async () => {
+ const [recipient1, recipient2, recipient3, recipient4] = await create();
+
+ const recipients = await service.fetchRecipients({ method: ['email'] });
+ expect(recipients).toEqual([recipient1, recipient2]);
+ });
+
+ test('webhookã®ã¿', async () => {
+ const [recipient1, recipient2, recipient3, recipient4] = await create();
+
+ const recipients = await service.fetchRecipients({ method: ['webhook'] });
+ expect(recipients).toEqual([recipient3, recipient4]);
+ });
+
+ test('ã™ã¹ã¦', async () => {
+ const [recipient1, recipient2, recipient3, recipient4] = await create();
+
+ const recipients = await service.fetchRecipients({ method: ['email', 'webhook'] });
+ expect(recipients).toEqual([recipient1, recipient2, recipient3, recipient4]);
+ });
+
+ test('ID指定', async () => {
+ const [recipient1, recipient2, recipient3, recipient4] = await create();
+
+ const recipients = await service.fetchRecipients({ ids: [recipient1.id, recipient3.id] });
+ expect(recipients).toEqual([recipient1, recipient3]);
+ });
+
+ test('ID指定(method=emailã§ã¯ãªã„IDãŒæ··ã–りã“ã¾ãªã„)', async () => {
+ const [recipient1, recipient2, recipient3, recipient4] = await create();
+
+ const recipients = await service.fetchRecipients({ ids: [recipient1.id, recipient3.id], method: ['email'] });
+ expect(recipients).toEqual([recipient1]);
+ });
+
+ test('ID指定(method=webhookã§ã¯ãªã„IDãŒæ··ã–りã“ã¾ãªã„)', async () => {
+ const [recipient1, recipient2, recipient3, recipient4] = await create();
+
+ const recipients = await service.fetchRecipients({ ids: [recipient1.id, recipient3.id], method: ['webhook'] });
+ expect(recipients).toEqual([recipient3]);
+ });
+ });
+});
diff --git a/packages/backend/test/unit/ApMfmService.ts b/packages/backend/test/unit/ApMfmService.ts
index 79cb81f5c9..e81a321c9b 100644
--- a/packages/backend/test/unit/ApMfmService.ts
+++ b/packages/backend/test/unit/ApMfmService.ts
@@ -23,10 +23,10 @@ describe('ApMfmService', () => {
describe('getNoteHtml', () => {
test('Do not provide _misskey_content for simple text', () => {
- const note: MiNote = {
+ const note = {
text: 'テキスト #タグ @mention 🊠:emoji: https://example.com',
mentionedRemoteUsers: '[]',
- } as any;
+ };
const { content, noMisskeyContent } = apMfmService.getNoteHtml(note);
@@ -35,10 +35,10 @@ describe('ApMfmService', () => {
});
test('Provide _misskey_content for MFM', () => {
- const note: MiNote = {
+ const note = {
text: '$[tada foo]',
mentionedRemoteUsers: '[]',
- } as any;
+ };
const { content, noMisskeyContent } = apMfmService.getNoteHtml(note);
diff --git a/packages/backend/test/unit/FileInfoService.ts b/packages/backend/test/unit/FileInfoService.ts
index 40d187f5a8..29bd03a201 100644
--- a/packages/backend/test/unit/FileInfoService.ts
+++ b/packages/backend/test/unit/FileInfoService.ts
@@ -12,7 +12,7 @@ import { ModuleMocker } from 'jest-mock';
import { Test } from '@nestjs/testing';
import { afterAll, beforeAll, describe, test } from '@jest/globals';
import { GlobalModule } from '@/GlobalModule.js';
-import { FileInfoService } from '@/core/FileInfoService.js';
+import { FileInfo, FileInfoService } from '@/core/FileInfoService.js';
//import { DI } from '@/di-symbols.js';
import { AiService } from '@/core/AiService.js';
import { LoggerService } from '@/core/LoggerService.js';
@@ -28,6 +28,15 @@ const moduleMocker = new ModuleMocker(global);
describe('FileInfoService', () => {
let app: TestingModule;
let fileInfoService: FileInfoService;
+ const strip = (fileInfo: FileInfo): Omit<Partial<FileInfo>, 'warnings' | 'blurhash' | 'sensitive' | 'porn'> => {
+ const fi: Partial<FileInfo> = fileInfo;
+ delete fi.warnings;
+ delete fi.sensitive;
+ delete fi.blurhash;
+ delete fi.porn;
+
+ return fi;
+ }
beforeAll(async () => {
app = await Test.createTestingModule({
@@ -63,11 +72,7 @@ describe('FileInfoService', () => {
test('Empty file', async () => {
const path = `${resources}/emptyfile`;
- const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any;
- delete info.warnings;
- delete info.blurhash;
- delete info.sensitive;
- delete info.porn;
+ const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }));
assert.deepStrictEqual(info, {
size: 0,
md5: 'd41d8cd98f00b204e9800998ecf8427e',
@@ -83,32 +88,24 @@ describe('FileInfoService', () => {
describe('IMAGE', () => {
test('Generic JPEG', async () => {
- const path = `${resources}/Lenna.jpg`;
- const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any;
- delete info.warnings;
- delete info.blurhash;
- delete info.sensitive;
- delete info.porn;
+ const path = `${resources}/192.jpg`;
+ const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }));
assert.deepStrictEqual(info, {
- size: 25360,
- md5: '091b3f259662aa31e2ffef4519951168',
+ size: 5131,
+ md5: '8c9ed0677dd2b8f9f7472c3af247e5e3',
type: {
mime: 'image/jpeg',
ext: 'jpg',
},
- width: 512,
- height: 512,
+ width: 192,
+ height: 192,
orientation: undefined,
});
});
test('Generic APNG', async () => {
const path = `${resources}/anime.png`;
- const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any;
- delete info.warnings;
- delete info.blurhash;
- delete info.sensitive;
- delete info.porn;
+ const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }));
assert.deepStrictEqual(info, {
size: 1868,
md5: '08189c607bea3b952704676bb3c979e0',
@@ -124,11 +121,7 @@ describe('FileInfoService', () => {
test('Generic AGIF', async () => {
const path = `${resources}/anime.gif`;
- const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any;
- delete info.warnings;
- delete info.blurhash;
- delete info.sensitive;
- delete info.porn;
+ const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }));
assert.deepStrictEqual(info, {
size: 2248,
md5: '32c47a11555675d9267aee1a86571e7e',
@@ -144,11 +137,7 @@ describe('FileInfoService', () => {
test('PNG with alpha', async () => {
const path = `${resources}/with-alpha.png`;
- const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any;
- delete info.warnings;
- delete info.blurhash;
- delete info.sensitive;
- delete info.porn;
+ const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }));
assert.deepStrictEqual(info, {
size: 3772,
md5: 'f73535c3e1e27508885b69b10cf6e991',
@@ -164,11 +153,7 @@ describe('FileInfoService', () => {
test('Generic SVG', async () => {
const path = `${resources}/image.svg`;
- const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any;
- delete info.warnings;
- delete info.blurhash;
- delete info.sensitive;
- delete info.porn;
+ const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }));
assert.deepStrictEqual(info, {
size: 505,
md5: 'b6f52b4b021e7b92cdd04509c7267965',
@@ -185,11 +170,7 @@ describe('FileInfoService', () => {
test('SVG with XML definition', async () => {
// https://github.com/misskey-dev/misskey/issues/4413
const path = `${resources}/with-xml-def.svg`;
- const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any;
- delete info.warnings;
- delete info.blurhash;
- delete info.sensitive;
- delete info.porn;
+ const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }));
assert.deepStrictEqual(info, {
size: 544,
md5: '4b7a346cde9ccbeb267e812567e33397',
@@ -205,11 +186,7 @@ describe('FileInfoService', () => {
test('Dimension limit', async () => {
const path = `${resources}/25000x25000.png`;
- const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any;
- delete info.warnings;
- delete info.blurhash;
- delete info.sensitive;
- delete info.porn;
+ const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }));
assert.deepStrictEqual(info, {
size: 75933,
md5: '268c5dde99e17cf8fe09f1ab3f97df56',
@@ -225,11 +202,7 @@ describe('FileInfoService', () => {
test('Rotate JPEG', async () => {
const path = `${resources}/rotate.jpg`;
- const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any;
- delete info.warnings;
- delete info.blurhash;
- delete info.sensitive;
- delete info.porn;
+ const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }));
assert.deepStrictEqual(info, {
size: 12624,
md5: '68d5b2d8d1d1acbbce99203e3ec3857e',
@@ -247,11 +220,7 @@ describe('FileInfoService', () => {
describe('AUDIO', () => {
test('MP3', async () => {
const path = `${resources}/kick_gaba7.mp3`;
- const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any;
- delete info.warnings;
- delete info.blurhash;
- delete info.sensitive;
- delete info.porn;
+ const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }));
delete info.width;
delete info.height;
delete info.orientation;
@@ -267,11 +236,7 @@ describe('FileInfoService', () => {
test('WAV', async () => {
const path = `${resources}/kick_gaba7.wav`;
- const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any;
- delete info.warnings;
- delete info.blurhash;
- delete info.sensitive;
- delete info.porn;
+ const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }));
delete info.width;
delete info.height;
delete info.orientation;
@@ -287,11 +252,7 @@ describe('FileInfoService', () => {
test('AAC', async () => {
const path = `${resources}/kick_gaba7.aac`;
- const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any;
- delete info.warnings;
- delete info.blurhash;
- delete info.sensitive;
- delete info.porn;
+ const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }));
delete info.width;
delete info.height;
delete info.orientation;
@@ -307,11 +268,7 @@ describe('FileInfoService', () => {
test('FLAC', async () => {
const path = `${resources}/kick_gaba7.flac`;
- const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any;
- delete info.warnings;
- delete info.blurhash;
- delete info.sensitive;
- delete info.porn;
+ const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }));
delete info.width;
delete info.height;
delete info.orientation;
@@ -327,11 +284,7 @@ describe('FileInfoService', () => {
test('MPEG-4 AUDIO (M4A)', async () => {
const path = `${resources}/kick_gaba7.m4a`;
- const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any;
- delete info.warnings;
- delete info.blurhash;
- delete info.sensitive;
- delete info.porn;
+ const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }));
delete info.width;
delete info.height;
delete info.orientation;
@@ -347,11 +300,7 @@ describe('FileInfoService', () => {
test('WEBM AUDIO', async () => {
const path = `${resources}/kick_gaba7.webm`;
- const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any;
- delete info.warnings;
- delete info.blurhash;
- delete info.sensitive;
- delete info.porn;
+ const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }));
delete info.width;
delete info.height;
delete info.orientation;
diff --git a/packages/backend/test/unit/RoleService.ts b/packages/backend/test/unit/RoleService.ts
index ec441735d7..b6cbe4c520 100644
--- a/packages/backend/test/unit/RoleService.ts
+++ b/packages/backend/test/unit/RoleService.ts
@@ -3,17 +3,23 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
-import { UserEntityService } from '@/core/entities/UserEntityService.js';
-
process.env.NODE_ENV = 'test';
+import { setTimeout } from 'node:timers/promises';
import { jest } from '@jest/globals';
import { ModuleMocker } from 'jest-mock';
import { Test } from '@nestjs/testing';
import * as lolex from '@sinonjs/fake-timers';
import { GlobalModule } from '@/GlobalModule.js';
import { RoleService } from '@/core/RoleService.js';
-import type { MiRole, MiUser, RoleAssignmentsRepository, RolesRepository, UsersRepository } from '@/models/_.js';
+import {
+ MiRole,
+ MiRoleAssignment,
+ MiUser,
+ RoleAssignmentsRepository,
+ RolesRepository,
+ UsersRepository,
+} from '@/models/_.js';
import { DI } from '@/di-symbols.js';
import { MetaService } from '@/core/MetaService.js';
import { genAidx } from '@/misc/id/aidx.js';
@@ -23,7 +29,7 @@ import { GlobalEventService } from '@/core/GlobalEventService.js';
import { secureRndstr } from '@/misc/secure-rndstr.js';
import { NotificationService } from '@/core/NotificationService.js';
import { RoleCondFormulaValue } from '@/models/Role.js';
-import { sleep } from '../utils.js';
+import { UserEntityService } from '@/core/entities/UserEntityService.js';
import type { TestingModule } from '@nestjs/testing';
import type { MockFunctionMetadata } from 'jest-mock';
@@ -39,27 +45,27 @@ describe('RoleService', () => {
let notificationService: jest.Mocked<NotificationService>;
let clock: lolex.InstalledClock;
- function createUser(data: Partial<MiUser> = {}) {
+ async function createUser(data: Partial<MiUser> = {}) {
const un = secureRndstr(16);
- return usersRepository.insert({
+ const x = await usersRepository.insert({
id: genAidx(Date.now()),
username: un,
usernameLower: un,
...data,
- })
- .then(x => usersRepository.findOneByOrFail(x.identifiers[0]));
+ });
+ return await usersRepository.findOneByOrFail(x.identifiers[0]);
}
- function createRole(data: Partial<MiRole> = {}) {
- return rolesRepository.insert({
+ async function createRole(data: Partial<MiRole> = {}) {
+ const x = await rolesRepository.insert({
id: genAidx(Date.now()),
updatedAt: new Date(),
lastUsedAt: new Date(),
name: '',
description: '',
...data,
- })
- .then(x => rolesRepository.findOneByOrFail(x.identifiers[0]));
+ });
+ return await rolesRepository.findOneByOrFail(x.identifiers[0]);
}
function createConditionalRole(condFormula: RoleCondFormulaValue, data: Partial<MiRole> = {}) {
@@ -71,6 +77,20 @@ describe('RoleService', () => {
});
}
+ async function assignRole(args: Partial<MiRoleAssignment>) {
+ const id = genAidx(Date.now());
+ const expiresAt = new Date();
+ expiresAt.setDate(expiresAt.getDate() + 1);
+
+ await roleAssignmentsRepository.insert({
+ id,
+ expiresAt,
+ ...args,
+ });
+
+ return await roleAssignmentsRepository.findOneByOrFail({ id });
+ }
+
function aidx() {
return genAidx(Date.now());
}
@@ -258,13 +278,103 @@ describe('RoleService', () => {
// ストリーミング経由ã§å映ã•れるã¾ã§ã¡ã‚‡ã£ã¨å¾…ã¤
clock.uninstall();
- await sleep(100);
+ await setTimeout(100);
const resultAfter25hAgain = await roleService.getUserPolicies(user.id);
expect(resultAfter25hAgain.canManageCustomEmojis).toBe(true);
});
});
+ describe('getModeratorIds', () => {
+ test('includeAdmins = false, excludeExpire = false', async () => {
+ const [adminUser1, adminUser2, modeUser1, modeUser2, normalUser1, normalUser2] = await Promise.all([
+ createUser(), createUser(), createUser(), createUser(), createUser(), createUser(),
+ ]);
+
+ const role1 = await createRole({ name: 'admin', isAdministrator: true });
+ const role2 = await createRole({ name: 'moderator', isModerator: true });
+ const role3 = await createRole({ name: 'normal' });
+
+ await Promise.all([
+ assignRole({ userId: adminUser1.id, roleId: role1.id }),
+ assignRole({ userId: adminUser2.id, roleId: role1.id, expiresAt: new Date(Date.now() - 1000) }),
+ assignRole({ userId: modeUser1.id, roleId: role2.id }),
+ assignRole({ userId: modeUser2.id, roleId: role2.id, expiresAt: new Date(Date.now() - 1000) }),
+ assignRole({ userId: normalUser1.id, roleId: role3.id }),
+ assignRole({ userId: normalUser2.id, roleId: role3.id, expiresAt: new Date(Date.now() - 1000) }),
+ ]);
+
+ const result = await roleService.getModeratorIds(false, false);
+ expect(result).toEqual([modeUser1.id, modeUser2.id]);
+ });
+
+ test('includeAdmins = false, excludeExpire = true', async () => {
+ const [adminUser1, adminUser2, modeUser1, modeUser2, normalUser1, normalUser2] = await Promise.all([
+ createUser(), createUser(), createUser(), createUser(), createUser(), createUser(),
+ ]);
+
+ const role1 = await createRole({ name: 'admin', isAdministrator: true });
+ const role2 = await createRole({ name: 'moderator', isModerator: true });
+ const role3 = await createRole({ name: 'normal' });
+
+ await Promise.all([
+ assignRole({ userId: adminUser1.id, roleId: role1.id }),
+ assignRole({ userId: adminUser2.id, roleId: role1.id, expiresAt: new Date(Date.now() - 1000) }),
+ assignRole({ userId: modeUser1.id, roleId: role2.id }),
+ assignRole({ userId: modeUser2.id, roleId: role2.id, expiresAt: new Date(Date.now() - 1000) }),
+ assignRole({ userId: normalUser1.id, roleId: role3.id }),
+ assignRole({ userId: normalUser2.id, roleId: role3.id, expiresAt: new Date(Date.now() - 1000) }),
+ ]);
+
+ const result = await roleService.getModeratorIds(false, true);
+ expect(result).toEqual([modeUser1.id]);
+ });
+
+ test('includeAdmins = true, excludeExpire = false', async () => {
+ const [adminUser1, adminUser2, modeUser1, modeUser2, normalUser1, normalUser2] = await Promise.all([
+ createUser(), createUser(), createUser(), createUser(), createUser(), createUser(),
+ ]);
+
+ const role1 = await createRole({ name: 'admin', isAdministrator: true });
+ const role2 = await createRole({ name: 'moderator', isModerator: true });
+ const role3 = await createRole({ name: 'normal' });
+
+ await Promise.all([
+ assignRole({ userId: adminUser1.id, roleId: role1.id }),
+ assignRole({ userId: adminUser2.id, roleId: role1.id, expiresAt: new Date(Date.now() - 1000) }),
+ assignRole({ userId: modeUser1.id, roleId: role2.id }),
+ assignRole({ userId: modeUser2.id, roleId: role2.id, expiresAt: new Date(Date.now() - 1000) }),
+ assignRole({ userId: normalUser1.id, roleId: role3.id }),
+ assignRole({ userId: normalUser2.id, roleId: role3.id, expiresAt: new Date(Date.now() - 1000) }),
+ ]);
+
+ const result = await roleService.getModeratorIds(true, false);
+ expect(result).toEqual([adminUser1.id, adminUser2.id, modeUser1.id, modeUser2.id]);
+ });
+
+ test('includeAdmins = true, excludeExpire = true', async () => {
+ const [adminUser1, adminUser2, modeUser1, modeUser2, normalUser1, normalUser2] = await Promise.all([
+ createUser(), createUser(), createUser(), createUser(), createUser(), createUser(),
+ ]);
+
+ const role1 = await createRole({ name: 'admin', isAdministrator: true });
+ const role2 = await createRole({ name: 'moderator', isModerator: true });
+ const role3 = await createRole({ name: 'normal' });
+
+ await Promise.all([
+ assignRole({ userId: adminUser1.id, roleId: role1.id }),
+ assignRole({ userId: adminUser2.id, roleId: role1.id, expiresAt: new Date(Date.now() - 1000) }),
+ assignRole({ userId: modeUser1.id, roleId: role2.id }),
+ assignRole({ userId: modeUser2.id, roleId: role2.id, expiresAt: new Date(Date.now() - 1000) }),
+ assignRole({ userId: normalUser1.id, roleId: role3.id }),
+ assignRole({ userId: normalUser2.id, roleId: role3.id, expiresAt: new Date(Date.now() - 1000) }),
+ ]);
+
+ const result = await roleService.getModeratorIds(true, true);
+ expect(result).toEqual([adminUser1.id, modeUser1.id]);
+ });
+ });
+
describe('conditional role', () => {
test('~ã‹ã¤ï½ž', async () => {
const [user1, user2, user3, user4] = await Promise.all([
@@ -697,7 +807,7 @@ describe('RoleService', () => {
await roleService.assign(user.id, role.id);
clock.uninstall();
- await sleep(100);
+ await setTimeout(100);
const assignments = await roleAssignmentsRepository.find({
where: {
@@ -725,7 +835,7 @@ describe('RoleService', () => {
await roleService.assign(user.id, role.id);
clock.uninstall();
- await sleep(100);
+ await setTimeout(100);
const assignments = await roleAssignmentsRepository.find({
where: {
diff --git a/packages/backend/test/unit/SystemWebhookService.ts b/packages/backend/test/unit/SystemWebhookService.ts
new file mode 100644
index 0000000000..790cd1490e
--- /dev/null
+++ b/packages/backend/test/unit/SystemWebhookService.ts
@@ -0,0 +1,516 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { setTimeout } from 'node:timers/promises';
+import { afterEach, beforeEach, describe, expect, jest } from '@jest/globals';
+import { Test, TestingModule } from '@nestjs/testing';
+import { MiUser } from '@/models/User.js';
+import { MiSystemWebhook, SystemWebhookEventType } from '@/models/SystemWebhook.js';
+import { SystemWebhooksRepository, UsersRepository } from '@/models/_.js';
+import { IdService } from '@/core/IdService.js';
+import { GlobalModule } from '@/GlobalModule.js';
+import { ModerationLogService } from '@/core/ModerationLogService.js';
+import { GlobalEventService } from '@/core/GlobalEventService.js';
+import { DI } from '@/di-symbols.js';
+import { QueueService } from '@/core/QueueService.js';
+import { LoggerService } from '@/core/LoggerService.js';
+import { SystemWebhookService } from '@/core/SystemWebhookService.js';
+import { randomString } from '../utils.js';
+
+describe('SystemWebhookService', () => {
+ let app: TestingModule;
+ let service: SystemWebhookService;
+
+ // --------------------------------------------------------------------------------------
+
+ let usersRepository: UsersRepository;
+ let systemWebhooksRepository: SystemWebhooksRepository;
+ let idService: IdService;
+ let queueService: jest.Mocked<QueueService>;
+
+ // --------------------------------------------------------------------------------------
+
+ let root: MiUser;
+
+ // --------------------------------------------------------------------------------------
+
+ async function createUser(data: Partial<MiUser> = {}) {
+ return await usersRepository
+ .insert({
+ id: idService.gen(),
+ ...data,
+ })
+ .then(x => usersRepository.findOneByOrFail(x.identifiers[0]));
+ }
+
+ async function createWebhook(data: Partial<MiSystemWebhook> = {}) {
+ return systemWebhooksRepository
+ .insert({
+ id: idService.gen(),
+ name: randomString(),
+ on: ['abuseReport'],
+ url: 'https://example.com',
+ secret: randomString(),
+ ...data,
+ })
+ .then(x => systemWebhooksRepository.findOneByOrFail(x.identifiers[0]));
+ }
+
+ // --------------------------------------------------------------------------------------
+
+ async function beforeAllImpl() {
+ app = await Test
+ .createTestingModule({
+ imports: [
+ GlobalModule,
+ ],
+ providers: [
+ SystemWebhookService,
+ IdService,
+ LoggerService,
+ GlobalEventService,
+ {
+ provide: QueueService, useFactory: () => ({ systemWebhookDeliver: jest.fn() }),
+ },
+ {
+ provide: ModerationLogService, useFactory: () => ({ log: () => Promise.resolve() }),
+ },
+ ],
+ })
+ .compile();
+
+ usersRepository = app.get(DI.usersRepository);
+ systemWebhooksRepository = app.get(DI.systemWebhooksRepository);
+
+ service = app.get(SystemWebhookService);
+ idService = app.get(IdService);
+ queueService = app.get(QueueService) as jest.Mocked<QueueService>;
+
+ app.enableShutdownHooks();
+ }
+
+ async function afterAllImpl() {
+ await app.close();
+ }
+
+ async function beforeEachImpl() {
+ root = await createUser({ isRoot: true, username: 'root', usernameLower: 'root' });
+ }
+
+ async function afterEachImpl() {
+ await usersRepository.delete({});
+ await systemWebhooksRepository.delete({});
+ }
+
+ // --------------------------------------------------------------------------------------
+
+ describe('アプリを毎回作り直ã™å¿…è¦ã®ãªã„グループ', () => {
+ beforeAll(beforeAllImpl);
+ afterAll(afterAllImpl);
+ beforeEach(beforeEachImpl);
+ afterEach(afterEachImpl);
+
+ describe('fetchSystemWebhooks', () => {
+ test('フィルタãªã—', async () => {
+ const webhook1 = await createWebhook({
+ isActive: true,
+ on: ['abuseReport'],
+ });
+ const webhook2 = await createWebhook({
+ isActive: false,
+ on: ['abuseReport'],
+ });
+ const webhook3 = await createWebhook({
+ isActive: true,
+ on: ['abuseReportResolved'],
+ });
+ const webhook4 = await createWebhook({
+ isActive: false,
+ on: [],
+ });
+
+ const fetchedWebhooks = await service.fetchSystemWebhooks();
+ expect(fetchedWebhooks).toEqual([webhook1, webhook2, webhook3, webhook4]);
+ });
+
+ test('activeã®ã¿', async () => {
+ const webhook1 = await createWebhook({
+ isActive: true,
+ on: ['abuseReport'],
+ });
+ const webhook2 = await createWebhook({
+ isActive: false,
+ on: ['abuseReport'],
+ });
+ const webhook3 = await createWebhook({
+ isActive: true,
+ on: ['abuseReportResolved'],
+ });
+ const webhook4 = await createWebhook({
+ isActive: false,
+ on: [],
+ });
+
+ const fetchedWebhooks = await service.fetchSystemWebhooks({ isActive: true });
+ expect(fetchedWebhooks).toEqual([webhook1, webhook3]);
+ });
+
+ test('特定ã®ã‚¤ãƒ™ãƒ³ãƒˆã®ã¿', async () => {
+ const webhook1 = await createWebhook({
+ isActive: true,
+ on: ['abuseReport'],
+ });
+ const webhook2 = await createWebhook({
+ isActive: false,
+ on: ['abuseReport'],
+ });
+ const webhook3 = await createWebhook({
+ isActive: true,
+ on: ['abuseReportResolved'],
+ });
+ const webhook4 = await createWebhook({
+ isActive: false,
+ on: [],
+ });
+
+ const fetchedWebhooks = await service.fetchSystemWebhooks({ on: ['abuseReport'] });
+ expect(fetchedWebhooks).toEqual([webhook1, webhook2]);
+ });
+
+ test('activeãªç‰¹å®šã®ã‚¤ãƒ™ãƒ³ãƒˆã®ã¿', async () => {
+ const webhook1 = await createWebhook({
+ isActive: true,
+ on: ['abuseReport'],
+ });
+ const webhook2 = await createWebhook({
+ isActive: false,
+ on: ['abuseReport'],
+ });
+ const webhook3 = await createWebhook({
+ isActive: true,
+ on: ['abuseReportResolved'],
+ });
+ const webhook4 = await createWebhook({
+ isActive: false,
+ on: [],
+ });
+
+ const fetchedWebhooks = await service.fetchSystemWebhooks({ on: ['abuseReport'], isActive: true });
+ expect(fetchedWebhooks).toEqual([webhook1]);
+ });
+
+ test('ID指定', async () => {
+ const webhook1 = await createWebhook({
+ isActive: true,
+ on: ['abuseReport'],
+ });
+ const webhook2 = await createWebhook({
+ isActive: false,
+ on: ['abuseReport'],
+ });
+ const webhook3 = await createWebhook({
+ isActive: true,
+ on: ['abuseReportResolved'],
+ });
+ const webhook4 = await createWebhook({
+ isActive: false,
+ on: [],
+ });
+
+ const fetchedWebhooks = await service.fetchSystemWebhooks({ ids: [webhook1.id, webhook4.id] });
+ expect(fetchedWebhooks).toEqual([webhook1, webhook4]);
+ });
+
+ test('ID指定(ä»–æ¡ä»¶ã¨ANDã«ãªã‚‹ã‹è¦‹ãŸã„)', async () => {
+ const webhook1 = await createWebhook({
+ isActive: true,
+ on: ['abuseReport'],
+ });
+ const webhook2 = await createWebhook({
+ isActive: false,
+ on: ['abuseReport'],
+ });
+ const webhook3 = await createWebhook({
+ isActive: true,
+ on: ['abuseReportResolved'],
+ });
+ const webhook4 = await createWebhook({
+ isActive: false,
+ on: [],
+ });
+
+ const fetchedWebhooks = await service.fetchSystemWebhooks({ ids: [webhook1.id, webhook4.id], isActive: false });
+ expect(fetchedWebhooks).toEqual([webhook4]);
+ });
+ });
+
+ describe('createSystemWebhook', () => {
+ test('ä½œæˆæˆåŠŸ ', async () => {
+ const params = {
+ isActive: true,
+ name: randomString(),
+ on: ['abuseReport'] as SystemWebhookEventType[],
+ url: 'https://example.com',
+ secret: randomString(),
+ };
+
+ const webhook = await service.createSystemWebhook(params, root);
+ expect(webhook).toMatchObject(params);
+ });
+ });
+
+ describe('updateSystemWebhook', () => {
+ test('æ›´æ–°æˆåŠŸ', async () => {
+ const webhook = await createWebhook({
+ isActive: true,
+ on: ['abuseReport'],
+ });
+
+ const params = {
+ id: webhook.id,
+ isActive: false,
+ name: randomString(),
+ on: ['abuseReport'] as SystemWebhookEventType[],
+ url: randomString(),
+ secret: randomString(),
+ };
+
+ const updatedWebhook = await service.updateSystemWebhook(params, root);
+ expect(updatedWebhook).toMatchObject(params);
+ });
+ });
+
+ describe('deleteSystemWebhook', () => {
+ test('削除æˆåŠŸ', async () => {
+ const webhook = await createWebhook({
+ isActive: true,
+ on: ['abuseReport'],
+ });
+
+ await service.deleteSystemWebhook(webhook.id, root);
+
+ await expect(systemWebhooksRepository.findOneBy({ id: webhook.id })).resolves.toBeNull();
+ });
+ });
+ });
+
+ describe('アプリを毎回作り直ã™å¿…è¦ãŒã‚るグループ', () => {
+ beforeEach(async () => {
+ await beforeAllImpl();
+ await beforeEachImpl();
+ });
+
+ afterEach(async () => {
+ await afterEachImpl();
+ await afterAllImpl();
+ });
+
+ describe('enqueueSystemWebhook', () => {
+ test('キューã«è¿½åŠ æˆåŠŸ', async () => {
+ const webhook = await createWebhook({
+ isActive: true,
+ on: ['abuseReport'],
+ });
+ await service.enqueueSystemWebhook(webhook.id, 'abuseReport', { foo: 'bar' });
+
+ expect(queueService.systemWebhookDeliver).toHaveBeenCalled();
+ });
+
+ test('éžã‚¢ã‚¯ãƒ†ã‚£ãƒ–ãªWebhookã¯ã‚­ãƒ¥ãƒ¼ã«è¿½åŠ ã•れãªã„', async () => {
+ const webhook = await createWebhook({
+ isActive: false,
+ on: ['abuseReport'],
+ });
+ await service.enqueueSystemWebhook(webhook.id, 'abuseReport', { foo: 'bar' });
+
+ expect(queueService.systemWebhookDeliver).not.toHaveBeenCalled();
+ });
+
+ test('未許å¯ã®ã‚¤ãƒ™ãƒ³ãƒˆç¨®åˆ¥ãŒæ¸¡ã•れãŸå ´åˆã¯Webhookã¯ã‚­ãƒ¥ãƒ¼ã«è¿½åŠ ã•れãªã„', async () => {
+ const webhook1 = await createWebhook({
+ isActive: true,
+ on: [],
+ });
+ const webhook2 = await createWebhook({
+ isActive: true,
+ on: ['abuseReportResolved'],
+ });
+ await service.enqueueSystemWebhook(webhook1.id, 'abuseReport', { foo: 'bar' });
+ await service.enqueueSystemWebhook(webhook2.id, 'abuseReport', { foo: 'bar' });
+
+ expect(queueService.systemWebhookDeliver).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('fetchActiveSystemWebhooks', () => {
+ describe('systemWebhookCreated', () => {
+ test('ActiveãªWebhookãŒè¿½åŠ ã•ã‚ŒãŸæ™‚ã€ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã«è¿½åŠ ã•れã¦ã„ã‚‹', async () => {
+ const webhook = await service.createSystemWebhook(
+ {
+ isActive: true,
+ name: randomString(),
+ on: ['abuseReport'],
+ url: 'https://example.com',
+ secret: randomString(),
+ },
+ root,
+ );
+
+ // redisã§ã®é…ä¿¡çµŒç”±ã§æ›´æ–°ã•れるã®ã§ã¡ã‚‡ã£ã¨å¾…ã¤
+ await setTimeout(500);
+
+ const fetchedWebhooks = await service.fetchActiveSystemWebhooks();
+ expect(fetchedWebhooks).toEqual([webhook]);
+ });
+
+ test('NotActiveãªWebhookãŒè¿½åŠ ã•ã‚ŒãŸæ™‚ã€ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã«è¿½åŠ ã•れã¦ã„ãªã„', async () => {
+ const webhook = await service.createSystemWebhook(
+ {
+ isActive: false,
+ name: randomString(),
+ on: ['abuseReport'],
+ url: 'https://example.com',
+ secret: randomString(),
+ },
+ root,
+ );
+
+ // redisã§ã®é…ä¿¡çµŒç”±ã§æ›´æ–°ã•れるã®ã§ã¡ã‚‡ã£ã¨å¾…ã¤
+ await setTimeout(500);
+
+ const fetchedWebhooks = await service.fetchActiveSystemWebhooks();
+ expect(fetchedWebhooks).toEqual([]);
+ });
+ });
+
+ describe('systemWebhookUpdated', () => {
+ test('ActiveãªWebhookãŒç·¨é›†ã•ã‚ŒãŸæ™‚ã€ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã«å映ã•れã¦ã„ã‚‹', async () => {
+ const id = idService.gen();
+ await createWebhook({ id });
+ // キャッシュ作æˆ
+ const webhook1 = await service.fetchActiveSystemWebhooks();
+ // 読ã¿è¾¼ã¾ã‚Œã¦ã„ã‚‹ã“ã¨ã‚’ãƒã‚§ãƒƒã‚¯
+ expect(webhook1.length).toEqual(1);
+ expect(webhook1[0].id).toEqual(id);
+
+ const webhook2 = await service.updateSystemWebhook(
+ {
+ id,
+ isActive: true,
+ name: randomString(),
+ on: ['abuseReport'],
+ url: 'https://example.com',
+ secret: randomString(),
+ },
+ root,
+ );
+
+ // redisã§ã®é…ä¿¡çµŒç”±ã§æ›´æ–°ã•れるã®ã§ã¡ã‚‡ã£ã¨å¾…ã¤
+ await setTimeout(500);
+
+ const fetchedWebhooks = await service.fetchActiveSystemWebhooks();
+ expect(fetchedWebhooks).toEqual([webhook2]);
+ });
+
+ test('NotActiveãªWebhookãŒç·¨é›†ã•ã‚ŒãŸæ™‚ã€ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã«è¿½åŠ ã•れãªã„', async () => {
+ const id = idService.gen();
+ await createWebhook({ id, isActive: false });
+ // キャッシュ作æˆ
+ const webhook1 = await service.fetchActiveSystemWebhooks();
+ // 読ã¿è¾¼ã¾ã‚Œã¦ã„ãªã„ã“ã¨ã‚’ãƒã‚§ãƒƒã‚¯
+ expect(webhook1.length).toEqual(0);
+
+ const webhook2 = await service.updateSystemWebhook(
+ {
+ id,
+ isActive: false,
+ name: randomString(),
+ on: ['abuseReport'],
+ url: 'https://example.com',
+ secret: randomString(),
+ },
+ root,
+ );
+
+ // redisã§ã®é…ä¿¡çµŒç”±ã§æ›´æ–°ã•れるã®ã§ã¡ã‚‡ã£ã¨å¾…ã¤
+ await setTimeout(500);
+
+ const fetchedWebhooks = await service.fetchActiveSystemWebhooks();
+ expect(fetchedWebhooks.length).toEqual(0);
+ });
+
+ test('NotActiveãªWebhookãŒActiveã«ã•ã‚ŒãŸæ™‚ã€ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã«è¿½åŠ ã•れã¦ã„ã‚‹', async () => {
+ const id = idService.gen();
+ const baseWebhook = await createWebhook({ id, isActive: false });
+ // キャッシュ作æˆ
+ const webhook1 = await service.fetchActiveSystemWebhooks();
+ // 読ã¿è¾¼ã¾ã‚Œã¦ã„ãªã„ã“ã¨ã‚’ãƒã‚§ãƒƒã‚¯
+ expect(webhook1.length).toEqual(0);
+
+ const webhook2 = await service.updateSystemWebhook(
+ {
+ ...baseWebhook,
+ isActive: true,
+ },
+ root,
+ );
+
+ // redisã§ã®é…ä¿¡çµŒç”±ã§æ›´æ–°ã•れるã®ã§ã¡ã‚‡ã£ã¨å¾…ã¤
+ await setTimeout(500);
+
+ const fetchedWebhooks = await service.fetchActiveSystemWebhooks();
+ expect(fetchedWebhooks).toEqual([webhook2]);
+ });
+
+ test('ActiveãªWebhookãŒNotActiveã«ã•ã‚ŒãŸæ™‚ã€ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã‹ã‚‰å‰Šé™¤ã•れã¦ã„ã‚‹', async () => {
+ const id = idService.gen();
+ const baseWebhook = await createWebhook({ id, isActive: true });
+ // キャッシュ作æˆ
+ const webhook1 = await service.fetchActiveSystemWebhooks();
+ // 読ã¿è¾¼ã¾ã‚Œã¦ã„ã‚‹ã“ã¨ã‚’ãƒã‚§ãƒƒã‚¯
+ expect(webhook1.length).toEqual(1);
+ expect(webhook1[0].id).toEqual(id);
+
+ const webhook2 = await service.updateSystemWebhook(
+ {
+ ...baseWebhook,
+ isActive: false,
+ },
+ root,
+ );
+
+ // redisã§ã®é…ä¿¡çµŒç”±ã§æ›´æ–°ã•れるã®ã§ã¡ã‚‡ã£ã¨å¾…ã¤
+ await setTimeout(500);
+
+ const fetchedWebhooks = await service.fetchActiveSystemWebhooks();
+ expect(fetchedWebhooks.length).toEqual(0);
+ });
+ });
+
+ describe('systemWebhookDeleted', () => {
+ test('キャッシュã‹ã‚‰å‰Šé™¤ã•れã¦ã„ã‚‹', async () => {
+ const id = idService.gen();
+ const baseWebhook = await createWebhook({ id, isActive: true });
+ // キャッシュ作æˆ
+ const webhook1 = await service.fetchActiveSystemWebhooks();
+ // 読ã¿è¾¼ã¾ã‚Œã¦ã„ã‚‹ã“ã¨ã‚’ãƒã‚§ãƒƒã‚¯
+ expect(webhook1.length).toEqual(1);
+ expect(webhook1[0].id).toEqual(id);
+
+ const webhook2 = await service.deleteSystemWebhook(
+ id,
+ root,
+ );
+
+ // redisã§ã®é…ä¿¡çµŒç”±ã§æ›´æ–°ã•れるã®ã§ã¡ã‚‡ã£ã¨å¾…ã¤
+ await setTimeout(500);
+
+ const fetchedWebhooks = await service.fetchActiveSystemWebhooks();
+ expect(fetchedWebhooks.length).toEqual(0);
+ });
+ });
+ });
+ });
+});
diff --git a/packages/backend/test/unit/UserSearchService.ts b/packages/backend/test/unit/UserSearchService.ts
new file mode 100644
index 0000000000..7ea325d420
--- /dev/null
+++ b/packages/backend/test/unit/UserSearchService.ts
@@ -0,0 +1,265 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Test, TestingModule } from '@nestjs/testing';
+import { describe, jest, test } from '@jest/globals';
+import { In } from 'typeorm';
+import { UserSearchService } from '@/core/UserSearchService.js';
+import { FollowingsRepository, MiUser, UserProfilesRepository, UsersRepository } from '@/models/_.js';
+import { IdService } from '@/core/IdService.js';
+import { GlobalModule } from '@/GlobalModule.js';
+import { DI } from '@/di-symbols.js';
+import { UserEntityService } from '@/core/entities/UserEntityService.js';
+
+describe('UserSearchService', () => {
+ let app: TestingModule;
+ let service: UserSearchService;
+
+ let usersRepository: UsersRepository;
+ let followingsRepository: FollowingsRepository;
+ let idService: IdService;
+ let userProfilesRepository: UserProfilesRepository;
+
+ let root: MiUser;
+ let alice: MiUser;
+ let alyce: MiUser;
+ let alycia: MiUser;
+ let alysha: MiUser;
+ let alyson: MiUser;
+ let alyssa: MiUser;
+ let bob: MiUser;
+ let bobbi: MiUser;
+ let bobbie: MiUser;
+ let bobby: MiUser;
+
+ async function createUser(data: Partial<MiUser> = {}) {
+ const user = await usersRepository
+ .insert({
+ id: idService.gen(),
+ ...data,
+ })
+ .then(x => usersRepository.findOneByOrFail(x.identifiers[0]));
+
+ await userProfilesRepository.insert({
+ userId: user.id,
+ });
+
+ return user;
+ }
+
+ async function createFollowings(follower: MiUser, followees: MiUser[]) {
+ for (const followee of followees) {
+ await followingsRepository.insert({
+ id: idService.gen(),
+ followerId: follower.id,
+ followeeId: followee.id,
+ });
+ }
+ }
+
+ async function setActive(users: MiUser[]) {
+ for (const user of users) {
+ await usersRepository.update(user.id, {
+ updatedAt: new Date(),
+ });
+ }
+ }
+
+ async function setInactive(users: MiUser[]) {
+ for (const user of users) {
+ await usersRepository.update(user.id, {
+ updatedAt: new Date(0),
+ });
+ }
+ }
+
+ async function setSuspended(users: MiUser[]) {
+ for (const user of users) {
+ await usersRepository.update(user.id, {
+ isSuspended: true,
+ });
+ }
+ }
+
+ beforeAll(async () => {
+ app = await Test
+ .createTestingModule({
+ imports: [
+ GlobalModule,
+ ],
+ providers: [
+ UserSearchService,
+ {
+ provide: UserEntityService, useFactory: jest.fn(() => ({
+ // ã¨ã‚Šã‚ãˆãšIDãŒè¿”れã°ç¢ºèªãŒå‡ºæ¥ã‚‹ã®ã§
+ packMany: (value: any) => value,
+ })),
+ },
+ IdService,
+ ],
+ })
+ .compile();
+
+ await app.init();
+
+ usersRepository = app.get(DI.usersRepository);
+ userProfilesRepository = app.get(DI.userProfilesRepository);
+ followingsRepository = app.get(DI.followingsRepository);
+
+ service = app.get(UserSearchService);
+ idService = app.get(IdService);
+ });
+
+ beforeEach(async () => {
+ root = await createUser({ username: 'root', usernameLower: 'root', isRoot: true });
+ alice = await createUser({ username: 'Alice', usernameLower: 'alice' });
+ alyce = await createUser({ username: 'Alyce', usernameLower: 'alyce' });
+ alycia = await createUser({ username: 'Alycia', usernameLower: 'alycia' });
+ alysha = await createUser({ username: 'Alysha', usernameLower: 'alysha' });
+ alyson = await createUser({ username: 'Alyson', usernameLower: 'alyson', host: 'example.com' });
+ alyssa = await createUser({ username: 'Alyssa', usernameLower: 'alyssa', host: 'example.com' });
+ bob = await createUser({ username: 'Bob', usernameLower: 'bob' });
+ bobbi = await createUser({ username: 'Bobbi', usernameLower: 'bobbi' });
+ bobbie = await createUser({ username: 'Bobbie', usernameLower: 'bobbie', host: 'example.com' });
+ bobby = await createUser({ username: 'Bobby', usernameLower: 'bobby', host: 'example.com' });
+ });
+
+ afterEach(async () => {
+ await usersRepository.delete({});
+ });
+
+ afterAll(async () => {
+ await app.close();
+ });
+
+ describe('search', () => {
+ test('フォロー中ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ–ユーザã®ã†ã¡ã€"al"ã‹ã‚‰å§‹ã¾ã‚‹äººãŒå…¨å“¡ãƒ’ットã™ã‚‹', async () => {
+ await createFollowings(root, [alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]);
+ await setActive([alice, alyce, alyssa, bob, bobbi, bobbie, bobby]);
+ await setInactive([alycia, alysha, alyson]);
+
+ const result = await service.search(
+ { username: 'al' },
+ { limit: 100 },
+ root,
+ );
+
+ // alycia, alysha, alysonã¯éžã‚¢ã‚¯ãƒ†ã‚£ãƒ–ãªã®ã§å¾Œã‚ã«è¡Œã
+ expect(result).toEqual([alice, alyce, alyssa, alycia, alysha, alyson].map(x => x.id));
+ });
+
+ test('フォロー中ã®éžã‚¢ã‚¯ãƒ†ã‚£ãƒ–ユーザã®ã†ã¡ã€"al"ã‹ã‚‰å§‹ã¾ã‚‹äººãŒå…¨å“¡ãƒ’ットã™ã‚‹', async () => {
+ await createFollowings(root, [alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]);
+ await setInactive([alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]);
+
+ const result = await service.search(
+ { username: 'al' },
+ { limit: 100 },
+ root,
+ );
+
+ // alice, alyceã¯ãƒ•ォローã—ã¦ã„ãªã„ã®ã§å¾Œã‚ã«è¡Œã
+ expect(result).toEqual([alycia, alysha, alyson, alyssa, alice, alyce].map(x => x.id));
+ });
+
+ test('フォローã—ã¦ã„ãªã„アクティブユーザã®ã†ã¡ã€"al"ã‹ã‚‰å§‹ã¾ã‚‹äººãŒå…¨å“¡ãƒ’ットã™ã‚‹', async () => {
+ await setActive([alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]);
+ await setInactive([alice, alyce, alycia]);
+
+ const result = await service.search(
+ { username: 'al' },
+ { limit: 100 },
+ root,
+ );
+
+ // alice, alyce, alyciaã¯éžã‚¢ã‚¯ãƒ†ã‚£ãƒ–ãªã®ã§å¾Œã‚ã«è¡Œã
+ expect(result).toEqual([alysha, alyson, alyssa, alice, alyce, alycia].map(x => x.id));
+ });
+
+ test('フォローã—ã¦ã„ãªã„éžã‚¢ã‚¯ãƒ†ã‚£ãƒ–ユーザã®ã†ã¡ã€"al"ã‹ã‚‰å§‹ã¾ã‚‹äººãŒå…¨å“¡ãƒ’ットã™ã‚‹', async () => {
+ await setInactive([alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]);
+
+ const result = await service.search(
+ { username: 'al' },
+ { limit: 100 },
+ root,
+ );
+
+ expect(result).toEqual([alice, alyce, alycia, alysha, alyson, alyssa].map(x => x.id));
+ });
+
+ test('フォロー(アクティブ)ã€ãƒ•ォロー(éžã‚¢ã‚¯ãƒ†ã‚£ãƒ–)ã€éžãƒ•ォロー(アクティブ)ã€éžãƒ•ォロー(éžã‚¢ã‚¯ãƒ†ã‚£ãƒ–)混在時ã®å„ªå…ˆé †ä½åº¦ç¢ºèª', async () => {
+ await createFollowings(root, [alyson, alyssa, bob, bobbi, bobbie]);
+ await setActive([root, alyssa, bob, bobbi, alyce, alycia]);
+ await setInactive([alyson, alice, alysha, bobbie, bobby]);
+
+ const result = await service.search(
+ { },
+ { limit: 100 },
+ root,
+ );
+
+ // 見る用
+ // const users = await usersRepository.findBy({ id: In(result) }).then(it => new Map(it.map(x => [x.id, x])));
+ // console.log(result.map(x => users.get(x as any)).map(it => it?.username));
+
+ // フォローã—ã¦ã¦ã‚¢ã‚¯ãƒ†ã‚£ãƒ–ãªã®ã§å…ˆé ­: alyssa, bob, bobbi
+ // フォローã—ã¦ã¦éžã‚¢ã‚¯ãƒ†ã‚£ãƒ–ãªã®ã§æ¬¡: alyson, bobbie
+ // フォローã—ã¦ãªã„ã‘ã©ã‚¢ã‚¯ãƒ†ã‚£ãƒ–ãªã®ã§æ¬¡: alyce, alycia, root(アルファベット順的ã«ã“ã“ã«ãªã‚‹)
+ // フォローã—ã¦ãªã„ã—éžã‚¢ã‚¯ãƒ†ã‚£ãƒ–ãªã®ã§æœ€å¾Œ: alice, alysha, bobby
+ expect(result).toEqual([alyssa, bob, bobbi, alyson, bobbie, alyce, alycia, root, alice, alysha, bobby].map(x => x.id));
+ });
+
+ test('[éžãƒ­ã‚°ã‚¤ãƒ³] アクティブユーザã®ã†ã¡ã€"al"ã‹ã‚‰å§‹ã¾ã‚‹äººãŒå…¨å“¡ãƒ’ットã™ã‚‹', async () => {
+ await setActive([alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]);
+ await setInactive([alice, alyce, alycia]);
+
+ const result = await service.search(
+ { username: 'al' },
+ { limit: 100 },
+ );
+
+ // alice, alyce, alyciaã¯éžã‚¢ã‚¯ãƒ†ã‚£ãƒ–ãªã®ã§å¾Œã‚ã«è¡Œã
+ expect(result).toEqual([alysha, alyson, alyssa, alice, alyce, alycia].map(x => x.id));
+ });
+
+ test('[éžãƒ­ã‚°ã‚¤ãƒ³] éžã‚¢ã‚¯ãƒ†ã‚£ãƒ–ユーザã®ã†ã¡ã€"al"ã‹ã‚‰å§‹ã¾ã‚‹äººãŒå…¨å“¡ãƒ’ットã™ã‚‹', async () => {
+ await setInactive([alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]);
+
+ const result = await service.search(
+ { username: 'al' },
+ { limit: 100 },
+ );
+
+ expect(result).toEqual([alice, alyce, alycia, alysha, alyson, alyssa].map(x => x.id));
+ });
+
+ test('フォロー中ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ–ユーザã®ã†ã¡ã€"al"ã‹ã‚‰å§‹ã¾ã‚Š"example.com"ã«ã„る人ãŒå…¨å“¡ãƒ’ットã™ã‚‹', async () => {
+ await createFollowings(root, [alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]);
+ await setActive([alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]);
+
+ const result = await service.search(
+ { username: 'al', host: 'exam' },
+ { limit: 100 },
+ root,
+ );
+
+ expect(result).toEqual([alyson, alyssa].map(x => x.id));
+ });
+
+ test('サスペンド済ã¿ãƒ¦ãƒ¼ã‚¶ã¯å‡ºãªã„', async () => {
+ await setActive([alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]);
+ await setSuspended([alice, alyce, alycia]);
+
+ const result = await service.search(
+ { username: 'al' },
+ { limit: 100 },
+ root,
+ );
+
+ expect(result).toEqual([alysha, alyson, alyssa].map(x => x.id));
+ });
+ });
+});
diff --git a/packages/backend/test/utils.ts b/packages/backend/test/utils.ts
index 86814fffe0..26de19eaf1 100644
--- a/packages/backend/test/utils.ts
+++ b/packages/backend/test/utils.ts
@@ -12,11 +12,14 @@ import WebSocket, { ClientOptions } from 'ws';
import fetch, { File, RequestInit, type Headers } from 'node-fetch';
import { DataSource } from 'typeorm';
import { JSDOM } from 'jsdom';
-import { DEFAULT_POLICIES } from '@/core/RoleService.js';
-import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js';
+import { type Response } from 'node-fetch';
+import Fastify from 'fastify';
import { entities } from '../src/postgres.js';
import { loadConfig } from '../src/config.js';
import type * as misskey from 'misskey-js';
+import { DEFAULT_POLICIES } from '@/core/RoleService.js';
+import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js';
+import { ApiError } from '@/server/api/error.js';
export { server as startServer, jobQueue as startJobQueue } from '@/boot/common.js';
@@ -25,11 +28,23 @@ export interface UserToken {
bearer?: boolean;
}
+export type SystemWebhookPayload = {
+ server: string;
+ hookId: string;
+ eventId: string;
+ createdAt: string;
+ type: string;
+ body: any;
+}
+
const config = loadConfig();
export const port = config.port;
export const origin = config.url;
export const host = new URL(config.url).host;
+export const WEBHOOK_HOST = 'http://localhost:15080';
+export const WEBHOOK_PORT = 15080;
+
export const cookie = (me: UserToken): string => {
return `token=${me.token};`;
};
@@ -47,27 +62,28 @@ export const successfulApiCall = async <E extends keyof misskey.Endpoints, P ext
const res = await api(endpoint, parameters, user);
const status = assertion.status ?? (res.body == null ? 204 : 200);
assert.strictEqual(res.status, status, inspect(res.body, { depth: 5, colors: true }));
- return res.body;
+
+ return res.body as misskey.api.SwitchCaseResponseType<E, P>;
};
-export const failedApiCall = async <T, E extends keyof misskey.Endpoints, P extends misskey.Endpoints[E]['req']>(request: ApiRequest<E, P>, assertion: {
+export const failedApiCall = async <E extends keyof misskey.Endpoints, P extends misskey.Endpoints[E]['req']>(request: ApiRequest<E, P>, assertion: {
status: number,
code: string,
id: string
-}): Promise<T> => {
+}): Promise<void> => {
const { endpoint, parameters, user } = request;
const { status, code, id } = assertion;
const res = await api(endpoint, parameters, user);
assert.strictEqual(res.status, status, inspect(res.body));
- assert.strictEqual(res.body.error.code, code, inspect(res.body));
- assert.strictEqual(res.body.error.id, id, inspect(res.body));
- return res.body;
+ assert.ok(res.body);
+ assert.strictEqual(castAsError(res.body as any).error.code, code, inspect(res.body));
+ assert.strictEqual(castAsError(res.body as any).error.id, id, inspect(res.body));
};
-export const api = async <E extends keyof misskey.Endpoints>(path: E, params: misskey.Endpoints[E]['req'], me?: UserToken): Promise<{
+export const api = async <E extends keyof misskey.Endpoints, P extends misskey.Endpoints[E]['req']>(path: E, params: P, me?: UserToken): Promise<{
status: number,
headers: Headers,
- body: any
+ body: misskey.api.SwitchCaseResponseType<E, P>
}> => {
const bodyAuth: Record<string, string> = {};
const headers: Record<string, string> = {
@@ -88,13 +104,14 @@ export const api = async <E extends keyof misskey.Endpoints>(path: E, params: mi
});
const body = res.headers.get('content-type') === 'application/json; charset=utf-8'
- ? await res.json()
+ ? await res.json() as misskey.api.SwitchCaseResponseType<E, P>
: null;
return {
status: res.status,
headers: res.headers,
- body,
+ // FIXME: removing this non-null assertion: requires better typing around empty response.
+ body: body!,
};
};
@@ -140,7 +157,8 @@ export const post = async (user: UserToken, params: misskey.Endpoints['notes/cre
const res = await api('notes/create', q, user);
- return res.body ? res.body.createdNote : null;
+ // FIXME: the return type should reflect this fact.
+ return (res.body ? res.body.createdNote : null)!;
};
export const createAppToken = async (user: UserToken, permissions: (typeof misskey.permissions)[number][]) => {
@@ -296,7 +314,7 @@ export const uploadFile = async (user?: UserToken, { path, name, blob }: UploadO
body: misskey.entities.DriveFile | null
}> => {
const absPath = path == null
- ? new URL('resources/Lenna.jpg', import.meta.url)
+ ? new URL('resources/192.jpg', import.meta.url)
: isAbsolute(path.toString())
? new URL(path)
: new URL(path, new URL('resources/', import.meta.url));
@@ -454,7 +472,7 @@ export type SimpleGetResponse = {
type: string | null,
location: string | null
};
-export const simpleGet = async (path: string, accept = '*/*', cookie: any = undefined): Promise<SimpleGetResponse> => {
+export const simpleGet = async (path: string, accept = '*/*', cookie: any = undefined, bodyExtractor: (res: Response) => Promise<string | null> = _ => Promise.resolve(null)): Promise<SimpleGetResponse> => {
const res = await relativeFetch(path, {
headers: {
Accept: accept,
@@ -482,7 +500,7 @@ export const simpleGet = async (path: string, accept = '*/*', cookie: any = unde
const body =
jsonTypes.includes(res.headers.get('content-type') ?? '') ? await res.json() :
htmlTypes.includes(res.headers.get('content-type') ?? '') ? new JSDOM(await res.text()) :
- null;
+ await bodyExtractor(res);
return {
status: res.status,
@@ -604,14 +622,6 @@ export async function initTestDb(justBorrow = false, initEntities?: any[]) {
return db;
}
-export function sleep(msec: number) {
- return new Promise<void>(res => {
- setTimeout(() => {
- res();
- }, msec);
- });
-}
-
export async function sendEnvUpdateRequest(params: { key: string, value?: string }) {
const res = await fetch(
`http://localhost:${port + 1000}/env`,
@@ -642,3 +652,43 @@ export async function sendEnvResetRequest() {
throw new Error('server env update failed.');
}
}
+
+// 与ãˆã‚‰ã‚ŒãŸå€¤ã‚’強制的ã«ã‚¨ãƒ©ãƒ¼ã¨ã¿ãªã™ã€‚ã“ã®é–¢æ•°ã¯åž‹å®‰å…¨æ€§ã‚’破壊ã™ã‚‹ãŸã‚ã€ç•°å¸¸ç³»ã®ã‚¢ã‚µãƒ¼ã‚·ãƒ§ãƒ³ä»¥å¤–ã§ç”¨ã„られるã¹ãã§ã¯ãªã„。
+// FIXME(misskey-js): misskey-jsãŒã‚¨ãƒ©ãƒ¼æƒ…報を公開ã™ã‚‹ã‚ˆã†ã«ãªã£ãŸã‚‰ã“ã®é–¢æ•°ã‚’廃止ã™ã‚‹
+export function castAsError(obj: Record<string, unknown>): { error: ApiError } {
+ return obj as { error: ApiError };
+}
+
+export async function captureWebhook<T = SystemWebhookPayload>(postAction: () => Promise<void>, port = WEBHOOK_PORT): Promise<T> {
+ const fastify = Fastify();
+
+ let timeoutHandle: NodeJS.Timeout | null = null;
+ const result = await new Promise<string>(async (resolve, reject) => {
+ fastify.all('/', async (req, res) => {
+ timeoutHandle && clearTimeout(timeoutHandle);
+
+ const body = JSON.stringify(req.body);
+ res.status(200).send('ok');
+ await fastify.close();
+ resolve(body);
+ });
+
+ await fastify.listen({ port });
+
+ timeoutHandle = setTimeout(async () => {
+ await fastify.close();
+ reject(new Error('timeout'));
+ }, 3000);
+
+ try {
+ await postAction();
+ } catch (e) {
+ await fastify.close();
+ reject(e);
+ }
+ });
+
+ await fastify.close();
+
+ return JSON.parse(result) as T;
+}
diff --git a/packages/frontend/.eslintrc.cjs b/packages/frontend/.eslintrc.cjs
deleted file mode 100644
index 20f88dc078..0000000000
--- a/packages/frontend/.eslintrc.cjs
+++ /dev/null
@@ -1,82 +0,0 @@
-module.exports = {
- root: true,
- env: {
- 'node': false,
- },
- parser: 'vue-eslint-parser',
- parserOptions: {
- 'parser': '@typescript-eslint/parser',
- tsconfigRootDir: __dirname,
- project: ['./tsconfig.json'],
- extraFileExtensions: ['.vue'],
- },
- extends: [
- '../shared/.eslintrc.js',
- 'plugin:vue/vue3-recommended',
- ],
- rules: {
- '@typescript-eslint/no-empty-interface': [
- 'error',
- {
- 'allowSingleExtends': true,
- },
- ],
- // window ã®ç¦æ­¢ç†ç”±: グローãƒãƒ«ã‚¹ã‚³ãƒ¼ãƒ—ã¨è¡çªã—ã€äºˆæœŸã›ã¬çµæžœã‚’æ‹›ããŸã‚
- // e ã®ç¦æ­¢ç†ç”±: error ã‚„ event ãªã©ã€è¤‡æ•°ã®ã‚­ãƒ¼ãƒ¯ãƒ¼ãƒ‰ã®é ­æ–‡å­—ã§ã‚り分ã‹ã‚Šã«ãã„ãŸã‚
- 'id-denylist': ['error', 'window', 'e'],
- 'no-shadow': ['warn'],
- 'vue/attributes-order': ['error', {
- 'alphabetical': false,
- }],
- 'vue/no-use-v-if-with-v-for': ['error', {
- 'allowUsingIterationVar': false,
- }],
- 'vue/no-ref-as-operand': 'error',
- 'vue/no-multi-spaces': ['error', {
- 'ignoreProperties': false,
- }],
- 'vue/no-v-html': 'warn',
- 'vue/order-in-components': 'error',
- 'vue/html-indent': ['warn', 'tab', {
- 'attribute': 1,
- 'baseIndent': 0,
- 'closeBracket': 0,
- 'alignAttributesVertically': true,
- 'ignores': [],
- }],
- 'vue/html-closing-bracket-spacing': ['warn', {
- 'startTag': 'never',
- 'endTag': 'never',
- 'selfClosingTag': 'never',
- }],
- 'vue/multi-word-component-names': 'warn',
- 'vue/require-v-for-key': 'warn',
- 'vue/no-unused-components': 'warn',
- 'vue/no-unused-vars': 'warn',
- 'vue/no-dupe-keys': 'warn',
- 'vue/valid-v-for': 'warn',
- 'vue/return-in-computed-property': 'warn',
- 'vue/no-setup-props-destructure': 'warn',
- 'vue/max-attributes-per-line': 'off',
- 'vue/html-self-closing': 'off',
- 'vue/singleline-html-element-content-newline': 'off',
- 'vue/v-on-event-hyphenation': ['error', 'never', { autofix: true }],
- 'vue/attribute-hyphenation': ['error', 'never'],
- },
- globals: {
- // Node.js
- 'module': false,
- 'require': false,
- '__dirname': false,
-
- // Misskey
- '_DEV_': false,
- '_LANGS_': false,
- '_VERSION_': false,
- '_ENV_': false,
- '_PERF_PREFIX_': false,
- '_DATA_TRANSFER_DRIVE_FILE_': false,
- '_DATA_TRANSFER_DRIVE_FOLDER_': false,
- '_DATA_TRANSFER_DECK_COLUMN_': false,
- },
-};
diff --git a/packages/frontend/.storybook/changes.ts b/packages/frontend/.storybook/changes.ts
index 7c70972e1e..1299910499 100644
--- a/packages/frontend/.storybook/changes.ts
+++ b/packages/frontend/.storybook/changes.ts
@@ -47,14 +47,12 @@ await fs.readFile(
)
)
.map((path) => path.replace(/(?:(?<=\.stories)\.(?:impl|meta)|\.msw)(?=\.ts$)/g, ''))
- .map((path) => (path.startsWith('.') ? path : `./${path}`))
);
if (
micromatch(Array.from(modules), [
'../../assets/**',
'../../fluent-emojis/**',
'../../locales/ja-JP.yml',
- '../../misskey-assets/**',
'assets/**',
'public/**',
'../../pnpm-lock.yaml',
diff --git a/packages/frontend/.storybook/charts.ts b/packages/frontend/.storybook/charts.ts
new file mode 100644
index 0000000000..5015012a82
--- /dev/null
+++ b/packages/frontend/.storybook/charts.ts
@@ -0,0 +1,48 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { DefaultBodyType, HttpResponse, HttpResponseResolver, JsonBodyType, PathParams, http } from 'msw';
+import seedrandom from 'seedrandom';
+import { action } from '@storybook/addon-actions';
+
+function getChartArray(seed: string, limit: number, option?: { accumulate?: boolean, mul?: number }): number[] {
+ const rng = seedrandom(seed);
+ const max = Math.floor(option?.mul ?? 250 * rng());
+ let accumulation = 0;
+ const array: number[] = [];
+ for (let i = 0; i < limit; i++) {
+ const num = Math.floor((max + 1) * rng());
+ if (option?.accumulate) {
+ accumulation += num;
+ array.unshift(accumulation);
+ } else {
+ array.push(num);
+ }
+ }
+ return array;
+}
+
+export function getChartResolver(fields: string[], option?: { accumulate?: boolean, mulMap?: Record<string, number> }): HttpResponseResolver<PathParams, DefaultBodyType, JsonBodyType> {
+ return ({ request }) => {
+ action(`GET ${request.url}`)();
+ const limitParam = new URL(request.url).searchParams.get('limit');
+ const limit = limitParam ? parseInt(limitParam) : 30;
+ const res = {};
+ for (const field of fields) {
+ const layers = field.split('.');
+ let current = res;
+ while (layers.length > 1) {
+ const currentKey = layers.shift()!;
+ if (current[currentKey] == null) current[currentKey] = {};
+ current = current[currentKey];
+ }
+ current[layers[0]] = getChartArray(field, limit, {
+ accumulate: option?.accumulate,
+ mul: option?.mulMap != null && field in option.mulMap ? option.mulMap[field] : undefined,
+ });
+ }
+ return HttpResponse.json(res);
+ };
+}
diff --git a/packages/frontend/.storybook/fakes.ts b/packages/frontend/.storybook/fakes.ts
index 3a24ccb248..ab04d3e60c 100644
--- a/packages/frontend/.storybook/fakes.ts
+++ b/packages/frontend/.storybook/fakes.ts
@@ -22,6 +22,55 @@ export function abuseUserReport() {
};
}
+export function channel(id = 'somechannelid', name = 'Some Channel', bannerUrl: string | null = 'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/fedi.jpg?raw=true'): entities.Channel {
+ return {
+ id,
+ createdAt: '2016-12-28T22:49:51.000Z',
+ lastNotedAt: '2016-12-28T22:49:51.000Z',
+ name,
+ description: null,
+ userId: null,
+ bannerUrl,
+ pinnedNoteIds: [],
+ color: '#000',
+ isArchived: false,
+ usersCount: 1,
+ notesCount: 1,
+ isSensitive: false,
+ allowRenoteToExternal: false,
+ };
+}
+
+export function clip(id = 'someclipid', name = 'Some Clip'): entities.Clip {
+ return {
+ id,
+ createdAt: '2016-12-28T22:49:51.000Z',
+ lastClippedAt: null,
+ userId: 'someuserid',
+ user: userLite(),
+ notesCount: undefined,
+ name,
+ description: 'Some clip description',
+ isPublic: false,
+ favoritedCount: 0,
+ };
+}
+
+export function emojiDetailed(id = 'someemojiid', name = 'some_emoji'): entities.EmojiDetailed {
+ return {
+ id,
+ aliases: ['alias1', 'alias2'],
+ name,
+ category: 'emojiCategory',
+ host: null,
+ url: '/client-assets/about-icon.png',
+ license: null,
+ isSensitive: false,
+ localOnly: false,
+ roleIdsThatCanBeUsedThisEmojiAsReaction: ['roleId1', 'roleId2'],
+ };
+}
+
export function galleryPost(isSensitive = false) {
return {
id: 'somepostid',
@@ -65,7 +114,65 @@ export function file(isSensitive = false) {
};
}
-export function userDetailed(id = 'someuserid', username = 'miskist', host = 'misskey-hub.net', name = 'Misskey User'): entities.UserDetailed {
+export function folder(id = 'somefolderid', name = 'Some Folder', parentId: string | null = null): entities.DriveFolder {
+ return {
+ id,
+ createdAt: '2016-12-28T22:49:51.000Z',
+ name,
+ parentId,
+ };
+}
+
+export function federationInstance(): entities.FederationInstance {
+ return {
+ id: 'someinstanceid',
+ firstRetrievedAt: '2021-01-01T00:00:00.000Z',
+ host: 'misskey-hub.net',
+ usersCount: 10,
+ notesCount: 20,
+ followingCount: 5,
+ followersCount: 15,
+ isNotResponding: false,
+ isSuspended: false,
+ suspensionState: 'none',
+ isBlocked: false,
+ softwareName: 'misskey',
+ softwareVersion: '2024.5.0',
+ openRegistrations: false,
+ name: 'Misskey Hub',
+ description: '',
+ maintainerName: '',
+ maintainerEmail: '',
+ isSilenced: false,
+ iconUrl: 'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/about-icon.png?raw=true',
+ faviconUrl: '',
+ themeColor: '',
+ infoUpdatedAt: '',
+ latestRequestReceivedAt: '',
+ };
+}
+
+export function note(id = 'somenoteid'): entities.Note {
+ return {
+ id,
+ createdAt: '2016-12-28T22:49:51.000Z',
+ deletedAt: null,
+ text: 'some note',
+ cw: null,
+ userId: 'someuserid',
+ user: userLite(),
+ visibility: 'public',
+ reactionAcceptance: 'nonSensitiveOnly',
+ reactionEmojis: {},
+ reactions: {},
+ myReaction: null,
+ reactionCount: 0,
+ renoteCount: 0,
+ repliesCount: 0,
+ };
+}
+
+export function userLite(id = 'someuserid', username = 'miskist', host: entities.UserDetailed['host'] = 'misskey-hub.net', name: entities.UserDetailed['name'] = 'Misskey User'): entities.UserLite {
return {
id,
username,
@@ -76,6 +183,12 @@ export function userDetailed(id = 'someuserid', username = 'miskist', host = 'mi
avatarBlurhash: 'eQFRshof5NWBRi},juayfPju53WB?0ofs;s*a{ofjuay^SoMEJR%ay',
avatarDecorations: [],
emojis: {},
+ };
+}
+
+export function userDetailed(id = 'someuserid', username = 'miskist', host: entities.UserDetailed['host'] = 'misskey-hub.net', name: entities.UserDetailed['name'] = 'Misskey User'): entities.UserDetailed {
+ return {
+ ...userLite(id, username, host, name),
bannerBlurhash: 'eQA^IW^-MH8w9tE8I=S^o{$*R4RikXtSxutRozjEnNR.RQadoyozog',
bannerUrl: 'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/fedi.jpg?raw=true',
birthday: '2014-06-20',
@@ -126,7 +239,7 @@ export function userDetailed(id = 'someuserid', username = 'miskist', host = 'mi
movedTo: null,
alsoKnownAs: null,
notify: 'none',
- memo: null
+ memo: null,
};
}
diff --git a/packages/frontend/.storybook/generate.tsx b/packages/frontend/.storybook/generate.tsx
index d74c83a500..52c01aaf70 100644
--- a/packages/frontend/.storybook/generate.tsx
+++ b/packages/frontend/.storybook/generate.tsx
@@ -397,13 +397,14 @@ function toStories(component: string): Promise<string> {
const globs = await Promise.all([
glob('src/components/global/Mk*.vue'),
glob('src/components/global/RouterView.vue'),
- glob('src/components/Mk{A,B}*.vue'),
- glob('src/components/MkDigitalClock.vue'),
+ glob('src/components/Mk[A-E]*.vue'),
glob('src/components/MkGalleryPostPreview.vue'),
glob('src/components/MkSignupServerRules.vue'),
glob('src/components/MkUserSetupDialog.vue'),
glob('src/components/MkUserSetupDialog.*.vue'),
+ glob('src/components/MkInstanceCardMini.vue'),
glob('src/components/MkInviteCode.vue'),
+ glob('src/pages/search.vue'),
glob('src/pages/user/home.vue'),
]);
const components = globs.flat();
diff --git a/packages/frontend/.storybook/main.ts b/packages/frontend/.storybook/main.ts
index d3822942cd..9f318cf449 100644
--- a/packages/frontend/.storybook/main.ts
+++ b/packages/frontend/.storybook/main.ts
@@ -15,6 +15,7 @@ const _dirname = fileURLToPath(new URL('.', import.meta.url));
const config = {
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
+ staticDirs: [{ from: '../assets', to: '/client-assets' }],
addons: [
getAbsolutePath('@storybook/addon-essentials'),
getAbsolutePath('@storybook/addon-interactions'),
diff --git a/packages/frontend/.storybook/preview.ts b/packages/frontend/.storybook/preview.ts
index 982a2979ac..d000a28232 100644
--- a/packages/frontend/.storybook/preview.ts
+++ b/packages/frontend/.storybook/preview.ts
@@ -3,11 +3,11 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
-import { FORCE_REMOUNT } from '@storybook/core-events';
+import { FORCE_RE_RENDER, FORCE_REMOUNT } from '@storybook/core-events';
import { addons } from '@storybook/preview-api';
import { type Preview, setup } from '@storybook/vue3';
import isChromatic from 'chromatic/isChromatic';
-import { initialize, mswDecorator } from 'msw-storybook-addon';
+import { initialize, mswLoader } from 'msw-storybook-addon';
import { userDetailed } from './fakes.js';
import locale from './locale.js';
import { commonHandlers, onUnhandledRequest } from './mocks.js';
@@ -16,7 +16,7 @@ import '../src/style.scss';
const appInitialized = Symbol();
-let lastStory = null;
+let lastStory: string | null = null;
let moduleInitialized = false;
let unobserve = () => {};
let misskeyOS = null;
@@ -110,7 +110,7 @@ const preview = {
}).catch(() => {});
Promise.all([resetIndexedDBPromise, resetDefaultStorePromise]).then(() => {
initLocalStorage();
- channel.emit(FORCE_REMOUNT, { storyId: context.id });
+ channel.emit(FORCE_RE_RENDER, { storyId: context.id });
});
}
const story = Story();
@@ -122,7 +122,6 @@ const preview = {
}
return story;
},
- mswDecorator,
(Story, context) => {
return {
setup() {
@@ -137,6 +136,7 @@ const preview = {
};
},
],
+ loaders: [mswLoader],
parameters: {
controls: {
exclude: /^__/,
diff --git a/packages/frontend/eslint.config.js b/packages/frontend/eslint.config.js
new file mode 100644
index 0000000000..dd8f03dac5
--- /dev/null
+++ b/packages/frontend/eslint.config.js
@@ -0,0 +1,95 @@
+import globals from 'globals';
+import tsParser from '@typescript-eslint/parser';
+import parser from 'vue-eslint-parser';
+import pluginVue from 'eslint-plugin-vue';
+import pluginMisskey from '@misskey-dev/eslint-plugin';
+import sharedConfig from '../shared/eslint.config.js';
+
+export default [
+ ...sharedConfig,
+ {
+ files: ['src/**/*.vue'],
+ ...pluginMisskey.configs.typescript,
+ },
+ ...pluginVue.configs['flat/recommended'],
+ {
+ files: ['src/**/*.{ts,vue}'],
+ languageOptions: {
+ globals: {
+ ...Object.fromEntries(Object.entries(globals.node).map(([key]) => [key, 'off'])),
+ ...globals.browser,
+
+ // Node.js
+ module: false,
+ require: false,
+ __dirname: false,
+
+ // Misskey
+ _DEV_: false,
+ _LANGS_: false,
+ _VERSION_: false,
+ _ENV_: false,
+ _PERF_PREFIX_: false,
+ _DATA_TRANSFER_DRIVE_FILE_: false,
+ _DATA_TRANSFER_DRIVE_FOLDER_: false,
+ _DATA_TRANSFER_DECK_COLUMN_: false,
+ },
+ parser,
+ parserOptions: {
+ extraFileExtensions: ['.vue'],
+ parser: tsParser,
+ project: ['./tsconfig.json'],
+ sourceType: 'module',
+ tsconfigRootDir: import.meta.dirname,
+ },
+ },
+ rules: {
+ '@typescript-eslint/no-empty-interface': ['error', {
+ allowSingleExtends: true,
+ }],
+ // window ã®ç¦æ­¢ç†ç”±: グローãƒãƒ«ã‚¹ã‚³ãƒ¼ãƒ—ã¨è¡çªã—ã€äºˆæœŸã›ã¬çµæžœã‚’æ‹›ããŸã‚
+ // e ã®ç¦æ­¢ç†ç”±: error ã‚„ event ãªã©ã€è¤‡æ•°ã®ã‚­ãƒ¼ãƒ¯ãƒ¼ãƒ‰ã®é ­æ–‡å­—ã§ã‚り分ã‹ã‚Šã«ãã„ãŸã‚
+ 'id-denylist': ['error', 'window', 'e'],
+ 'no-shadow': ['warn'],
+ 'vue/attributes-order': ['error', {
+ alphabetical: false,
+ }],
+ 'vue/no-use-v-if-with-v-for': ['error', {
+ allowUsingIterationVar: false,
+ }],
+ 'vue/no-ref-as-operand': 'error',
+ 'vue/no-multi-spaces': ['error', {
+ ignoreProperties: false,
+ }],
+ 'vue/no-v-html': 'warn',
+ 'vue/order-in-components': 'error',
+ 'vue/html-indent': ['warn', 'tab', {
+ attribute: 1,
+ baseIndent: 0,
+ closeBracket: 0,
+ alignAttributesVertically: true,
+ ignores: [],
+ }],
+ 'vue/html-closing-bracket-spacing': ['warn', {
+ startTag: 'never',
+ endTag: 'never',
+ selfClosingTag: 'never',
+ }],
+ 'vue/multi-word-component-names': 'warn',
+ 'vue/require-v-for-key': 'warn',
+ 'vue/no-unused-components': 'warn',
+ 'vue/no-unused-vars': 'warn',
+ 'vue/no-dupe-keys': 'warn',
+ 'vue/valid-v-for': 'warn',
+ 'vue/return-in-computed-property': 'warn',
+ 'vue/no-setup-props-reactivity-loss': 'warn',
+ 'vue/max-attributes-per-line': 'off',
+ 'vue/html-self-closing': 'off',
+ 'vue/singleline-html-element-content-newline': 'off',
+ 'vue/v-on-event-hyphenation': ['error', 'never', {
+ autofix: true,
+ }],
+ 'vue/attribute-hyphenation': ['error', 'never'],
+ },
+ },
+];
diff --git a/packages/frontend/package.json b/packages/frontend/package.json
index 56b824c0c5..244d117de2 100644
--- a/packages/frontend/package.json
+++ b/packages/frontend/package.json
@@ -22,26 +22,26 @@
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
"@misskey-dev/browser-image-resizer": "2024.1.0",
"@rollup/plugin-json": "6.1.0",
- "@rollup/plugin-replace": "5.0.5",
+ "@rollup/plugin-replace": "5.0.7",
"@rollup/pluginutils": "5.1.0",
- "@syuilo/aiscript": "0.18.0",
+ "@syuilo/aiscript": "0.19.0",
"@tabler/icons-webfont": "3.3.0",
"@twemoji/parser": "15.1.1",
- "@vitejs/plugin-vue": "5.0.4",
- "@vue/compiler-sfc": "3.4.26",
- "aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.9",
+ "@vitejs/plugin-vue": "5.1.0",
+ "@vue/compiler-sfc": "3.4.34",
+ "aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.11",
"astring": "1.8.6",
"broadcast-channel": "7.0.0",
"buraha": "0.0.1",
"canvas-confetti": "1.9.3",
- "chart.js": "4.4.2",
+ "chart.js": "4.4.3",
"chartjs-adapter-date-fns": "3.0.0",
"chartjs-chart-matrix": "2.0.1",
"chartjs-plugin-gradient": "0.6.1",
"chartjs-plugin-zoom": "2.0.1",
- "chromatic": "11.3.0",
- "compare-versions": "6.1.0",
- "cropperjs": "2.0.0-beta.5",
+ "chromatic": "11.5.6",
+ "compare-versions": "6.1.1",
+ "cropperjs": "2.0.0-rc.1",
"date-fns": "2.30.0",
"escape-regexp": "0.0.1",
"estree-walker": "3.0.3",
@@ -55,87 +55,87 @@
"misskey-bubble-game": "workspace:*",
"misskey-js": "workspace:*",
"misskey-reversi": "workspace:*",
- "photoswipe": "5.4.3",
+ "photoswipe": "5.4.4",
"punycode": "2.3.1",
- "rollup": "4.17.2",
+ "rollup": "4.19.1",
"sanitize-html": "2.13.0",
- "sass": "1.76.0",
- "shiki": "1.4.0",
+ "sass": "1.77.8",
+ "shiki": "1.12.0",
"strict-event-emitter-types": "2.0.0",
"textarea-caret": "3.1.0",
- "three": "0.164.1",
- "throttle-debounce": "5.0.0",
+ "three": "0.167.0",
+ "throttle-debounce": "5.0.2",
"tinycolor2": "1.6.0",
- "tsc-alias": "1.8.8",
+ "tsc-alias": "1.8.10",
"tsconfig-paths": "4.2.0",
- "typescript": "5.4.5",
- "uuid": "9.0.1",
- "v-code-diff": "1.11.0",
- "vite": "5.2.11",
- "vue": "3.4.26",
+ "typescript": "5.5.4",
+ "uuid": "10.0.0",
+ "v-code-diff": "1.12.0",
+ "vite": "5.3.5",
+ "vue": "3.4.34",
"vuedraggable": "next"
},
"devDependencies": {
- "@misskey-dev/eslint-plugin": "1.0.0",
"@misskey-dev/summaly": "5.1.0",
- "@storybook/addon-actions": "8.0.9",
- "@storybook/addon-essentials": "8.0.9",
- "@storybook/addon-interactions": "8.0.9",
- "@storybook/addon-links": "8.0.9",
- "@storybook/addon-mdx-gfm": "8.0.9",
- "@storybook/addon-storysource": "8.0.9",
- "@storybook/blocks": "8.0.9",
- "@storybook/components": "8.0.9",
- "@storybook/core-events": "8.0.9",
- "@storybook/manager-api": "8.0.9",
- "@storybook/preview-api": "8.0.9",
- "@storybook/react": "8.0.9",
- "@storybook/react-vite": "8.0.9",
- "@storybook/test": "8.0.9",
- "@storybook/theming": "8.0.9",
- "@storybook/types": "8.0.9",
- "@storybook/vue3": "8.0.9",
- "@storybook/vue3-vite": "8.0.9",
- "@testing-library/vue": "8.0.3",
+ "@storybook/addon-actions": "8.2.6",
+ "@storybook/addon-essentials": "8.2.6",
+ "@storybook/addon-interactions": "8.2.6",
+ "@storybook/addon-links": "8.2.6",
+ "@storybook/addon-mdx-gfm": "8.2.6",
+ "@storybook/addon-storysource": "8.2.6",
+ "@storybook/blocks": "8.2.6",
+ "@storybook/components": "8.2.6",
+ "@storybook/core-events": "8.2.6",
+ "@storybook/manager-api": "8.2.6",
+ "@storybook/preview-api": "8.2.6",
+ "@storybook/react": "8.2.6",
+ "@storybook/react-vite": "8.2.6",
+ "@storybook/test": "8.2.6",
+ "@storybook/theming": "8.2.6",
+ "@storybook/types": "8.2.6",
+ "@storybook/vue3": "8.2.6",
+ "@storybook/vue3-vite": "8.1.11",
+ "@testing-library/vue": "8.1.0",
"@types/escape-regexp": "0.0.3",
"@types/estree": "1.0.5",
- "@types/matter-js": "0.19.6",
- "@types/micromatch": "4.0.7",
- "@types/node": "20.12.7",
+ "@types/matter-js": "0.19.7",
+ "@types/micromatch": "4.0.9",
+ "@types/node": "20.14.12",
"@types/punycode": "2.1.4",
"@types/sanitize-html": "2.11.0",
+ "@types/seedrandom": "3.0.8",
"@types/throttle-debounce": "5.0.2",
"@types/tinycolor2": "1.4.6",
- "@types/uuid": "9.0.8",
- "@types/ws": "8.5.10",
- "@typescript-eslint/eslint-plugin": "7.7.1",
- "@typescript-eslint/parser": "7.7.1",
- "@vitest/coverage-v8": "0.34.6",
- "@vue/runtime-core": "3.4.26",
- "acorn": "8.11.3",
+ "@types/uuid": "10.0.0",
+ "@types/ws": "8.5.11",
+ "@typescript-eslint/eslint-plugin": "7.17.0",
+ "@typescript-eslint/parser": "7.17.0",
+ "@vitest/coverage-v8": "1.6.0",
+ "@vue/runtime-core": "3.4.34",
+ "acorn": "8.12.1",
"cross-env": "7.0.3",
- "cypress": "13.8.1",
- "eslint": "8.57.0",
+ "cypress": "13.13.1",
"eslint-plugin-import": "2.29.1",
- "eslint-plugin-vue": "9.25.0",
+ "eslint-plugin-vue": "9.27.0",
"fast-glob": "3.3.2",
"happy-dom": "10.0.3",
"intersection-observer": "0.12.2",
- "micromatch": "4.0.5",
- "msw": "2.2.14",
- "msw-storybook-addon": "2.0.1",
- "nodemon": "3.1.0",
- "prettier": "3.2.5",
+ "micromatch": "4.0.7",
+ "msw": "2.3.4",
+ "msw-storybook-addon": "2.0.3",
+ "nodemon": "3.1.4",
+ "prettier": "3.3.3",
"react": "18.3.1",
"react-dom": "18.3.1",
- "start-server-and-test": "2.0.3",
- "storybook": "8.0.9",
+ "seedrandom": "3.0.5",
+ "start-server-and-test": "2.0.4",
+ "storybook": "8.2.6",
"storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme",
"vite-plugin-turbosnap": "1.0.3",
- "vitest": "0.34.6",
+ "vitest": "1.6.0",
"vitest-fetch-mock": "0.2.2",
- "vue-component-type-helpers": "2.0.16",
- "vue-eslint-parser": "9.4.2",
- "vue-tsc": "2.0.16"
+ "vue-component-type-helpers": "2.0.29",
+ "vue-eslint-parser": "9.4.3",
+ "vue-tsc": "2.0.29"
}
}
diff --git a/packages/frontend/src/account.ts b/packages/frontend/src/account.ts
index 7f20e0b1a2..4172016f89 100644
--- a/packages/frontend/src/account.ts
+++ b/packages/frontend/src/account.ts
@@ -120,7 +120,7 @@ function fetchAccount(token: string, id?: string, forceShowDialog?: boolean): Pr
res.json().then(done2, fail2);
}))
.then(async res => {
- if (res.error) {
+ if ('error' in res) {
if (res.error.id === 'a8c724b3-6e9c-4b46-b1a8-bc3ed6258370') {
// SUSPENDED
if (forceShowDialog || $i && (token === $i.token || id === $i.id)) {
@@ -184,10 +184,12 @@ export async function refreshAccount() {
export async function login(token: Account['token'], redirect?: string) {
const showing = ref(true);
- popup(defineAsyncComponent(() => import('@/components/MkWaitingDialog.vue')), {
+ const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkWaitingDialog.vue')), {
success: false,
showing: showing,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
if (_DEV_) console.log('logging as token ', token);
const me = await fetchAccount(token, undefined, true)
.catch(reason => {
@@ -223,21 +225,23 @@ export async function openAccountMenu(opts: {
if (!$i) return;
function showSigninDialog() {
- popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), {}, {
+ const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), {}, {
done: res => {
addAccount(res.id, res.i);
success();
},
- }, 'closed');
+ closed: () => dispose(),
+ });
}
function createAccount() {
- popup(defineAsyncComponent(() => import('@/components/MkSignupDialog.vue')), {}, {
+ const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSignupDialog.vue')), {}, {
done: res => {
addAccount(res.id, res.i);
switchAccountWithToken(res.i);
},
- }, 'closed');
+ closed: () => dispose(),
+ });
}
async function switchAccount(account: Misskey.entities.UserDetailed) {
diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts
index 5cb19f388a..2a549d1e8b 100644
--- a/packages/frontend/src/boot/main-boot.ts
+++ b/packages/frontend/src/boot/main-boot.ts
@@ -5,6 +5,7 @@
import { createApp, defineAsyncComponent, markRaw } from 'vue';
import { common } from './common.js';
+import type * as Misskey from 'misskey-js';
import { ui } from '@/config.js';
import { i18n } from '@/i18n.js';
import { alert, confirm, popup, post, toast } from '@/os.js';
@@ -13,7 +14,6 @@ import * as sound from '@/scripts/sound.js';
import { $i, signout, updateAccount } from '@/account.js';
import { instance } from '@/instance.js';
import { ColdDeviceStorage, defaultStore } from '@/store.js';
-import { makeHotkey } from '@/scripts/hotkey.js';
import { reactionPicker } from '@/scripts/reaction-picker.js';
import { miLocalStorage } from '@/local-storage.js';
import { claimAchievement, claimedAchievements } from '@/scripts/achievements.js';
@@ -21,6 +21,7 @@ import { initializeSw } from '@/scripts/initialize-sw.js';
import { deckStore } from '@/ui/deck/deck-store.js';
import { emojiPicker } from '@/scripts/emoji-picker.js';
import { mainRouter } from '@/router/main.js';
+import { type Keymap, makeHotkey } from '@/scripts/hotkey.js';
export async function mainBoot() {
const { isClientUpdated } = await common(() => createApp(
@@ -35,7 +36,9 @@ export async function mainBoot() {
emojiPicker.init();
if (isClientUpdated && $i) {
- popup(defineAsyncComponent(() => import('@/components/MkUpdated.vue')), {}, {}, 'closed');
+ const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkUpdated.vue')), {}, {
+ closed: () => dispose(),
+ });
}
const stream = useStream();
@@ -67,14 +70,6 @@ export async function mainBoot() {
});
}
- const hotkeys = {
- 'd': (): void => {
- defaultStore.set('darkMode', !defaultStore.state.darkMode);
- },
- 's': (): void => {
- mainRouter.push('/search');
- },
- };
try {
if (defaultStore.state.enableSeasonalScreenEffect) {
const month = new Date().getMonth() + 1;
@@ -96,36 +91,41 @@ export async function mainBoot() {
}).render();
}
}
- }
+ }
} catch (error) {
// console.error(error);
console.error('Failed to initialise the seasonal screen effect canvas context:', error);
}
if ($i) {
- // only add post shortcuts if logged in
- hotkeys['p|n'] = post;
-
defaultStore.loaded.then(() => {
if (defaultStore.state.accountSetupWizard !== -1) {
- popup(defineAsyncComponent(() => import('@/components/MkUserSetupDialog.vue')), {}, {}, 'closed');
+ const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkUserSetupDialog.vue')), {}, {
+ closed: () => dispose(),
+ });
}
});
for (const announcement of ($i.unreadAnnouncements ?? []).filter(x => x.display === 'dialog')) {
- popup(defineAsyncComponent(() => import('@/components/MkAnnouncementDialog.vue')), {
+ const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkAnnouncementDialog.vue')), {
announcement,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
}
- stream.on('announcementCreated', (ev) => {
+ function onAnnouncementCreated (ev: { announcement: Misskey.entities.Announcement }) {
const announcement = ev.announcement;
if (announcement.display === 'dialog') {
- popup(defineAsyncComponent(() => import('@/components/MkAnnouncementDialog.vue')), {
+ const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkAnnouncementDialog.vue')), {
announcement,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
}
- });
+ }
+
+ stream.on('announcementCreated', onAnnouncementCreated);
if ($i.isDeleted) {
alert({
@@ -247,13 +247,17 @@ export async function mainBoot() {
const neverShowDonationInfo = miLocalStorage.getItem('neverShowDonationInfo');
if (neverShowDonationInfo !== 'true' && (createdAt.getTime() < (Date.now() - (1000 * 60 * 60 * 24 * 3))) && !location.pathname.startsWith('/miauth')) {
if (latestDonationInfoShownAt == null || (new Date(latestDonationInfoShownAt).getTime() < (Date.now() - (1000 * 60 * 60 * 24 * 30)))) {
- popup(defineAsyncComponent(() => import('@/components/MkDonation.vue')), {}, {}, 'closed');
+ const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkDonation.vue')), {}, {
+ closed: () => dispose(),
+ });
}
}
const modifiedVersionMustProminentlyOfferInAgplV3Section13Read = miLocalStorage.getItem('modifiedVersionMustProminentlyOfferInAgplV3Section13Read');
if (modifiedVersionMustProminentlyOfferInAgplV3Section13Read !== 'true' && instance.repositoryUrl !== 'https://github.com/misskey-dev/misskey') {
- popup(defineAsyncComponent(() => import('@/components/MkSourceCodeAvailablePopup.vue')), {}, {}, 'closed');
+ const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSourceCodeAvailablePopup.vue')), {}, {
+ closed: () => dispose(),
+ });
}
if ('Notification' in window) {
@@ -314,6 +318,9 @@ export async function mainBoot() {
updateAccount({ hasUnreadAnnouncement: false });
});
+ // 個人宛ã¦ãŠçŸ¥ã‚‰ã›ãŒç™ºè¡Œã•れãŸã¨ã
+ main.on('announcementCreated', onAnnouncementCreated);
+
// トークンãŒå†ç”Ÿæˆã•れãŸã¨ã
// ã“ã®ã¾ã¾ã§ã¯MisskeyãŒåˆ©ç”¨ã§ããªã„ã®ã§å¼·åˆ¶çš„ã«ã‚µã‚¤ãƒ³ã‚¢ã‚¦ãƒˆã•ã›ã‚‹
main.on('myTokenRegenerated', () => {
@@ -322,7 +329,19 @@ export async function mainBoot() {
}
// shortcut
- document.addEventListener('keydown', makeHotkey(hotkeys));
+ const keymap = {
+ 'p|n': () => {
+ if ($i == null) return;
+ post();
+ },
+ 'd': () => {
+ defaultStore.set('darkMode', !defaultStore.state.darkMode);
+ },
+ 's': () => {
+ mainRouter.push('/search');
+ },
+ } as const satisfies Keymap;
+ document.addEventListener('keydown', makeHotkey(keymap), { passive: false });
initializeSw();
}
diff --git a/packages/frontend/src/boot/sub-boot.ts b/packages/frontend/src/boot/sub-boot.ts
index 017457822b..35c84d5568 100644
--- a/packages/frontend/src/boot/sub-boot.ts
+++ b/packages/frontend/src/boot/sub-boot.ts
@@ -5,9 +5,12 @@
import { createApp, defineAsyncComponent } from 'vue';
import { common } from './common.js';
+import { emojiPicker } from '@/scripts/emoji-picker.js';
export async function subBoot() {
const { isClientUpdated } = await common(() => createApp(
defineAsyncComponent(() => import('@/ui/minimum.vue')),
));
+
+ emojiPicker.init();
}
diff --git a/packages/frontend/src/components/MkAchievements.vue b/packages/frontend/src/components/MkAchievements.vue
index 5d103fa789..c8134416b5 100644
--- a/packages/frontend/src/components/MkAchievements.vue
+++ b/packages/frontend/src/components/MkAchievements.vue
@@ -153,7 +153,7 @@ onMounted(() => {
background: linear-gradient(0deg, #ffee20, #eb7018);
}
- &:before {
+ &::before {
content: "";
display: block;
position: absolute;
@@ -173,7 +173,7 @@ onMounted(() => {
background: linear-gradient(0deg, #e1e1e1, #7c7c7c);
}
- &:before {
+ &::before {
content: "";
display: block;
position: absolute;
diff --git a/packages/frontend/src/components/MkAntennaEditor.stories.impl.ts b/packages/frontend/src/components/MkAntennaEditor.stories.impl.ts
new file mode 100644
index 0000000000..1749e07a4e
--- /dev/null
+++ b/packages/frontend/src/components/MkAntennaEditor.stories.impl.ts
@@ -0,0 +1,62 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+import { action } from '@storybook/addon-actions';
+import { StoryObj } from '@storybook/vue3';
+import { HttpResponse, http } from 'msw';
+import { commonHandlers } from '../../.storybook/mocks.js';
+import MkAntennaEditor from './MkAntennaEditor.vue';
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ MkAntennaEditor,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ events() {
+ return {
+ created: action('created'),
+ updated: action('updated'),
+ deleted: action('deleted'),
+ };
+ },
+ },
+ template: '<MkAntennaEditor v-bind="props" v-on="events" />',
+ };
+ },
+ args: {
+ },
+ parameters: {
+ layout: 'fullscreen',
+ msw: {
+ handlers: [
+ ...commonHandlers,
+ http.post('/api/antennas/create', async ({ request }) => {
+ action('POST /api/antennas/create')(await request.json());
+ return HttpResponse.json({});
+ }),
+ http.post('/api/antennas/update', async ({ request }) => {
+ action('POST /api/antennas/update')(await request.json());
+ return HttpResponse.json({});
+ }),
+ http.post('/api/antennas/delete', async ({ request }) => {
+ action('POST /api/antennas/delete')(await request.json());
+ return HttpResponse.json();
+ }),
+ ],
+ },
+ },
+} satisfies StoryObj<typeof MkAntennaEditor>;
diff --git a/packages/frontend/src/pages/my-antennas/editor.vue b/packages/frontend/src/components/MkAntennaEditor.vue
index 2949bfc02c..cb7ee3d6ca 100644
--- a/packages/frontend/src/pages/my-antennas/editor.vue
+++ b/packages/frontend/src/components/MkAntennaEditor.vue
@@ -41,8 +41,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkSwitch v-model="withFile">{{ i18n.ts.withFileAntenna }}</MkSwitch>
</div>
<div :class="$style.actions">
- <MkButton inline primary @click="saveAntenna()"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton>
- <MkButton v-if="antenna.id != null" inline danger @click="deleteAntenna()"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton>
+ <div class="_buttons">
+ <MkButton inline primary @click="saveAntenna()"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton>
+ <MkButton v-if="initialAntenna.id != null" inline danger @click="deleteAntenna()"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton>
+ </div>
</div>
</div>
</MkSpacer>
@@ -59,28 +61,53 @@ import MkSwitch from '@/components/MkSwitch.vue';
import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { i18n } from '@/i18n.js';
+import { deepMerge } from '@/scripts/merge.js';
+import type { DeepPartial } from '@/scripts/merge.js';
+
+type PartialAllowedAntenna = Omit<Misskey.entities.Antenna, 'id' | 'createdAt' | 'updatedAt'> & {
+ id?: string;
+ createdAt?: string;
+ updatedAt?: string;
+};
const props = defineProps<{
- antenna: Misskey.entities.Antenna
+ antenna?: DeepPartial<PartialAllowedAntenna>;
}>();
+const initialAntenna = deepMerge<PartialAllowedAntenna>(props.antenna ?? {}, {
+ name: '',
+ src: 'all',
+ userListId: null,
+ users: [],
+ keywords: [],
+ excludeKeywords: [],
+ excludeBots: false,
+ withReplies: false,
+ caseSensitive: false,
+ localOnly: false,
+ withFile: false,
+ isActive: true,
+ hasUnreadNote: false,
+ notify: false,
+});
+
const emit = defineEmits<{
- (ev: 'created'): void,
- (ev: 'updated'): void,
+ (ev: 'created', newAntenna: Misskey.entities.Antenna): void,
+ (ev: 'updated', editedAntenna: Misskey.entities.Antenna): void,
(ev: 'deleted'): void,
}>();
-const name = ref<string>(props.antenna.name);
-const src = ref<Misskey.entities.AntennasCreateRequest['src']>(props.antenna.src);
-const userListId = ref<string | null>(props.antenna.userListId);
-const users = ref<string>(props.antenna.users.join('\n'));
-const keywords = ref<string>(props.antenna.keywords.map(x => x.join(' ')).join('\n'));
-const excludeKeywords = ref<string>(props.antenna.excludeKeywords.map(x => x.join(' ')).join('\n'));
-const caseSensitive = ref<boolean>(props.antenna.caseSensitive);
-const localOnly = ref<boolean>(props.antenna.localOnly);
-const excludeBots = ref<boolean>(props.antenna.excludeBots);
-const withReplies = ref<boolean>(props.antenna.withReplies);
-const withFile = ref<boolean>(props.antenna.withFile);
+const name = ref<string>(initialAntenna.name);
+const src = ref<Misskey.entities.AntennasCreateRequest['src']>(initialAntenna.src);
+const userListId = ref<string | null>(initialAntenna.userListId);
+const users = ref<string>(initialAntenna.users.join('\n'));
+const keywords = ref<string>(initialAntenna.keywords.map(x => x.join(' ')).join('\n'));
+const excludeKeywords = ref<string>(initialAntenna.excludeKeywords.map(x => x.join(' ')).join('\n'));
+const caseSensitive = ref<boolean>(initialAntenna.caseSensitive);
+const localOnly = ref<boolean>(initialAntenna.localOnly);
+const excludeBots = ref<boolean>(initialAntenna.excludeBots);
+const withReplies = ref<boolean>(initialAntenna.withReplies);
+const withFile = ref<boolean>(initialAntenna.withFile);
const userLists = ref<Misskey.entities.UserList[] | null>(null);
watch(() => src.value, async () => {
@@ -104,24 +131,26 @@ async function saveAntenna() {
excludeKeywords: excludeKeywords.value.trim().split('\n').map(x => x.trim().split(' ')),
};
- if (props.antenna.id == null) {
- await os.apiWithDialog('antennas/create', antennaData);
- emit('created');
+ if (initialAntenna.id == null) {
+ const res = await os.apiWithDialog('antennas/create', antennaData);
+ emit('created', res);
} else {
- await os.apiWithDialog('antennas/update', { ...antennaData, antennaId: props.antenna.id });
- emit('updated');
+ const res = await os.apiWithDialog('antennas/update', { ...antennaData, antennaId: initialAntenna.id });
+ emit('updated', res);
}
}
async function deleteAntenna() {
+ if (initialAntenna.id == null) return;
+
const { canceled } = await os.confirm({
type: 'warning',
- text: i18n.tsx.removeAreYouSure({ x: props.antenna.name }),
+ text: i18n.tsx.removeAreYouSure({ x: initialAntenna.name }),
});
if (canceled) return;
await misskeyApi('antennas/delete', {
- antennaId: props.antenna.id,
+ antennaId: initialAntenna.id,
});
os.success();
diff --git a/packages/frontend/src/components/MkAntennaEditorDialog.stories.impl.ts b/packages/frontend/src/components/MkAntennaEditorDialog.stories.impl.ts
new file mode 100644
index 0000000000..1c6ca83b47
--- /dev/null
+++ b/packages/frontend/src/components/MkAntennaEditorDialog.stories.impl.ts
@@ -0,0 +1,63 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+import { action } from '@storybook/addon-actions';
+import { StoryObj } from '@storybook/vue3';
+import { HttpResponse, http } from 'msw';
+import { commonHandlers } from '../../.storybook/mocks.js';
+import MkAntennaEditorDialog from './MkAntennaEditorDialog.vue';
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ MkAntennaEditorDialog,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ events() {
+ return {
+ created: action('created'),
+ updated: action('updated'),
+ deleted: action('deleted'),
+ closed: action('closed'),
+ };
+ },
+ },
+ template: '<MkAntennaEditorDialog v-bind="props" v-on="events" />',
+ };
+ },
+ args: {
+ },
+ parameters: {
+ layout: 'centered',
+ msw: {
+ handlers: [
+ ...commonHandlers,
+ http.post('/api/antennas/create', async ({ request }) => {
+ action('POST /api/antennas/create')(await request.json());
+ return HttpResponse.json({});
+ }),
+ http.post('/api/antennas/update', async ({ request }) => {
+ action('POST /api/antennas/update')(await request.json());
+ return HttpResponse.json({});
+ }),
+ http.post('/api/antennas/delete', async ({ request }) => {
+ action('POST /api/antennas/delete')(await request.json());
+ return HttpResponse.json();
+ }),
+ ],
+ },
+ },
+} satisfies StoryObj<typeof MkAntennaEditorDialog>;
diff --git a/packages/frontend/src/components/MkAntennaEditorDialog.vue b/packages/frontend/src/components/MkAntennaEditorDialog.vue
new file mode 100644
index 0000000000..6d815d29f3
--- /dev/null
+++ b/packages/frontend/src/components/MkAntennaEditorDialog.vue
@@ -0,0 +1,63 @@
+<!--
+SPDX-FileCopyrightText: syuilo and misskey-project
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
+<template>
+<MkModalWindow
+ ref="dialog"
+ :withOkButton="false"
+ :width="500"
+ :height="550"
+ @close="close()"
+ @closed="emit('closed')"
+>
+ <template #header>{{ antenna == null ? i18n.ts.createAntenna : i18n.ts.editAntenna }}</template>
+ <XAntennaEditor
+ :antenna="antenna"
+ @created="onAntennaCreated"
+ @updated="onAntennaUpdated"
+ @deleted="onAntennaDeleted"
+ />
+</MkModalWindow>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef } from 'vue';
+import * as Misskey from 'misskey-js';
+import MkModalWindow from '@/components/MkModalWindow.vue';
+import XAntennaEditor from '@/components/MkAntennaEditor.vue';
+import { i18n } from '@/i18n.js';
+
+defineProps<{
+ antenna?: Misskey.entities.Antenna;
+}>();
+
+const emit = defineEmits<{
+ (ev: 'created', newAntenna: Misskey.entities.Antenna): void,
+ (ev: 'updated', editedAntenna: Misskey.entities.Antenna): void,
+ (ev: 'deleted'): void,
+ (ev: 'closed'): void,
+}>();
+
+const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
+
+function onAntennaCreated(newAntenna: Misskey.entities.Antenna) {
+ emit('created', newAntenna);
+ dialog.value?.close();
+}
+
+function onAntennaUpdated(editedAntenna: Misskey.entities.Antenna) {
+ emit('updated', editedAntenna);
+ dialog.value?.close();
+}
+
+function onAntennaDeleted() {
+ emit('deleted');
+ dialog.value?.close();
+}
+
+function close() {
+ dialog.value?.close();
+}
+</script>
diff --git a/packages/frontend/src/components/MkButton.vue b/packages/frontend/src/components/MkButton.vue
index 3489255b91..9560efb7d9 100644
--- a/packages/frontend/src/components/MkButton.vue
+++ b/packages/frontend/src/components/MkButton.vue
@@ -11,6 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:type="type"
:name="name"
:value="value"
+ :disabled="disabled"
@click="emit('click', $event)"
@mousedown="onMousedown"
>
@@ -55,6 +56,7 @@ const props = defineProps<{
asLike?: boolean;
name?: string;
value?: string;
+ disabled?: boolean;
}>();
const emit = defineEmits<{
@@ -248,7 +250,6 @@ function onMousedown(evt: MouseEvent): void {
}
&:focus-visible {
- outline: solid 2px var(--focus);
outline-offset: 2px;
}
diff --git a/packages/frontend/src/components/MkCaptcha.vue b/packages/frontend/src/components/MkCaptcha.vue
index c64bb47e77..c5b6e0caed 100644
--- a/packages/frontend/src/components/MkCaptcha.vue
+++ b/packages/frontend/src/components/MkCaptcha.vue
@@ -104,7 +104,6 @@ async function requestRender() {
});
} else if (props.provider === 'mcaptcha' && props.instanceUrl && props.sitekey) {
const { default: Widget } = await import('@mcaptcha/vanilla-glue');
- // @ts-expect-error avoid typecheck error
new Widget({
siteKey: {
instanceUrl: new URL(props.instanceUrl),
diff --git a/packages/frontend/src/components/MkChannelFollowButton.stories.impl.ts b/packages/frontend/src/components/MkChannelFollowButton.stories.impl.ts
new file mode 100644
index 0000000000..b9770670dc
--- /dev/null
+++ b/packages/frontend/src/components/MkChannelFollowButton.stories.impl.ts
@@ -0,0 +1,71 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+/* eslint-disable import/no-default-export */
+import { StoryObj } from '@storybook/vue3';
+import { HttpResponse, http } from 'msw';
+import { action } from '@storybook/addon-actions';
+import { expect, userEvent, within } from '@storybook/test';
+import { channel } from '../../.storybook/fakes.js';
+import { commonHandlers } from '../../.storybook/mocks.js';
+import MkChannelFollowButton from './MkChannelFollowButton.vue';
+import { i18n } from '@/i18n.js';
+
+function sleep(ms: number) {
+ return new Promise(resolve => setTimeout(resolve, ms));
+}
+
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ MkChannelFollowButton,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ },
+ template: '<MkChannelFollowButton v-bind="props" />',
+ };
+ },
+ args: {
+ channel: channel(),
+ full: true,
+ },
+ async play({ canvasElement }) {
+ const canvas = within(canvasElement);
+ const buttonElement = canvas.getByRole<HTMLButtonElement>('button');
+ await expect(buttonElement).toHaveTextContent(i18n.ts.follow);
+ await userEvent.click(buttonElement);
+ await sleep(1000);
+ await expect(buttonElement).toHaveTextContent(i18n.ts.unfollow);
+ await userEvent.click(buttonElement);
+ },
+ parameters: {
+ layout: 'centered',
+ msw: {
+ handlers: [
+ ...commonHandlers,
+ http.post('/api/channels/follow', async ({ request }) => {
+ action('POST /api/channels/follow')(await request.json());
+ return HttpResponse.json({});
+ }),
+ http.post('/api/channels/unfollow', async ({ request }) => {
+ action('POST /api/channels/unfollow')(await request.json());
+ return HttpResponse.json({});
+ }),
+ ],
+ },
+ },
+} satisfies StoryObj<typeof MkChannelFollowButton>;
diff --git a/packages/frontend/src/components/MkChannelFollowButton.vue b/packages/frontend/src/components/MkChannelFollowButton.vue
index 6b1b380e41..35dc3ad4bf 100644
--- a/packages/frontend/src/components/MkChannelFollowButton.vue
+++ b/packages/frontend/src/components/MkChannelFollowButton.vue
@@ -26,17 +26,18 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { ref } from 'vue';
+import * as Misskey from 'misskey-js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { i18n } from '@/i18n.js';
const props = withDefaults(defineProps<{
- channel: Record<string, any>;
+ channel: Misskey.entities.Channel;
full?: boolean;
}>(), {
full: false,
});
-const isFollowing = ref<boolean>(props.channel.isFollowing);
+const isFollowing = ref(props.channel.isFollowing);
const wait = ref(false);
async function onClick() {
@@ -86,17 +87,7 @@ async function onClick() {
}
&:focus-visible {
- &:after {
- content: "";
- pointer-events: none;
- position: absolute;
- top: -5px;
- right: -5px;
- bottom: -5px;
- left: -5px;
- border: 2px solid var(--focus);
- border-radius: 32px;
- }
+ outline-offset: 2px;
}
&:hover {
diff --git a/packages/frontend/src/components/MkChannelList.stories.impl.ts b/packages/frontend/src/components/MkChannelList.stories.impl.ts
new file mode 100644
index 0000000000..f69b20c049
--- /dev/null
+++ b/packages/frontend/src/components/MkChannelList.stories.impl.ts
@@ -0,0 +1,65 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+/* eslint-disable import/no-default-export */
+import { StoryObj } from '@storybook/vue3';
+import { HttpResponse, http } from 'msw';
+import { action } from '@storybook/addon-actions';
+import { channel } from '../../.storybook/fakes.js';
+import { commonHandlers } from '../../.storybook/mocks.js';
+import MkChannelList from './MkChannelList.vue';
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ MkChannelList,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ },
+ template: '<MkChannelList v-bind="props" />',
+ };
+ },
+ args: {
+ pagination: {
+ endpoint: 'channels/search',
+ limit: 10,
+ },
+ },
+ parameters: {
+ chromatic: {
+ // NOTE: ロードãŒçµ‚ã‚ã‚‹ã¾ã§å¾…ã¤
+ delay: 3000,
+ },
+ layout: 'fullscreen',
+ msw: {
+ handlers: [
+ ...commonHandlers,
+ http.post('/api/channels/search', async ({ request, params }) => {
+ action('POST /api/channels/search')(await request.json());
+ return HttpResponse.json(params.untilId === 'lastchannel' ? [] : [
+ channel(),
+ channel('lastchannel', 'Last Channel', null),
+ ]);
+ }),
+ ],
+ },
+ },
+ decorators: [
+ () => ({
+ template: '<div style="display: flex; align-items: center; justify-content: center; height: 100vh"><div style="max-width: 700px; width: 100%; margin: 3rem"><story/></div></div>',
+ }),
+ ],
+} satisfies StoryObj<typeof MkChannelList>;
diff --git a/packages/frontend/src/components/MkChannelPreview.stories.impl.ts b/packages/frontend/src/components/MkChannelPreview.stories.impl.ts
new file mode 100644
index 0000000000..de0193c78f
--- /dev/null
+++ b/packages/frontend/src/components/MkChannelPreview.stories.impl.ts
@@ -0,0 +1,43 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+/* eslint-disable import/no-default-export */
+import { StoryObj } from '@storybook/vue3';
+import { channel } from '../../.storybook/fakes.js';
+import MkChannelPreview from './MkChannelPreview.vue';
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ MkChannelPreview,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ },
+ template: '<MkChannelPreview v-bind="props" />',
+ };
+ },
+ args: {
+ channel: channel(),
+ },
+ parameters: {
+ layout: 'fullscreen',
+ },
+ decorators: [
+ () => ({
+ template: '<div style="display: flex; align-items: center; justify-content: center; height: 100vh"><div style="max-width: 700px; width: 100%; margin: 3rem"><story/></div></div>',
+ }),
+ ],
+} satisfies StoryObj<typeof MkChannelPreview>;
diff --git a/packages/frontend/src/components/MkChannelPreview.vue b/packages/frontend/src/components/MkChannelPreview.vue
index 4ff64dc4ba..c30cb66c07 100644
--- a/packages/frontend/src/components/MkChannelPreview.vue
+++ b/packages/frontend/src/components/MkChannelPreview.vue
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<div style="position: relative;">
- <MkA :to="`/channels/${channel.id}`" class="eftoefju _panel" tabindex="-1" @click="updateLastReadedAt">
+ <MkA :to="`/channels/${channel.id}`" class="eftoefju _panel" @click="updateLastReadedAt">
<div class="banner" :style="bannerStyle">
<div class="fade"></div>
<div class="name"><i class="ti ti-device-tv"></i> {{ channel.name }}</div>
@@ -80,6 +80,7 @@ const bannerStyle = computed(() => {
<style lang="scss" scoped>
.eftoefju {
display: block;
+ position: relative;
overflow: hidden;
width: 100%;
@@ -87,6 +88,22 @@ const bannerStyle = computed(() => {
text-decoration: none;
}
+ &:focus-within {
+ outline: none;
+
+ &::after {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ border-radius: inherit;
+ pointer-events: none;
+ box-shadow: inset 0 0 0 2px var(--focus);
+ }
+ }
+
> .banner {
position: relative;
width: 100%;
diff --git a/packages/frontend/src/components/MkChart.stories.impl.ts b/packages/frontend/src/components/MkChart.stories.impl.ts
new file mode 100644
index 0000000000..1bcb9c30d8
--- /dev/null
+++ b/packages/frontend/src/components/MkChart.stories.impl.ts
@@ -0,0 +1,80 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+/* eslint-disable import/no-default-export */
+import { StoryObj } from '@storybook/vue3';
+import { http } from 'msw';
+import { commonHandlers } from '../../.storybook/mocks.js';
+import { getChartResolver } from '../../.storybook/charts.js';
+import MkChart from './MkChart.vue';
+
+const Base = {
+ render(args) {
+ return {
+ components: {
+ MkChart,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ },
+ template: '<MkChart v-bind="props" />',
+ };
+ },
+ args: {
+ src: 'federation',
+ span: 'hour',
+ nowForChromatic: 1716263640000,
+ },
+ parameters: {
+ layout: 'centered',
+ msw: {
+ handlers: [
+ ...commonHandlers,
+ http.get('/api/charts/federation', getChartResolver(
+ ['deliveredInstances', 'inboxInstances', 'stalled', 'sub', 'pub', 'pubsub', 'subActive', 'pubActive'],
+ )),
+ http.get('/api/charts/notes', getChartResolver(
+ ['local.total', 'remote.total'],
+ { accumulate: true },
+ )),
+ http.get('/api/charts/drive', getChartResolver(
+ ['local.incSize', 'local.decSize', 'remote.incSize', 'remote.decSize'],
+ { mulMap: { 'local.incSize': 1e7, 'local.decSize': 5e6, 'remote.incSize': 1e6, 'remote.decSize': 5e5 } },
+ )),
+ ],
+ },
+ },
+} satisfies StoryObj<typeof MkChart>;
+export const FederationChart = {
+ ...Base,
+ args: {
+ ...Base.args,
+ src: 'federation',
+ },
+} satisfies StoryObj<typeof MkChart>;
+export const NotesTotalChart = {
+ ...Base,
+ args: {
+ ...Base.args,
+ src: 'notes-total',
+ },
+} satisfies StoryObj<typeof MkChart>;
+export const DriveChart = {
+ ...Base,
+ args: {
+ ...Base.args,
+ src: 'drive',
+ },
+} satisfies StoryObj<typeof MkChart>;
diff --git a/packages/frontend/src/components/MkChart.vue b/packages/frontend/src/components/MkChart.vue
index 04b6d2f29c..4b24562249 100644
--- a/packages/frontend/src/components/MkChart.vue
+++ b/packages/frontend/src/components/MkChart.vue
@@ -19,8 +19,9 @@ SPDX-License-Identifier: AGPL-3.0-only
id-denylist violation when setting it. This is causing about 60+ lint issues.
As this is part of Chart.js's API it makes sense to disable the check here.
*/
-import { onMounted, ref, shallowRef, watch, PropType } from 'vue';
+import { onMounted, ref, shallowRef, watch } from 'vue';
import { Chart } from 'chart.js';
+import * as Misskey from 'misskey-js';
import { misskeyApiGet } from '@/scripts/misskey-api.js';
import { defaultStore } from '@/store.js';
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
@@ -34,44 +35,63 @@ import MkChartLegend from '@/components/MkChartLegend.vue';
initChart();
-const props = defineProps({
- src: {
- type: String,
- required: true,
- },
- args: {
- type: Object,
- required: false,
- },
- limit: {
- type: Number,
- required: false,
- default: 90,
- },
- span: {
- type: String as PropType<'hour' | 'day'>,
- required: true,
- },
- detailed: {
- type: Boolean,
- required: false,
- default: false,
- },
- stacked: {
- type: Boolean,
- required: false,
- default: false,
- },
- bar: {
- type: Boolean,
- required: false,
- default: false,
- },
- aspectRatio: {
- type: Number,
- required: false,
- default: null,
- },
+type ChartSrc =
+ | 'federation'
+ | 'ap-request'
+ | 'users'
+ | 'users-total'
+ | 'active-users'
+ | 'notes'
+ | 'local-notes'
+ | 'remote-notes'
+ | 'notes-total'
+ | 'drive'
+ | 'drive-files'
+ | 'instance-requests'
+ | 'instance-users'
+ | 'instance-users-total'
+ | 'instance-notes'
+ | 'instance-notes-total'
+ | 'instance-ff'
+ | 'instance-ff-total'
+ | 'instance-drive-usage'
+ | 'instance-drive-usage-total'
+ | 'instance-drive-files'
+ | 'instance-drive-files-total'
+ | 'per-user-notes'
+ | 'per-user-pv'
+ | 'per-user-following'
+ | 'per-user-followers'
+ | 'per-user-drive'
+
+const props = withDefaults(defineProps<{
+ src: ChartSrc;
+ args?: {
+ host?: string;
+ user?: Misskey.entities.UserLite;
+ withoutAll?: boolean;
+ };
+ limit?: number;
+ span: 'hour' | 'day';
+ detailed?: boolean;
+ stacked?: boolean;
+ bar?: boolean;
+ aspectRatio?: number | null;
+ nowForChromatic?: number;
+}>(), {
+ args: undefined,
+ limit: 90,
+ detailed: false,
+ stacked: false,
+ bar: false,
+ aspectRatio: null,
+
+ /**
+ * @desc Overwrites current date to fix background lines of chart.
+ * @ignore Only used for Chromatic. Don't use this for production.
+ * @see https://github.com/misskey-dev/misskey/pull/13830#issuecomment-2155886151
+ */
+ nowForChromatic: undefined,
});
const legendEl = shallowRef<InstanceType<typeof MkChartLegend>>();
@@ -94,7 +114,8 @@ const getColor = (i) => {
return colorSets[i % colorSets.length];
};
-const now = new Date();
+// eslint-disable-next-line vue/no-setup-props-reactivity-loss
+const now = props.nowForChromatic != null ? new Date(props.nowForChromatic) : new Date();
let chartInstance: Chart | null = null;
let chartData: {
series: {
diff --git a/packages/backend/src/misc/prelude/math.ts b/packages/frontend/src/components/MkChartLegend.stories.impl.ts
index 38556def2d..06146e20e4 100644
--- a/packages/backend/src/misc/prelude/math.ts
+++ b/packages/frontend/src/components/MkChartLegend.stories.impl.ts
@@ -3,6 +3,5 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
-export function gcd(a: number, b: number): number {
- return b === 0 ? a : gcd(b, a % b);
-}
+import MkChartLegend from './MkChartLegend.vue';
+void MkChartLegend;
diff --git a/packages/frontend/src/components/MkChartTooltip.stories.impl.ts b/packages/frontend/src/components/MkChartTooltip.stories.impl.ts
new file mode 100644
index 0000000000..289a9e9f27
--- /dev/null
+++ b/packages/frontend/src/components/MkChartTooltip.stories.impl.ts
@@ -0,0 +1,7 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import MkChartTooltip from './MkChartTooltip.vue';
+void MkChartTooltip;
diff --git a/packages/frontend/src/components/MkClickerGame.stories.impl.ts b/packages/frontend/src/components/MkClickerGame.stories.impl.ts
new file mode 100644
index 0000000000..36313f965d
--- /dev/null
+++ b/packages/frontend/src/components/MkClickerGame.stories.impl.ts
@@ -0,0 +1,77 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+/* eslint-disable import/no-default-export */
+import { StoryObj } from '@storybook/vue3';
+import { HttpResponse, http } from 'msw';
+import { action } from '@storybook/addon-actions';
+import { expect, userEvent, within } from '@storybook/test';
+import { commonHandlers } from '../../.storybook/mocks.js';
+import MkClickerGame from './MkClickerGame.vue';
+
+function sleep(ms: number) {
+ return new Promise(resolve => setTimeout(resolve, ms));
+}
+
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ MkClickerGame,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ },
+ template: '<MkClickerGame v-bind="props" />',
+ };
+ },
+ async play({ canvasElement }) {
+ await sleep(1000);
+ const canvas = within(canvasElement);
+ const count = canvas.getByTestId('count');
+ await expect(count).toHaveTextContent('0');
+ const buttonElement = canvas.getByRole<HTMLButtonElement>('button');
+ await userEvent.click(buttonElement);
+ await expect(count).toHaveTextContent('1');
+ },
+ parameters: {
+ layout: 'centered',
+ msw: {
+ handlers: [
+ ...commonHandlers,
+ http.post('/api/i/registry/get', async ({ request }) => {
+ action('POST /api/i/registry/get')(await request.json());
+ return HttpResponse.json({
+ error: {
+ message: 'No such key.',
+ code: 'NO_SUCH_KEY',
+ id: 'ac3ed68a-62f0-422b-a7bc-d5e09e8f6a6a',
+ },
+ }, {
+ status: 400,
+ });
+ }),
+ http.post('/api/i/registry/set', async ({ request }) => {
+ action('POST /api/i/registry/set')(await request.json());
+ return HttpResponse.json(undefined, { status: 204 });
+ }),
+ http.post('/api/i/claim-achievement', async ({ request }) => {
+ action('POST /api/i/claim-achievement')(await request.json());
+ return HttpResponse.json(undefined, { status: 204 });
+ }),
+ ],
+ },
+ },
+} satisfies StoryObj<typeof MkClickerGame>;
diff --git a/packages/frontend/src/components/MkClickerGame.vue b/packages/frontend/src/components/MkClickerGame.vue
index 23046bf345..00506fb735 100644
--- a/packages/frontend/src/components/MkClickerGame.vue
+++ b/packages/frontend/src/components/MkClickerGame.vue
@@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div>
<div v-if="game.ready" :class="$style.game">
<div :class="$style.cps" class="">{{ number(cps) }}cps</div>
- <div :class="$style.count" class=""><i class="ti ti-cookie" style="font-size: 70%;"></i> {{ number(cookies) }}</div>
+ <div :class="$style.count" class="" data-testid="count"><i class="ti ti-cookie" style="font-size: 70%;"></i> {{ number(cookies) }}</div>
<button v-click-anime class="_button" @click="onClick">
<img src="/client-assets/cookie.png" :class="$style.img">
</button>
@@ -35,7 +35,9 @@ const prevCookies = ref(0);
function onClick(ev: MouseEvent) {
const x = ev.clientX;
const y = ev.clientY;
- os.popup(MkPlusOneEffect, { x, y }, {}, 'end');
+ const { dispose } = os.popup(MkPlusOneEffect, { x, y }, {
+ end: () => dispose(),
+ });
saveData.value!.cookies++;
saveData.value!.totalCookies++;
diff --git a/packages/frontend/src/components/MkClipPreview.stories.impl.ts b/packages/frontend/src/components/MkClipPreview.stories.impl.ts
new file mode 100644
index 0000000000..62503fb98a
--- /dev/null
+++ b/packages/frontend/src/components/MkClipPreview.stories.impl.ts
@@ -0,0 +1,44 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+/* eslint-disable import/no-default-export */
+import { StoryObj } from '@storybook/vue3';
+import { clip } from '../../.storybook/fakes.js';
+import MkClipPreview from './MkClipPreview.vue';
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ MkClipPreview,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ },
+ template: '<MkClipPreview v-bind="props" />',
+ };
+ },
+ args: {
+ clip: clip(),
+ noUserInfo: false,
+ },
+ parameters: {
+ layout: 'fullscreen',
+ },
+ decorators: [
+ () => ({
+ template: '<div style="display: flex; align-items: center; justify-content: center; height: 100vh"><div style="max-width: 700px; width: 100%; margin: 3rem"><story/></div></div>',
+ }),
+ ],
+} satisfies StoryObj<typeof MkClipPreview>;
diff --git a/packages/frontend/src/components/MkClipPreview.vue b/packages/frontend/src/components/MkClipPreview.vue
index 6299a28e9f..dd550733cb 100644
--- a/packages/frontend/src/components/MkClipPreview.vue
+++ b/packages/frontend/src/components/MkClipPreview.vue
@@ -12,10 +12,12 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="clip.lastClippedAt">{{ i18n.ts.updatedAt }}: <MkTime :time="clip.lastClippedAt" mode="detail"/></div>
<div v-if="clip.notesCount != null">{{ i18n.ts.notesCount }}: {{ number(clip.notesCount) }} / {{ $i?.policies.noteEachClipsLimit }} ({{ i18n.tsx.remainingN({ n: remaining }) }})</div>
</div>
- <div :class="$style.divider"></div>
- <div>
- <MkAvatar :user="clip.user" :class="$style.userAvatar" indicator link preview/> <MkUserName :user="clip.user" :nowrap="false"/>
- </div>
+ <template v-if="!props.noUserInfo">
+ <div :class="$style.divider"></div>
+ <div>
+ <MkAvatar :user="clip.user" :class="$style.userAvatar" indicator link preview/> <MkUserName :user="clip.user" :nowrap="false"/>
+ </div>
+ </template>
</div>
</MkA>
</template>
@@ -27,9 +29,12 @@ import { i18n } from '@/i18n.js';
import { $i } from '@/account.js';
import number from '@/filters/number.js';
-const props = defineProps<{
+const props = withDefaults(defineProps<{
clip: Misskey.entities.Clip;
-}>();
+ noUserInfo?: boolean;
+}>(), {
+ noUserInfo: false,
+});
const remaining = computed(() => {
return ($i?.policies && props.clip.notesCount != null) ? ($i.policies.noteEachClipsLimit - props.clip.notesCount) : i18n.ts.unknown;
@@ -40,6 +45,14 @@ const remaining = computed(() => {
.link {
display: block;
+ &:focus-visible {
+ outline: none;
+
+ .root {
+ box-shadow: inset 0 0 0 2px var(--focus);
+ }
+ }
+
&:hover {
text-decoration: none;
color: var(--accent);
diff --git a/packages/frontend/src/components/MkCode.core.stories.impl.ts b/packages/frontend/src/components/MkCode.core.stories.impl.ts
new file mode 100644
index 0000000000..91990fffd5
--- /dev/null
+++ b/packages/frontend/src/components/MkCode.core.stories.impl.ts
@@ -0,0 +1,7 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import MkCode_core from './MkCode.core.vue';
+void MkCode_core;
diff --git a/packages/frontend/src/components/MkCode.stories.impl.ts b/packages/frontend/src/components/MkCode.stories.impl.ts
new file mode 100644
index 0000000000..b7e53e8e35
--- /dev/null
+++ b/packages/frontend/src/components/MkCode.stories.impl.ts
@@ -0,0 +1,44 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+/* eslint-disable import/no-default-export */
+import { StoryObj } from '@storybook/vue3';
+import MkCode from './MkCode.vue';
+const code = `for (let i, 100) {
+ <: if (i % 15 == 0) "FizzBuzz"
+ elif (i % 3 == 0) "Fizz"
+ elif (i % 5 == 0) "Buzz"
+ else i
+}`;
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ MkCode,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ },
+ template: '<MkCode v-bind="props" />',
+ };
+ },
+ args: {
+ code,
+ lang: 'is',
+ },
+ parameters: {
+ layout: 'centered',
+ },
+} satisfies StoryObj<typeof MkCode>;
diff --git a/packages/frontend/src/components/MkCode.vue b/packages/frontend/src/components/MkCode.vue
index a3c80e743b..1d4c0b6366 100644
--- a/packages/frontend/src/components/MkCode.vue
+++ b/packages/frontend/src/components/MkCode.vue
@@ -30,7 +30,7 @@ import * as os from '@/os.js';
import MkLoading from '@/components/global/MkLoading.vue';
import { defaultStore } from '@/store.js';
import { i18n } from '@/i18n.js';
-import copyToClipboard from '@/scripts/copy-to-clipboard.js';
+import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
const props = defineProps<{
code: string;
diff --git a/packages/frontend/src/components/MkCodeEditor.stories.impl.ts b/packages/frontend/src/components/MkCodeEditor.stories.impl.ts
new file mode 100644
index 0000000000..5c410c4886
--- /dev/null
+++ b/packages/frontend/src/components/MkCodeEditor.stories.impl.ts
@@ -0,0 +1,62 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+/* eslint-disable import/no-default-export */
+import { StoryObj } from '@storybook/vue3';
+import { action } from '@storybook/addon-actions';
+import MkCodeEditor from './MkCodeEditor.vue';
+const code = `for (let i, 100) {
+ <: if (i % 15 == 0) "FizzBuzz"
+ elif (i % 3 == 0) "Fizz"
+ elif (i % 5 == 0) "Buzz"
+ else i
+}`;
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ MkCodeEditor,
+ },
+ data() {
+ return {
+ code,
+ };
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ events() {
+ return {
+ 'change': action('change'),
+ 'keydown': action('keydown'),
+ 'enter': action('enter'),
+ 'update:modelValue': action('update:modelValue'),
+ };
+ },
+ },
+ template: '<MkCodeEditor v-model="code" v-bind="props" v-on="events" />',
+ };
+ },
+ args: {
+ lang: 'aiscript',
+ },
+ parameters: {
+ layout: 'fullscreen',
+ },
+ decorators: [
+ () => ({
+ template: '<div style="display: flex; align-items: center; justify-content: center; height: 100vh"><div style="max-width: 800px; width: 100%; margin: 3rem"><Suspense><story/></Suspense></div></div>',
+ }),
+ ],
+} satisfies StoryObj<typeof MkCodeEditor>;
diff --git a/packages/frontend/src/components/MkCodeInline.stories.impl.ts b/packages/frontend/src/components/MkCodeInline.stories.impl.ts
new file mode 100644
index 0000000000..51d4d106ff
--- /dev/null
+++ b/packages/frontend/src/components/MkCodeInline.stories.impl.ts
@@ -0,0 +1,37 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+/* eslint-disable import/no-default-export */
+import { StoryObj } from '@storybook/vue3';
+import MkCodeInline from './MkCodeInline.vue';
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ MkCodeInline,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ },
+ template: '<MkCodeInline v-bind="props"/>',
+ };
+ },
+ args: {
+ code: '<: "Hello, world!"',
+ },
+ parameters: {
+ layout: 'centered',
+ },
+} satisfies StoryObj<typeof MkCodeInline>;
diff --git a/packages/frontend/src/components/MkColorInput.stories.impl.ts b/packages/frontend/src/components/MkColorInput.stories.impl.ts
new file mode 100644
index 0000000000..61383e2cae
--- /dev/null
+++ b/packages/frontend/src/components/MkColorInput.stories.impl.ts
@@ -0,0 +1,50 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+/* eslint-disable import/no-default-export */
+import { StoryObj } from '@storybook/vue3';
+import { action } from '@storybook/addon-actions';
+import MkColorInput from './MkColorInput.vue';
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ MkColorInput,
+ },
+ data() {
+ return {
+ color: '#cccccc',
+ };
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ events() {
+ return {
+ 'update:modelValue': action('update:modelValue'),
+ };
+ },
+ },
+ template: '<MkColorInput v-model="color" v-bind="props" v-on="events" />',
+ };
+ },
+ parameters: {
+ layout: 'fullscreen',
+ },
+ decorators: [
+ () => ({
+ template: '<div style="display: flex; align-items: center; justify-content: center; height: 100vh"><div style="max-width: 800px; width: 100%; margin: 3rem"><story/></div></div>',
+ }),
+ ],
+} satisfies StoryObj<typeof MkColorInput>;
diff --git a/packages/frontend/src/components/MkContainer.stories.impl.ts b/packages/frontend/src/components/MkContainer.stories.impl.ts
new file mode 100644
index 0000000000..72a7659521
--- /dev/null
+++ b/packages/frontend/src/components/MkContainer.stories.impl.ts
@@ -0,0 +1,7 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import MkContainer from './MkContainer.vue';
+void MkContainer;
diff --git a/packages/frontend/src/components/MkContextMenu.stories.impl.ts b/packages/frontend/src/components/MkContextMenu.stories.impl.ts
new file mode 100644
index 0000000000..1ff0f51bd4
--- /dev/null
+++ b/packages/frontend/src/components/MkContextMenu.stories.impl.ts
@@ -0,0 +1,58 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+/* eslint-disable import/no-default-export */
+import { StoryObj } from '@storybook/vue3';
+import { userEvent, within } from '@storybook/test';
+import MkContextMenu from './MkContextMenu.vue';
+import * as os from '@/os.js';
+export const Empty = {
+ render(args) {
+ return {
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ },
+ methods: {
+ onContextmenu(ev: MouseEvent) {
+ os.contextMenu(args.items, ev);
+ },
+ },
+ template: '<div @contextmenu.stop="onContextmenu">Right Click Here</div>',
+ };
+ },
+ args: {
+ items: [],
+ },
+ async play({ canvasElement }) {
+ const canvas = within(canvasElement);
+ const target = canvas.getByText('Right Click Here');
+ await userEvent.pointer({ keys: '[MouseRight>]', target });
+ },
+ parameters: {
+ layout: 'centered',
+ },
+} satisfies StoryObj<typeof MkContextMenu>;
+export const SomeTabs = {
+ ...Empty,
+ args: {
+ items: [
+ {
+ text: 'Home',
+ icon: 'ti ti-home',
+ action() {},
+ },
+ ],
+ },
+} satisfies StoryObj<typeof MkContextMenu>;
diff --git a/packages/frontend/src/components/MkContextMenu.vue b/packages/frontend/src/components/MkContextMenu.vue
index a807742bb9..8ea8fa6cf3 100644
--- a/packages/frontend/src/components/MkContextMenu.vue
+++ b/packages/frontend/src/components/MkContextMenu.vue
@@ -12,7 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:leaveToClass="defaultStore.state.animation ? $style.transition_fade_leaveTo : ''"
>
<div ref="rootEl" :class="$style.root" :style="{ zIndex }" @contextmenu.prevent.stop="() => {}">
- <MkMenu :items="items" :align="'left'" @close="$emit('closed')"/>
+ <MkMenu :items="items" :align="'left'" @close="emit('closed')"/>
</div>
</Transition>
</template>
diff --git a/packages/frontend/src/components/MkCropperDialog.stories.impl.ts b/packages/frontend/src/components/MkCropperDialog.stories.impl.ts
new file mode 100644
index 0000000000..ce13093975
--- /dev/null
+++ b/packages/frontend/src/components/MkCropperDialog.stories.impl.ts
@@ -0,0 +1,75 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+/* eslint-disable import/no-default-export */
+import { StoryObj } from '@storybook/vue3';
+import { HttpResponse, http } from 'msw';
+import { action } from '@storybook/addon-actions';
+import { file } from '../../.storybook/fakes.js';
+import { commonHandlers } from '../../.storybook/mocks.js';
+import MkCropperDialog from './MkCropperDialog.vue';
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ MkCropperDialog,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ events() {
+ return {
+ 'ok': action('ok'),
+ 'cancel': action('cancel'),
+ 'closed': action('closed'),
+ };
+ },
+ },
+ template: '<MkCropperDialog v-bind="props" v-on="events" />',
+ };
+ },
+ args: {
+ file: file(),
+ aspectRatio: NaN,
+ },
+ parameters: {
+ chromatic: {
+ // NOTE: ロードãŒçµ‚ã‚ã‚‹ã¾ã§å¾…ã¤
+ delay: 3000,
+ },
+ layout: 'centered',
+ msw: {
+ handlers: [
+ ...commonHandlers,
+ http.get('/proxy/image.webp', async ({ request }) => {
+ const url = new URL(request.url).searchParams.get('url');
+ if (url === 'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/fedi.jpg?raw=true') {
+ const image = await (await fetch('client-assets/fedi.jpg')).blob();
+ return new HttpResponse(image, {
+ headers: {
+ 'Content-Type': 'image/jpeg',
+ },
+ });
+ } else {
+ return new HttpResponse(null, { status: 404 });
+ }
+ }),
+ http.post('/api/drive/files/create', async ({ request }) => {
+ action('POST /api/drive/files/create')(await request.formData());
+ return HttpResponse.json(file());
+ }),
+ ],
+ },
+ },
+} satisfies StoryObj<typeof MkCropperDialog>;
diff --git a/packages/frontend/src/components/MkCustomEmojiDetailedDialog.stories.impl.ts b/packages/frontend/src/components/MkCustomEmojiDetailedDialog.stories.impl.ts
new file mode 100644
index 0000000000..8a05e06311
--- /dev/null
+++ b/packages/frontend/src/components/MkCustomEmojiDetailedDialog.stories.impl.ts
@@ -0,0 +1,38 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+/* eslint-disable import/no-default-export */
+import { StoryObj } from '@storybook/vue3';
+import { emojiDetailed } from '../../.storybook/fakes.js';
+import MkCustomEmojiDetailedDialog from './MkCustomEmojiDetailedDialog.vue';
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ MkCustomEmojiDetailedDialog,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ },
+ template: '<MkCustomEmojiDetailedDialog v-bind="props" />',
+ };
+ },
+ args: {
+ emoji: emojiDetailed(),
+ },
+ parameters: {
+ layout: 'centered',
+ },
+} satisfies StoryObj<typeof MkCustomEmojiDetailedDialog>;
diff --git a/packages/frontend/src/components/MkCwButton.stories.impl.ts b/packages/frontend/src/components/MkCwButton.stories.impl.ts
new file mode 100644
index 0000000000..5d6ea56da9
--- /dev/null
+++ b/packages/frontend/src/components/MkCwButton.stories.impl.ts
@@ -0,0 +1,79 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+/* eslint-disable import/no-default-export */
+import { StoryObj } from '@storybook/vue3';
+import { action } from '@storybook/addon-actions';
+import { expect, userEvent, within } from '@storybook/test';
+import { file } from '../../.storybook/fakes.js';
+import MkCwButton from './MkCwButton.vue';
+import { i18n } from '@/i18n.js';
+
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ MkCwButton,
+ },
+ data() {
+ return {
+ showContent: false,
+ };
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ events() {
+ return {
+ 'update:modelValue': action('update:modelValue'),
+ };
+ },
+ },
+ template: '<MkCwButton v-model="showContent" v-bind="props" v-on="events" />',
+ };
+ },
+ args: {
+ text: 'Some CW content',
+ },
+ async play({ canvasElement }) {
+ const canvas = within(canvasElement);
+ const buttonElement = canvas.getByRole<HTMLButtonElement>('button');
+ await expect(buttonElement).toHaveTextContent(i18n.ts._cw.show);
+ await expect(buttonElement).toHaveTextContent(i18n.tsx._cw.chars({ count: 15 }));
+ await userEvent.click(buttonElement);
+ await expect(buttonElement).toHaveTextContent(i18n.ts._cw.hide);
+ await userEvent.click(buttonElement);
+ },
+ parameters: {
+ chromatic: {
+ // NOTE: テストãŒçµ‚ã‚ã‚‹ã¾ã§å¾…ã¤
+ delay: 5000,
+ },
+ layout: 'centered',
+ },
+} satisfies StoryObj<typeof MkCwButton>;
+export const IncludesTextAndDriveFile = {
+ ...Default,
+ args: {
+ text: 'Some CW content',
+ files: [file()],
+ },
+ async play({ canvasElement }) {
+ const canvas = within(canvasElement);
+ const buttonElement = canvas.getByRole<HTMLButtonElement>('button');
+ await expect(buttonElement).toHaveTextContent(i18n.tsx._cw.chars({ count: 15 }));
+ await expect(buttonElement).toHaveTextContent(' / ');
+ await expect(buttonElement).toHaveTextContent(i18n.tsx._cw.files({ count: 1 }));
+ },
+} satisfies StoryObj<typeof MkCwButton>;
diff --git a/packages/frontend/src/components/MkCwButton.vue b/packages/frontend/src/components/MkCwButton.vue
index a2cb3185f4..b5f6e78b6c 100644
--- a/packages/frontend/src/components/MkCwButton.vue
+++ b/packages/frontend/src/components/MkCwButton.vue
@@ -45,11 +45,11 @@ function toggle() {
.label {
margin-left: 4px;
- &:before {
+ &::before {
content: '(';
}
- &:after {
+ &::after {
content: ')';
}
}
diff --git a/packages/frontend/src/components/MkDateSeparatedList.stories.impl.ts b/packages/frontend/src/components/MkDateSeparatedList.stories.impl.ts
new file mode 100644
index 0000000000..0e5635754c
--- /dev/null
+++ b/packages/frontend/src/components/MkDateSeparatedList.stories.impl.ts
@@ -0,0 +1,7 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import MkDateSeparatedList from './MkDateSeparatedList.vue';
+void MkDateSeparatedList;
diff --git a/packages/frontend/src/components/MkDateSeparatedList.vue b/packages/frontend/src/components/MkDateSeparatedList.vue
index 85e131cf9b..f16981716c 100644
--- a/packages/frontend/src/components/MkDateSeparatedList.vue
+++ b/packages/frontend/src/components/MkDateSeparatedList.vue
@@ -130,7 +130,7 @@ export default defineComponent({
el.style.left = '';
}
- // eslint-disable-next-line vue/no-setup-props-destructure
+ // eslint-disable-next-line vue/no-setup-props-reactivity-loss
const classes = {
[$style['date-separated-list']]: true,
[$style['date-separated-list-nogap']]: props.noGap,
diff --git a/packages/frontend/src/components/MkDialog.stories.impl.ts b/packages/frontend/src/components/MkDialog.stories.impl.ts
new file mode 100644
index 0000000000..2d8d3661f2
--- /dev/null
+++ b/packages/frontend/src/components/MkDialog.stories.impl.ts
@@ -0,0 +1,159 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { action } from '@storybook/addon-actions';
+import { expect, userEvent, waitFor, within } from '@storybook/test';
+import { StoryObj } from '@storybook/vue3';
+import { i18n } from '@/i18n.js';
+import MkDialog from './MkDialog.vue';
+const Base = {
+ render(args) {
+ return {
+ components: {
+ MkDialog,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ events() {
+ return {
+ done: action('done'),
+ closed: action('closed'),
+ };
+ },
+ },
+ template: '<MkDialog v-bind="props" v-on="events" />',
+ };
+ },
+ args: {
+ text: 'Hello, world!',
+ },
+ parameters: {
+ layout: 'centered',
+ },
+} satisfies StoryObj<typeof MkDialog>;
+export const Success = {
+ ...Base,
+ args: {
+ ...Base.args,
+ type: 'success',
+ },
+} satisfies StoryObj<typeof MkDialog>;
+export const Error = {
+ ...Base,
+ args: {
+ ...Base.args,
+ type: 'error',
+ },
+} satisfies StoryObj<typeof MkDialog>;
+export const Warning = {
+ ...Base,
+ args: {
+ ...Base.args,
+ type: 'warning',
+ },
+} satisfies StoryObj<typeof MkDialog>;
+export const Info = {
+ ...Base,
+ args: {
+ ...Base.args,
+ type: 'info',
+ },
+} satisfies StoryObj<typeof MkDialog>;
+export const Question = {
+ ...Base,
+ args: {
+ ...Base.args,
+ type: 'question',
+ },
+} satisfies StoryObj<typeof MkDialog>;
+export const Waiting = {
+ ...Base,
+ args: {
+ ...Base.args,
+ type: 'waiting',
+ },
+} satisfies StoryObj<typeof MkDialog>;
+export const DialogWithActions = {
+ ...Question,
+ args: {
+ ...Question.args,
+ text: i18n.ts.areYouSure,
+ actions: [
+ {
+ text: i18n.ts.yes,
+ primary: true,
+ callback() {
+ action('YES')();
+ },
+ },
+ {
+ text: i18n.ts.no,
+ callback() {
+ action('NO')();
+ },
+ },
+ ],
+ },
+} satisfies StoryObj<typeof MkDialog>;
+export const DialogWithDangerActions = {
+ ...Warning,
+ args: {
+ ...Warning.args,
+ text: i18n.ts.resetAreYouSure,
+ actions: [
+ {
+ text: i18n.ts.yes,
+ danger: true,
+ primary: true,
+ callback() {
+ action('YES')();
+ },
+ },
+ {
+ text: i18n.ts.no,
+ callback() {
+ action('NO')();
+ },
+ },
+ ],
+ },
+} satisfies StoryObj<typeof MkDialog>;
+export const DialogWithInput = {
+ ...Question,
+ args: {
+ ...Question.args,
+ title: 'Hello, world!',
+ text: undefined,
+ input: {
+ placeholder: i18n.ts.inputMessageHere,
+ type: 'text',
+ default: null,
+ minLength: 2,
+ maxLength: 3,
+ },
+ },
+ async play({ canvasElement }) {
+ const canvas = within(canvasElement);
+ await expect(canvasElement).toHaveTextContent(i18n.tsx._dialog.charactersBelow({ current: 0, min: 2 }));
+ const okButton = canvas.getByRole('button', { name: i18n.ts.ok });
+ await expect(okButton).toBeDisabled();
+ const input = canvas.getByRole<HTMLInputElement>('combobox');
+ await waitFor(() => userEvent.hover(input));
+ await waitFor(() => userEvent.click(input));
+ await waitFor(() => userEvent.type(input, 'M'));
+ await expect(canvasElement).toHaveTextContent(i18n.tsx._dialog.charactersBelow({ current: 1, min: 2 }));
+ await waitFor(() => userEvent.type(input, 'i'));
+ await expect(okButton).toBeEnabled();
+ },
+} satisfies StoryObj<typeof MkDialog>;
diff --git a/packages/frontend/src/components/MkDialog.vue b/packages/frontend/src/components/MkDialog.vue
index c52404a319..16cf5b1b75 100644
--- a/packages/frontend/src/components/MkDialog.vue
+++ b/packages/frontend/src/components/MkDialog.vue
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
-<MkModal ref="modal" :preferType="'dialog'" :zPriority="'high'" @click="done(true)" @closed="emit('closed')">
+<MkModal ref="modal" :preferType="'dialog'" :zPriority="'high'" @click="done(true)" @closed="emit('closed')" @esc="cancel()">
<div :class="$style.root">
<div v-if="icon" :class="$style.icon">
<i :class="icon"></i>
@@ -36,7 +36,12 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkInput>
<MkSelect v-if="select" v-model="selectedValue" autofocus>
<template v-if="select.items">
- <option v-for="item in select.items" :value="item.value">{{ item.text }}</option>
+ <template v-for="item in select.items">
+ <optgroup v-if="'sectionTitle' in item" :label="item.sectionTitle">
+ <option v-for="subItem in item.items" :value="subItem.value">{{ subItem.text }}</option>
+ </optgroup>
+ <option v-else :value="item.value">{{ item.text }}</option>
+ </template>
</template>
</MkSelect>
<div v-if="(showOkButton || showCancelButton) && !actions" :class="$style.buttons">
@@ -51,7 +56,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { onBeforeUnmount, onMounted, ref, shallowRef, computed } from 'vue';
+import { ref, shallowRef, computed } from 'vue';
import MkModal from '@/components/MkModal.vue';
import MkButton from '@/components/MkButton.vue';
import MkInput from '@/components/MkInput.vue';
@@ -67,11 +72,16 @@ type Input = {
maxLength?: number;
};
+type SelectItem = {
+ value: any;
+ text: string;
+};
+
type Select = {
- items: {
- value: any;
- text: string;
- }[];
+ items: (SelectItem | {
+ sectionTitle: string;
+ items: SelectItem[];
+ })[];
default: string | null;
};
@@ -156,10 +166,6 @@ function onBgClick() {
if (props.cancelableByBgClick) cancel();
}
*/
-function onKeydown(evt: KeyboardEvent) {
- if (evt.key === 'Escape') cancel();
-}
-
function onInputKeydown(evt: KeyboardEvent) {
if (evt.key === 'Enter' && okButtonDisabledReason.value === null) {
evt.preventDefault();
@@ -167,14 +173,6 @@ function onInputKeydown(evt: KeyboardEvent) {
ok();
}
}
-
-onMounted(() => {
- document.addEventListener('keydown', onKeydown);
-});
-
-onBeforeUnmount(() => {
- document.removeEventListener('keydown', onKeydown);
-});
</script>
<style lang="scss" module>
diff --git a/packages/backend/src/misc/prelude/symbol.ts b/packages/frontend/src/components/MkDivider.stories.impl.ts
index 7e8d39bdb6..a593111987 100644
--- a/packages/backend/src/misc/prelude/symbol.ts
+++ b/packages/frontend/src/components/MkDivider.stories.impl.ts
@@ -3,4 +3,5 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
-export const fallback = Symbol('fallback');
+import MkDivider from './MkDivider.vue';
+void MkDivider;
diff --git a/packages/frontend/src/components/MkDivider.vue b/packages/frontend/src/components/MkDivider.vue
new file mode 100644
index 0000000000..e4e3af99e4
--- /dev/null
+++ b/packages/frontend/src/components/MkDivider.vue
@@ -0,0 +1,32 @@
+<!--
+SPDX-FileCopyrightText: syuilo and misskey-project
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
+<template>
+<div
+ class="default" :style="[
+ marginTopBottom ? { marginTop: marginTopBottom, marginBottom: marginTopBottom } : {},
+ marginLeftRight ? { marginLeft: marginLeftRight, marginRight: marginLeftRight } : {},
+ borderStyle ? { borderStyle: borderStyle } : {},
+ borderWidth ? { borderWidth: borderWidth } : {},
+ borderColor ? { borderColor: borderColor } : {},
+ ]"
+/>
+</template>
+
+<script setup lang="ts">
+defineProps<{
+ marginTopBottom?: string;
+ marginLeftRight?: string;
+ borderStyle?: string;
+ borderWidth?: string;
+ borderColor?: string;
+}>();
+</script>
+
+<style scoped lang="scss">
+.default {
+ border-top: solid 0.5px var(--divider);
+}
+</style>
diff --git a/packages/frontend/src/components/MkDonation.stories.impl.ts b/packages/frontend/src/components/MkDonation.stories.impl.ts
new file mode 100644
index 0000000000..27d6b7df6c
--- /dev/null
+++ b/packages/frontend/src/components/MkDonation.stories.impl.ts
@@ -0,0 +1,54 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { action } from '@storybook/addon-actions';
+import { StoryObj } from '@storybook/vue3';
+import { onBeforeUnmount } from 'vue';
+import MkDonation from './MkDonation.vue';
+import { instance } from '@/instance.js';
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ MkDonation,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ events() {
+ return {
+ closed: action('closed'),
+ };
+ },
+ },
+ template: '<MkDonation v-bind="props" v-on="events" />',
+ };
+ },
+ args: {
+ // @ts-expect-error name is used for mocking instance
+ name: 'Misskey Hub',
+ },
+ decorators: [
+ (_, { args }) => ({
+ setup() {
+ // @ts-expect-error name is used for mocking instance
+ instance.name = args.name;
+ onBeforeUnmount(() => instance.name = null);
+ },
+ template: '<story/>',
+ }),
+ ],
+ parameters: {
+ layout: 'centered',
+ },
+} satisfies StoryObj<typeof MkDonation>;
diff --git a/packages/frontend/src/components/MkDrive.file.stories.impl.ts b/packages/frontend/src/components/MkDrive.file.stories.impl.ts
new file mode 100644
index 0000000000..5f6e6a0667
--- /dev/null
+++ b/packages/frontend/src/components/MkDrive.file.stories.impl.ts
@@ -0,0 +1,48 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { action } from '@storybook/addon-actions';
+import { StoryObj } from '@storybook/vue3';
+import MkDrive_file from './MkDrive.file.vue';
+import { file } from '../../.storybook/fakes.js';
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ MkDrive_file,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ events() {
+ return {
+ chosen: action('chosen'),
+ dragstart: action('dragstart'),
+ dragend: action('dragend'),
+ };
+ },
+ },
+ template: '<MkDrive_file v-bind="props" v-on="events" />',
+ };
+ },
+ args: {
+ file: file(),
+ },
+ parameters: {
+ chromatic: {
+ // NOTE: ロードãŒçµ‚ã‚ã‚‹ã¾ã§å¾…ã¤
+ delay: 3000,
+ },
+ layout: 'centered',
+ },
+} satisfies StoryObj<typeof MkDrive_file>;
diff --git a/packages/frontend/src/components/MkDrive.file.vue b/packages/frontend/src/components/MkDrive.file.vue
index 4106b0a436..90284890a5 100644
--- a/packages/frontend/src/components/MkDrive.file.vue
+++ b/packages/frontend/src/components/MkDrive.file.vue
@@ -115,14 +115,14 @@ function onDragend() {
background: rgba(#000, 0.05);
> .label {
- &:before,
- &:after {
+ &::before,
+ &::after {
background: #0b65a5;
}
&.red {
- &:before,
- &:after {
+ &::before,
+ &::after {
background: #c12113;
}
}
@@ -133,14 +133,14 @@ function onDragend() {
background: rgba(#000, 0.1);
> .label {
- &:before,
- &:after {
+ &::before,
+ &::after {
background: #0b588c;
}
&.red {
- &:before,
- &:after {
+ &::before,
+ &::after {
background: #ce2212;
}
}
@@ -159,8 +159,8 @@ function onDragend() {
}
> .label {
- &:before,
- &:after {
+ &::before,
+ &::after {
display: none;
}
}
@@ -181,8 +181,8 @@ function onDragend() {
left: 0;
pointer-events: none;
- &:before,
- &:after {
+ &::before,
+ &::after {
content: "";
display: block;
position: absolute;
@@ -190,14 +190,14 @@ function onDragend() {
background: #0c7ac9;
}
- &:before {
+ &::before {
top: 0;
left: 57px;
width: 28px;
height: 8px;
}
- &:after {
+ &::after {
top: 57px;
left: 0;
width: 8px;
@@ -205,8 +205,8 @@ function onDragend() {
}
&.red {
- &:before,
- &:after {
+ &::before,
+ &::after {
background: #c12113;
}
}
diff --git a/packages/frontend/src/components/MkDrive.folder.stories.impl.ts b/packages/frontend/src/components/MkDrive.folder.stories.impl.ts
new file mode 100644
index 0000000000..5f8ef48520
--- /dev/null
+++ b/packages/frontend/src/components/MkDrive.folder.stories.impl.ts
@@ -0,0 +1,70 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { action } from '@storybook/addon-actions';
+import { StoryObj } from '@storybook/vue3';
+import { http, HttpResponse } from 'msw';
+import * as Misskey from 'misskey-js';
+import MkDrive_folder from './MkDrive.folder.vue';
+import { folder } from '../../.storybook/fakes.js';
+import { commonHandlers } from '../../.storybook/mocks.js';
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ MkDrive_folder,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ events() {
+ return {
+ chosen: action('chosen'),
+ move: action('move'),
+ upload: action('upload'),
+ removeFile: action('removeFile'),
+ removeFolder: action('removeFolder'),
+ dragstart: action('dragstart'),
+ dragend: action('dragend'),
+ };
+ },
+ },
+ template: '<MkDrive_folder v-bind="props" v-on="events" />',
+ };
+ },
+ args: {
+ folder: folder(),
+ },
+ parameters: {
+ layout: 'centered',
+ msw: {
+ handlers: [
+ ...commonHandlers,
+ http.post('/api/drive/folders/delete', async ({ request }) => {
+ action('POST /api/drive/folders/delete')(await request.json());
+ return HttpResponse.json(undefined, { status: 204 });
+ }),
+ http.post('/api/drive/folders/update', async ({ request }) => {
+ const req = await request.json() as Misskey.entities.DriveFoldersUpdateRequest;
+ action('POST /api/drive/folders/update')(req);
+ return HttpResponse.json({
+ ...folder(),
+ id: req.folderId,
+ name: req.name ?? folder().name,
+ parentId: req.parentId ?? folder().parentId,
+ });
+ }),
+ ],
+ },
+ },
+} satisfies StoryObj<typeof MkDrive_folder>;
diff --git a/packages/frontend/src/components/MkDrive.folder.vue b/packages/frontend/src/components/MkDrive.folder.vue
index 8da0d78f35..d6dfaf34e5 100644
--- a/packages/frontend/src/components/MkDrive.folder.vue
+++ b/packages/frontend/src/components/MkDrive.folder.vue
@@ -27,7 +27,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<p v-if="defaultStore.state.uploadFolder == folder.id" :class="$style.upload">
{{ i18n.ts.uploadFolder }}
</p>
- <button v-if="selectMode" class="_button" :class="[$style.checkbox, { [$style.checked]: isSelected }]" @click.prevent.stop="checkboxClicked"></button>
+ <button v-if="selectMode" class="_button" :class="$style.checkboxWrapper" @click.prevent.stop="checkboxClicked">
+ <div :class="[$style.checkbox, { [$style.checked]: isSelected }]"></div>
+ </button>
</div>
</template>
@@ -39,7 +41,7 @@ import { misskeyApi } from '@/scripts/misskey-api.js';
import { i18n } from '@/i18n.js';
import { defaultStore } from '@/store.js';
import { claimAchievement } from '@/scripts/achievements.js';
-import copyToClipboard from '@/scripts/copy-to-clipboard.js';
+import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
import { MenuItem } from '@/types/menu.js';
const props = withDefaults(defineProps<{
@@ -53,6 +55,7 @@ const props = withDefaults(defineProps<{
const emit = defineEmits<{
(ev: 'chosen', v: Misskey.entities.DriveFolder): void;
+ (ev: 'unchose', v: Misskey.entities.DriveFolder): void;
(ev: 'move', v: Misskey.entities.DriveFolder): void;
(ev: 'upload', file: File, folder: Misskey.entities.DriveFolder);
(ev: 'removeFile', v: Misskey.entities.DriveFile['id']): void;
@@ -68,7 +71,11 @@ const isDragging = ref(false);
const title = computed(() => props.folder.name);
function checkboxClicked() {
- emit('chosen', props.folder);
+ if (props.isSelected) {
+ emit('unchose', props.folder);
+ } else {
+ emit('chosen', props.folder);
+ }
}
function onClick() {
@@ -222,6 +229,17 @@ function rename() {
});
}
+function move() {
+ os.selectDriveFolder(false).then(folder => {
+ if (folder[0] && folder[0].id === props.folder.id) return;
+
+ misskeyApi('drive/folders/update', {
+ folderId: props.folder.id,
+ parentId: folder[0] ? folder[0].id : null,
+ });
+ });
+}
+
function deleteFolder() {
misskeyApi('drive/folders/delete', {
folderId: props.folder.id,
@@ -257,15 +275,20 @@ function onContextmenu(ev: MouseEvent) {
text: i18n.ts.openInWindow,
icon: 'ti ti-app-window',
action: () => {
- os.popup(defineAsyncComponent(() => import('@/components/MkDriveWindow.vue')), {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkDriveWindow.vue')), {
initialFolder: props.folder,
}, {
- }, 'closed');
+ closed: () => dispose(),
+ });
},
}, { type: 'divider' }, {
text: i18n.ts.rename,
icon: 'ti ti-forms',
action: rename,
+ }, {
+ text: i18n.ts.move,
+ icon: 'ti ti ti-folder-symlink',
+ action: move,
}, { type: 'divider' }, {
text: i18n.ts.delete,
icon: 'ti ti-trash',
@@ -295,7 +318,7 @@ function onContextmenu(ev: MouseEvent) {
cursor: pointer;
&.draghover {
- &:after {
+ &::after {
content: "";
pointer-events: none;
position: absolute;
@@ -309,17 +332,43 @@ function onContextmenu(ev: MouseEvent) {
}
}
-.checkbox {
+.checkboxWrapper {
position: absolute;
- bottom: 8px;
- right: 8px;
- width: 16px;
- height: 16px;
- background: #fff;
- border: solid 1px #000;
+ border-radius: 50%;
+ bottom: 2px;
+ right: 2px;
+ padding: 8px;
+ box-sizing: border-box;
+
+ > .checkbox {
+ position: relative;
+ width: 18px;
+ height: 18px;
+ background: #fff;
+ border: solid 2px var(--divider);
+ border-radius: 4px;
+ box-sizing: border-box;
+
+ &.checked {
+ border-color: var(--accent);
+ background: var(--accent);
+
+ &::after {
+ content: "\ea5e";
+ font-family: 'tabler-icons';
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ color: #fff;
+ font-size: 12px;
+ line-height: 22px;
+ }
+ }
+ }
- &.checked {
- background: var(--accent);
+ &:hover {
+ background: var(--accentedBg);
}
}
diff --git a/packages/frontend/src/components/MkDrive.navFolder.stories.impl.ts b/packages/frontend/src/components/MkDrive.navFolder.stories.impl.ts
new file mode 100644
index 0000000000..9d49f24fa4
--- /dev/null
+++ b/packages/frontend/src/components/MkDrive.navFolder.stories.impl.ts
@@ -0,0 +1,7 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import MkDrive_navFolder from './MkDrive.navFolder.vue';
+void MkDrive_navFolder;
diff --git a/packages/frontend/src/components/MkDrive.stories.impl.ts b/packages/frontend/src/components/MkDrive.stories.impl.ts
new file mode 100644
index 0000000000..fe20e61415
--- /dev/null
+++ b/packages/frontend/src/components/MkDrive.stories.impl.ts
@@ -0,0 +1,82 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { action } from '@storybook/addon-actions';
+import { StoryObj } from '@storybook/vue3';
+import { http, HttpResponse } from 'msw';
+import * as Misskey from 'misskey-js';
+import MkDrive from './MkDrive.vue';
+import { file, folder } from '../../.storybook/fakes.js';
+import { commonHandlers } from '../../.storybook/mocks.js';
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ MkDrive,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ events() {
+ return {
+ selected: action('selected'),
+ 'change-selection': action('change-selection'),
+ 'move-root': action('move-root'),
+ cd: action('cd'),
+ 'open-folder': action('open-folder'),
+ };
+ },
+ },
+ template: '<MkDrive v-bind="props" v-on="events" />',
+ };
+ },
+ parameters: {
+ chromatic: {
+ // NOTE: ロードãŒçµ‚ã‚ã‚‹ã¾ã§å¾…ã¤
+ delay: 3000,
+ },
+ layout: 'centered',
+ msw: {
+ handlers: [
+ ...commonHandlers,
+ http.post('/api/drive/files', async ({ request }) => {
+ action('POST /api/drive/files')(await request.json());
+ return HttpResponse.json([file()]);
+ }),
+ http.post('/api/drive/folders', async ({ request }) => {
+ action('POST /api/drive/folders')(await request.json());
+ return HttpResponse.json([folder(crypto.randomUUID())]);
+ }),
+ http.post('/api/drive/folders/create', async ({ request }) => {
+ const req = await request.json() as Misskey.entities.DriveFoldersCreateRequest;
+ action('POST /api/drive/folders/create')(req);
+ return HttpResponse.json(folder(crypto.randomUUID(), req.name, req.parentId));
+ }),
+ http.post('/api/drive/folders/delete', async ({ request }) => {
+ action('POST /api/drive/folders/delete')(await request.json());
+ return HttpResponse.json(undefined, { status: 204 });
+ }),
+ http.post('/api/drive/folders/update', async ({ request }) => {
+ const req = await request.json() as Misskey.entities.DriveFoldersUpdateRequest;
+ action('POST /api/drive/folders/update')(req);
+ return HttpResponse.json({
+ ...folder(),
+ id: req.folderId,
+ name: req.name ?? folder().name,
+ parentId: req.parentId ?? folder().parentId,
+ });
+ }),
+ ]
+ },
+ },
+} satisfies StoryObj<typeof MkDrive>;
diff --git a/packages/frontend/src/components/MkDrive.vue b/packages/frontend/src/components/MkDrive.vue
index a9717b4fb7..dbb4917069 100644
--- a/packages/frontend/src/components/MkDrive.vue
+++ b/packages/frontend/src/components/MkDrive.vue
@@ -52,6 +52,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:selectMode="select === 'folder'"
:isSelected="selectedFolders.some(x => x.id === f.id)"
@chosen="chooseFolder"
+ @unchose="unchoseFolder"
@move="move"
@upload="upload"
@removeFile="removeFile"
@@ -428,6 +429,11 @@ function chooseFolder(folderToChoose: Misskey.entities.DriveFolder) {
}
}
+function unchoseFolder(folderToUnchose: Misskey.entities.DriveFolder) {
+ selectedFolders.value = selectedFolders.value.filter(f => f.id !== folderToUnchose.id);
+ emit('change-selection', selectedFolders.value);
+}
+
function move(target?: Misskey.entities.DriveFolder | Misskey.entities.DriveFolder['id' | 'parentId']) {
if (!target) {
goRoot();
diff --git a/packages/frontend/src/components/MkDriveFileThumbnail.stories.impl.ts b/packages/frontend/src/components/MkDriveFileThumbnail.stories.impl.ts
new file mode 100644
index 0000000000..3fa24d7edb
--- /dev/null
+++ b/packages/frontend/src/components/MkDriveFileThumbnail.stories.impl.ts
@@ -0,0 +1,41 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { StoryObj } from '@storybook/vue3';
+import MkDriveFileThumbnail from './MkDriveFileThumbnail.vue';
+import { file } from '../../.storybook/fakes.js';
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ MkDriveFileThumbnail,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ },
+ template: '<MkDriveFileThumbnail v-bind="props" />',
+ };
+ },
+ args: {
+ file: file(),
+ fit: 'contain',
+ },
+ parameters: {
+ chromatic: {
+ // NOTE: ロードãŒçµ‚ã‚ã‚‹ã¾ã§å¾…ã¤
+ delay: 3000,
+ },
+ layout: 'centered',
+ },
+} satisfies StoryObj<typeof MkDriveFileThumbnail>;
diff --git a/packages/frontend/src/components/MkDriveFileThumbnail.vue b/packages/frontend/src/components/MkDriveFileThumbnail.vue
index 706c9a55c7..2c47a70970 100644
--- a/packages/frontend/src/components/MkDriveFileThumbnail.vue
+++ b/packages/frontend/src/components/MkDriveFileThumbnail.vue
@@ -26,7 +26,7 @@ import ImgWithBlurhash from '@/components/MkImgWithBlurhash.vue';
const props = defineProps<{
file: Misskey.entities.DriveFile;
- fit: string;
+ fit: 'cover' | 'contain';
}>();
const is = computed(() => {
diff --git a/packages/frontend/src/components/MkDriveSelectDialog.stories.impl.ts b/packages/frontend/src/components/MkDriveSelectDialog.stories.impl.ts
new file mode 100644
index 0000000000..fe8f705165
--- /dev/null
+++ b/packages/frontend/src/components/MkDriveSelectDialog.stories.impl.ts
@@ -0,0 +1,7 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import MkDriveSelectDialog from './MkDriveSelectDialog.vue';
+void MkDriveSelectDialog;
diff --git a/packages/frontend/src/components/MkDriveWindow.stories.impl.ts b/packages/frontend/src/components/MkDriveWindow.stories.impl.ts
new file mode 100644
index 0000000000..faa1f7fd5f
--- /dev/null
+++ b/packages/frontend/src/components/MkDriveWindow.stories.impl.ts
@@ -0,0 +1,7 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import MkDriveWindow from './MkDriveWindow.vue';
+void MkDriveWindow;
diff --git a/packages/frontend/src/components/MkEmojiPicker.section.stories.impl.ts b/packages/frontend/src/components/MkEmojiPicker.section.stories.impl.ts
new file mode 100644
index 0000000000..69aef577de
--- /dev/null
+++ b/packages/frontend/src/components/MkEmojiPicker.section.stories.impl.ts
@@ -0,0 +1,7 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import MkEmojiPicker_section from './MkEmojiPicker.section.vue';
+void MkEmojiPicker_section;
diff --git a/packages/frontend/src/components/MkEmojiPicker.stories.impl.ts b/packages/frontend/src/components/MkEmojiPicker.stories.impl.ts
new file mode 100644
index 0000000000..d38d8de808
--- /dev/null
+++ b/packages/frontend/src/components/MkEmojiPicker.stories.impl.ts
@@ -0,0 +1,54 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { action } from '@storybook/addon-actions';
+import { expect, userEvent, waitFor, within } from '@storybook/test';
+import { StoryObj } from '@storybook/vue3';
+import { i18n } from '@/i18n.js';
+import MkEmojiPicker from './MkEmojiPicker.vue';
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ MkEmojiPicker,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ events() {
+ return {
+ chosen: action('chosen'),
+ };
+ },
+ },
+ template: '<MkEmojiPicker v-bind="props" v-on="events" />',
+ };
+ },
+ async play({ canvasElement }) {
+ const canvas = within(canvasElement);
+ const faceSection = canvas.getByText(/face/i);
+ await waitFor(() => userEvent.click(faceSection));
+ const grinning = canvasElement.querySelector('[data-emoji="😀"]');
+ await expect(grinning).toBeInTheDocument();
+ if (grinning == null) throw new Error(); // NOTE: not called
+ await waitFor(() => userEvent.click(grinning));
+ const recentUsedSection = canvas.getByText(new RegExp(i18n.ts.recentUsed)).parentElement;
+ await expect(recentUsedSection).toBeInTheDocument();
+ if (recentUsedSection == null) throw new Error(); // NOTE: not called
+ await expect(within(recentUsedSection).getByAltText('😀')).toBeInTheDocument();
+ await expect(within(recentUsedSection).queryByAltText('😬')).toEqual(null);
+ },
+ parameters: {
+ layout: 'centered',
+ },
+} satisfies StoryObj<typeof MkEmojiPicker>;
diff --git a/packages/frontend/src/components/MkEmojiPicker.vue b/packages/frontend/src/components/MkEmojiPicker.vue
index 8a6bef54d8..4a3ed69f47 100644
--- a/packages/frontend/src/components/MkEmojiPicker.vue
+++ b/packages/frontend/src/components/MkEmojiPicker.vue
@@ -5,7 +5,19 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<div class="omfetrab" :class="['s' + size, 'w' + width, 'h' + height, { asDrawer, asWindow }]" :style="{ maxHeight: maxHeight ? maxHeight + 'px' : undefined }">
- <input ref="searchEl" :value="q" class="search" data-prevent-emoji-insert :class="{ filled: q != null && q != '' }" :placeholder="i18n.ts.search" type="search" autocapitalize="off" @input="input()" @paste.stop="paste" @keydown.stop.prevent.enter="onEnter">
+ <input
+ ref="searchEl"
+ :value="q"
+ class="search"
+ data-prevent-emoji-insert
+ :class="{ filled: q != null && q != '' }"
+ :placeholder="i18n.ts.search"
+ type="search"
+ autocapitalize="off"
+ @input="input()"
+ @paste.stop="paste"
+ @keydown="onKeydown"
+ >
<!-- Firefoxã®Tabãƒ•ã‚©ãƒ¼ã‚«ã‚¹ãŒæƒ³å®šå¤–ã®æŒ™å‹•ã¨ãªã‚‹ãŸã‚tabindex="-1"を追加 https://github.com/misskey-dev/misskey/issues/10744 -->
<div ref="emojisEl" class="emojis" tabindex="-1">
<section class="result">
@@ -139,6 +151,7 @@ const props = withDefaults(defineProps<{
const emit = defineEmits<{
(ev: 'chosen', v: string): void;
+ (ev: 'esc'): void;
}>();
const searchEl = shallowRef<HTMLInputElement>();
@@ -402,7 +415,9 @@ function chosen(emoji: any, ev?: MouseEvent) {
const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2);
- os.popup(MkRippleEffect, { x, y }, {}, 'end');
+ const { dispose } = os.popup(MkRippleEffect, { x, y }, {
+ end: () => dispose(),
+ });
}
const key = getKey(emoji);
@@ -431,9 +446,18 @@ function paste(event: ClipboardEvent): void {
}
}
-function onEnter(ev: KeyboardEvent) {
+function onKeydown(ev: KeyboardEvent) {
if (ev.isComposing || ev.key === 'Process' || ev.keyCode === 229) return;
- done();
+ if (ev.key === 'Enter') {
+ ev.preventDefault();
+ ev.stopPropagation();
+ done();
+ }
+ if (ev.key === 'Escape') {
+ ev.preventDefault();
+ ev.stopPropagation();
+ emit('esc');
+ }
}
function done(query?: string): boolean | void {
@@ -700,11 +724,6 @@ defineExpose({
border-radius: 4px;
font-size: 24px;
- &:focus-visible {
- outline: solid 2px var(--focus);
- z-index: 1;
- }
-
&:hover {
background: rgba(0, 0, 0, 0.05);
}
diff --git a/packages/frontend/src/components/MkEmojiPickerDialog.stories.impl.ts b/packages/frontend/src/components/MkEmojiPickerDialog.stories.impl.ts
new file mode 100644
index 0000000000..131087ad45
--- /dev/null
+++ b/packages/frontend/src/components/MkEmojiPickerDialog.stories.impl.ts
@@ -0,0 +1,7 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import MkEmojiPickerDialog from './MkEmojiPickerDialog.vue';
+void MkEmojiPickerDialog;
diff --git a/packages/frontend/src/components/MkEmojiPickerDialog.vue b/packages/frontend/src/components/MkEmojiPickerDialog.vue
index adcea839ee..7e1ffbfa9e 100644
--- a/packages/frontend/src/components/MkEmojiPickerDialog.vue
+++ b/packages/frontend/src/components/MkEmojiPickerDialog.vue
@@ -9,10 +9,12 @@ SPDX-License-Identifier: AGPL-3.0-only
v-slot="{ type, maxHeight }"
:zPriority="'middle'"
:preferType="defaultStore.state.emojiPickerUseDrawerForMobile === false ? 'popup' : 'auto'"
+ :hasInteractionWithOtherFocusTrappedEls="true"
:transparentBg="true"
:manualShowing="manualShowing"
:src="src"
@click="modal?.close()"
+ @esc="modal?.close()"
@opening="opening"
@close="emit('close')"
@closed="emit('closed')"
@@ -28,6 +30,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:asDrawer="type === 'drawer'"
:max-height="maxHeight"
@chosen="chosen"
+ @esc="modal?.close()"
/>
</MkModal>
</template>
diff --git a/packages/frontend/src/components/MkFlashPreview.vue b/packages/frontend/src/components/MkFlashPreview.vue
index c5dd877971..6783804cc5 100644
--- a/packages/frontend/src/components/MkFlashPreview.vue
+++ b/packages/frontend/src/components/MkFlashPreview.vue
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
-<MkA :to="`/play/${flash.id}`" class="vhpxefrk _panel" tabindex="-1">
+<MkA :to="`/play/${flash.id}`" class="vhpxefrk _panel">
<article>
<header>
<h1 :title="flash.title">{{ flash.title }}</h1>
@@ -39,6 +39,10 @@ const props = defineProps<{
color: var(--accent);
}
+ &:focus-visible {
+ outline-offset: -2px;
+ }
+
> article {
padding: 16px;
diff --git a/packages/frontend/src/components/MkFolder.vue b/packages/frontend/src/components/MkFolder.vue
index 9b8eb19a11..f805be7b57 100644
--- a/packages/frontend/src/components/MkFolder.vue
+++ b/packages/frontend/src/components/MkFolder.vue
@@ -7,10 +7,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<div ref="rootEl" :class="$style.root" role="group" :aria-expanded="opened">
<MkStickyContainer>
<template #header>
- <div :class="[$style.header, { [$style.opened]: opened }]" class="_button" role="button" data-cy-folder-header @click="toggle">
+ <button :class="[$style.header, { [$style.opened]: opened }]" class="_button" role="button" data-cy-folder-header @click="toggle">
<div :class="$style.headerIcon"><slot name="icon"></slot></div>
<div :class="$style.headerText">
- <div>
+ <div :class="$style.headerTextMain">
<MkCondensedLine :minScale="2 / 3"><slot name="label"></slot></MkCondensedLine>
</div>
<div :class="$style.headerTextSub">
@@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<i v-if="opened" class="ti ti-chevron-up icon"></i>
<i v-else class="ti ti-chevron-down icon"></i>
</div>
- </div>
+ </button>
</template>
<div v-if="openedAtLeastOnce" :class="[$style.body, { [$style.bgSame]: bgSame }]" :style="{ maxHeight: maxHeight ? `${maxHeight}px` : undefined, overflow: maxHeight ? `auto` : undefined }" :aria-hidden="!opened">
@@ -147,6 +147,10 @@ onMounted(() => {
background: var(--buttonHoverBg);
}
+ &:focus-within {
+ outline-offset: 2px;
+ }
+
&.active {
color: var(--accent);
background: var(--buttonHoverBg);
@@ -190,6 +194,12 @@ onMounted(() => {
padding-right: 12px;
}
+.headerTextMain,
+.headerTextSub {
+ width: fit-content;
+ max-width: 100%;
+}
+
.headerTextSub {
color: var(--fgTransparentWeak);
font-size: .85em;
diff --git a/packages/frontend/src/components/MkFollowButton.vue b/packages/frontend/src/components/MkFollowButton.vue
index 636e61db8f..d8ac8024b4 100644
--- a/packages/frontend/src/components/MkFollowButton.vue
+++ b/packages/frontend/src/components/MkFollowButton.vue
@@ -42,6 +42,8 @@ import { misskeyApi } from '@/scripts/misskey-api.js';
import { useStream } from '@/stream.js';
import { i18n } from '@/i18n.js';
import { claimAchievement } from '@/scripts/achievements.js';
+import { pleaseLogin } from '@/scripts/please-login.js';
+import { host } from '@/config.js';
import { $i } from '@/account.js';
import { defaultStore } from '@/store.js';
@@ -63,7 +65,7 @@ const hasPendingFollowRequestFromYou = ref(props.user.hasPendingFollowRequestFro
const wait = ref(false);
const connection = useStream().useChannel('main');
-if (props.user.isFollowing == null) {
+if (props.user.isFollowing == null && $i) {
misskeyApi('users/show', {
userId: props.user.id,
})
@@ -78,6 +80,8 @@ function onFollowChange(user: Misskey.entities.UserDetailed) {
}
async function onClick() {
+ pleaseLogin(undefined, { type: 'web', path: `/@${props.user.username}@${props.user.host ?? host}` });
+
wait.value = true;
try {
@@ -121,6 +125,8 @@ async function onClick() {
});
hasPendingFollowRequestFromYou.value = true;
+ if ($i == null) return;
+
claimAchievement('following1');
if ($i.followingCount >= 10) {
@@ -183,17 +189,7 @@ onBeforeUnmount(() => {
}
&:focus-visible {
- &:after {
- content: "";
- pointer-events: none;
- position: absolute;
- top: -5px;
- right: -5px;
- bottom: -5px;
- left: -5px;
- border: 2px solid var(--focus);
- border-radius: 32px;
- }
+ outline-offset: 2px;
}
&:hover {
diff --git a/packages/frontend/src/components/MkGalleryPostPreview.vue b/packages/frontend/src/components/MkGalleryPostPreview.vue
index 47cccd9b7c..2bb5b8762a 100644
--- a/packages/frontend/src/components/MkGalleryPostPreview.vue
+++ b/packages/frontend/src/components/MkGalleryPostPreview.vue
@@ -83,7 +83,7 @@ function leaveHover(): void {
> article {
> footer {
- &:before {
+ &::before {
opacity: 1;
}
}
@@ -139,7 +139,7 @@ function leaveHover(): void {
text-shadow: 0 0 8px #000;
background: linear-gradient(transparent, rgba(0, 0, 0, 0.7));
- &:before {
+ &::before {
content: "";
display: block;
position: absolute;
diff --git a/packages/frontend/src/components/MkImgWithBlurhash.vue b/packages/frontend/src/components/MkImgWithBlurhash.vue
index 4e3fafe845..8d301f16bd 100644
--- a/packages/frontend/src/components/MkImgWithBlurhash.vue
+++ b/packages/frontend/src/components/MkImgWithBlurhash.vue
@@ -14,8 +14,8 @@ SPDX-License-Identifier: AGPL-3.0-only
:enterToClass="defaultStore.state.animation && props.transition?.enterToClass || undefined"
:leaveFromClass="defaultStore.state.animation && props.transition?.leaveFromClass || undefined"
>
- <canvas v-show="hide" key="canvas" ref="canvas" :class="$style.canvas" :width="canvasWidth" :height="canvasHeight" :title="title ?? undefined"/>
- <img v-show="!hide" key="img" ref="img" :height="imgHeight" :width="imgWidth" :class="$style.img" :src="src ?? undefined" :title="title ?? undefined" :alt="alt ?? undefined" loading="eager" decoding="async"/>
+ <canvas v-show="hide" key="canvas" ref="canvas" :class="$style.canvas" :width="canvasWidth" :height="canvasHeight" :title="title ?? undefined" tabindex="-1"/>
+ <img v-show="!hide" key="img" ref="img" :height="imgHeight ?? undefined" :width="imgWidth ?? undefined" :class="$style.img" :src="src ?? undefined" :title="title ?? undefined" :alt="alt ?? undefined" loading="eager" decoding="async" tabindex="-1"/>
</TransitionGroup>
</div>
</template>
@@ -151,22 +151,26 @@ function drawImage(bitmap: CanvasImageSource) {
}
function drawAvg() {
- if (!canvas.value || !props.hash) return;
+ if (!canvas.value) return;
+
+ const color = (props.hash != null && extractAvgColorFromBlurhash(props.hash)) || '#888';
const ctx = canvas.value.getContext('2d');
if (!ctx) return;
// avgColorã§ãŠèŒ¶ã‚’ã«ã”ã™
ctx.beginPath();
- ctx.fillStyle = extractAvgColorFromBlurhash(props.hash) ?? '#888';
+ ctx.fillStyle = color;
ctx.fillRect(0, 0, canvasWidth.value, canvasHeight.value);
}
async function draw() {
- if (props.hash == null) return;
+ if (import.meta.env.MODE === 'test' && props.hash == null) return;
drawAvg();
+ if (props.hash == null) return;
+
if (props.onlyAvgColor) return;
const work = await canvasPromise;
diff --git a/packages/frontend/src/components/MkInput.vue b/packages/frontend/src/components/MkInput.vue
index 88ef4635e6..e695564f92 100644
--- a/packages/frontend/src/components/MkInput.vue
+++ b/packages/frontend/src/components/MkInput.vue
@@ -79,7 +79,7 @@ const props = defineProps<{
const emit = defineEmits<{
(ev: 'change', _ev: KeyboardEvent): void;
(ev: 'keydown', _ev: KeyboardEvent): void;
- (ev: 'enter'): void;
+ (ev: 'enter', _ev: KeyboardEvent): void;
(ev: 'update:modelValue', value: string | number): void;
}>();
@@ -111,7 +111,7 @@ const onKeydown = (ev: KeyboardEvent) => {
emit('keydown', ev);
if (ev.code === 'Enter') {
- emit('enter');
+ emit('enter', ev);
}
};
diff --git a/packages/frontend/src/components/MkInstanceCardMini.stories.impl.ts b/packages/frontend/src/components/MkInstanceCardMini.stories.impl.ts
new file mode 100644
index 0000000000..9e8de9d878
--- /dev/null
+++ b/packages/frontend/src/components/MkInstanceCardMini.stories.impl.ts
@@ -0,0 +1,65 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+import { StoryObj } from '@storybook/vue3';
+import { HttpResponse, http } from 'msw';
+import { federationInstance } from '../../.storybook/fakes.js';
+import { commonHandlers } from '../../.storybook/mocks.js';
+import { getChartResolver } from '../../.storybook/charts.js';
+import MkInstanceCardMini from './MkInstanceCardMini.vue';
+
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ MkInstanceCardMini,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ },
+ template: '<MkInstanceCardMini v-bind="props" />',
+ };
+ },
+ args: {
+ instance: federationInstance(),
+ },
+ parameters: {
+ layout: 'centered',
+ msw: {
+ handlers: [
+ ...commonHandlers,
+ http.get('/undefined/preview.webp', async ({ request }) => {
+ const urlStr = new URL(request.url).searchParams.get('url');
+ if (urlStr == null) {
+ return new HttpResponse(null, { status: 404 });
+ }
+ const url = new URL(urlStr);
+
+ if (url.href.startsWith('https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/')) {
+ const image = await (await fetch(`client-assets/${url.pathname.split('/').pop()}`)).blob();
+ return new HttpResponse(image, {
+ headers: {
+ 'Content-Type': 'image/jpeg',
+ },
+ });
+ } else {
+ return new HttpResponse(null, { status: 404 });
+ }
+ }),
+ http.get('/api/charts/instance', getChartResolver(['requests.received'])),
+ ],
+ },
+ },
+} satisfies StoryObj<typeof MkInstanceCardMini>;
diff --git a/packages/frontend/src/components/MkInstanceCardMini.vue b/packages/frontend/src/components/MkInstanceCardMini.vue
index e26aef0f69..17c974dd04 100644
--- a/packages/frontend/src/components/MkInstanceCardMini.vue
+++ b/packages/frontend/src/components/MkInstanceCardMini.vue
@@ -29,8 +29,8 @@ const chartValues = ref<number[] | null>(null);
misskeyApiGet('charts/instance', { host: props.instance.host, limit: 16 + 1, span: 'day' }).then(res => {
// 今日ã®ã¶ã‚“ã®å€¤ã¯ã¾ã é€”中ã®å€¤ã§ã‚りã€ãれもå«ã‚ã‚‹ã¨å¤§æŠµã®å ´åˆå‰æ—¥ã‚ˆã‚Šã‚‚下é™ã—ã¦ã„るよã†ãªã‚°ãƒ©ãƒ•ã«ãªã£ã¦ã—ã¾ã†ãŸã‚今日ã¯å¼¾ã
- res['requests.received'].splice(0, 1);
- chartValues.value = res['requests.received'];
+ res.requests.received.splice(0, 1);
+ chartValues.value = res.requests.received;
});
function getInstanceIcon(instance): string {
diff --git a/packages/frontend/src/components/MkInviteCode.vue b/packages/frontend/src/components/MkInviteCode.vue
index 1c6f412dc1..de51a98789 100644
--- a/packages/frontend/src/components/MkInviteCode.vue
+++ b/packages/frontend/src/components/MkInviteCode.vue
@@ -62,7 +62,7 @@ import { computed } from 'vue';
import * as Misskey from 'misskey-js';
import MkFolder from '@/components/MkFolder.vue';
import MkButton from '@/components/MkButton.vue';
-import copyToClipboard from '@/scripts/copy-to-clipboard.js';
+import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
import { i18n } from '@/i18n.js';
import * as os from '@/os.js';
diff --git a/packages/frontend/src/components/MkKeyValue.vue b/packages/frontend/src/components/MkKeyValue.vue
index 20b1ef2be2..50c9e16e5e 100644
--- a/packages/frontend/src/components/MkKeyValue.vue
+++ b/packages/frontend/src/components/MkKeyValue.vue
@@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { } from 'vue';
-import copyToClipboard from '@/scripts/copy-to-clipboard.js';
+import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
diff --git a/packages/frontend/src/components/MkLaunchPad.vue b/packages/frontend/src/components/MkLaunchPad.vue
index f9d4334c4c..8e3c19bd12 100644
--- a/packages/frontend/src/components/MkLaunchPad.vue
+++ b/packages/frontend/src/components/MkLaunchPad.vue
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
-<MkModal ref="modal" v-slot="{ type, maxHeight }" :preferType="preferedModalType" :anchor="anchor" :transparentBg="true" :src="src" @click="modal?.close()" @closed="emit('closed')">
+<MkModal ref="modal" v-slot="{ type, maxHeight }" :preferType="preferedModalType" :anchor="anchor" :transparentBg="true" :src="src" @click="modal?.close()" @closed="emit('closed')" @esc="modal?.close()">
<div class="szkkfdyq _popup _shadow" :class="{ asDrawer: type === 'drawer' }" :style="{ maxHeight: maxHeight ? maxHeight + 'px' : '' }">
<div class="main">
<template v-for="item in items" :key="item.text">
diff --git a/packages/frontend/src/components/MkLink.vue b/packages/frontend/src/components/MkLink.vue
index 5d54a58e97..e842ec2d6e 100644
--- a/packages/frontend/src/components/MkLink.vue
+++ b/packages/frontend/src/components/MkLink.vue
@@ -37,11 +37,13 @@ const el = ref<HTMLElement | { $el: HTMLElement }>();
if (isEnabledUrlPreview.value) {
useTooltip(el, (showing) => {
- os.popup(defineAsyncComponent(() => import('@/components/MkUrlPreviewPopup.vue')), {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkUrlPreviewPopup.vue')), {
showing,
url: props.url,
source: el.value instanceof HTMLElement ? el.value : el.value?.$el,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
});
}
</script>
diff --git a/packages/frontend/src/components/MkMediaAudio.vue b/packages/frontend/src/components/MkMediaAudio.vue
index 5d2edf467e..a080550ddf 100644
--- a/packages/frontend/src/components/MkMediaAudio.vue
+++ b/packages/frontend/src/components/MkMediaAudio.vue
@@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only
@contextmenu.stop
@keydown.stop
>
- <button v-if="hide" :class="$style.hidden" @click="hide = false">
+ <button v-if="hide" :class="$style.hidden" @click="show">
<div :class="$style.hiddenTextWrapper">
<b v-if="audio.isSensitive" style="display: block;"><i class="ti ti-eye-exclamation"></i> {{ i18n.ts.sensitive }}{{ defaultStore.state.dataSaver.media ? ` (${i18n.ts.audio}${audio.size ? ' ' + bytes(audio.size) : ''})` : '' }}</b>
<b v-else style="display: block;"><i class="ti ti-music"></i> {{ defaultStore.state.dataSaver.media && audio.size ? bytes(audio.size) : i18n.ts.audio }}</b>
@@ -39,23 +39,37 @@ SPDX-License-Identifier: AGPL-3.0-only
<audio
ref="audioEl"
preload="metadata"
+ @keydown.prevent="() => {}"
>
<source :src="audio.url">
</audio>
<div :class="[$style.controlsChild, $style.controlsLeft]">
- <button class="_button" :class="$style.controlButton" @click="togglePlayPause">
+ <button
+ :class="['_button', $style.controlButton]"
+ tabindex="-1"
+ @click.stop="togglePlayPause"
+ >
<i v-if="isPlaying" class="ti ti-player-pause-filled"></i>
<i v-else class="ti ti-player-play-filled"></i>
</button>
</div>
<div :class="[$style.controlsChild, $style.controlsRight]">
- <button class="_button" :class="$style.controlButton" @click="showMenu">
+ <button
+ :class="['_button', $style.controlButton]"
+ tabindex="-1"
+ @click.stop="() => {}"
+ @mousedown.prevent.stop="showMenu"
+ >
<i class="ti ti-settings"></i>
</button>
</div>
<div :class="[$style.controlsChild, $style.controlsTime]">{{ hms(elapsedTimeMs) }}</div>
<div :class="[$style.controlsChild, $style.controlsVolume]">
- <button class="_button" :class="$style.controlButton" @click="toggleMute">
+ <button
+ :class="['_button', $style.controlButton]"
+ tabindex="-1"
+ @click.stop="toggleMute"
+ >
<i v-if="volume === 0" class="ti ti-volume-3"></i>
<i v-else class="ti ti-volume"></i>
</button>
@@ -80,6 +94,7 @@ import type { MenuItem } from '@/types/menu.js';
import { defaultStore } from '@/store.js';
import { i18n } from '@/i18n.js';
import * as os from '@/os.js';
+import { type Keymap } from '@/scripts/hotkey.js';
import bytes from '@/filters/bytes.js';
import { hms } from '@/filters/hms.js';
import MkMediaRange from '@/components/MkMediaRange.vue';
@@ -90,32 +105,44 @@ const props = defineProps<{
}>();
const keymap = {
- 'up': () => {
- if (hasFocus() && audioEl.value) {
- volume.value = Math.min(volume.value + 0.1, 1);
- }
+ 'up': {
+ allowRepeat: true,
+ callback: () => {
+ if (hasFocus() && audioEl.value) {
+ volume.value = Math.min(volume.value + 0.1, 1);
+ }
+ },
},
- 'down': () => {
- if (hasFocus() && audioEl.value) {
- volume.value = Math.max(volume.value - 0.1, 0);
- }
+ 'down': {
+ allowRepeat: true,
+ callback: () => {
+ if (hasFocus() && audioEl.value) {
+ volume.value = Math.max(volume.value - 0.1, 0);
+ }
+ },
},
- 'left': () => {
- if (hasFocus() && audioEl.value) {
- audioEl.value.currentTime = Math.max(audioEl.value.currentTime - 5, 0);
- }
+ 'left': {
+ allowRepeat: true,
+ callback: () => {
+ if (hasFocus() && audioEl.value) {
+ audioEl.value.currentTime = Math.max(audioEl.value.currentTime - 5, 0);
+ }
+ },
},
- 'right': () => {
- if (hasFocus() && audioEl.value) {
- audioEl.value.currentTime = Math.min(audioEl.value.currentTime + 5, audioEl.value.duration);
- }
+ 'right': {
+ allowRepeat: true,
+ callback: () => {
+ if (hasFocus() && audioEl.value) {
+ audioEl.value.currentTime = Math.min(audioEl.value.currentTime + 5, audioEl.value.duration);
+ }
+ },
},
'space': () => {
if (hasFocus()) {
togglePlayPause();
}
},
-};
+} as const satisfies Keymap;
// PlayerElã‚‚ã—ãã¯ãã®å­è¦ç´ ã«ãƒ•ォーカスãŒã‚ã‚‹ã‹ã©ã†ã‹
function hasFocus() {
@@ -126,9 +153,21 @@ function hasFocus() {
const playerEl = shallowRef<HTMLDivElement>();
const audioEl = shallowRef<HTMLAudioElement>();
-// eslint-disable-next-line vue/no-setup-props-destructure
+// eslint-disable-next-line vue/no-setup-props-reactivity-loss
const hide = ref((defaultStore.state.nsfw === 'force' || defaultStore.state.dataSaver.media) ? true : (props.audio.isSensitive && defaultStore.state.nsfw !== 'ignore'));
+async function show() {
+ if (props.audio.isSensitive && defaultStore.state.confirmWhenRevealingSensitiveMedia) {
+ const { canceled } = await os.confirm({
+ type: 'question',
+ text: i18n.ts.sensitiveMediaRevealConfirm,
+ });
+ if (canceled) return;
+ }
+
+ hide.value = false;
+}
+
// Menu
const menuShowing = ref(false);
@@ -358,7 +397,7 @@ onDeactivated(() => {
border-radius: var(--radius);
overflow: clip;
- &:focus {
+ &:focus-visible {
outline: none;
}
}
@@ -424,6 +463,10 @@ onDeactivated(() => {
color: var(--accent);
background-color: var(--accentedBg);
}
+
+ &:focus-visible {
+ outline: none;
+ }
}
}
diff --git a/packages/frontend/src/components/MkMediaBanner.vue b/packages/frontend/src/components/MkMediaBanner.vue
index a219848b7f..11995e1f3b 100644
--- a/packages/frontend/src/components/MkMediaBanner.vue
+++ b/packages/frontend/src/components/MkMediaBanner.vue
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<div :class="$style.root">
<MkMediaAudio v-if="media.type.startsWith('audio') && media.type !== 'audio/midi'" :audio="media"/>
- <div v-else-if="media.isSensitive && hide" :class="$style.sensitive" @click="hide = false">
+ <div v-else-if="media.isSensitive && hide" :class="$style.sensitive" @click="show">
<span style="font-size: 1.6em;"><i class="ti ti-alert-triangle"></i></span>
<b>{{ i18n.ts.sensitive }}</b>
<span>{{ i18n.ts.clickToShow }}</span>
@@ -24,24 +24,30 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { shallowRef, watch, ref } from 'vue';
+import { ref } from 'vue';
import * as Misskey from 'misskey-js';
import { i18n } from '@/i18n.js';
+import { defaultStore } from '@/store.js';
+import * as os from '@/os.js';
import MkMediaAudio from '@/components/MkMediaAudio.vue';
-const props = withDefaults(defineProps<{
+const props = defineProps<{
media: Misskey.entities.DriveFile;
-}>(), {
-});
+}>();
-const audioEl = shallowRef<HTMLAudioElement>();
const hide = ref(true);
-watch(audioEl, () => {
- if (audioEl.value) {
- audioEl.value.volume = 0.3;
+async function show() {
+ if (props.media.isSensitive && defaultStore.state.confirmWhenRevealingSensitiveMedia) {
+ const { canceled } = await os.confirm({
+ type: 'question',
+ text: i18n.ts.sensitiveMediaRevealConfirm,
+ });
+ if (canceled) return;
}
-});
+
+ hide.value = false;
+}
</script>
<style lang="scss" module>
diff --git a/packages/frontend/src/components/MkMediaImage.vue b/packages/frontend/src/components/MkMediaImage.vue
index 82f36fe5c4..0d1409e2c8 100644
--- a/packages/frontend/src/components/MkMediaImage.vue
+++ b/packages/frontend/src/components/MkMediaImage.vue
@@ -83,11 +83,21 @@ const url = computed(() => (props.raw || defaultStore.state.loadRawImages)
: props.image.thumbnailUrl,
);
-function onclick() {
+async function onclick(ev: MouseEvent) {
if (!props.controls) {
return;
}
+
if (hide.value) {
+ ev.stopPropagation();
+ if (props.image.isSensitive && defaultStore.state.confirmWhenRevealingSensitiveMedia) {
+ const { canceled } = await os.confirm({
+ type: 'question',
+ text: i18n.ts.sensitiveMediaRevealConfirm,
+ });
+ if (canceled) return;
+ }
+
hide.value = false;
}
}
diff --git a/packages/frontend/src/components/MkMediaList.vue b/packages/frontend/src/components/MkMediaList.vue
index b1321a8ef9..2300802dcf 100644
--- a/packages/frontend/src/components/MkMediaList.vue
+++ b/packages/frontend/src/components/MkMediaList.vue
@@ -39,6 +39,7 @@ import XVideo from '@/components/MkMediaVideo.vue';
import * as os from '@/os.js';
import { FILE_TYPE_BROWSERSAFE } from '@/const.js';
import { defaultStore } from '@/store.js';
+import { focusParent } from '@/scripts/focus.js';
const props = defineProps<{
mediaList: Misskey.entities.DriveFile[];
@@ -49,7 +50,9 @@ const gallery = shallowRef<HTMLDivElement>();
const pswpZIndex = os.claimZIndex('middle');
document.documentElement.style.setProperty('--mk-pswp-root-z-index', pswpZIndex.toString());
const count = computed(() => props.mediaList.filter(media => previewable(media)).length);
-let lightbox: PhotoSwipeLightbox | null;
+let lightbox: PhotoSwipeLightbox | null = null;
+
+let activeEl: HTMLElement | null = null;
const popstateHandler = (): void => {
if (lightbox?.pswp && lightbox.pswp.isOpen === true) {
@@ -60,7 +63,7 @@ const popstateHandler = (): void => {
async function calcAspectRatio() {
if (!gallery.value) return;
- let img = props.mediaList[0];
+ const img = props.mediaList[0];
if (props.mediaList.length !== 1 || !(img.properties.width && img.properties.height)) {
gallery.value.style.aspectRatio = '';
@@ -131,18 +134,17 @@ onMounted(() => {
bgOpacity: 1,
showAnimationDuration: 100,
hideAnimationDuration: 100,
+ returnFocus: false,
pswpModule: PhotoSwipe,
});
- lightbox.on('itemData', (ev) => {
- const { itemData } = ev;
-
+ lightbox.addFilter('itemData', (itemData) => {
// element is children
const { element } = itemData;
const id = element?.dataset.id;
const file = props.mediaList.find(media => media.id === id);
- if (!file) return;
+ if (!file) return itemData;
itemData.src = file.url;
itemData.w = Number(file.properties.width);
@@ -154,44 +156,54 @@ onMounted(() => {
itemData.alt = file.comment ?? file.name;
itemData.comment = file.comment ?? file.name;
itemData.thumbCropped = true;
+
+ return itemData;
});
lightbox.on('uiRegister', () => {
lightbox?.pswp?.ui?.registerElement({
name: 'altText',
- className: 'pwsp__alt-text-container',
+ className: 'pswp__alt-text-container',
appendTo: 'wrapper',
- onInit: (el, pwsp) => {
- let textBox = document.createElement('p');
- textBox.className = 'pwsp__alt-text _acrylic';
+ onInit: (el, pswp) => {
+ const textBox = document.createElement('p');
+ textBox.className = 'pswp__alt-text _acrylic';
el.appendChild(textBox);
- pwsp.on('change', () => {
- textBox.textContent = pwsp.currSlide?.data.comment;
+ pswp.on('change', () => {
+ textBox.textContent = pswp.currSlide?.data.comment;
});
},
});
});
- lightbox.init();
-
- window.addEventListener('popstate', popstateHandler);
-
- lightbox.on('beforeOpen', () => {
+ lightbox.on('afterInit', () => {
+ activeEl = document.activeElement instanceof HTMLElement ? document.activeElement : null;
+ focusParent(activeEl, true, true);
+ lightbox?.pswp?.element?.focus({
+ preventScroll: true,
+ });
history.pushState(null, '', '#pswp');
});
- lightbox.on('close', () => {
+ lightbox.on('destroy', () => {
+ focusParent(activeEl, true, false);
+ activeEl = null;
if (window.location.hash === '#pswp') {
history.back();
}
});
+
+ window.addEventListener('popstate', popstateHandler);
+
+ lightbox.init();
});
onUnmounted(() => {
window.removeEventListener('popstate', popstateHandler);
lightbox?.destroy();
lightbox = null;
+ activeEl = null;
});
const previewable = (file: Misskey.entities.DriveFile): boolean => {
@@ -199,6 +211,16 @@ const previewable = (file: Misskey.entities.DriveFile): boolean => {
// FILE_TYPE_BROWSERSAFEã«é©åˆã—ãªã„ã‚‚ã®ã¯ãƒ–ラウザã§è¡¨ç¤ºã™ã‚‹ã®ã«ä¸é©åˆ‡
return (file.type.startsWith('video') || file.type.startsWith('image')) && FILE_TYPE_BROWSERSAFE.includes(file.type);
};
+
+const openGallery = () => {
+ if (props.mediaList.filter(media => previewable(media)).length > 0) {
+ lightbox?.loadAndOpen(0);
+ }
+};
+
+defineExpose({
+ openGallery,
+});
</script>
<style lang="scss" module>
@@ -298,7 +320,7 @@ const previewable = (file: Misskey.entities.DriveFile): boolean => {
backdrop-filter: var(--modalBgFilter);
}
-.pwsp__alt-text-container {
+.pswp__alt-text-container {
display: flex;
flex-direction: row;
align-items: center;
@@ -312,7 +334,7 @@ const previewable = (file: Misskey.entities.DriveFile): boolean => {
max-width: 800px;
}
-.pwsp__alt-text {
+.pswp__alt-text {
color: var(--fg);
margin: 0 auto;
text-align: center;
diff --git a/packages/frontend/src/components/MkMediaVideo.vue b/packages/frontend/src/components/MkMediaVideo.vue
index 1e3868bc36..7c5a365148 100644
--- a/packages/frontend/src/components/MkMediaVideo.vue
+++ b/packages/frontend/src/components/MkMediaVideo.vue
@@ -18,7 +18,7 @@ SPDX-License-Identifier: AGPL-3.0-only
@contextmenu.stop
@keydown.stop
>
- <button v-if="hide" :class="$style.hidden" @click="hide = false">
+ <button v-if="hide" :class="$style.hidden" @click="show">
<div :class="$style.hiddenTextWrapper">
<b v-if="video.isSensitive" style="display: block;"><i class="ti ti-eye-exclamation"></i> {{ i18n.ts.sensitive }}{{ defaultStore.state.dataSaver.media ? ` (${i18n.ts.video}${video.size ? ' ' + bytes(video.size) : ''})` : '' }}</b>
<b v-else style="display: block;"><i class="ti ti-movie"></i> {{ defaultStore.state.dataSaver.media && video.size ? bytes(video.size) : i18n.ts.video }}</b>
@@ -112,6 +112,7 @@ SPDX-License-Identifier: AGPL-3.0-only
import { ref, shallowRef, computed, watch, onDeactivated, onActivated, onMounted } from 'vue';
import * as Misskey from 'misskey-js';
import type { MenuItem } from '@/types/menu.js';
+import { type Keymap } from '@/scripts/hotkey.js';
import bytes from '@/filters/bytes.js';
import { hms } from '@/filters/hms.js';
import { defaultStore } from '@/store.js';
@@ -127,32 +128,44 @@ const props = defineProps<{
}>();
const keymap = {
- 'up': () => {
- if (hasFocus() && videoEl.value) {
- volume.value = Math.min(volume.value + 0.1, 1);
- }
+ 'up': {
+ allowRepeat: true,
+ callback: () => {
+ if (hasFocus() && videoEl.value) {
+ volume.value = Math.min(volume.value + 0.1, 1);
+ }
+ },
},
- 'down': () => {
- if (hasFocus() && videoEl.value) {
- volume.value = Math.max(volume.value - 0.1, 0);
- }
+ 'down': {
+ allowRepeat: true,
+ callback: () => {
+ if (hasFocus() && videoEl.value) {
+ volume.value = Math.max(volume.value - 0.1, 0);
+ }
+ },
},
- 'left': () => {
- if (hasFocus() && videoEl.value) {
- videoEl.value.currentTime = Math.max(videoEl.value.currentTime - 5, 0);
- }
+ 'left': {
+ allowRepeat: true,
+ callback: () => {
+ if (hasFocus() && videoEl.value) {
+ videoEl.value.currentTime = Math.max(videoEl.value.currentTime - 5, 0);
+ }
+ },
},
- 'right': () => {
- if (hasFocus() && videoEl.value) {
- videoEl.value.currentTime = Math.min(videoEl.value.currentTime + 5, videoEl.value.duration);
- }
+ 'right': {
+ allowRepeat: true,
+ callback: () => {
+ if (hasFocus() && videoEl.value) {
+ videoEl.value.currentTime = Math.min(videoEl.value.currentTime + 5, videoEl.value.duration);
+ }
+ },
},
'space': () => {
if (hasFocus()) {
togglePlayPause();
}
},
-};
+} as const satisfies Keymap;
// PlayerElã‚‚ã—ãã¯ãã®å­è¦ç´ ã«ãƒ•ォーカスãŒã‚ã‚‹ã‹ã©ã†ã‹
function hasFocus() {
@@ -160,9 +173,21 @@ function hasFocus() {
return playerEl.value === document.activeElement || playerEl.value.contains(document.activeElement);
}
-// eslint-disable-next-line vue/no-setup-props-destructure
+// eslint-disable-next-line vue/no-setup-props-reactivity-loss
const hide = ref((defaultStore.state.nsfw === 'force' || defaultStore.state.dataSaver.media) ? true : (props.video.isSensitive && defaultStore.state.nsfw !== 'ignore'));
+async function show() {
+ if (props.video.isSensitive && defaultStore.state.confirmWhenRevealingSensitiveMedia) {
+ const { canceled } = await os.confirm({
+ type: 'question',
+ text: i18n.ts.sensitiveMediaRevealConfirm,
+ });
+ if (canceled) return;
+ }
+
+ hide.value = false;
+}
+
// Menu
const menuShowing = ref(false);
@@ -468,7 +493,7 @@ onDeactivated(() => {
position: relative;
overflow: clip;
- &:focus {
+ &:focus-visible {
outline: none;
}
}
@@ -575,6 +600,10 @@ onDeactivated(() => {
border-radius: 99rem;
font-size: 1.1rem;
+
+ &:focus-visible {
+ outline: none;
+ }
}
.videoLoading {
@@ -638,6 +667,10 @@ onDeactivated(() => {
&:hover {
background-color: var(--accent);
}
+
+ &:focus-visible {
+ outline: none;
+ }
}
}
diff --git a/packages/frontend/src/components/MkMenu.child.vue b/packages/frontend/src/components/MkMenu.child.vue
index dfb6d34618..235790556c 100644
--- a/packages/frontend/src/components/MkMenu.child.vue
+++ b/packages/frontend/src/components/MkMenu.child.vue
@@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { nextTick, onMounted, onUnmounted, shallowRef, watch } from 'vue';
+import { nextTick, onMounted, onUnmounted, provide, shallowRef, watch } from 'vue';
import MkMenu from './MkMenu.vue';
import { MenuItem } from '@/types/menu.js';
@@ -19,7 +19,6 @@ const props = defineProps<{
targetElement: HTMLElement;
rootElement: HTMLElement;
width?: number;
- viaKeyboard?: boolean;
}>();
const emit = defineEmits<{
@@ -27,6 +26,8 @@ const emit = defineEmits<{
(ev: 'actioned'): void;
}>();
+provide('isNestingMenu', true);
+
const el = shallowRef<HTMLElement>();
const align = 'left';
diff --git a/packages/frontend/src/components/MkMenu.vue b/packages/frontend/src/components/MkMenu.vue
index d91239b9e2..c0728d56fa 100644
--- a/packages/frontend/src/components/MkMenu.vue
+++ b/packages/frontend/src/components/MkMenu.vue
@@ -4,23 +4,42 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
-<div role="menu">
+<div role="menu" @focusin.passive.stop="() => {}">
<div
- ref="itemsEl" v-hotkey="keymap"
+ ref="itemsEl"
+ v-hotkey="keymap"
+ tabindex="0"
class="_popup _shadow"
- :class="[$style.root, { [$style.center]: align === 'center', [$style.asDrawer]: asDrawer }]"
- :style="{ width: (width && !asDrawer) ? width + 'px' : '', maxHeight: maxHeight ? maxHeight + 'px' : '' }"
- @contextmenu.self="e => e.preventDefault()"
+ :class="{
+ [$style.root]: true,
+ [$style.center]: align === 'center',
+ [$style.asDrawer]: asDrawer,
+ }"
+ :style="{
+ width: (width && !asDrawer) ? `${width}px` : '',
+ maxHeight: maxHeight ? `min(${maxHeight}px, calc(100dvh - 32px))` : 'calc(100dvh - 32px)',
+ }"
+ @keydown.stop="() => {}"
+ @contextmenu.self.prevent="() => {}"
>
- <template v-for="(item, i) in (items2 ?? [])">
- <div v-if="item.type === 'divider'" role="separator" :class="$style.divider"></div>
- <span v-else-if="item.type === 'label'" role="menuitem" :class="[$style.label, $style.item]">
+ <template v-for="item in (items2 ?? [])">
+ <div v-if="item.type === 'divider'" role="separator" tabindex="-1" :class="$style.divider"></div>
+ <span v-else-if="item.type === 'label'" role="menuitem" tabindex="-1" :class="[$style.label, $style.item]">
<span style="opacity: 0.7;">{{ item.text }}</span>
</span>
- <span v-else-if="item.type === 'pending'" role="menuitem" :tabindex="i" :class="[$style.pending, $style.item]">
+ <span v-else-if="item.type === 'pending'" role="menuitem" tabindex="0" :class="[$style.pending, $style.item]">
<span><MkEllipsis/></span>
</span>
- <MkA v-else-if="item.type === 'link'" role="menuitem" :to="item.to" :tabindex="i" class="_button" :class="$style.item" @click.passive="close(true)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
+ <MkA
+ v-else-if="item.type === 'link'"
+ role="menuitem"
+ tabindex="0"
+ :class="['_button', $style.item]"
+ :to="item.to"
+ @click.passive="close(true)"
+ @mouseenter.passive="onItemMouseEnter"
+ @mouseleave.passive="onItemMouseLeave"
+ >
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]"></i>
<MkAvatar v-if="item.avatar" :user="item.avatar" :class="$style.avatar"/>
<div :class="$style.item_content">
@@ -28,20 +47,49 @@ SPDX-License-Identifier: AGPL-3.0-only
<span v-if="item.indicate" :class="$style.indicator"><i class="_indicatorCircle"></i></span>
</div>
</MkA>
- <a v-else-if="item.type === 'a'" role="menuitem" :href="item.href" :target="item.target" :download="item.download" :tabindex="i" class="_button" :class="$style.item" @click="close(true)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
+ <a
+ v-else-if="item.type === 'a'"
+ role="menuitem"
+ tabindex="0"
+ :class="['_button', $style.item]"
+ :href="item.href"
+ :target="item.target"
+ :rel="item.target === '_blank' ? 'noopener noreferrer' : undefined"
+ :download="item.download"
+ @click.passive="close(true)"
+ @mouseenter.passive="onItemMouseEnter"
+ @mouseleave.passive="onItemMouseLeave"
+ >
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]"></i>
<div :class="$style.item_content">
<span :class="$style.item_content_text">{{ item.text }}</span>
<span v-if="item.indicate" :class="$style.indicator"><i class="_indicatorCircle"></i></span>
</div>
</a>
- <button v-else-if="item.type === 'user'" role="menuitem" :tabindex="i" class="_button" :class="[$style.item, { [$style.active]: item.active }]" :disabled="item.active" @click="clicked(item.action, $event)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
+ <button
+ v-else-if="item.type === 'user'"
+ role="menuitem"
+ tabindex="0"
+ :class="['_button', $style.item, { [$style.active]: item.active }]"
+ @click.prevent="item.active ? close(false) : clicked(item.action, $event)"
+ @mouseenter.passive="onItemMouseEnter"
+ @mouseleave.passive="onItemMouseLeave"
+ >
<MkAvatar :user="item.user" :class="$style.avatar"/><MkUserName :user="item.user"/>
<div v-if="item.indicate" :class="$style.item_content">
<span :class="$style.indicator"><i class="_indicatorCircle"></i></span>
</div>
</button>
- <button v-else-if="item.type === 'switch'" role="menuitemcheckbox" :tabindex="i" class="_button" :class="[$style.item, $style.switch, { [$style.switchDisabled]: item.disabled } ]" @click="switchItem(item)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
+ <button
+ v-else-if="item.type === 'switch'"
+ role="menuitemcheckbox"
+ tabindex="0"
+ :class="['_button', $style.item]"
+ :disabled="unref(item.disabled)"
+ @click.prevent="switchItem(item)"
+ @mouseenter.passive="onItemMouseEnter"
+ @mouseleave.passive="onItemMouseLeave"
+ >
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]"></i>
<MkSwitchButton v-else :class="$style.switchButton" :checked="item.ref" :disabled="item.disabled" @toggle="switchItem(item)"/>
<div :class="$style.item_content">
@@ -49,29 +97,61 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkSwitchButton v-if="item.icon" :class="[$style.switchButton, $style.caret]" :checked="item.ref" :disabled="item.disabled" @toggle="switchItem(item)"/>
</div>
</button>
- <button v-else-if="item.type === 'radio'" class="_button" role="menuitem" :tabindex="i" :class="[$style.item, $style.parent, { [$style.childShowing]: childShowingItem === item }]" @mouseenter="preferClick ? null : showRadioOptions(item, $event)" @click="!preferClick ? null : showRadioOptions(item, $event)">
+ <button
+ v-else-if="item.type === 'radio'"
+ role="menuitem"
+ tabindex="0"
+ :class="['_button', $style.item, $style.parent, { [$style.active]: childShowingItem === item }]"
+ :disabled="unref(item.disabled)"
+ @mouseenter.prevent="preferClick ? null : showRadioOptions(item, $event)"
+ @keydown.enter.prevent="preferClick ? null : showRadioOptions(item, $event)"
+ @click.prevent="!preferClick ? null : showRadioOptions(item, $event)"
+ >
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]" style="pointer-events: none;"></i>
<div :class="$style.item_content">
<span :class="$style.item_content_text" style="pointer-events: none;">{{ item.text }}</span>
<span :class="$style.caret" style="pointer-events: none;"><i class="ti ti-chevron-right ti-fw"></i></span>
</div>
</button>
- <button v-else-if="item.type === 'radioOption'" :tabindex="i" class="_button" role="menuitem" :class="[$style.item, { [$style.radioActive]: item.active }]" @click="clicked(item.action, $event, false)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
+ <button
+ v-else-if="item.type === 'radioOption'"
+ role="menuitemradio"
+ tabindex="0"
+ :class="['_button', $style.item, $style.radio, { [$style.active]: unref(item.active) }]"
+ @click.prevent="unref(item.active) ? null : clicked(item.action, $event, false)"
+ @mouseenter.passive="onItemMouseEnter"
+ @mouseleave.passive="onItemMouseLeave"
+ >
<div :class="$style.icon">
- <span :class="[$style.radio, { [$style.radioChecked]: item.active }]"></span>
+ <span :class="[$style.radioIcon, { [$style.radioChecked]: unref(item.active) }]"></span>
</div>
<div :class="$style.item_content">
<span :class="$style.item_content_text">{{ item.text }}</span>
</div>
</button>
- <button v-else-if="item.type === 'parent'" class="_button" role="menuitem" :tabindex="i" :class="[$style.item, $style.parent, { [$style.childShowing]: childShowingItem === item }]" @mouseenter="preferClick ? null : showChildren(item, $event)" @click="!preferClick ? null : showChildren(item, $event)">
+ <button
+ v-else-if="item.type === 'parent'"
+ role="menuitem"
+ tabindex="0"
+ :class="['_button', $style.item, $style.parent, { [$style.active]: childShowingItem === item }]"
+ @mouseenter.prevent="preferClick ? null : showChildren(item, $event)"
+ @keydown.enter.prevent="preferClick ? null : showChildren(item, $event)"
+ @click.prevent="!preferClick ? null : showChildren(item, $event)"
+ >
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]" style="pointer-events: none;"></i>
<div :class="$style.item_content">
<span :class="$style.item_content_text" style="pointer-events: none;">{{ item.text }}</span>
<span :class="$style.caret" style="pointer-events: none;"><i class="ti ti-chevron-right ti-fw"></i></span>
</div>
</button>
- <button v-else :tabindex="i" class="_button" role="menuitem" :class="[$style.item, { [$style.danger]: item.danger, [$style.active]: getValue(item.active) }]" :disabled="getValue(item.active)" @click="clicked(item.action, $event)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
+ <button
+ v-else role="menuitem"
+ tabindex="0"
+ :class="['_button', $style.item, { [$style.danger]: item.danger, [$style.active]: unref(item.active) }]"
+ @click.prevent="unref(item.active) ? close(false) : clicked(item.action, $event)"
+ @mouseenter.passive="onItemMouseEnter"
+ @mouseleave.passive="onItemMouseLeave"
+ >
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]"></i>
<MkAvatar v-if="item.avatar" :user="item.avatar" :class="$style.avatar"/>
<div :class="$style.item_content">
@@ -80,24 +160,26 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
</button>
</template>
- <span v-if="items2 == null || items2.length === 0" :class="[$style.none, $style.item]">
+ <span v-if="items2 == null || items2.length === 0" tabindex="-1" :class="[$style.none, $style.item]">
<span>{{ i18n.ts.none }}</span>
</span>
</div>
<div v-if="childMenu">
- <XChild ref="child" :items="childMenu" :targetElement="childTarget!" :rootElement="itemsEl!" showing @actioned="childActioned" @close="close(false)"/>
+ <XChild ref="child" :items="childMenu" :targetElement="childTarget!" :rootElement="itemsEl!" @actioned="childActioned" @closed="closeChild"/>
</div>
</div>
</template>
<script lang="ts">
-import { ComputedRef, computed, defineAsyncComponent, isRef, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue';
-import { focusPrev, focusNext } from '@/scripts/focus.js';
+import { computed, defineAsyncComponent, inject, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, unref, watch } from 'vue';
import MkSwitchButton from '@/components/MkSwitch.button.vue';
import { MenuItem, InnerMenuItem, MenuPending, MenuAction, MenuSwitch, MenuRadio, MenuRadioOption, MenuParent } from '@/types/menu.js';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { isTouchUsing } from '@/scripts/touch.js';
+import { type Keymap } from '@/scripts/hotkey.js';
+import { isFocusable } from '@/scripts/focus.js';
+import { getNodeOrNull } from '@/scripts/get-dom-node-or-null.js';
const childrenCache = new WeakMap<MenuParent, MenuItem[]>();
</script>
@@ -107,7 +189,6 @@ const XChild = defineAsyncComponent(() => import('./MkMenu.child.vue'));
const props = defineProps<{
items: MenuItem[];
- viaKeyboard?: boolean;
asDrawer?: boolean;
align?: 'center' | string;
width?: number;
@@ -119,17 +200,28 @@ const emit = defineEmits<{
(ev: 'hide'): void;
}>();
-const itemsEl = shallowRef<HTMLDivElement>();
+const isNestingMenu = inject<boolean>('isNestingMenu', false);
+
+const itemsEl = shallowRef<HTMLElement>();
const items2 = ref<InnerMenuItem[]>();
const child = shallowRef<InstanceType<typeof XChild>>();
-const keymap = computed(() => ({
- 'up|k|shift+tab': focusUp,
- 'down|j|tab': focusDown,
- 'esc': close,
-}));
+const keymap = {
+ 'up|k|shift+tab': {
+ allowRepeat: true,
+ callback: () => focusUp(),
+ },
+ 'down|j|tab': {
+ allowRepeat: true,
+ callback: () => focusDown(),
+ },
+ 'esc': {
+ allowRepeat: true,
+ callback: () => close(false),
+ },
+} as const satisfies Keymap;
const childShowingItem = ref<MenuItem | null>();
@@ -167,25 +259,19 @@ function childActioned() {
close(true);
}
-const onGlobalMousedown = (event: MouseEvent) => {
- if (childTarget.value && (event.target === childTarget.value || childTarget.value.contains(event.target as Node))) return;
- if (child.value && child.value.checkHit(event)) return;
- closeChild();
-};
-
let childCloseTimer: null | number = null;
-function onItemMouseEnter(item) {
+function onItemMouseEnter() {
childCloseTimer = window.setTimeout(() => {
closeChild();
}, 300);
}
-function onItemMouseLeave(item) {
+function onItemMouseLeave() {
if (childCloseTimer) window.clearTimeout(childCloseTimer);
}
-async function showRadioOptions(item: MenuRadio, ev: MouseEvent) {
+async function showRadioOptions(item: MenuRadio, ev: Event) {
const children: MenuItem[] = Object.keys(item.options).map<MenuRadioOption>(key => {
const value = item.options[key];
return {
@@ -200,7 +286,7 @@ async function showRadioOptions(item: MenuRadio, ev: MouseEvent) {
if (props.asDrawer) {
os.popupMenu(children, ev.currentTarget ?? ev.target).finally(() => {
- emit('close');
+ close(false);
});
emit('hide');
} else {
@@ -210,7 +296,7 @@ async function showRadioOptions(item: MenuRadio, ev: MouseEvent) {
}
}
-async function showChildren(item: MenuParent, ev: MouseEvent) {
+async function showChildren(item: MenuParent, ev: Event) {
const children: MenuItem[] = await (async () => {
if (childrenCache.has(item)) {
return childrenCache.get(item)!;
@@ -227,7 +313,7 @@ async function showChildren(item: MenuParent, ev: MouseEvent) {
if (props.asDrawer) {
os.popupMenu(children, ev.currentTarget ?? ev.target).finally(() => {
- emit('close');
+ close(false);
});
emit('hide');
} else {
@@ -246,41 +332,87 @@ function clicked(fn: MenuAction, ev: MouseEvent, doClose = true) {
}
function close(actioned = false) {
- emit('close', actioned);
+ disposeHandlers();
+ nextTick(() => {
+ closeChild();
+ emit('close', actioned);
+ });
+}
+
+function switchItem(item: MenuSwitch & { ref: any }) {
+ if (item.disabled !== undefined && (typeof item.disabled === 'boolean' ? item.disabled : item.disabled.value)) return;
+ item.ref = !item.ref;
}
function focusUp() {
- focusPrev(document.activeElement);
+ if (disposed) return;
+ if (!itemsEl.value?.contains(document.activeElement)) return;
+
+ const focusableElements = Array.from(itemsEl.value.children).filter(isFocusable);
+ const activeIndex = focusableElements.findIndex(el => el === document.activeElement);
+ const targetIndex = (activeIndex !== -1 && activeIndex !== 0) ? (activeIndex - 1) : (focusableElements.length - 1);
+ const targetElement = focusableElements.at(targetIndex) ?? itemsEl.value;
+
+ targetElement.focus();
}
function focusDown() {
- focusNext(document.activeElement);
-}
+ if (disposed) return;
+ if (!itemsEl.value?.contains(document.activeElement)) return;
-function switchItem(item: MenuSwitch & { ref: any }) {
- if (item.disabled !== undefined && (typeof item.disabled === 'boolean' ? item.disabled : item.disabled.value)) return;
- item.ref = !item.ref;
-}
+ const focusableElements = Array.from(itemsEl.value.children).filter(isFocusable);
+ const activeIndex = focusableElements.findIndex(el => el === document.activeElement);
+ const targetIndex = (activeIndex !== -1 && activeIndex !== (focusableElements.length - 1)) ? (activeIndex + 1) : 0;
+ const targetElement = focusableElements.at(targetIndex) ?? itemsEl.value;
-function getValue<T>(item?: ComputedRef<T> | T) {
- return isRef(item) ? item.value : item;
+ targetElement.focus();
}
-onMounted(() => {
- if (props.viaKeyboard) {
- nextTick(() => {
- if (itemsEl.value) focusNext(itemsEl.value.children[0], true, false);
- });
- }
+const onGlobalFocusin = (ev: FocusEvent) => {
+ if (disposed) return;
+ if (itemsEl.value?.parentElement?.contains(getNodeOrNull(ev.target))) return;
+ nextTick(() => {
+ if (itemsEl.value != null && isFocusable(itemsEl.value)) {
+ itemsEl.value.focus({ preventScroll: true });
+ nextTick(() => focusDown());
+ }
+ });
+};
- // TODO: アクティブãªè¦ç´ ã¾ã§ã‚¹ã‚¯ãƒ­ãƒ¼ãƒ«
- //itemsEl.scrollTo();
+const onGlobalMousedown = (ev: MouseEvent) => {
+ if (disposed) return;
+ if (childTarget.value?.contains(getNodeOrNull(ev.target))) return;
+ if (child.value?.checkHit(ev)) return;
+ closeChild();
+};
+const setupHandlers = () => {
+ if (!isNestingMenu) {
+ document.addEventListener('focusin', onGlobalFocusin, { passive: true });
+ }
document.addEventListener('mousedown', onGlobalMousedown, { passive: true });
+};
+
+let disposed = false;
+
+const disposeHandlers = () => {
+ disposed = true;
+ if (!isNestingMenu) {
+ document.removeEventListener('focusin', onGlobalFocusin);
+ }
+ document.removeEventListener('mousedown', onGlobalMousedown);
+};
+
+onMounted(() => {
+ setupHandlers();
+
+ if (!isNestingMenu) {
+ nextTick(() => itemsEl.value?.focus({ preventScroll: true }));
+ }
});
onBeforeUnmount(() => {
- document.removeEventListener('mousedown', onGlobalMousedown);
+ disposeHandlers();
});
</script>
@@ -293,6 +425,10 @@ onBeforeUnmount(() => {
overflow: auto;
overscroll-behavior: contain;
+ &:focus-visible {
+ outline: none;
+ }
+
&.center {
> .item {
text-align: center;
@@ -310,7 +446,7 @@ onBeforeUnmount(() => {
font-size: 1em;
padding: 12px 24px;
- &:before {
+ &::before {
width: calc(100% - 24px);
border-radius: 12px;
}
@@ -340,8 +476,10 @@ onBeforeUnmount(() => {
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
+ text-decoration: none !important;
+ color: var(--menuFg, var(--fg));
- &:before {
+ &::before {
content: "";
display: block;
position: absolute;
@@ -355,56 +493,56 @@ onBeforeUnmount(() => {
border-radius: 6px;
}
- &:not(:disabled):hover {
- color: var(--accent);
- text-decoration: none;
+ &:focus-visible {
+ outline: none;
- &:before {
- background: var(--accentedBg);
+ &:not(:hover):not(:active)::before {
+ outline: var(--focus) solid 2px;
+ outline-offset: -2px;
}
}
- &.danger {
- color: #ff2a2a;
-
- &:hover {
- color: #fff;
+ &:not(:disabled) {
+ &:hover,
+ &:focus-visible:active,
+ &:focus-visible.active {
+ color: var(--menuHoverFg, var(--accent));
- &:before {
- background: #ff4242;
+ &::before {
+ background-color: var(--menuHoverBg, var(--accentedBg));
}
}
- &:active {
- color: #fff;
+ &:not(:focus-visible):active,
+ &:not(:focus-visible).active {
+ color: var(--menuActiveFg, var(--fgOnAccent));
- &:before {
- background: #d42e2e !important;
+ &::before {
+ background-color: var(--menuActiveBg, var(--accent));
}
}
}
- &:active,
- &.active {
- color: var(--fgOnAccent) !important;
- opacity: 1;
-
- &:before {
- background: var(--accent) !important;
- }
+ &:disabled {
+ cursor: not-allowed;
}
- &.radioActive {
- color: var(--accent) !important;
- opacity: 1;
+ &.danger {
+ --menuFg: #ff2a2a;
+ --menuHoverFg: #fff;
+ --menuHoverBg: #ff4242;
+ --menuActiveFg: #fff;
+ --menuActiveBg: #d42e2e;
+ }
- &:before {
- background-color: var(--accentedBg) !important;
- }
+ &.radio {
+ --menuActiveFg: var(--accent);
+ --menuActiveBg: var(--accentedBg);
}
- &:not(:active):focus-visible {
- box-shadow: 0 0 0 2px var(--focus) inset;
+ &.parent {
+ --menuActiveFg: var(--accent);
+ --menuActiveBg: var(--accentedBg);
}
&.label {
@@ -422,22 +560,6 @@ onBeforeUnmount(() => {
pointer-events: none;
opacity: 0.7;
}
-
- &.parent {
- pointer-events: auto;
- display: flex;
- align-items: center;
- cursor: default;
-
- &.childShowing {
- color: var(--accent);
- text-decoration: none;
-
- &:before {
- background: var(--accentedBg);
- }
- }
- }
}
.item_content {
@@ -456,18 +578,6 @@ onBeforeUnmount(() => {
overflow: hidden;
}
-.switch {
- position: relative;
- display: flex;
- transition: all 0.2s ease;
- user-select: none;
- cursor: pointer;
-}
-
-.switchDisabled {
- cursor: not-allowed;
-}
-
.switchButton {
margin-left: -2px;
--height: 1.35em;
@@ -479,14 +589,6 @@ onBeforeUnmount(() => {
text-overflow: ellipsis;
}
-.switchInput {
- position: absolute;
- width: 0;
- height: 0;
- opacity: 0;
- margin: 0;
-}
-
.icon {
margin-right: 8px;
line-height: 1;
@@ -515,12 +617,12 @@ onBeforeUnmount(() => {
border-top: solid 0.5px var(--divider);
}
-.radio {
+.radioIcon {
display: inline-block;
position: relative;
width: 1em;
height: 1em;
- vertical-align: -.125em;
+ vertical-align: -0.125em;
border-radius: 50%;
border: solid 2px var(--divider);
background-color: var(--panel);
diff --git a/packages/frontend/src/components/MkModal.vue b/packages/frontend/src/components/MkModal.vue
index 9e69ab2207..f8032f9b43 100644
--- a/packages/frontend/src/components/MkModal.vue
+++ b/packages/frontend/src/components/MkModal.vue
@@ -30,9 +30,9 @@ SPDX-License-Identifier: AGPL-3.0-only
[$style.transition_modal_leaveTo]: transitionName === 'modal',
[$style.transition_send_leaveTo]: transitionName === 'send',
})"
- :duration="transitionDuration" appear @afterLeave="emit('closed')" @enter="emit('opening')" @afterEnter="onOpened"
+ :duration="transitionDuration" appear @afterLeave="onClosed" @enter="emit('opening')" @afterEnter="onOpened"
>
- <div v-show="manualShowing != null ? manualShowing : showing" v-hotkey.global="keymap" :class="[$style.root, { [$style.drawer]: type === 'drawer', [$style.dialog]: type === 'dialog', [$style.popup]: type === 'popup' }]" :style="{ zIndex, pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }">
+ <div v-show="manualShowing != null ? manualShowing : showing" ref="modalRootEl" v-hotkey.global="keymap" :class="[$style.root, { [$style.drawer]: type === 'drawer', [$style.dialog]: type === 'dialog', [$style.popup]: type === 'popup' }]" :style="{ zIndex, pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }">
<div data-cy-bg :data-cy-transparent="isEnableBgTransparent" class="_modalBg" :class="[$style.bg, { [$style.bgTransparent]: isEnableBgTransparent }]" :style="{ zIndex }" @click="onBgClick" @mousedown="onBgClick" @contextmenu.prevent.stop="() => {}"></div>
<div ref="content" :class="[$style.content, { [$style.fixed]: fixed }]" :style="{ zIndex }" @click.self="onBgClick">
<slot :max-height="maxHeight" :type="type"></slot>
@@ -47,6 +47,9 @@ import * as os from '@/os.js';
import { isTouchUsing } from '@/scripts/touch.js';
import { defaultStore } from '@/store.js';
import { deviceKind } from '@/scripts/device-kind.js';
+import { type Keymap } from '@/scripts/hotkey.js';
+import { focusTrap } from '@/scripts/focus-trap.js';
+import { focusParent } from '@/scripts/focus.js';
function getFixedContainer(el: Element | null): Element | null {
if (el == null || el.tagName === 'BODY') return null;
@@ -68,6 +71,8 @@ const props = withDefaults(defineProps<{
zPriority?: 'low' | 'middle' | 'high';
noOverlap?: boolean;
transparentBg?: boolean;
+ hasInteractionWithOtherFocusTrappedEls?: boolean;
+ returnFocusTo?: HTMLElement | null;
}>(), {
manualShowing: null,
src: null,
@@ -76,6 +81,8 @@ const props = withDefaults(defineProps<{
zPriority: 'low',
noOverlap: true,
transparentBg: false,
+ hasInteractionWithOtherFocusTrappedEls: false,
+ returnFocusTo: null,
});
const emit = defineEmits<{
@@ -93,6 +100,7 @@ const maxHeight = ref<number>();
const fixed = ref(false);
const transformOrigin = ref('center');
const showing = ref(true);
+const modalRootEl = shallowRef<HTMLElement>();
const content = shallowRef<HTMLElement>();
const zIndex = os.claimZIndex(props.zPriority);
const useSendAnime = ref(false);
@@ -131,6 +139,7 @@ const transitionDuration = computed((() =>
: 0
));
+let releaseFocusTrap: (() => void) | null = null;
let contentClicking = false;
function close(opts: { useSendAnimation?: boolean } = {}) {
@@ -154,8 +163,11 @@ if (type.value === 'drawer') {
}
const keymap = {
- 'esc': () => emit('esc'),
-};
+ 'esc': {
+ allowRepeat: true,
+ callback: () => emit('esc'),
+ },
+} as const satisfies Keymap;
const MARGIN = 16;
const SCROLLBAR_THICKNESS = 16;
@@ -292,6 +304,10 @@ const onOpened = () => {
}, { passive: true });
};
+const onClosed = () => {
+ emit('closed');
+};
+
const alignObserver = new ResizeObserver((entries, observer) => {
align();
});
@@ -309,6 +325,20 @@ onMounted(() => {
align();
}, { immediate: true });
+ watch([showing, () => props.manualShowing], ([showing, manualShowing]) => {
+ if (manualShowing === true || (manualShowing == null && showing === true)) {
+ if (modalRootEl.value != null) {
+ const { release } = focusTrap(modalRootEl.value, props.hasInteractionWithOtherFocusTrappedEls);
+
+ releaseFocusTrap = release;
+ modalRootEl.value.focus();
+ }
+ } else {
+ releaseFocusTrap?.();
+ focusParent(props.returnFocusTo ?? props.src, true, false);
+ }
+ }, { immediate: true });
+
nextTick(() => {
alignObserver.observe(content.value!);
});
diff --git a/packages/frontend/src/components/MkModalWindow.vue b/packages/frontend/src/components/MkModalWindow.vue
index d3657afa94..c3c7812036 100644
--- a/packages/frontend/src/components/MkModalWindow.vue
+++ b/packages/frontend/src/components/MkModalWindow.vue
@@ -4,15 +4,15 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
-<MkModal ref="modal" :preferType="'dialog'" @click="onBgClick" @closed="$emit('closed')">
- <div ref="rootEl" :class="$style.root" :style="{ width: `${width}px`, height: `min(${height}px, 100%)` }" @keydown="onKeydown">
+<MkModal ref="modal" :preferType="'dialog'" @click="onBgClick" @closed="emit('closed')" @esc="emit('esc')">
+ <div ref="rootEl" :class="$style.root" :style="{ width: `${width}px`, height: `min(${height}px, 100%)` }">
<div ref="headerEl" :class="$style.header">
- <button v-if="withOkButton" :class="$style.headerButton" class="_button" @click="$emit('close')"><i class="ti ti-x"></i></button>
+ <button v-if="withOkButton && withCloseButton" :class="$style.headerButton" class="_button" @click="emit('close')"><i class="ti ti-x"></i></button>
<span :class="$style.title">
<slot name="header"></slot>
</span>
- <button v-if="!withOkButton" :class="$style.headerButton" class="_button" data-cy-modal-window-close @click="$emit('close')"><i class="ti ti-x"></i></button>
- <button v-if="withOkButton" :class="$style.headerButton" class="_button" :disabled="okButtonDisabled" @click="$emit('ok')"><i class="ti ti-check"></i></button>
+ <button v-if="!withOkButton && withCloseButton" :class="$style.headerButton" class="_button" data-cy-modal-window-close @click="emit('close')"><i class="ti ti-x"></i></button>
+ <button v-if="withOkButton" :class="$style.headerButton" class="_button" :disabled="okButtonDisabled" @click="emit('ok')"><i class="ti ti-check"></i></button>
</div>
<div :class="$style.body">
<slot :width="bodyWidth" :height="bodyHeight"></slot>
@@ -27,11 +27,13 @@ import MkModal from './MkModal.vue';
const props = withDefaults(defineProps<{
withOkButton: boolean;
+ withCloseButton: boolean;
okButtonDisabled: boolean;
width: number;
height: number;
}>(), {
withOkButton: false,
+ withCloseButton: true,
okButtonDisabled: false,
width: 400,
height: 500,
@@ -42,6 +44,7 @@ const emit = defineEmits<{
(event: 'close'): void;
(event: 'closed'): void;
(event: 'ok'): void;
+ (event: 'esc'): void;
}>();
const modal = shallowRef<InstanceType<typeof MkModal>>();
@@ -50,21 +53,13 @@ const headerEl = shallowRef<HTMLElement>();
const bodyWidth = ref(0);
const bodyHeight = ref(0);
-const close = () => {
+function close() {
modal.value?.close();
-};
+}
-const onBgClick = () => {
+function onBgClick() {
emit('click');
-};
-
-const onKeydown = (evt) => {
- if (evt.which === 27) { // Esc
- evt.preventDefault();
- evt.stopPropagation();
- close();
- }
-};
+}
const ro = new ResizeObserver((entries, observer) => {
if (rootEl.value == null || headerEl.value == null) return;
diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue
index 22b1691a86..13273a53b4 100644
--- a/packages/frontend/src/components/MkNote.vue
+++ b/packages/frontend/src/components/MkNote.vue
@@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
ref="rootEl"
v-hotkey="keymap"
:class="[$style.root, { [$style.showActionsOnlyHover]: defaultStore.state.showNoteActionsOnlyHover }]"
- :tabindex="!isDeleted ? '-1' : undefined"
+ :tabindex="isDeleted ? '-1' : '0'"
>
<MkNoteSub v-if="appearNote.reply && !renoteCollapsed" :note="appearNote.reply" :class="$style.replyTo"/>
<div v-if="pinned" :class="$style.tip"><i class="ti ti-pin"></i> {{ i18n.ts.pinnedNote }}</div>
@@ -28,7 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
</I18n>
<div :class="$style.renoteInfo">
- <button ref="renoteTime" :class="$style.renoteTime" class="_button" @click="showRenoteMenu()">
+ <button ref="renoteTime" :class="$style.renoteTime" class="_button" @mousedown.prevent="showRenoteMenu()">
<i class="ti ti-dots" :class="$style.renoteMenu"></i>
<MkTime :time="note.createdAt"/>
</button>
@@ -79,7 +79,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
</div>
<div v-if="appearNote.files && appearNote.files.length > 0">
- <MkMediaList :mediaList="appearNote.files"/>
+ <MkMediaList ref="galleryEl" :mediaList="appearNote.files"/>
</div>
<MkPoll v-if="appearNote.poll" :noteId="appearNote.id" :poll="appearNote.poll" :class="$style.poll"/>
<div v-if="isEnabledUrlPreview">
@@ -110,7 +110,7 @@ SPDX-License-Identifier: AGPL-3.0-only
ref="renoteButton"
:class="$style.footerButton"
class="_button"
- @mousedown="renote()"
+ @mousedown.prevent="renote()"
>
<i class="ti ti-repeat"></i>
<p v-if="appearNote.renoteCount > 0" :class="$style.footerButtonCount">{{ number(appearNote.renoteCount) }}</p>
@@ -125,10 +125,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<i v-else class="ti ti-plus"></i>
<p v-if="(appearNote.reactionAcceptance === 'likeOnly' || defaultStore.state.showReactionsCount) && appearNote.reactionCount > 0" :class="$style.footerButtonCount">{{ number(appearNote.reactionCount) }}</p>
</button>
- <button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" :class="$style.footerButton" class="_button" @mousedown="clip()">
+ <button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" :class="$style.footerButton" class="_button" @mousedown.prevent="clip()">
<i class="ti ti-paperclip"></i>
</button>
- <button ref="menuButton" :class="$style.footerButton" class="_button" @mousedown="showMenu()">
+ <button ref="menuButton" :class="$style.footerButton" class="_button" @mousedown.prevent="showMenu()">
<i class="ti ti-dots"></i>
</button>
</footer>
@@ -174,8 +174,7 @@ import MkPoll from '@/components/MkPoll.vue';
import MkUsersTooltip from '@/components/MkUsersTooltip.vue';
import MkUrlPreview from '@/components/MkUrlPreview.vue';
import MkInstanceTicker from '@/components/MkInstanceTicker.vue';
-import { pleaseLogin } from '@/scripts/please-login.js';
-import { focusPrev, focusNext } from '@/scripts/focus.js';
+import { pleaseLogin, type OpenOnRemoteOptions } from '@/scripts/please-login.js';
import { checkWordMute } from '@/scripts/check-word-mute.js';
import { userPage } from '@/filters/user.js';
import number from '@/filters/number.js';
@@ -197,7 +196,10 @@ import { MenuItem } from '@/types/menu.js';
import MkRippleEffect from '@/components/MkRippleEffect.vue';
import { showMovedDialog } from '@/scripts/show-moved-dialog.js';
import { shouldCollapsed } from '@/scripts/collapsed.js';
+import { host } from '@/config.js';
import { isEnabledUrlPreview } from '@/instance.js';
+import { type Keymap } from '@/scripts/hotkey.js';
+import { focusPrev, focusNext } from '@/scripts/focus.js';
const props = withDefaults(defineProps<{
note: Misskey.entities.Note;
@@ -256,6 +258,7 @@ const renoteTime = shallowRef<HTMLElement>();
const reactButton = shallowRef<HTMLElement>();
const clipButton = shallowRef<HTMLElement>();
const appearNote = computed(() => isRenote ? note.value.renote as Misskey.entities.Note : note.value);
+const galleryEl = shallowRef<InstanceType<typeof MkMediaList>>();
const isMyRenote = $i && ($i.id === note.value.userId);
const showContent = ref(false);
const parsed = computed(() => appearNote.value.text ? mfm.parse(appearNote.value.text) : null);
@@ -276,6 +279,11 @@ const renoteCollapsed = ref(
),
);
+const pleaseLoginContext = computed<OpenOnRemoteOptions>(() => ({
+ type: 'lookup',
+ url: `https://${host}/notes/${appearNote.value.id}`,
+}));
+
/* Overload Functionã«LintãŒå¯¾å¿œã—ã¦ã„ãªã„ã®ã§ã‚³ãƒ¡ãƒ³ãƒˆã‚¢ã‚¦ãƒˆ
function checkMute(noteToCheck: Misskey.entities.Note, mutedWords: Array<string | string[]> | undefined | null, checkOnly: true): boolean;
function checkMute(noteToCheck: Misskey.entities.Note, mutedWords: Array<string | string[]> | undefined | null, checkOnly: false): boolean | 'sensitiveMute';
@@ -294,15 +302,53 @@ function checkMute(noteToCheck: Misskey.entities.Note, mutedWords: Array<string
}
const keymap = {
- 'r': () => reply(true),
- 'e|a|plus': () => react(true),
- 'q': () => renote(true),
- 'up|k|shift+tab': focusBefore,
- 'down|j|tab': focusAfter,
- 'esc': blur,
- 'm|o': () => showMenu(true),
- 's': () => showContent.value !== showContent.value,
-};
+ 'r': () => {
+ if (renoteCollapsed.value) return;
+ reply();
+ },
+ 'e|a|plus': () => {
+ if (renoteCollapsed.value) return;
+ react();
+ },
+ 'q': () => {
+ if (renoteCollapsed.value) return;
+ renote();
+ },
+ 'm': () => {
+ if (renoteCollapsed.value) return;
+ showMenu();
+ },
+ 'c': () => {
+ if (renoteCollapsed.value) return;
+ if (!defaultStore.state.showClipButtonInNoteFooter) return;
+ clip();
+ },
+ 'o': () => {
+ if (renoteCollapsed.value) return;
+ galleryEl.value?.openGallery();
+ },
+ 'v|enter': () => {
+ if (renoteCollapsed.value) {
+ renoteCollapsed.value = false;
+ } else if (appearNote.value.cw != null) {
+ showContent.value = !showContent.value;
+ } else if (isLong) {
+ collapsed.value = !collapsed.value;
+ }
+ },
+ 'esc': {
+ allowRepeat: true,
+ callback: () => blur(),
+ },
+ 'up|k|shift+tab': {
+ allowRepeat: true,
+ callback: () => focusBefore(),
+ },
+ 'down|j|tab': {
+ allowRepeat: true,
+ callback: () => focusAfter(),
+ },
+} as const satisfies Keymap;
provide('react', (reaction: string) => {
misskeyApi('notes/reactions/create', {
@@ -335,12 +381,14 @@ if (!props.mock) {
if (users.length < 1) return;
- os.popup(MkUsersTooltip, {
+ const { dispose } = os.popup(MkUsersTooltip, {
showing,
users,
count: appearNote.value.renoteCount,
targetElement: renoteButton.value,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
});
if (appearNote.value.reactionAcceptance === 'likeOnly') {
@@ -355,19 +403,21 @@ if (!props.mock) {
if (users.length < 1) return;
- os.popup(MkReactionsViewerDetails, {
+ const { dispose } = os.popup(MkReactionsViewerDetails, {
showing,
reaction: 'â¤ï¸',
users,
count: appearNote.value.reactionCount,
targetElement: reactButton.value!,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
});
}
}
function renote(viaKeyboard = false) {
- pleaseLogin();
+ pleaseLogin(undefined, pleaseLoginContext.value);
showMovedDialog();
const { menu } = getRenoteMenu({ note: note.value, renoteButton, mock: props.mock });
@@ -376,22 +426,21 @@ function renote(viaKeyboard = false) {
});
}
-function reply(viaKeyboard = false): void {
- pleaseLogin();
+function reply(): void {
+ pleaseLogin(undefined, pleaseLoginContext.value);
if (props.mock) {
return;
}
os.post({
reply: appearNote.value,
channel: appearNote.value.channel,
- animation: !viaKeyboard,
}).then(() => {
focus();
});
}
-function react(viaKeyboard = false): void {
- pleaseLogin();
+function react(): void {
+ pleaseLogin(undefined, pleaseLoginContext.value);
showMovedDialog();
if (appearNote.value.reactionAcceptance === 'likeOnly') {
sound.playMisskeySfx('reaction');
@@ -409,7 +458,9 @@ function react(viaKeyboard = false): void {
const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2);
- os.popup(MkRippleEffect, { x, y }, {}, 'end');
+ const { dispose } = os.popup(MkRippleEffect, { x, y }, {
+ end: () => dispose(),
+ });
}
} else {
blur();
@@ -483,18 +534,16 @@ function onContextmenu(ev: MouseEvent): void {
}
}
-function showMenu(viaKeyboard = false): void {
+function showMenu(): void {
if (props.mock) {
return;
}
const { menu, cleanup } = getNoteMenu({ note: note.value, translating, translation, isDeleted, currentClip: currentClip?.value });
- os.popupMenu(menu, menuButton.value, {
- viaKeyboard,
- }).then(focus).finally(cleanup);
+ os.popupMenu(menu, menuButton.value).then(focus).finally(cleanup);
}
-async function clip() {
+async function clip(): Promise<void> {
if (props.mock) {
return;
}
@@ -502,7 +551,7 @@ async function clip() {
os.popupMenu(await getNoteClipMenu({ note: note.value, isDeleted, currentClip: currentClip?.value }), clipButton.value).then(focus);
}
-function showRenoteMenu(viaKeyboard = false): void {
+function showRenoteMenu(): void {
if (props.mock) {
return;
}
@@ -522,23 +571,19 @@ function showRenoteMenu(viaKeyboard = false): void {
}
if (isMyRenote) {
- pleaseLogin();
+ pleaseLogin(undefined, pleaseLoginContext.value);
os.popupMenu([
getCopyNoteLinkMenu(note.value, i18n.ts.copyLinkRenote),
{ type: 'divider' },
getUnrenote(),
- ], renoteTime.value, {
- viaKeyboard: viaKeyboard,
- });
+ ], renoteTime.value);
} else {
os.popupMenu([
getCopyNoteLinkMenu(note.value, i18n.ts.copyLinkRenote),
{ type: 'divider' },
getAbuseNoteMenu(note.value, i18n.ts.reportAbuseRenote),
($i?.isModerator || $i?.isAdmin) ? getUnrenote() : undefined,
- ], renoteTime.value, {
- viaKeyboard: viaKeyboard,
- });
+ ], renoteTime.value);
}
}
@@ -551,11 +596,11 @@ function blur() {
}
function focusBefore() {
- focusPrev(rootEl.value ?? null);
+ focusPrev(rootEl.value);
}
function focusAfter() {
- focusNext(rootEl.value ?? null);
+ focusNext(rootEl.value);
}
function readPromo() {
@@ -593,7 +638,7 @@ function emitUpdReaction(emoji: string, delta: number) {
&:focus-visible {
outline: none;
- &:after {
+ &::after {
content: "";
pointer-events: none;
display: block;
@@ -606,7 +651,7 @@ function emitUpdReaction(emoji: string, delta: number) {
margin: auto;
width: calc(100% - 8px);
height: calc(100% - 8px);
- border: dashed 1px var(--focus);
+ border: dashed 2px var(--focus);
border-radius: var(--radius);
box-sizing: border-box;
}
diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue
index ed1c0a9e96..9a3e595789 100644
--- a/packages/frontend/src/components/MkNoteDetailed.vue
+++ b/packages/frontend/src/components/MkNoteDetailed.vue
@@ -10,6 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
ref="rootEl"
v-hotkey="keymap"
:class="$style.root"
+ :tabindex="isDeleted ? '-1' : '0'"
>
<div v-if="appearNote.reply && appearNote.reply.replyId">
<div v-if="!conversationLoaded" style="padding: 16px">
@@ -31,7 +32,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</I18n>
</span>
<div :class="$style.renoteInfo">
- <button ref="renoteTime" class="_button" :class="$style.renoteTime" @click="showRenoteMenu()">
+ <button ref="renoteTime" class="_button" :class="$style.renoteTime" @mousedown.prevent="showRenoteMenu()">
<i v-if="isMyRenote" class="ti ti-dots" style="margin-right: 4px;"></i>
<MkTime :time="note.createdAt"/>
</button>
@@ -92,7 +93,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
</div>
<div v-if="appearNote.files && appearNote.files.length > 0">
- <MkMediaList :mediaList="appearNote.files"/>
+ <MkMediaList ref="galleryEl" :mediaList="appearNote.files"/>
</div>
<MkPoll v-if="appearNote.poll" ref="pollViewer" :noteId="appearNote.id" :poll="appearNote.poll" :class="$style.poll"/>
<div v-if="isEnabledUrlPreview">
@@ -118,7 +119,7 @@ SPDX-License-Identifier: AGPL-3.0-only
ref="renoteButton"
class="_button"
:class="$style.noteFooterButton"
- @mousedown="renote()"
+ @mousedown.prevent="renote()"
>
<i class="ti ti-repeat"></i>
<p v-if="appearNote.renoteCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.renoteCount) }}</p>
@@ -133,10 +134,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<i v-else class="ti ti-plus"></i>
<p v-if="(appearNote.reactionAcceptance === 'likeOnly' || defaultStore.state.showReactionsCount) && appearNote.reactionCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.reactionCount) }}</p>
</button>
- <button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" class="_button" :class="$style.noteFooterButton" @mousedown="clip()">
+ <button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" class="_button" :class="$style.noteFooterButton" @mousedown.prevent="clip()">
<i class="ti ti-paperclip"></i>
</button>
- <button ref="menuButton" class="_button" :class="$style.noteFooterButton" @mousedown="showMenu()">
+ <button ref="menuButton" class="_button" :class="$style.noteFooterButton" @mousedown.prevent="showMenu()">
<i class="ti ti-dots"></i>
</button>
</footer>
@@ -208,7 +209,7 @@ import MkPoll from '@/components/MkPoll.vue';
import MkUsersTooltip from '@/components/MkUsersTooltip.vue';
import MkUrlPreview from '@/components/MkUrlPreview.vue';
import MkInstanceTicker from '@/components/MkInstanceTicker.vue';
-import { pleaseLogin } from '@/scripts/please-login.js';
+import { pleaseLogin, type OpenOnRemoteOptions } from '@/scripts/please-login.js';
import { checkWordMute } from '@/scripts/check-word-mute.js';
import { userPage } from '@/filters/user.js';
import { notePage } from '@/filters/note.js';
@@ -221,6 +222,7 @@ import { reactionPicker } from '@/scripts/reaction-picker.js';
import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm.js';
import { $i } from '@/account.js';
import { i18n } from '@/i18n.js';
+import { host } from '@/config.js';
import { getNoteClipMenu, getNoteMenu, getRenoteMenu } from '@/scripts/get-note-menu.js';
import { useNoteCapture } from '@/scripts/use-note-capture.js';
import { deepClone } from '@/scripts/clone.js';
@@ -233,6 +235,7 @@ import MkPagination, { type Paging } from '@/components/MkPagination.vue';
import MkReactionIcon from '@/components/MkReactionIcon.vue';
import MkButton from '@/components/MkButton.vue';
import { isEnabledUrlPreview } from '@/instance.js';
+import { type Keymap } from '@/scripts/hotkey.js';
const props = withDefaults(defineProps<{
note: Misskey.entities.Note;
@@ -280,6 +283,7 @@ const renoteTime = shallowRef<HTMLElement>();
const reactButton = shallowRef<HTMLElement>();
const clipButton = shallowRef<HTMLElement>();
const appearNote = computed(() => isRenote ? note.value.renote as Misskey.entities.Note : note.value);
+const galleryEl = shallowRef<InstanceType<typeof MkMediaList>>();
const isMyRenote = $i && ($i.id === note.value.userId);
const showContent = ref(false);
const isDeleted = ref(false);
@@ -293,14 +297,31 @@ const conversation = ref<Misskey.entities.Note[]>([]);
const replies = ref<Misskey.entities.Note[]>([]);
const canRenote = computed(() => ['public', 'home'].includes(appearNote.value.visibility) || appearNote.value.userId === $i?.id);
+const pleaseLoginContext = computed<OpenOnRemoteOptions>(() => ({
+ type: 'lookup',
+ url: `https://${host}/notes/${appearNote.value.id}`,
+}));
+
const keymap = {
- 'r': () => reply(true),
- 'e|a|plus': () => react(true),
- 'q': () => renote(true),
- 'esc': blur,
- 'm|o': () => showMenu(true),
- 's': () => showContent.value !== showContent.value,
-};
+ 'r': () => reply(),
+ 'e|a|plus': () => react(),
+ 'q': () => renote(),
+ 'm': () => showMenu(),
+ 'c': () => {
+ if (!defaultStore.state.showClipButtonInNoteFooter) return;
+ clip();
+ },
+ 'o': () => galleryEl.value?.openGallery(),
+ 'v|enter': () => {
+ if (appearNote.value.cw != null) {
+ showContent.value = !showContent.value;
+ }
+ },
+ 'esc': {
+ allowRepeat: true,
+ callback: () => blur(),
+ },
+} as const satisfies Keymap;
provide('react', (reaction: string) => {
misskeyApi('notes/reactions/create', {
@@ -346,12 +367,14 @@ useTooltip(renoteButton, async (showing) => {
if (users.length < 1) return;
- os.popup(MkUsersTooltip, {
+ const { dispose } = os.popup(MkUsersTooltip, {
showing,
users,
count: appearNote.value.renoteCount,
targetElement: renoteButton.value,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
});
if (appearNote.value.reactionAcceptance === 'likeOnly') {
@@ -366,40 +389,39 @@ if (appearNote.value.reactionAcceptance === 'likeOnly') {
if (users.length < 1) return;
- os.popup(MkReactionsViewerDetails, {
+ const { dispose } = os.popup(MkReactionsViewerDetails, {
showing,
reaction: 'â¤ï¸',
users,
count: appearNote.value.reactionCount,
targetElement: reactButton.value!,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
});
}
-function renote(viaKeyboard = false) {
- pleaseLogin();
+function renote() {
+ pleaseLogin(undefined, pleaseLoginContext.value);
showMovedDialog();
const { menu } = getRenoteMenu({ note: note.value, renoteButton });
- os.popupMenu(menu, renoteButton.value, {
- viaKeyboard,
- });
+ os.popupMenu(menu, renoteButton.value);
}
-function reply(viaKeyboard = false): void {
- pleaseLogin();
+function reply(): void {
+ pleaseLogin(undefined, pleaseLoginContext.value);
showMovedDialog();
os.post({
reply: appearNote.value,
channel: appearNote.value.channel,
- animation: !viaKeyboard,
}).then(() => {
focus();
});
}
-function react(viaKeyboard = false): void {
- pleaseLogin();
+function react(): void {
+ pleaseLogin(undefined, pleaseLoginContext.value);
showMovedDialog();
if (appearNote.value.reactionAcceptance === 'likeOnly') {
sound.playMisskeySfx('reaction');
@@ -408,12 +430,14 @@ function react(viaKeyboard = false): void {
noteId: appearNote.value.id,
reaction: 'â¤ï¸',
});
- const el = reactButton.value as HTMLElement | null | undefined;
+ const el = reactButton.value;
if (el) {
const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2);
- os.popup(MkRippleEffect, { x, y }, {}, 'end');
+ const { dispose } = os.popup(MkRippleEffect, { x, y }, {
+ end: () => dispose(),
+ });
}
} else {
blur();
@@ -470,20 +494,18 @@ function onContextmenu(ev: MouseEvent): void {
}
}
-function showMenu(viaKeyboard = false): void {
+function showMenu(): void {
const { menu, cleanup } = getNoteMenu({ note: note.value, translating, translation, isDeleted });
- os.popupMenu(menu, menuButton.value, {
- viaKeyboard,
- }).then(focus).finally(cleanup);
+ os.popupMenu(menu, menuButton.value).then(focus).finally(cleanup);
}
-async function clip() {
+async function clip(): Promise<void> {
os.popupMenu(await getNoteClipMenu({ note: note.value, isDeleted }), clipButton.value).then(focus);
}
-function showRenoteMenu(viaKeyboard = false): void {
+function showRenoteMenu(): void {
if (!isMyRenote) return;
- pleaseLogin();
+ pleaseLogin(undefined, pleaseLoginContext.value);
os.popupMenu([{
text: i18n.ts.unrenote,
icon: 'ti ti-trash',
@@ -494,9 +516,7 @@ function showRenoteMenu(viaKeyboard = false): void {
});
isDeleted.value = true;
},
- }], renoteTime.value, {
- viaKeyboard: viaKeyboard,
- });
+ }], renoteTime.value);
}
function focus() {
@@ -538,6 +558,28 @@ function loadConversation() {
transition: box-shadow 0.1s ease;
overflow: clip;
contain: content;
+
+ &:focus-visible {
+ outline: none;
+
+ &::after {
+ content: "";
+ pointer-events: none;
+ display: block;
+ position: absolute;
+ z-index: 10;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ margin: auto;
+ width: calc(100% - 8px);
+ height: calc(100% - 8px);
+ border: dashed 2px var(--focus);
+ border-radius: var(--radius);
+ box-sizing: border-box;
+ }
+ }
}
.replyTo {
diff --git a/packages/frontend/src/components/MkNotePreview.vue b/packages/frontend/src/components/MkNotePreview.vue
index cc2f770cda..c4479bb0d6 100644
--- a/packages/frontend/src/components/MkNotePreview.vue
+++ b/packages/frontend/src/components/MkNotePreview.vue
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<div :class="$style.root">
- <MkAvatar :class="$style.avatar" :user="user" link preview/>
+ <MkAvatar :class="$style.avatar" :user="user"/>
<div :class="$style.main">
<div :class="$style.header">
<MkUserName :user="user" :nowrap="true"/>
diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue
index 73cd7cd5b3..ee65743574 100644
--- a/packages/frontend/src/components/MkNotification.vue
+++ b/packages/frontend/src/components/MkNotification.vue
@@ -6,14 +6,14 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<div :class="$style.root">
<div :class="$style.head">
- <MkAvatar v-if="['pollEnded', 'note'].includes(notification.type) && notification.note" :class="$style.icon" :user="notification.note.user" link preview/>
+ <MkAvatar v-if="['pollEnded', 'note'].includes(notification.type) && 'note' in notification" :class="$style.icon" :user="notification.note.user" link preview/>
<MkAvatar v-else-if="['roleAssigned', 'achievementEarned'].includes(notification.type)" :class="$style.icon" :user="$i" link preview/>
<div v-else-if="notification.type === 'reaction:grouped' && notification.note.reactionAcceptance === 'likeOnly'" :class="[$style.icon, $style.icon_reactionGroupHeart]"><i class="ti ti-heart" style="line-height: 1;"></i></div>
<div v-else-if="notification.type === 'reaction:grouped'" :class="[$style.icon, $style.icon_reactionGroup]"><i class="ti ti-plus" style="line-height: 1;"></i></div>
<div v-else-if="notification.type === 'renote:grouped'" :class="[$style.icon, $style.icon_renoteGroup]"><i class="ti ti-repeat" style="line-height: 1;"></i></div>
<img v-else-if="notification.type === 'test'" :class="$style.icon" :src="infoImageUrl"/>
- <MkAvatar v-else-if="notification.user" :class="$style.icon" :user="notification.user" link preview/>
- <img v-else-if="notification.icon" :class="[$style.icon, $style.icon_app]" :src="notification.icon" alt=""/>
+ <MkAvatar v-else-if="'user' in notification" :class="$style.icon" :user="notification.user" link preview/>
+ <img v-else-if="'icon' in notification" :class="[$style.icon, $style.icon_app]" :src="notification.icon" alt=""/>
<div
:class="[$style.subIcon, {
[$style.t_follow]: notification.type === 'follow',
@@ -164,13 +164,13 @@ const props = withDefaults(defineProps<{
const followRequestDone = ref(false);
const acceptFollowRequest = () => {
- if (props.notification.user == null) return;
+ if (!('user' in props.notification)) return;
followRequestDone.value = true;
misskeyApi('following/requests/accept', { userId: props.notification.user.id });
};
const rejectFollowRequest = () => {
- if (props.notification.user == null) return;
+ if (!('user' in props.notification)) return;
followRequestDone.value = true;
misskeyApi('following/requests/reject', { userId: props.notification.user.id });
};
@@ -343,7 +343,7 @@ function getActualReactedUsersCount(notification: Misskey.entities.Notification)
margin-right: 4px;
position: relative;
- &:before {
+ &::before {
position: absolute;
transform: rotate(180deg);
}
diff --git a/packages/frontend/src/components/MkPagePreview.vue b/packages/frontend/src/components/MkPagePreview.vue
index f6dc00698c..8559d4b96e 100644
--- a/packages/frontend/src/components/MkPagePreview.vue
+++ b/packages/frontend/src/components/MkPagePreview.vue
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
-<MkA :to="`/@${page.user.username}/pages/${page.name}`" class="vhpxefrj" tabindex="-1">
+<MkA :to="`/@${page.user.username}/pages/${page.name}`" class="vhpxefrj">
<div v-if="page.eyeCatchingImage" class="thumbnail">
<MediaImage
:image="page.eyeCatchingImage"
@@ -50,12 +50,29 @@ const props = defineProps<{
<style lang="scss" scoped>
.vhpxefrj {
display: block;
+ position: relative;
&:hover {
text-decoration: none;
color: var(--accent);
}
+ &:focus-within {
+ outline: none;
+
+ &::after {
+ content: "";
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ border-radius: var(--radius);
+ pointer-events: none;
+ box-shadow: inset 0 0 0 2px var(--focus);
+ }
+ }
+
> .thumbnail {
& + article {
border-radius: 0 0 var(--radius) var(--radius);
diff --git a/packages/frontend/src/components/MkPageWindow.vue b/packages/frontend/src/components/MkPageWindow.vue
index aa4509b14b..bd86b01591 100644
--- a/packages/frontend/src/components/MkPageWindow.vue
+++ b/packages/frontend/src/components/MkPageWindow.vue
@@ -33,7 +33,7 @@ import { computed, onMounted, onUnmounted, provide, ref, shallowRef } from 'vue'
import RouterView from '@/components/global/RouterView.vue';
import MkWindow from '@/components/MkWindow.vue';
import { popout as _popout } from '@/scripts/popout.js';
-import copyToClipboard from '@/scripts/copy-to-clipboard.js';
+import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
import { url } from '@/config.js';
import { useScrollPositionManager } from '@/nirax.js';
import { i18n } from '@/i18n.js';
diff --git a/packages/frontend/src/components/MkPoll.vue b/packages/frontend/src/components/MkPoll.vue
index a98690f1c3..72bd8f4f6c 100644
--- a/packages/frontend/src/components/MkPoll.vue
+++ b/packages/frontend/src/components/MkPoll.vue
@@ -34,7 +34,9 @@ import { pleaseLogin } from '@/scripts/please-login.js';
import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { i18n } from '@/i18n.js';
+import { host } from '@/config.js';
import { useInterval } from '@/scripts/use-interval.js';
+import type { OpenOnRemoteOptions } from '@/scripts/please-login.js';
const props = defineProps<{
noteId: string;
@@ -60,6 +62,11 @@ const timer = computed(() => i18n.tsx._poll[
const showResult = ref(props.readOnly || isVoted.value);
+const pleaseLoginContext = computed<OpenOnRemoteOptions>(() => ({
+ type: 'lookup',
+ url: `https://${host}/notes/${props.noteId}`,
+}));
+
// 期é™ä»˜ãアンケート
if (props.poll.expiresAt) {
const tick = () => {
@@ -76,7 +83,7 @@ if (props.poll.expiresAt) {
}
const vote = async (id) => {
- pleaseLogin();
+ pleaseLogin(undefined, pleaseLoginContext.value);
if (props.readOnly || closed.value || isVoted.value) return;
diff --git a/packages/frontend/src/components/MkPollEditor.vue b/packages/frontend/src/components/MkPollEditor.vue
index db74354bbb..3726ddf822 100644
--- a/packages/frontend/src/components/MkPollEditor.vue
+++ b/packages/frontend/src/components/MkPollEditor.vue
@@ -37,7 +37,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkInput>
</section>
<section v-else-if="expiration === 'after'">
- <MkInput v-model="after" small type="number" class="input">
+ <MkInput v-model="after" small type="number" min="1" class="input">
<template #label>{{ i18n.ts._poll.duration }}</template>
</MkInput>
<MkSelect v-model="unit" small>
diff --git a/packages/frontend/src/components/MkPopupMenu.vue b/packages/frontend/src/components/MkPopupMenu.vue
index be0b07612a..8a0c7b1e54 100644
--- a/packages/frontend/src/components/MkPopupMenu.vue
+++ b/packages/frontend/src/components/MkPopupMenu.vue
@@ -4,8 +4,8 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
-<MkModal ref="modal" v-slot="{ type, maxHeight }" :manualShowing="manualShowing" :zPriority="'high'" :src="src" :transparentBg="true" @click="click" @close="onModalClose" @closed="onModalClosed">
- <MkMenu :items="items" :align="align" :width="width" :max-height="maxHeight" :asDrawer="type === 'drawer'" :class="{ [$style.drawer]: type === 'drawer' }" @close="onMenuClose" @hide="hide"/>
+<MkModal ref="modal" v-slot="{ type, maxHeight }" :manualShowing="manualShowing" :zPriority="'high'" :src="src" :transparentBg="true" :returnFocusTo="returnFocusTo" @click="click" @close="onModalClose" @closed="onModalClosed">
+ <MkMenu :items="items" :align="align" :width="width" :max-height="maxHeight" :asDrawer="type === 'drawer'" :returnFocusTo="returnFocusTo" :class="{ [$style.drawer]: type === 'drawer' }" @close="onMenuClose" @hide="hide"/>
</MkModal>
</template>
@@ -19,8 +19,8 @@ defineProps<{
items: MenuItem[];
align?: 'center' | string;
width?: number;
- viaKeyboard?: boolean;
src?: any;
+ returnFocusTo?: HTMLElement | null;
}>();
const emit = defineEmits<{
diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue
index 1df9007681..51ec941c97 100644
--- a/packages/frontend/src/components/MkPostForm.vue
+++ b/packages/frontend/src/components/MkPostForm.vue
@@ -259,7 +259,7 @@ const canPost = computed((): boolean => {
1 <= files.value.length ||
poll.value != null ||
props.renote != null ||
- (props.reply != null && quoteId.value != null)
+ quoteId.value != null
) &&
(textLength.value <= maxTextLength.value) &&
(!poll.value || poll.value.choices.length >= 2);
@@ -367,6 +367,8 @@ function watchForDraft() {
watch(files, () => saveDraft(), { deep: true });
watch(visibility, () => saveDraft());
watch(localOnly, () => saveDraft());
+ watch(quoteId, () => saveDraft());
+ watch(reactionAcceptance, () => saveDraft());
}
function checkMissingMention() {
@@ -463,7 +465,7 @@ function setVisibility() {
return;
}
- os.popup(defineAsyncComponent(() => import('@/components/MkVisibilityPicker.vue')), {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkVisibilityPicker.vue')), {
currentVisibility: visibility.value,
isSilenced: $i.isSilenced,
localOnly: localOnly.value,
@@ -476,7 +478,8 @@ function setVisibility() {
defaultStore.set('visibility', visibility.value);
}
},
- }, 'closed');
+ closed: () => dispose(),
+ });
}
async function toggleLocalOnly() {
@@ -569,6 +572,7 @@ function clear() {
function onKeydown(ev: KeyboardEvent) {
if (ev.key === 'Enter' && (ev.ctrlKey || ev.metaKey) && canPost.value) post();
+
if (ev.key === 'Escape') emit('esc');
}
@@ -624,8 +628,8 @@ async function onPaste(ev: ClipboardEvent) {
return;
}
- const fileName = formatTimeString(new Date(), defaultStore.state.pastedFileName).replace(/{{number}}/g, "0");
- const file = new File([paste], `${fileName}.txt`, { type: "text/plain" });
+ const fileName = formatTimeString(new Date(), defaultStore.state.pastedFileName).replace(/{{number}}/g, '0');
+ const file = new File([paste], `${fileName}.txt`, { type: 'text/plain' });
upload(file, `${fileName}.txt`);
});
}
@@ -701,6 +705,8 @@ function saveDraft() {
files: files.value,
poll: poll.value,
visibleUserIds: visibility.value === 'specified' ? visibleUsers.value.map(x => x.id) : undefined,
+ quoteId: quoteId.value,
+ reactionAcceptance: reactionAcceptance.value,
},
};
@@ -731,7 +737,9 @@ async function post(ev?: MouseEvent) {
const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2);
- os.popup(MkRippleEffect, { x, y }, {}, 'end');
+ const { dispose } = os.popup(MkRippleEffect, { x, y }, {
+ end: () => dispose(),
+ });
}
}
@@ -898,10 +906,23 @@ async function insertEmoji(ev: MouseEvent) {
textAreaReadOnly.value = true;
const target = ev.currentTarget ?? ev.target;
if (target == null) return;
+
+ // emojiPickerã¯ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ãŒé–‰ã˜ãšã«textareaã¨ã‚„りã¨ã‚Šã™ã‚‹ã®ã§ã€
+ // focustrapã‚’ã‹ã‘ã¦ã„ã‚‹ã¨insertTextAtCursorãŒåйã‹ãªã„
+ // ãã®ãŸã‚ã€æŠ•ç¨¿ãƒ•ã‚©ãƒ¼ãƒ ã®ãƒ†ã‚­ã‚¹ãƒˆã«ç›´æŽ¥æ³¨å…¥ã™ã‚‹
+ // See: https://github.com/misskey-dev/misskey/pull/14282
+ // https://github.com/misskey-dev/misskey/issues/14274
+
+ let pos = textareaEl.value?.selectionStart ?? 0;
+ let posEnd = textareaEl.value?.selectionEnd ?? text.value.length;
emojiPicker.show(
target as HTMLElement,
emoji => {
- insertTextAtCursor(textareaEl.value, emoji);
+ const textBefore = text.value.substring(0, pos);
+ const textAfter = text.value.substring(posEnd);
+ text.value = textBefore + emoji + textAfter;
+ pos += emoji.length;
+ posEnd += emoji.length;
},
() => {
textAreaReadOnly.value = false;
@@ -987,6 +1008,8 @@ onMounted(() => {
users.forEach(u => pushVisibleUser(u));
});
}
+ quoteId.value = draft.data.quoteId;
+ reactionAcceptance.value = draft.data.reactionAcceptance;
}
}
@@ -994,9 +1017,11 @@ onMounted(() => {
if (props.initialNote) {
const init = props.initialNote;
text.value = init.text ? init.text : '';
- files.value = init.files ?? [];
- cw.value = init.cw ?? null;
useCw.value = init.cw != null;
+ cw.value = init.cw ?? null;
+ visibility.value = init.visibility;
+ localOnly.value = init.localOnly ?? false;
+ files.value = init.files ?? [];
if (init.poll) {
poll.value = {
choices: init.poll.choices.map(x => x.text),
@@ -1005,9 +1030,13 @@ onMounted(() => {
expiredAfter: null,
};
}
- visibility.value = init.visibility;
- localOnly.value = init.localOnly ?? false;
+ if (init.visibleUserIds) {
+ misskeyApi('users/show', { userIds: init.visibleUserIds }).then(users => {
+ users.forEach(u => pushVisibleUser(u));
+ });
+ }
quoteId.value = init.renote ? init.renote.id : null;
+ reactionAcceptance.value = init.reactionAcceptance;
}
nextTick(() => watchForDraft());
@@ -1080,6 +1109,15 @@ defineExpose({
margin: 12px 12px 12px 6px;
vertical-align: bottom;
+ &:focus-visible {
+ outline: none;
+
+ .submitInner {
+ outline: 2px solid var(--fgOnAccent);
+ outline-offset: -4px;
+ }
+ }
+
&:disabled {
opacity: 0.7;
}
diff --git a/packages/frontend/src/components/MkPostFormAttaches.vue b/packages/frontend/src/components/MkPostFormAttaches.vue
index 95eb367318..8854babb6b 100644
--- a/packages/frontend/src/components/MkPostFormAttaches.vue
+++ b/packages/frontend/src/components/MkPostFormAttaches.vue
@@ -108,7 +108,7 @@ async function rename(file) {
async function describe(file) {
if (mock) return;
- os.popup(defineAsyncComponent(() => import('@/components/MkFileCaptionEditWindow.vue')), {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkFileCaptionEditWindow.vue')), {
default: file.comment !== null ? file.comment : '',
file: file,
}, {
@@ -121,7 +121,8 @@ async function describe(file) {
file.comment = comment;
});
},
- }, 'closed');
+ closed: () => dispose(),
+ });
}
async function crop(file: Misskey.entities.DriveFile): Promise<void> {
diff --git a/packages/frontend/src/components/MkPostFormDialog.vue b/packages/frontend/src/components/MkPostFormDialog.vue
index ac37cb31bc..d6bca29050 100644
--- a/packages/frontend/src/components/MkPostFormDialog.vue
+++ b/packages/frontend/src/components/MkPostFormDialog.vue
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
-<MkModal ref="modal" :preferType="'dialog'" @click="modal?.close()" @closed="onModalClosed()">
+<MkModal ref="modal" :preferType="'dialog'" @click="modal?.close()" @closed="onModalClosed()" @esc="modal?.close()">
<MkPostForm ref="form" :class="$style.form" v-bind="props" autofocus freezeAfterPosted @posted="onPosted" @cancel="modal?.close()" @esc="modal?.close()"/>
</MkModal>
</template>
diff --git a/packages/frontend/src/components/MkPreview.vue b/packages/frontend/src/components/MkPreview.vue
new file mode 100644
index 0000000000..d950d66c6e
--- /dev/null
+++ b/packages/frontend/src/components/MkPreview.vue
@@ -0,0 +1,150 @@
+<!--
+SPDX-FileCopyrightText: syuilo and misskey-project
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
+<template>
+<div :class="$style.preview">
+ <div :class="$style.preview__content1">
+ <MkInput v-model="text">
+ <template #label>Text</template>
+ </MkInput>
+ <MkSwitch v-model="flag" :class="$style.preview__content1__switch_button">
+ <span>Switch is now {{ flag ? 'on' : 'off' }}</span>
+ </MkSwitch>
+ <div :class="$style.preview__content1__input">
+ <MkRadio v-model="radio" value="misskey">Misskey</MkRadio>
+ <MkRadio v-model="radio" value="mastodon">Mastodon</MkRadio>
+ <MkRadio v-model="radio" value="pleroma">Pleroma</MkRadio>
+ </div>
+ <div :class="$style.preview__content1__button">
+ <MkButton inline>This is</MkButton>
+ <MkButton inline primary>the button</MkButton>
+ </div>
+ </div>
+ <div :class="$style.preview__content2" style="pointer-events: none;">
+ <Mfm :text="mfm"/>
+ </div>
+ <div :class="$style.preview__content3">
+ <MkButton inline primary @click="openMenu">Open menu</MkButton>
+ <MkButton inline primary @click="openDialog">Open dialog</MkButton>
+ <MkButton inline primary @click="openForm">Open form</MkButton>
+ <MkButton inline primary @click="openDrive">Open drive</MkButton>
+ </div>
+</div>
+</template>
+
+<script lang="ts" setup>
+import { ref } from 'vue';
+import MkButton from '@/components/MkButton.vue';
+import MkInput from '@/components/MkInput.vue';
+import MkSwitch from '@/components/MkSwitch.vue';
+import MkTextarea from '@/components/MkTextarea.vue';
+import MkRadio from '@/components/MkRadio.vue';
+import * as os from '@/os.js';
+import * as config from '@/config.js';
+import { $i } from '@/account.js';
+
+const text = ref('');
+const flag = ref(true);
+const radio = ref('misskey');
+const mfm = ref(`Hello world! This is an @example mention. BTW you are @${$i ? $i.username : 'guest'}.\nAlso, here is ${config.url} and [example link](${config.url}). for more details, see https://example.com.\nAs you know #misskey is open-source software.`);
+
+const openDialog = async () => {
+ await os.alert({
+ type: 'warning',
+ title: 'Oh my Aichan',
+ text: 'Lorem ipsum dolor sit amet, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
+ });
+};
+
+const openForm = async () => {
+ await os.form('Example form', {
+ foo: {
+ type: 'boolean',
+ default: true,
+ label: 'This is a boolean property',
+ },
+ bar: {
+ type: 'number',
+ default: 300,
+ label: 'This is a number property',
+ },
+ baz: {
+ type: 'string',
+ default: 'Misskey makes you happy.',
+ label: 'This is a string property',
+ },
+ });
+};
+
+const openDrive = async () => {
+ await os.selectDriveFile(false);
+};
+
+const selectUser = async () => {
+ await os.selectUser();
+};
+
+const openMenu = async (ev: Event) => {
+ os.popupMenu([{
+ type: 'label',
+ text: 'Fruits',
+ }, {
+ text: 'Create some apples',
+ action: () => {},
+ }, {
+ text: 'Read some oranges',
+ action: () => {},
+ }, {
+ text: 'Update some melons',
+ action: () => {},
+ }, {
+ text: 'Delete some bananas',
+ danger: true,
+ action: () => {},
+ }], ev.currentTarget ?? ev.target);
+};
+</script>
+
+<style lang="scss" module>
+.preview {
+ padding: 16px;
+
+ &__content1 {
+
+ &__switch_button {
+ padding: 16px 0 8px 0;
+ }
+
+ &__input {
+ padding: 8px 0 8px 0;
+
+ div {
+ margin: 0 8px 8px 0;
+ }
+ }
+
+ &__button {
+ padding: 4px 0 8px 0;
+
+ button {
+ margin: 0 8px 8px 0;
+ }
+ }
+ }
+
+ &__content2 {
+ padding: 8px 0 8px 0;
+ }
+
+ &__content3 {
+ padding: 8px 0 8px 0;
+
+ button {
+ margin: 0 8px 8px 0;
+
+ }
+ }
+}
+</style>
diff --git a/packages/frontend/src/components/MkRadio.vue b/packages/frontend/src/components/MkRadio.vue
index 6676e3bf5b..22fc86723e 100644
--- a/packages/frontend/src/components/MkRadio.vue
+++ b/packages/frontend/src/components/MkRadio.vue
@@ -9,6 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:class="[$style.root, { [$style.disabled]: disabled, [$style.checked]: checked }]"
:aria-checked="checked"
:aria-disabled="disabled"
+ role="checkbox"
@click="toggle"
>
<input
@@ -69,6 +70,11 @@ function toggle(): void {
border-color: var(--inputBorderHover) !important;
}
+ &:focus-within {
+ outline: none;
+ box-shadow: 0 0 0 2px var(--focus);
+ }
+
&.checked {
background-color: var(--accentedBg) !important;
border-color: var(--accentedBg) !important;
@@ -78,7 +84,7 @@ function toggle(): void {
> .button {
border-color: var(--accent);
- &:after {
+ &::after {
background-color: var(--accent);
transform: scale(1);
opacity: 1;
@@ -104,7 +110,7 @@ function toggle(): void {
border-radius: 100%;
transition: inherit;
- &:after {
+ &::after {
content: '';
display: block;
position: absolute;
diff --git a/packages/frontend/src/components/MkRadios.vue b/packages/frontend/src/components/MkRadios.vue
index 549438f61b..705c93f770 100644
--- a/packages/frontend/src/components/MkRadios.vue
+++ b/packages/frontend/src/components/MkRadios.vue
@@ -29,6 +29,9 @@ export default defineComponent({
// ãªãœã‹Fragmentã«ãªã‚‹ã“ã¨ãŒã‚ã‚‹ãŸã‚
if (options.length === 1 && options[0].props == null) options = options[0].children as VNode[];
+ // vnodeã®ã†ã¡v-if=falseãªã‚‚ã®ã‚’除外ã™ã‚‹(trueã«ãªã‚‹ã‚‚ã®ã¯optionãªã©ä»–typeã«ãªã‚‹)
+ options = options.filter(vnode => !(typeof vnode.type === 'symbol' && vnode.type.description === 'v-cmt' && vnode.children === 'v-if'));
+
return () => h('div', {
class: 'novjtcto',
}, [
@@ -40,6 +43,7 @@ export default defineComponent({
}, options.map(option => h(MkRadio, {
key: option.key as string,
value: option.props?.value,
+ disabled: option.props?.disabled,
modelValue: value.value,
'onUpdate:modelValue': _v => value.value = _v,
}, () => option.children)),
diff --git a/packages/frontend/src/components/MkRange.vue b/packages/frontend/src/components/MkRange.vue
index 15f8128e98..1eae642937 100644
--- a/packages/frontend/src/components/MkRange.vue
+++ b/packages/frontend/src/components/MkRange.vue
@@ -101,17 +101,19 @@ const steps = computed(() => {
}
});
-const onMousedown = (ev: MouseEvent | TouchEvent) => {
+function onMousedown(ev: MouseEvent | TouchEvent) {
ev.preventDefault();
const tooltipShowing = ref(true);
- os.popup(defineAsyncComponent(() => import('@/components/MkTooltip.vue')), {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkTooltip.vue')), {
showing: tooltipShowing,
text: computed(() => {
return props.textConverter(finalValue.value);
}),
targetElement: thumbEl,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
const style = document.createElement('style');
style.appendChild(document.createTextNode('* { cursor: grabbing !important; } body * { pointer-events: none !important; }'));
@@ -152,7 +154,7 @@ const onMousedown = (ev: MouseEvent | TouchEvent) => {
window.addEventListener('touchmove', onDrag);
window.addEventListener('mouseup', onMouseup, { once: true });
window.addEventListener('touchend', onMouseup, { once: true });
-};
+}
</script>
<style lang="scss" scoped>
diff --git a/packages/frontend/src/components/MkReactionIcon.vue b/packages/frontend/src/components/MkReactionIcon.vue
index 068a2968db..c0cbd8a65d 100644
--- a/packages/frontend/src/components/MkReactionIcon.vue
+++ b/packages/frontend/src/components/MkReactionIcon.vue
@@ -24,11 +24,13 @@ const elRef = shallowRef();
if (props.withTooltip) {
useTooltip(elRef, (showing) => {
- os.popup(defineAsyncComponent(() => import('@/components/MkReactionTooltip.vue')), {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkReactionTooltip.vue')), {
showing,
reaction: props.reaction.replace(/^:(\w+):$/, ':$1@.:'),
targetElement: elRef.value.$el,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
});
}
</script>
diff --git a/packages/frontend/src/components/MkReactionsViewer.details.vue b/packages/frontend/src/components/MkReactionsViewer.details.vue
index 8b5e6efdf3..60118fadd2 100644
--- a/packages/frontend/src/components/MkReactionsViewer.details.vue
+++ b/packages/frontend/src/components/MkReactionsViewer.details.vue
@@ -81,6 +81,7 @@ function getReactionName(reaction: string): string {
}
.user {
+ display: flex;
line-height: 24px;
padding-top: 4px;
white-space: nowrap;
diff --git a/packages/frontend/src/components/MkReactionsViewer.reaction.vue b/packages/frontend/src/components/MkReactionsViewer.reaction.vue
index c41811febe..26223364ab 100644
--- a/packages/frontend/src/components/MkReactionsViewer.reaction.vue
+++ b/packages/frontend/src/components/MkReactionsViewer.reaction.vue
@@ -114,10 +114,12 @@ async function menu(ev) {
text: i18n.ts.info,
icon: 'ti ti-info-circle',
action: async () => {
- os.popup(MkCustomEmojiDetailedDialog, {
+ const { dispose } = os.popup(MkCustomEmojiDetailedDialog, {
emoji: await misskeyApiGet('emoji', {
name: props.reaction.replace(/:/g, '').replace(/@\./, ''),
}),
+ }, {
+ closed: () => dispose(),
});
},
}], ev.currentTarget ?? ev.target);
@@ -129,7 +131,9 @@ function anime() {
const rect = buttonEl.value.getBoundingClientRect();
const x = rect.left + 16;
const y = rect.top + (buttonEl.value.offsetHeight / 2);
- os.popup(MkReactionEffect, { reaction: props.reaction, x, y }, {}, 'end');
+ const { dispose } = os.popup(MkReactionEffect, { reaction: props.reaction, x, y }, {
+ end: () => dispose(),
+ });
}
watch(() => props.count, (newCount, oldCount) => {
@@ -151,13 +155,15 @@ if (!mock) {
const users = reactions.map(x => x.user);
- os.popup(XDetails, {
+ const { dispose } = os.popup(XDetails, {
showing,
reaction: props.reaction,
users,
count: props.count,
targetElement: buttonEl.value,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
}, 100);
}
</script>
diff --git a/packages/frontend/src/components/MkSelect.vue b/packages/frontend/src/components/MkSelect.vue
index 358d9b1f4b..0eba8d6a9c 100644
--- a/packages/frontend/src/components/MkSelect.vue
+++ b/packages/frontend/src/components/MkSelect.vue
@@ -6,20 +6,29 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<div>
<div :class="$style.label" @click="focus"><slot name="label"></slot></div>
- <div ref="container" :class="[$style.input, { [$style.inline]: inline, [$style.disabled]: disabled, [$style.focused]: focused }]" @mousedown.prevent="show">
+ <div
+ ref="container"
+ tabindex="0"
+ :class="[$style.input, { [$style.inline]: inline, [$style.disabled]: disabled, [$style.focused]: focused || opening }]"
+ @focus="focused = true"
+ @blur="focused = false"
+ @mousedown.prevent="show"
+ @keydown.space.enter="show"
+ >
<div ref="prefixEl" :class="$style.prefix"><slot name="prefix"></slot></div>
<select
ref="inputEl"
v-model="v"
v-adaptive-border
+ tabindex="-1"
:class="$style.inputCore"
:disabled="disabled"
:required="required"
:readonly="readonly"
:placeholder="placeholder"
- @focus="focused = true"
- @blur="focused = false"
@input="onInput"
+ @mousedown.prevent="() => {}"
+ @keydown.prevent="() => {}"
>
<slot></slot>
</select>
@@ -75,7 +84,7 @@ const height =
props.large ? 39 :
36;
-const focus = () => inputEl.value?.focus();
+const focus = () => container.value?.focus();
const onInput = (ev) => {
changed.value = true;
};
@@ -126,7 +135,9 @@ onMounted(() => {
});
function show() {
- focused.value = true;
+ if (opening.value) return;
+ focus();
+
opening.value = true;
const menu: MenuItem[] = [];
@@ -173,8 +184,6 @@ function show() {
onClosing: () => {
opening.value = false;
},
- }).then(() => {
- focused.value = false;
});
}
</script>
@@ -225,6 +234,10 @@ function show() {
}
}
+ &:focus {
+ outline: none;
+ }
+
&:hover {
> .inputCore {
border-color: var(--inputBorderHover) !important;
diff --git a/packages/frontend/src/components/MkSignin.vue b/packages/frontend/src/components/MkSignin.vue
index 970aff825d..781145e1bc 100644
--- a/packages/frontend/src/components/MkSignin.vue
+++ b/packages/frontend/src/components/MkSignin.vue
@@ -6,10 +6,23 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<form :class="{ signing, totpLogin }" @submit.prevent="onSubmit">
<div class="_gaps_m">
- <div v-show="withAvatar" :class="$style.avatar" :style="{ backgroundImage: user ? `url('${ user.avatarUrl }')` : undefined, marginBottom: message ? '1.5em' : undefined }"></div>
+ <div v-show="withAvatar" :class="$style.avatar" :style="{ backgroundImage: user ? `url('${user.avatarUrl}')` : undefined, marginBottom: message ? '1.5em' : undefined }"></div>
<MkInfo v-if="message">
{{ message }}
</MkInfo>
+ <div v-if="openOnRemote" class="_gaps_m">
+ <div class="_gaps_s">
+ <MkButton type="button" rounded primary style="margin: 0 auto;" @click="openRemote(openOnRemote)">
+ {{ i18n.ts.continueOnRemote }} <i class="ti ti-external-link"></i>
+ </MkButton>
+ <button type="button" class="_button" :class="$style.instanceManualSelectButton" @click="specifyHostAndOpenRemote(openOnRemote)">
+ {{ i18n.ts.specifyServerHost }}
+ </button>
+ </div>
+ <div :class="$style.orHr">
+ <p :class="$style.orMsg">{{ i18n.ts.or }}</p>
+ </div>
+ </div>
<div v-if="!totpLogin" class="normal-signin _gaps_m">
<MkInput v-model="username" :placeholder="i18n.ts.username" type="text" pattern="^[a-zA-Z0-9_]+$" :spellcheck="false" autocomplete="username webauthn" autofocus required data-cy-signin-username @update:modelValue="onUsernameChange">
<template #prefix>@</template>
@@ -28,8 +41,8 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts.retry }}
</MkButton>
</div>
- <div v-if="user && user.securityKeys" class="or-hr">
- <p class="or-msg">{{ i18n.ts.or }}</p>
+ <div v-if="user && user.securityKeys" :class="$style.orHr">
+ <p :class="$style.orMsg">{{ i18n.ts.or }}</p>
</div>
<div class="twofa-group totp-group _gaps">
<MkInput v-if="user && user.usePasswordLessLogin" v-model="password" type="password" autocomplete="current-password" :withPasswordToggle="true" required>
@@ -53,6 +66,7 @@ import { defineAsyncComponent, ref } from 'vue';
import { toUnicode } from 'punycode/';
import * as Misskey from 'misskey-js';
import { supported as webAuthnSupported, get as webAuthnRequest, parseRequestOptionsFromJSON } from '@github/webauthn-json/browser-ponyfill';
+import type { OpenOnRemoteOptions } from '@/scripts/please-login.js';
import { showSuspendedDialog } from '@/scripts/show-suspended-dialog.js';
import MkButton from '@/components/MkButton.vue';
import MkInput from '@/components/MkInput.vue';
@@ -60,6 +74,7 @@ import MkInfo from '@/components/MkInfo.vue';
import { host as configHost } from '@/config.js';
import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
+import { query, extractDomain } from '@/scripts/url.js';
import { login } from '@/account.js';
import { i18n } from '@/i18n.js';
@@ -72,28 +87,22 @@ const host = ref(toUnicode(configHost));
const totpLogin = ref(false);
const isBackupCode = ref(false);
const queryingKey = ref(false);
-const credentialRequest = ref<CredentialRequestOptions | null>(null);
+let credentialRequest: CredentialRequestOptions | null = null;
const emit = defineEmits<{
(ev: 'login', v: any): void;
}>();
-const props = defineProps({
- withAvatar: {
- type: Boolean,
- required: false,
- default: true,
- },
- autoSet: {
- type: Boolean,
- required: false,
- default: false,
- },
- message: {
- type: String,
- required: false,
- default: '',
- },
+const props = withDefaults(defineProps<{
+ withAvatar?: boolean;
+ autoSet?: boolean;
+ message?: string,
+ openOnRemote?: OpenOnRemoteOptions,
+}>(), {
+ withAvatar: true,
+ autoSet: false,
+ message: '',
+ openOnRemote: undefined,
});
function onUsernameChange(): void {
@@ -113,14 +122,14 @@ function onLogin(res: any): Promise<void> | void {
}
async function queryKey(): Promise<void> {
- if (credentialRequest.value == null) return;
+ if (credentialRequest == null) return;
queryingKey.value = true;
- await webAuthnRequest(credentialRequest.value)
+ await webAuthnRequest(credentialRequest)
.catch(() => {
queryingKey.value = false;
return Promise.reject(null);
}).then(credential => {
- credentialRequest.value = null;
+ credentialRequest = null;
queryingKey.value = false;
signing.value = true;
return misskeyApi('signin', {
@@ -151,7 +160,7 @@ function onSubmit(): void {
}).then(res => {
totpLogin.value = true;
signing.value = false;
- credentialRequest.value = parseRequestOptionsFromJSON({
+ credentialRequest = parseRequestOptionsFromJSON({
publicKey: res,
});
})
@@ -218,8 +227,65 @@ function loginFailed(err: any): void {
}
function resetPassword(): void {
- os.popup(defineAsyncComponent(() => import('@/components/MkForgotPassword.vue')), {}, {
- }, 'closed');
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkForgotPassword.vue')), {}, {
+ closed: () => dispose(),
+ });
+}
+
+function openRemote(options: OpenOnRemoteOptions, targetHost?: string): void {
+ switch (options.type) {
+ case 'web':
+ case 'lookup': {
+ let _path: string;
+
+ if (options.type === 'lookup') {
+ // TODO: v2024.7.0以é™ãŒæµ¸é€ã—ã¦ããŸã‚‰æ­£å¼ãªURLã«å¤‰æ›´ã™ã‚‹â–¼
+ // _path = `/lookup?uri=${encodeURIComponent(_path)}`;
+ _path = `/authorize-follow?acct=${encodeURIComponent(options.url)}`;
+ } else {
+ _path = options.path;
+ }
+
+ if (targetHost) {
+ window.open(`https://${targetHost}${_path}`, '_blank', 'noopener');
+ } else {
+ window.open(`https://misskey-hub.net/mi-web/?path=${encodeURIComponent(_path)}`, '_blank', 'noopener');
+ }
+ break;
+ }
+ case 'share': {
+ const params = query(options.params);
+ if (targetHost) {
+ window.open(`https://${targetHost}/share?${params}`, '_blank', 'noopener');
+ } else {
+ window.open(`https://misskey-hub.net/share/?${params}`, '_blank', 'noopener');
+ }
+ break;
+ }
+ }
+}
+
+async function specifyHostAndOpenRemote(options: OpenOnRemoteOptions): Promise<void> {
+ const { canceled, result: hostTemp } = await os.inputText({
+ title: i18n.ts.inputHostName,
+ placeholder: 'misskey.example.com',
+ });
+
+ if (canceled) return;
+
+ let targetHost: string | null = hostTemp;
+
+ // ドメイン部分ã ã‘ã‚’å–り出ã™
+ targetHost = extractDomain(targetHost);
+ if (targetHost == null) {
+ os.alert({
+ type: 'error',
+ title: i18n.ts.invalidValue,
+ text: i18n.ts.tryAgain,
+ });
+ return;
+ }
+ openRemote(options, targetHost);
}
</script>
@@ -233,4 +299,36 @@ function resetPassword(): void {
background-size: cover;
border-radius: 100%;
}
+
+.instanceManualSelectButton {
+ display: block;
+ text-align: center;
+ opacity: .7;
+ font-size: .8em;
+
+ &:hover {
+ text-decoration: underline;
+ }
+}
+
+.orHr {
+ position: relative;
+ margin: .4em auto;
+ width: 100%;
+ height: 1px;
+ background: var(--divider);
+}
+
+.orMsg {
+ position: absolute;
+ top: -.6em;
+ display: inline-block;
+ padding: 0 1em;
+ background: var(--panel);
+ font-size: 0.8em;
+ color: var(--fgOnPanel);
+ margin: 0;
+ left: 50%;
+ transform: translateX(-50%);
+}
</style>
diff --git a/packages/frontend/src/components/MkSigninDialog.vue b/packages/frontend/src/components/MkSigninDialog.vue
index 33355bb99e..524c62b4d3 100644
--- a/packages/frontend/src/components/MkSigninDialog.vue
+++ b/packages/frontend/src/components/MkSigninDialog.vue
@@ -6,21 +6,22 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<MkModalWindow
ref="dialog"
- :width="370"
- :height="400"
+ :width="400"
+ :height="430"
@close="onClose"
@closed="emit('closed')"
>
<template #header>{{ i18n.ts.login }}</template>
<MkSpacer :marginMin="20" :marginMax="28">
- <MkSignin :autoSet="autoSet" :message="message" @login="onLogin"/>
+ <MkSignin :autoSet="autoSet" :message="message" :openOnRemote="openOnRemote" @login="onLogin"/>
</MkSpacer>
</MkModalWindow>
</template>
<script lang="ts" setup>
import { shallowRef } from 'vue';
+import type { OpenOnRemoteOptions } from '@/scripts/please-login.js';
import MkSignin from '@/components/MkSignin.vue';
import MkModalWindow from '@/components/MkModalWindow.vue';
import { i18n } from '@/i18n.js';
@@ -28,9 +29,11 @@ import { i18n } from '@/i18n.js';
withDefaults(defineProps<{
autoSet?: boolean;
message?: string,
+ openOnRemote?: OpenOnRemoteOptions,
}>(), {
autoSet: false,
message: '',
+ openOnRemote: undefined,
});
const emit = defineEmits<{
diff --git a/packages/frontend/src/components/MkSuperMenu.vue b/packages/frontend/src/components/MkSuperMenu.vue
index 3023f63e5d..1a880170be 100644
--- a/packages/frontend/src/components/MkSuperMenu.vue
+++ b/packages/frontend/src/components/MkSuperMenu.vue
@@ -10,15 +10,15 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="items">
<template v-for="(item, i) in group.items">
- <a v-if="item.type === 'a'" :href="item.href" :target="item.target" :tabindex="i" class="_button item" :class="{ danger: item.danger, active: item.active }">
+ <a v-if="item.type === 'a'" :href="item.href" :target="item.target" class="_button item" :class="{ danger: item.danger, active: item.active }">
<span v-if="item.icon" class="icon"><i :class="item.icon" class="ti-fw"></i></span>
<span class="text">{{ item.text }}</span>
</a>
- <button v-else-if="item.type === 'button'" :tabindex="i" class="_button item" :class="{ danger: item.danger, active: item.active }" :disabled="item.active" @click="ev => item.action(ev)">
+ <button v-else-if="item.type === 'button'" class="_button item" :class="{ danger: item.danger, active: item.active }" :disabled="item.active" @click="ev => item.action(ev)">
<span v-if="item.icon" class="icon"><i :class="item.icon" class="ti-fw"></i></span>
<span class="text">{{ item.text }}</span>
</button>
- <MkA v-else :to="item.to" :tabindex="i" class="_button item" :class="{ danger: item.danger, active: item.active }">
+ <MkA v-else :to="item.to" class="_button item" :class="{ danger: item.danger, active: item.active }">
<span v-if="item.icon" class="icon"><i :class="item.icon" class="ti-fw"></i></span>
<span class="text">{{ item.text }}</span>
</MkA>
@@ -67,6 +67,10 @@ defineProps<{
background: var(--panelHighlight);
}
+ &:focus-visible {
+ outline-offset: -2px;
+ }
+
&.active {
color: var(--accent);
background: var(--accentedBg);
diff --git a/packages/frontend/src/components/MkSwitch.vue b/packages/frontend/src/components/MkSwitch.vue
index a19b45448b..a0994d9cc9 100644
--- a/packages/frontend/src/components/MkSwitch.vue
+++ b/packages/frontend/src/components/MkSwitch.vue
@@ -10,10 +10,10 @@ SPDX-License-Identifier: AGPL-3.0-only
type="checkbox"
:disabled="disabled"
:class="$style.input"
- @keydown.enter="toggle"
+ @click="toggle"
>
- <XButton :checked="checked" :disabled="disabled" @toggle="toggle"/>
- <span :class="$style.body">
+ <XButton :class="$style.toggle" :checked="checked" :disabled="disabled" @toggle="toggle"/>
+ <span v-if="!noBody" :class="$style.body">
<!-- TODO: ç„¡åslotã®æ–¹ã¯å»ƒæ­¢ -->
<span :class="$style.label">
<span @click="toggle">
@@ -34,16 +34,19 @@ const props = defineProps<{
modelValue: boolean | Ref<boolean>;
disabled?: boolean;
helpText?: string;
+ noBody?: boolean;
}>();
const emit = defineEmits<{
(ev: 'update:modelValue', v: boolean): void;
+ (ev: 'change', v: boolean): void;
}>();
const checked = toRefs(props).modelValue;
const toggle = () => {
if (props.disabled) return;
emit('update:modelValue', !checked.value);
+ emit('change', !checked.value);
};
</script>
@@ -72,7 +75,13 @@ const toggle = () => {
height: 0;
opacity: 0;
margin: 0;
+
+ &:focus-visible ~ .toggle {
+ outline: 2px solid var(--focus);
+ outline-offset: 2px;
+ }
}
+
.body {
margin-left: 12px;
margin-top: 2px;
diff --git a/packages/frontend/src/components/MkSystemWebhookEditor.impl.ts b/packages/frontend/src/components/MkSystemWebhookEditor.impl.ts
new file mode 100644
index 0000000000..69b8edd85a
--- /dev/null
+++ b/packages/frontend/src/components/MkSystemWebhookEditor.impl.ts
@@ -0,0 +1,46 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { defineAsyncComponent } from 'vue';
+import * as os from '@/os.js';
+
+export type SystemWebhookEventType = 'abuseReport' | 'abuseReportResolved';
+
+export type MkSystemWebhookEditorProps = {
+ mode: 'create' | 'edit';
+ id?: string;
+ requiredEvents?: SystemWebhookEventType[];
+};
+
+export type MkSystemWebhookResult = {
+ id?: string;
+ isActive: boolean;
+ name: string;
+ on: SystemWebhookEventType[];
+ url: string;
+ secret: string;
+};
+
+export async function showSystemWebhookEditorDialog(props: MkSystemWebhookEditorProps): Promise<MkSystemWebhookResult | null> {
+ const { result } = await new Promise<{ result: MkSystemWebhookResult | null }>(async resolve => {
+ const { dispose } = os.popup(
+ defineAsyncComponent(() => import('@/components/MkSystemWebhookEditor.vue')),
+ props,
+ {
+ submitted: (ev: MkSystemWebhookResult) => {
+ resolve({ result: ev });
+ },
+ canceled: () => {
+ resolve({ result: null });
+ },
+ closed: () => {
+ dispose();
+ },
+ },
+ );
+ });
+
+ return result;
+}
diff --git a/packages/frontend/src/components/MkSystemWebhookEditor.vue b/packages/frontend/src/components/MkSystemWebhookEditor.vue
new file mode 100644
index 0000000000..f5c7a3160b
--- /dev/null
+++ b/packages/frontend/src/components/MkSystemWebhookEditor.vue
@@ -0,0 +1,238 @@
+<!--
+SPDX-FileCopyrightText: syuilo and misskey-project
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
+<template>
+<MkModalWindow
+ ref="dialogEl"
+ :width="450"
+ :height="590"
+ :canClose="true"
+ :withOkButton="false"
+ :okButtonDisabled="false"
+ @click="onCancelClicked"
+ @close="onCancelClicked"
+ @closed="emit('closed')"
+>
+ <template #header>
+ {{ mode === 'create' ? i18n.ts._webhookSettings.createWebhook : i18n.ts._webhookSettings.modifyWebhook }}
+ </template>
+
+ <div style="display: flex; flex-direction: column; min-height: 100%;">
+ <MkSpacer :marginMin="20" :marginMax="28" style="flex-grow: 1;">
+ <MkLoading v-if="loading !== 0"/>
+ <div v-else :class="$style.root" class="_gaps_m">
+ <MkInput v-model="title">
+ <template #label>{{ i18n.ts._webhookSettings.name }}</template>
+ </MkInput>
+ <MkInput v-model="url">
+ <template #label>URL</template>
+ </MkInput>
+ <MkInput v-model="secret">
+ <template #label>{{ i18n.ts._webhookSettings.secret }}</template>
+ </MkInput>
+ <MkFolder :defaultOpen="true">
+ <template #label>{{ i18n.ts._webhookSettings.trigger }}</template>
+
+ <div class="_gaps_s">
+ <MkSwitch v-model="events.abuseReport" :disabled="disabledEvents.abuseReport">
+ <template #label>{{ i18n.ts._webhookSettings._systemEvents.abuseReport }}</template>
+ </MkSwitch>
+ <MkSwitch v-model="events.abuseReportResolved" :disabled="disabledEvents.abuseReportResolved">
+ <template #label>{{ i18n.ts._webhookSettings._systemEvents.abuseReportResolved }}</template>
+ </MkSwitch>
+ <MkSwitch v-model="events.userCreated" :disabled="disabledEvents.userCreated">
+ <template #label>{{ i18n.ts._webhookSettings._systemEvents.userCreated }}</template>
+ </MkSwitch>
+ </div>
+ </MkFolder>
+
+ <MkSwitch v-model="isActive">
+ <template #label>{{ i18n.ts.enable }}</template>
+ </MkSwitch>
+ </div>
+ </MkSpacer>
+ <div :class="$style.footer" class="_buttonsCenter">
+ <MkButton primary rounded :disabled="disableSubmitButton" @click="onSubmitClicked">
+ <i class="ti ti-check"></i>
+ {{ i18n.ts.ok }}
+ </MkButton>
+ <MkButton rounded @click="onCancelClicked"><i class="ti ti-x"></i> {{ i18n.ts.cancel }}</MkButton>
+ </div>
+ </div>
+</MkModalWindow>
+</template>
+
+<script setup lang="ts">
+import { computed, onMounted, ref, shallowRef, toRefs } from 'vue';
+import MkInput from '@/components/MkInput.vue';
+import MkSwitch from '@/components/MkSwitch.vue';
+import {
+ MkSystemWebhookEditorProps,
+ MkSystemWebhookResult,
+ SystemWebhookEventType,
+} from '@/components/MkSystemWebhookEditor.impl.js';
+import { i18n } from '@/i18n.js';
+import MkButton from '@/components/MkButton.vue';
+import { misskeyApi } from '@/scripts/misskey-api.js';
+import MkModalWindow from '@/components/MkModalWindow.vue';
+import MkFolder from '@/components/MkFolder.vue';
+import * as os from '@/os.js';
+
+type EventType = {
+ abuseReport: boolean;
+ abuseReportResolved: boolean;
+ userCreated: boolean;
+}
+
+const emit = defineEmits<{
+ (ev: 'submitted', result: MkSystemWebhookResult): void;
+ (ev: 'canceled'): void;
+ (ev: 'closed'): void;
+}>();
+
+const dialogEl = shallowRef<InstanceType<typeof MkModalWindow>>();
+
+const props = defineProps<MkSystemWebhookEditorProps>();
+
+const { mode, id, requiredEvents } = toRefs(props);
+
+const loading = ref<number>(0);
+
+const title = ref<string>('');
+const url = ref<string>('');
+const secret = ref<string>('');
+const events = ref<EventType>({
+ abuseReport: true,
+ abuseReportResolved: true,
+ userCreated: true,
+});
+const isActive = ref<boolean>(true);
+
+const disabledEvents = ref<EventType>({
+ abuseReport: false,
+ abuseReportResolved: false,
+ userCreated: false,
+});
+
+const disableSubmitButton = computed(() => {
+ if (!title.value) {
+ return true;
+ }
+ if (!url.value) {
+ return true;
+ }
+ if (!secret.value) {
+ return true;
+ }
+
+ return false;
+});
+
+async function onSubmitClicked() {
+ await loadingScope(async () => {
+ const params = {
+ isActive: isActive.value,
+ name: title.value,
+ url: url.value,
+ secret: secret.value,
+ on: Object.keys(events.value).filter(ev => events.value[ev as keyof EventType]) as SystemWebhookEventType[],
+ };
+
+ try {
+ switch (mode.value) {
+ case 'create': {
+ const result = await misskeyApi('admin/system-webhook/create', params);
+ dialogEl.value?.close();
+ emit('submitted', result);
+ break;
+ }
+ case 'edit': {
+ // eslint-disable-next-line
+ const result = await misskeyApi('admin/system-webhook/update', { id: id.value!, ...params });
+ dialogEl.value?.close();
+ emit('submitted', result);
+ break;
+ }
+ }
+ // eslint-disable-next-line
+ } catch (ex: any) {
+ const msg = ex.message ?? i18n.ts.internalServerErrorDescription;
+ await os.alert({ type: 'error', title: i18n.ts.error, text: msg });
+ dialogEl.value?.close();
+ emit('canceled');
+ }
+ });
+}
+
+function onCancelClicked() {
+ dialogEl.value?.close();
+ emit('canceled');
+}
+
+async function loadingScope<T>(fn: () => Promise<T>): Promise<T> {
+ loading.value++;
+ try {
+ return await fn();
+ } finally {
+ loading.value--;
+ }
+}
+
+onMounted(async () => {
+ await loadingScope(async () => {
+ switch (mode.value) {
+ case 'edit': {
+ if (!id.value) {
+ throw new Error('id is required');
+ }
+
+ try {
+ const res = await misskeyApi('admin/system-webhook/show', { id: id.value });
+
+ title.value = res.name;
+ url.value = res.url;
+ secret.value = res.secret;
+ isActive.value = res.isActive;
+ for (const ev of Object.keys(events.value)) {
+ events.value[ev] = res.on.includes(ev as SystemWebhookEventType);
+ }
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ } catch (ex: any) {
+ const msg = ex.message ?? i18n.ts.internalServerErrorDescription;
+ await os.alert({ type: 'error', title: i18n.ts.error, text: msg });
+ dialogEl.value?.close();
+ emit('canceled');
+ }
+ break;
+ }
+ }
+
+ for (const ev of requiredEvents.value ?? []) {
+ disabledEvents.value[ev] = true;
+ }
+ });
+});
+</script>
+
+<style module lang="scss">
+.root {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: stretch;
+}
+
+.footer {
+ position: sticky;
+ z-index: 10000;
+ bottom: 0;
+ left: 0;
+ padding: 12px;
+ border-top: solid 0.5px var(--divider);
+ background: var(--acrylicBg);
+ -webkit-backdrop-filter: var(--blur, blur(15px));
+ backdrop-filter: var(--blur, blur(15px));
+}
+</style>
diff --git a/packages/frontend/src/components/MkTimeline.vue b/packages/frontend/src/components/MkTimeline.vue
index 03dccb18e9..ca87316bf7 100644
--- a/packages/frontend/src/components/MkTimeline.vue
+++ b/packages/frontend/src/components/MkTimeline.vue
@@ -19,6 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { computed, watch, onUnmounted, provide, ref, shallowRef } from 'vue';
import * as Misskey from 'misskey-js';
+import type { BasicTimelineType } from '@/timelines.js';
import MkNotes from '@/components/MkNotes.vue';
import MkPullToRefresh from '@/components/MkPullToRefresh.vue';
import { useStream } from '@/stream.js';
@@ -29,7 +30,7 @@ import { defaultStore } from '@/store.js';
import { Paging } from '@/components/MkPagination.vue';
const props = withDefaults(defineProps<{
- src: 'home' | 'local' | 'social' | 'global' | 'mentions' | 'directs' | 'list' | 'antenna' | 'channel' | 'role';
+ src: BasicTimelineType | 'mentions' | 'directs' | 'list' | 'antenna' | 'channel' | 'role';
list?: string;
antenna?: string;
channel?: string;
diff --git a/packages/frontend/src/components/MkTutorialDialog.PostNote.vue b/packages/frontend/src/components/MkTutorialDialog.PostNote.vue
index e1d88b5e5c..27483cc7c2 100644
--- a/packages/frontend/src/components/MkTutorialDialog.PostNote.vue
+++ b/packages/frontend/src/components/MkTutorialDialog.PostNote.vue
@@ -105,7 +105,7 @@ const exampleCWNote = reactive<Misskey.entities.Note>({
font-weight: bold;
text-align: left;
- &:before {
+ &::before {
content: "";
display: block;
width: calc(100% - 38px);
diff --git a/packages/frontend/src/components/MkTutorialDialog.Sensitive.vue b/packages/frontend/src/components/MkTutorialDialog.Sensitive.vue
index 7ae48dcd15..d8d4b5aab7 100644
--- a/packages/frontend/src/components/MkTutorialDialog.Sensitive.vue
+++ b/packages/frontend/src/components/MkTutorialDialog.Sensitive.vue
@@ -115,7 +115,7 @@ const exampleNote = reactive<Misskey.entities.Note>({
font-weight: bold;
text-align: left;
- &:before {
+ &::before {
content: "";
display: block;
width: calc(100% - 38px);
diff --git a/packages/frontend/src/components/MkTutorialDialog.Timeline.vue b/packages/frontend/src/components/MkTutorialDialog.Timeline.vue
index 57f26e86a7..2d4da3fbd4 100644
--- a/packages/frontend/src/components/MkTutorialDialog.Timeline.vue
+++ b/packages/frontend/src/components/MkTutorialDialog.Timeline.vue
@@ -7,10 +7,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_gaps">
<div style="text-align: center; padding: 0 16px;">{{ i18n.ts._initialTutorial._timeline.description1 }}</div>
<div class="_gaps_s">
- <div><i class="ti ti-home"></i> <b>{{ i18n.ts._timelines.home }}</b> … {{ i18n.ts._initialTutorial._timeline.home }}</div>
- <div><i class="ti ti-planet"></i> <b>{{ i18n.ts._timelines.local }}</b> … {{ i18n.ts._initialTutorial._timeline.local }}</div>
- <div><i class="ti ti-universe"></i> <b>{{ i18n.ts._timelines.social }}</b> … {{ i18n.ts._initialTutorial._timeline.social }}</div>
- <div><i class="ti ti-whirl"></i> <b>{{ i18n.ts._timelines.global }}</b> … {{ i18n.ts._initialTutorial._timeline.global }}</div>
+ <div v-for="tl in basicTimelineTypes">
+ <i :class="basicTimelineIconClass(tl)"></i> <b>{{ i18n.ts._timelines[tl] }}</b> … {{ i18n.ts._initialTutorial._timeline[tl] }}
+ </div>
</div>
<div class="_gaps_s">
<div>{{ i18n.ts._initialTutorial._timeline.description2 }}</div>
@@ -22,12 +21,12 @@ SPDX-License-Identifier: AGPL-3.0-only
<a href="https://misskey-hub.net/docs/for-users/features/timeline/" target="_blank" class="_link">{{ i18n.ts.help }}</a>
</template>
</I18n>
-
</div>
</template>
<script setup lang="ts">
import { i18n } from '@/i18n.js';
+import { basicTimelineIconClass, basicTimelineTypes } from '@/timelines.js';
</script>
<style lang="scss" module>
@@ -56,7 +55,7 @@ import { i18n } from '@/i18n.js';
font-weight: bold;
text-align: left;
- &:before {
+ &::before {
content: "";
display: block;
width: calc(100% - 38px);
diff --git a/packages/frontend/src/components/MkTutorialDialog.vue b/packages/frontend/src/components/MkTutorialDialog.vue
index d2711e4ec5..9adc8d466c 100644
--- a/packages/frontend/src/components/MkTutorialDialog.vue
+++ b/packages/frontend/src/components/MkTutorialDialog.vue
@@ -172,7 +172,7 @@ const emit = defineEmits<{
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
-// eslint-disable-next-line vue/no-setup-props-destructure
+// eslint-disable-next-line vue/no-setup-props-reactivity-loss
const page = ref(props.initialPage ?? 0);
watch(page, (to) => {
diff --git a/packages/frontend/src/components/MkUrlPreview.vue b/packages/frontend/src/components/MkUrlPreview.vue
index 6954f1f6ff..c868a22045 100644
--- a/packages/frontend/src/components/MkUrlPreview.vue
+++ b/packages/frontend/src/components/MkUrlPreview.vue
@@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only
scrolling="no"
:allow="player.allow == null ? 'autoplay;encrypted-media;fullscreen' : player.allow.filter(x => ['autoplay', 'clipboard-write', 'fullscreen', 'encrypted-media', 'picture-in-picture', 'web-share'].includes(x)).join(';')"
:class="$style.playerIframe"
- :src="player.url + (player.url.match(/\?/) ? '&autoplay=1&auto_play=1' : '?autoplay=1&auto_play=1')"
+ :src="transformPlayerUrl(player.url)"
:style="{ border: 0 }"
></iframe>
<span v-else>invalid url</span>
@@ -91,6 +91,7 @@ import * as os from '@/os.js';
import { deviceKind } from '@/scripts/device-kind.js';
import MkButton from '@/components/MkButton.vue';
import { versatileLang } from '@/scripts/intl-const.js';
+import { transformPlayerUrl } from '@/scripts/player-url-transform.js';
import { defaultStore } from '@/store.js';
type SummalyResult = Awaited<ReturnType<typeof summaly>>;
@@ -188,11 +189,13 @@ function adjustTweetHeight(message: any) {
if (height) tweetHeight.value = height;
}
-const openPlayer = (): void => {
- os.popup(defineAsyncComponent(() => import('@/components/MkYouTubePlayer.vue')), {
+function openPlayer(): void {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkYouTubePlayer.vue')), {
url: requestUrl.href,
+ }, {
+ // TODO
});
-};
+}
(window as any).addEventListener('message', adjustTweetHeight);
diff --git a/packages/frontend/src/components/MkUserInfo.vue b/packages/frontend/src/components/MkUserInfo.vue
index f247ba8fdd..f0b9606590 100644
--- a/packages/frontend/src/components/MkUserInfo.vue
+++ b/packages/frontend/src/components/MkUserInfo.vue
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<div class="_panel" :class="$style.root">
- <div :class="$style.banner" :style="user.bannerUrl ? `background-image: url(${user.bannerUrl})` : ''"></div>
+ <div :class="$style.banner" :style="user.bannerUrl ? `background-image: url(${defaultStore.state.disableShowingAnimatedImages ? getStaticImageUrl(user.bannerUrl) : user.bannerUrl})` : ''"></div>
<MkAvatar :class="$style.avatar" :user="user" indicator/>
<div :class="$style.title">
<MkA :class="$style.name" :to="userPage(user)"><MkUserName :user="user" :nowrap="false"/></MkA>
@@ -29,7 +29,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<p :class="$style.statusItemLabel">{{ i18n.ts.followers }}</p><span :class="$style.statusItemValue">{{ number(user.followersCount) }}</span>
</div>
</div>
- <MkFollowButton v-if="$i && user.id != $i.id" :class="$style.follow" :user="user" mini/>
+ <MkFollowButton v-if="user.id != $i?.id" :class="$style.follow" :user="user" mini/>
</div>
</template>
@@ -41,6 +41,8 @@ import { userPage } from '@/filters/user.js';
import { i18n } from '@/i18n.js';
import { $i } from '@/account.js';
import { isFollowingVisibleForMe, isFollowersVisibleForMe } from '@/scripts/isFfVisibleForMe.js';
+import { getStaticImageUrl } from '@/scripts/media-proxy.js';
+import { defaultStore } from '@/store.js';
defineProps<{
user: Misskey.entities.UserDetailed;
diff --git a/packages/frontend/src/components/MkUserPopup.vue b/packages/frontend/src/components/MkUserPopup.vue
index 41b27a1afb..ea1241002e 100644
--- a/packages/frontend/src/components/MkUserPopup.vue
+++ b/packages/frontend/src/components/MkUserPopup.vue
@@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
>
<div v-if="showing" :class="$style.root" class="_popup _shadow" :style="{ zIndex, top: top + 'px', left: left + 'px' }" @mouseover="() => { emit('mouseover'); }" @mouseleave="() => { emit('mouseleave'); }">
<div v-if="user != null">
- <div :class="$style.banner" :style="user.bannerUrl ? `background-image: url(${user.bannerUrl})` : ''">
+ <div :class="$style.banner" :style="user.bannerUrl ? `background-image: url(${defaultStore.state.disableShowingAnimatedImages ? getStaticImageUrl(user.bannerUrl) : user.bannerUrl})` : ''">
<span v-if="$i && $i.id != user.id && user.isFollowed" :class="$style.followed">{{ i18n.ts.followsYou }}</span>
</div>
<svg viewBox="0 0 128 128" :class="$style.avatarBack">
@@ -67,6 +67,7 @@ import { i18n } from '@/i18n.js';
import { defaultStore } from '@/store.js';
import { $i } from '@/account.js';
import { isFollowingVisibleForMe, isFollowersVisibleForMe } from '@/scripts/isFfVisibleForMe.js';
+import { getStaticImageUrl } from '@/scripts/media-proxy.js';
const props = defineProps<{
showing: boolean;
diff --git a/packages/frontend/src/components/MkUserSelectDialog.vue b/packages/frontend/src/components/MkUserSelectDialog.vue
index cc3ea78ffe..cbb40924f6 100644
--- a/packages/frontend/src/components/MkUserSelectDialog.vue
+++ b/packages/frontend/src/components/MkUserSelectDialog.vue
@@ -61,7 +61,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { onMounted, ref } from 'vue';
+import { onMounted, ref, shallowRef } from 'vue';
import * as Misskey from 'misskey-js';
import MkInput from '@/components/MkInput.vue';
import FormSplit from '@/components/form/split.vue';
@@ -91,7 +91,7 @@ const host = ref('');
const users = ref<Misskey.entities.UserLite[]>([]);
const recentUsers = ref<Misskey.entities.UserDetailed[]>([]);
const selected = ref<Misskey.entities.UserLite | null>(null);
-const dialogEl = ref();
+const dialogEl = shallowRef<InstanceType<typeof MkModalWindow>>();
function search() {
if (username.value === '' && host.value === '') {
@@ -122,7 +122,7 @@ async function ok() {
});
emit('ok', user);
- dialogEl.value.close();
+ dialogEl.value?.close();
// 最近使ã£ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼æ›´æ–°
let recents = defaultStore.state.recentlyUsedUsers;
@@ -133,7 +133,7 @@ async function ok() {
function cancel() {
emit('cancel');
- dialogEl.value.close();
+ dialogEl.value?.close();
}
onMounted(() => {
diff --git a/packages/frontend/src/components/MkUserSetupDialog.vue b/packages/frontend/src/components/MkUserSetupDialog.vue
index 1d376382ca..514350c930 100644
--- a/packages/frontend/src/components/MkUserSetupDialog.vue
+++ b/packages/frontend/src/components/MkUserSetupDialog.vue
@@ -148,7 +148,7 @@ const emit = defineEmits<{
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
-// eslint-disable-next-line vue/no-setup-props-destructure
+// eslint-disable-next-line vue/no-setup-props-reactivity-loss
const page = ref(defaultStore.state.accountSetupWizard);
watch(page, () => {
@@ -176,9 +176,11 @@ function setupComplete() {
function launchTutorial() {
setupComplete();
nextTick(() => {
- os.popup(defineAsyncComponent(() => import('@/components/MkTutorialDialog.vue')), {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkTutorialDialog.vue')), {
initialPage: 1,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
});
}
diff --git a/packages/frontend/src/components/MkVisibilityPicker.vue b/packages/frontend/src/components/MkVisibilityPicker.vue
index 5ecd41bfdf..75066bbc32 100644
--- a/packages/frontend/src/components/MkVisibilityPicker.vue
+++ b/packages/frontend/src/components/MkVisibilityPicker.vue
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
-<MkModal ref="modal" v-slot="{ type }" :zPriority="'high'" :src="src" @click="modal?.close()" @closed="emit('closed')">
+<MkModal ref="modal" v-slot="{ type }" :zPriority="'high'" :src="src" @click="modal?.close()" @closed="emit('closed')" @esc="modal?.close()">
<div class="_popup" :class="{ [$style.root]: true, [$style.asDrawer]: type === 'drawer' }">
<div :class="[$style.label, $style.item]">
{{ i18n.ts.visibility }}
diff --git a/packages/frontend/src/components/MkVisitorDashboard.vue b/packages/frontend/src/components/MkVisitorDashboard.vue
index f7963f9938..445780eca7 100644
--- a/packages/frontend/src/components/MkVisitorDashboard.vue
+++ b/packages/frontend/src/components/MkVisitorDashboard.vue
@@ -23,7 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<div class="_gaps_s" :class="$style.mainActions">
<MkButton :class="$style.mainAction" full rounded gradate data-cy-signup style="margin-right: 12px;" @click="signup()">{{ i18n.ts.joinThisServer }}</MkButton>
- <MkButton :class="$style.mainAction" full rounded @click="exploreOtherServers()">{{ i18n.ts.exploreOtherServers }}</MkButton>
+ <MkButton :class="$style.mainAction" full rounded link to="https://misskey-hub.net/servers/">{{ i18n.ts.exploreOtherServers }}</MkButton>
<MkButton :class="$style.mainAction" full rounded data-cy-signin @click="signin()">{{ i18n.ts.login }}</MkButton>
</div>
</div>
@@ -65,7 +65,8 @@ import { i18n } from '@/i18n.js';
import { instance } from '@/instance.js';
import MkNumber from '@/components/MkNumber.vue';
import XActiveUsersChart from '@/components/MkVisitorDashboard.ActiveUsersChart.vue';
-import { openInstanceMenu } from '@/ui/_common_/common';
+import { openInstanceMenu } from '@/ui/_common_/common.js';
+import type { MenuItem } from '@/types/menu.js';
const stats = ref<Misskey.entities.StatsResponse | null>(null);
@@ -74,24 +75,24 @@ misskeyApi('stats', {}).then((res) => {
});
function signin() {
- os.popup(XSigninDialog, {
+ const { dispose } = os.popup(XSigninDialog, {
autoSet: true,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
}
function signup() {
- os.popup(XSignupDialog, {
+ const { dispose } = os.popup(XSignupDialog, {
autoSet: true,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
}
-function showMenu(ev) {
+function showMenu(ev: MouseEvent) {
openInstanceMenu(ev);
}
-
-function exploreOtherServers() {
- window.open('https://misskey-hub.net/servers/', '_blank', 'noopener');
-}
</script>
<style lang="scss" module>
diff --git a/packages/frontend/src/components/MkYouTubePlayer.vue b/packages/frontend/src/components/MkYouTubePlayer.vue
index 1fad222fc5..e3711b3463 100644
--- a/packages/frontend/src/components/MkYouTubePlayer.vue
+++ b/packages/frontend/src/components/MkYouTubePlayer.vue
@@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="poamfof">
<Transition :name="defaultStore.state.animation ? 'fade' : ''" mode="out-in">
<div v-if="player.url && (player.url.startsWith('http://') || player.url.startsWith('https://'))" class="player">
- <iframe v-if="!fetching" :src="player.url + (player.url.match(/\?/) ? '&autoplay=1&auto_play=1' : '?autoplay=1&auto_play=1')" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen/>
+ <iframe v-if="!fetching" :src="transformPlayerUrl(player.url)" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
</div>
<span v-else>invalid url</span>
</Transition>
@@ -27,6 +27,7 @@ SPDX-License-Identifier: AGPL-3.0-only
import { ref } from 'vue';
import MkWindow from '@/components/MkWindow.vue';
import { versatileLang } from '@/scripts/intl-const.js';
+import { transformPlayerUrl } from '@/scripts/player-url-transform.js';
import { defaultStore } from '@/store.js';
const props = defineProps<{
diff --git a/packages/frontend/src/components/global/MkA.stories.impl.ts b/packages/frontend/src/components/global/MkA.stories.impl.ts
index c1d8cf0ca6..02e5a7f98c 100644
--- a/packages/frontend/src/components/global/MkA.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkA.stories.impl.ts
@@ -35,12 +35,10 @@ export const Default = {
// FIXME: 通るã‘ã©ãã®å¾Œè½ã¡ã‚‹ã®ã§ã‚³ãƒ¡ãƒ³ãƒˆã‚¢ã‚¦ãƒˆ
// await expect(a.href).toMatch(/^https?:\/\/.*#test$/);
await userEvent.pointer({ keys: '[MouseRight]', target: a });
- await tick();
const menu = canvas.getByRole('menu');
await expect(menu).toBeInTheDocument();
await userEvent.click(a);
a.blur();
- await tick();
await expect(menu).not.toBeInTheDocument();
},
args: {
diff --git a/packages/frontend/src/components/global/MkA.vue b/packages/frontend/src/components/global/MkA.vue
index d1e9113c48..3a45ca429f 100644
--- a/packages/frontend/src/components/global/MkA.vue
+++ b/packages/frontend/src/components/global/MkA.vue
@@ -16,7 +16,7 @@ export type MkABehavior = 'window' | 'browser' | null;
<script lang="ts" setup>
import { computed, inject, shallowRef } from 'vue';
import * as os from '@/os.js';
-import copyToClipboard from '@/scripts/copy-to-clipboard.js';
+import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
import { url } from '@/config.js';
import { i18n } from '@/i18n.js';
import { useRouter } from '@/router/supplier.js';
diff --git a/packages/frontend/src/components/global/MkAd.stories.impl.ts b/packages/frontend/src/components/global/MkAd.stories.impl.ts
index aef26ab92d..8c0b7ef52f 100644
--- a/packages/frontend/src/components/global/MkAd.stories.impl.ts
+++ b/packages/frontend/src/components/global/MkAd.stories.impl.ts
@@ -9,12 +9,6 @@ import { StoryObj } from '@storybook/vue3';
import MkAd from './MkAd.vue';
import { i18n } from '@/i18n.js';
-let lock: Promise<undefined> | undefined;
-
-function sleep(ms: number) {
- return new Promise(resolve => setTimeout(resolve, ms));
-}
-
const common = {
render(args) {
return {
@@ -37,56 +31,41 @@ const common = {
};
},
async play({ canvasElement, args }) {
- if (lock) {
- console.warn('This test is unexpectedly running twice in parallel, fix it!');
- console.warn('See also: https://github.com/misskey-dev/misskey/issues/11267');
- await lock;
+ const canvas = within(canvasElement);
+ const a = canvas.getByRole<HTMLAnchorElement>('link');
+ // FIXME: 通るã‘ã©ãã®å¾Œè½ã¡ã‚‹ã®ã§ã‚³ãƒ¡ãƒ³ãƒˆã‚¢ã‚¦ãƒˆ
+ // await expect(a.href).toMatch(/^https?:\/\/.*#test$/);
+ const img = within(a).getByRole('img');
+ await expect(img).toBeInTheDocument();
+ let buttons = canvas.getAllByRole<HTMLButtonElement>('button');
+ await expect(buttons).toHaveLength(1);
+ const i = buttons[0];
+ await expect(i).toBeInTheDocument();
+ await userEvent.click(i);
+ await expect(canvasElement).toHaveTextContent(i18n.ts._ad.back);
+ await expect(a).not.toBeInTheDocument();
+ await expect(i).not.toBeInTheDocument();
+ buttons = canvas.getAllByRole<HTMLButtonElement>('button');
+ const hasReduceFrequency = args.specify?.ratio !== 0;
+ await expect(buttons).toHaveLength(hasReduceFrequency ? 2 : 1);
+ const reduce = hasReduceFrequency ? buttons[0] : null;
+ const back = buttons[hasReduceFrequency ? 1 : 0];
+ if (reduce) {
+ await expect(reduce).toBeInTheDocument();
+ await expect(reduce).toHaveTextContent(i18n.ts._ad.reduceFrequencyOfThisAd);
}
-
- let resolve: (value?: any) => void;
- lock = new Promise(r => resolve = r);
-
- try {
- // NOTE: sleep ã—ãªã„ã¨ä½•æ•…ã‹è½ã¡ã‚‹
- await sleep(100);
- const canvas = within(canvasElement);
- const a = canvas.getByRole<HTMLAnchorElement>('link');
- // await expect(a.href).toMatch(/^https?:\/\/.*#test$/);
- const img = within(a).getByRole('img');
- await expect(img).toBeInTheDocument();
- let buttons = canvas.getAllByRole<HTMLButtonElement>('button');
- await expect(buttons).toHaveLength(1);
- const i = buttons[0];
- await expect(i).toBeInTheDocument();
- await userEvent.click(i);
- await expect(canvasElement).toHaveTextContent(i18n.ts._ad.back);
- await expect(a).not.toBeInTheDocument();
- await expect(i).not.toBeInTheDocument();
- buttons = canvas.getAllByRole<HTMLButtonElement>('button');
- const hasReduceFrequency = args.specify?.ratio !== 0;
- await expect(buttons).toHaveLength(hasReduceFrequency ? 2 : 1);
- const reduce = hasReduceFrequency ? buttons[0] : null;
- const back = buttons[hasReduceFrequency ? 1 : 0];
- if (reduce) {
- await expect(reduce).toBeInTheDocument();
- await expect(reduce).toHaveTextContent(i18n.ts._ad.reduceFrequencyOfThisAd);
- }
- await expect(back).toBeInTheDocument();
- await expect(back).toHaveTextContent(i18n.ts._ad.back);
- await userEvent.click(back);
- await waitFor(() => expect(canvas.queryByRole('img')).toBeTruthy());
- if (reduce) {
- await expect(reduce).not.toBeInTheDocument();
- }
- await expect(back).not.toBeInTheDocument();
- const aAgain = canvas.getByRole<HTMLAnchorElement>('link');
- await expect(aAgain).toBeInTheDocument();
- const imgAgain = within(aAgain).getByRole('img');
- await expect(imgAgain).toBeInTheDocument();
- } finally {
- resolve!();
- lock = undefined;
+ await expect(back).toBeInTheDocument();
+ await expect(back).toHaveTextContent(i18n.ts._ad.back);
+ await userEvent.click(back);
+ await waitFor(() => expect(canvas.queryByRole('img')).toBeTruthy());
+ if (reduce) {
+ await expect(reduce).not.toBeInTheDocument();
}
+ await expect(back).not.toBeInTheDocument();
+ const aAgain = canvas.getByRole<HTMLAnchorElement>('link');
+ await expect(aAgain).toBeInTheDocument();
+ const imgAgain = within(aAgain).getByRole('img');
+ await expect(imgAgain).toBeInTheDocument();
},
args: {
prefer: [],
diff --git a/packages/frontend/src/components/global/MkCustomEmoji.vue b/packages/frontend/src/components/global/MkCustomEmoji.vue
index 6123835340..dff56cd7f0 100644
--- a/packages/frontend/src/components/global/MkCustomEmoji.vue
+++ b/packages/frontend/src/components/global/MkCustomEmoji.vue
@@ -31,7 +31,7 @@ import { defaultStore } from '@/store.js';
import { customEmojisMap } from '@/custom-emojis.js';
import * as os from '@/os.js';
import { misskeyApiGet } from '@/scripts/misskey-api.js';
-import copyToClipboard from '@/scripts/copy-to-clipboard.js';
+import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
import * as sound from '@/scripts/sound.js';
import { i18n } from '@/i18n.js';
import MkCustomEmojiDetailedDialog from '@/components/MkCustomEmojiDetailedDialog.vue';
@@ -106,12 +106,12 @@ function onClick(ev: MouseEvent) {
text: i18n.ts.info,
icon: 'ti ti-info-circle',
action: async () => {
- os.popup(MkCustomEmojiDetailedDialog, {
+ const { dispose } = os.popup(MkCustomEmojiDetailedDialog, {
emoji: await misskeyApiGet('emoji', {
name: customEmojiName.value,
}),
}, {
- anchor: ev.target,
+ closed: () => dispose(),
});
},
}], ev.currentTarget ?? ev.target);
diff --git a/packages/frontend/src/components/global/MkEmoji.vue b/packages/frontend/src/components/global/MkEmoji.vue
index 65f75642b2..fa780d4ad3 100644
--- a/packages/frontend/src/components/global/MkEmoji.vue
+++ b/packages/frontend/src/components/global/MkEmoji.vue
@@ -14,7 +14,7 @@ import { char2fluentEmojiFilePath, char2twemojiFilePath } from '@/scripts/emoji-
import { defaultStore } from '@/store.js';
import { colorizeEmoji, getEmojiName } from '@/scripts/emojilist.js';
import * as os from '@/os.js';
-import copyToClipboard from '@/scripts/copy-to-clipboard.js';
+import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
import * as sound from '@/scripts/sound.js';
import { i18n } from '@/i18n.js';
diff --git a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts
index cab8d9c704..0d869892bd 100644
--- a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts
+++ b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts
@@ -65,7 +65,7 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
const validTime = (t: string | boolean | null | undefined) => {
if (t == null) return null;
if (typeof t === 'boolean') return null;
- return t.match(/^[0-9.]+s$/) ? t : null;
+ return t.match(/^\-?[0-9.]+s$/) ? t : null;
};
const validColor = (c: unknown): string | null => {
diff --git a/packages/frontend/src/components/global/MkStickyContainer.vue b/packages/frontend/src/components/global/MkStickyContainer.vue
index 89993e1b8e..b12dc8cb31 100644
--- a/packages/frontend/src/components/global/MkStickyContainer.vue
+++ b/packages/frontend/src/components/global/MkStickyContainer.vue
@@ -8,7 +8,11 @@ SPDX-License-Identifier: AGPL-3.0-only
<div ref="headerEl">
<slot name="header"></slot>
</div>
- <div ref="bodyEl" :data-sticky-container-header-height="headerHeight">
+ <div
+ ref="bodyEl"
+ :data-sticky-container-header-height="headerHeight"
+ :data-sticky-container-footer-height="footerHeight"
+ >
<slot></slot>
</div>
<div ref="footerEl">
diff --git a/packages/frontend/src/components/global/MkTime.vue b/packages/frontend/src/components/global/MkTime.vue
index 23fe99bd9c..027b226f3f 100644
--- a/packages/frontend/src/components/global/MkTime.vue
+++ b/packages/frontend/src/components/global/MkTime.vue
@@ -41,12 +41,12 @@ function getDateSafe(n: Date | string | number) {
}
}
-// eslint-disable-next-line vue/no-setup-props-destructure
+// eslint-disable-next-line vue/no-setup-props-reactivity-loss
const _time = props.time == null ? NaN : getDateSafe(props.time).getTime();
const invalid = Number.isNaN(_time);
const absolute = !invalid ? dateTimeFormat.format(_time) : i18n.ts._ago.invalid;
-// eslint-disable-next-line vue/no-setup-props-destructure
+// eslint-disable-next-line vue/no-setup-props-reactivity-loss
const now = ref(props.origin?.getTime() ?? Date.now());
const ago = computed(() => (now.value - _time) / 1000/*ms*/);
diff --git a/packages/frontend/src/components/global/MkUrl.vue b/packages/frontend/src/components/global/MkUrl.vue
index 9d4cd559d9..d2ddd4aa85 100644
--- a/packages/frontend/src/components/global/MkUrl.vue
+++ b/packages/frontend/src/components/global/MkUrl.vue
@@ -50,11 +50,13 @@ const el = ref();
if (props.showUrlPreview && isEnabledUrlPreview.value) {
useTooltip(el, (showing) => {
- os.popup(defineAsyncComponent(() => import('@/components/MkUrlPreviewPopup.vue')), {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkUrlPreviewPopup.vue')), {
showing,
url: props.url,
source: el.value instanceof HTMLElement ? el.value : el.value?.$el,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
});
}
diff --git a/packages/frontend/src/components/global/RouterView.vue b/packages/frontend/src/components/global/RouterView.vue
index 06cb30eff1..19bd794a5d 100644
--- a/packages/frontend/src/components/global/RouterView.vue
+++ b/packages/frontend/src/components/global/RouterView.vue
@@ -53,14 +53,14 @@ function resolveNested(current: Resolved, d = 0): Resolved | null {
const current = resolveNested(router.current)!;
const currentPageComponent = shallowRef('component' in current.route ? current.route.component : MkLoadingPage);
const currentPageProps = ref(current.props);
-const key = ref(current.route.path + JSON.stringify(Object.fromEntries(current.props)));
+const key = ref(router.getCurrentKey() + JSON.stringify(Object.fromEntries(current.props)));
function onChange({ resolved, key: newKey }) {
const current = resolveNested(resolved);
if (current == null || 'redirect' in current.route) return;
currentPageComponent.value = current.route.component;
currentPageProps.value = current.props;
- key.value = current.route.path + JSON.stringify(Object.fromEntries(current.props));
+ key.value = newKey + JSON.stringify(Object.fromEntries(current.props));
nextTick(() => {
// ページé·ç§»å®Œäº†å¾Œã«å†ã³ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã‚’有効化
diff --git a/packages/frontend/src/const.ts b/packages/frontend/src/const.ts
index 9e41926a97..e135bc69a0 100644
--- a/packages/frontend/src/const.ts
+++ b/packages/frontend/src/const.ts
@@ -87,6 +87,7 @@ export const ROLE_POLICIES = [
'canHideAds',
'driveCapacityMb',
'alwaysMarkNsfw',
+ 'canUpdateBioMedia',
'pinLimit',
'antennaLimit',
'wordMuteLimit',
diff --git a/packages/frontend/src/directives/hotkey.ts b/packages/frontend/src/directives/hotkey.ts
index b082b6edf2..0e5c7ede24 100644
--- a/packages/frontend/src/directives/hotkey.ts
+++ b/packages/frontend/src/directives/hotkey.ts
@@ -4,7 +4,7 @@
*/
import { Directive } from 'vue';
-import { makeHotkey } from '../scripts/hotkey.js';
+import { makeHotkey } from '@/scripts/hotkey.js';
export default {
mounted(el, binding) {
@@ -13,9 +13,9 @@ export default {
el._keyHandler = makeHotkey(binding.value);
if (el._hotkey_global) {
- document.addEventListener('keydown', el._keyHandler);
+ document.addEventListener('keydown', el._keyHandler, { passive: false });
} else {
- el.addEventListener('keydown', el._keyHandler);
+ el.addEventListener('keydown', el._keyHandler, { passive: false });
}
},
diff --git a/packages/frontend/src/directives/ripple.ts b/packages/frontend/src/directives/ripple.ts
index 2d724f771e..a043ff212d 100644
--- a/packages/frontend/src/directives/ripple.ts
+++ b/packages/frontend/src/directives/ripple.ts
@@ -17,7 +17,9 @@ export default {
const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2);
- popup(MkRippleEffect, { x, y }, {}, 'end');
+ const { dispose } = popup(MkRippleEffect, { x, y }, {
+ end: () => dispose(),
+ });
});
},
};
diff --git a/packages/frontend/src/directives/tooltip.ts b/packages/frontend/src/directives/tooltip.ts
index b1c1b19907..251ce5675f 100644
--- a/packages/frontend/src/directives/tooltip.ts
+++ b/packages/frontend/src/directives/tooltip.ts
@@ -51,13 +51,15 @@ export default {
if (self.text == null) return;
const showing = ref(true);
- popup(defineAsyncComponent(() => import('@/components/MkTooltip.vue')), {
+ const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkTooltip.vue')), {
showing,
text: self.text,
asMfm: binding.modifiers.mfm,
direction: binding.modifiers.left ? 'left' : binding.modifiers.right ? 'right' : binding.modifiers.top ? 'top' : binding.modifiers.bottom ? 'bottom' : 'top',
targetElement: el,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
self._close = () => {
showing.value = false;
diff --git a/packages/frontend/src/directives/user-preview.ts b/packages/frontend/src/directives/user-preview.ts
index 7a008a4486..278d842d09 100644
--- a/packages/frontend/src/directives/user-preview.ts
+++ b/packages/frontend/src/directives/user-preview.ts
@@ -35,7 +35,7 @@ export class UserPreview {
const showing = ref(true);
- popup(defineAsyncComponent(() => import('@/components/MkUserPopup.vue')), {
+ const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkUserPopup.vue')), {
showing,
q: this.user,
source: this.el,
@@ -47,7 +47,8 @@ export class UserPreview {
window.clearTimeout(this.showTimer);
this.hideTimer = window.setTimeout(this.close, 500);
},
- }, 'closed');
+ closed: () => dispose(),
+ });
this.promise = {
cancel: () => {
diff --git a/packages/frontend/src/filters/user.ts b/packages/frontend/src/filters/user.ts
index b713d41789..a87766764d 100644
--- a/packages/frontend/src/filters/user.ts
+++ b/packages/frontend/src/filters/user.ts
@@ -6,7 +6,7 @@
import * as Misskey from 'misskey-js';
import { url } from '@/config.js';
-export const acct = (user: misskey.Acct) => {
+export const acct = (user: Misskey.Acct) => {
return Misskey.acct.toString(user);
};
@@ -14,6 +14,6 @@ export const userName = (user: Misskey.entities.User) => {
return user.name || user.username;
};
-export const userPage = (user: misskey.Acct, path?, absolute = false) => {
+export const userPage = (user: Misskey.Acct, path?: string, absolute = false) => {
return `${absolute ? url : ''}/@${acct(user)}${(path ? `/${path}` : '')}`;
};
diff --git a/packages/frontend/src/i18n.ts b/packages/frontend/src/i18n.ts
index cc9faddb20..10d6adbcd0 100644
--- a/packages/frontend/src/i18n.ts
+++ b/packages/frontend/src/i18n.ts
@@ -11,6 +11,5 @@ import { I18n } from '@/scripts/i18n.js';
export const i18n = markRaw(new I18n<Locale>(locale));
export function updateI18n(newLocale: Locale) {
- // @ts-expect-error -- private field
i18n.locale = newLocale;
}
diff --git a/packages/frontend/src/os.ts b/packages/frontend/src/os.ts
index f656a52371..f42e2ed3c5 100644
--- a/packages/frontend/src/os.ts
+++ b/packages/frontend/src/os.ts
@@ -5,12 +5,13 @@
// TODO: ãªã‚“ã§ã‚‚ã‹ã‚“ã§ã‚‚os.tsã«çªã£è¾¼ã‚€ã®ã‚„ã‚ãŸã„ã®ã§ã‚ˆã—ãªã«åˆ†å‰²ã™ã‚‹
-import { Component, markRaw, Ref, ref, defineAsyncComponent } from 'vue';
+import { Component, markRaw, Ref, ref, defineAsyncComponent, nextTick } from 'vue';
import { EventEmitter } from 'eventemitter3';
import * as Misskey from 'misskey-js';
import type { ComponentProps as CP } from 'vue-component-type-helpers';
import type { Form, GetFormResultType } from '@/scripts/form.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
+import { defaultStore } from '@/store.js';
import { i18n } from '@/i18n.js';
import MkPostFormDialog from '@/components/MkPostFormDialog.vue';
import MkWaitingDialog from '@/components/MkWaitingDialog.vue';
@@ -22,8 +23,11 @@ import MkEmojiPickerDialog from '@/components/MkEmojiPickerDialog.vue';
import MkPopupMenu from '@/components/MkPopupMenu.vue';
import MkContextMenu from '@/components/MkContextMenu.vue';
import { MenuItem } from '@/types/menu.js';
-import copyToClipboard from '@/scripts/copy-to-clipboard.js';
+import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
+import { pleaseLogin } from '@/scripts/please-login.js';
import { showMovedDialog } from '@/scripts/show-moved-dialog.js';
+import { getHTMLElementOrNull } from '@/scripts/get-dom-node-or-null.js';
+import { focusParent } from '@/scripts/focus.js';
export const openingWindowsCount = ref(0);
@@ -116,11 +120,13 @@ export function promiseDialog<T extends Promise<any>>(
});
// NOTE: dynamic importã™ã‚‹ã¨æŒ™å‹•ãŒãŠã‹ã—ããªã‚‹(showingã®å¤‰æ›´ãŒä¼æ’­ã—ãªã„)
- popup(MkWaitingDialog, {
+ const { dispose } = popup(MkWaitingDialog, {
success: success,
showing: showing,
text: text,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
return promise;
}
@@ -166,28 +172,24 @@ type EmitsExtractor<T> = {
[K in keyof T as K extends `onVnode${string}` ? never : K extends `on${infer E}` ? Uncapitalize<E> : K extends string ? never : K]: T[K];
};
-export async function popup<T extends Component>(
+export function popup<T extends Component>(
component: T,
props: ComponentProps<T>,
events: ComponentEmit<T> = {} as ComponentEmit<T>,
- disposeEvent?: keyof ComponentEmit<T>,
-): Promise<{ dispose: () => void }> {
+): { dispose: () => void } {
markRaw(component);
const id = ++popupIdCount;
const dispose = () => {
// ã“ã®setTimeoutãŒç„¡ã„ã¨æŒ™å‹•ãŒãŠã‹ã—ããªã‚‹(autocompleteãŒé–‰ã˜ãªããªã‚‹)。Vueã®ãƒã‚°ï¼Ÿ
window.setTimeout(() => {
- popups.value = popups.value.filter(popup => popup.id !== id);
+ popups.value = popups.value.filter(p => p.id !== id);
}, 0);
};
const state = {
component,
props,
- events: disposeEvent ? {
- ...events,
- [disposeEvent]: dispose,
- } : events,
+ events,
id,
};
@@ -199,15 +201,19 @@ export async function popup<T extends Component>(
}
export function pageWindow(path: string) {
- popup(MkPageWindow, {
+ const { dispose } = popup(MkPageWindow, {
initialPath: path,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
}
export function toast(message: string) {
- popup(MkToast, {
+ const { dispose } = popup(MkToast, {
message,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
}
export function alert(props: {
@@ -216,11 +222,12 @@ export function alert(props: {
text?: string;
}): Promise<void> {
return new Promise(resolve => {
- popup(MkDialog, props, {
+ const { dispose } = popup(MkDialog, props, {
done: () => {
resolve();
},
- }, 'closed');
+ closed: () => dispose(),
+ });
});
}
@@ -232,14 +239,15 @@ export function confirm(props: {
cancelText?: string;
}): Promise<{ canceled: boolean }> {
return new Promise(resolve => {
- popup(MkDialog, {
+ const { dispose } = popup(MkDialog, {
...props,
showCancelButton: true,
}, {
done: result => {
resolve(result ? result : { canceled: true });
},
- }, 'closed');
+ closed: () => dispose(),
+ });
});
}
@@ -261,7 +269,7 @@ export function actions<T extends {
canceled: false; result: T[number]['value'];
}> {
return new Promise(resolve => {
- popup(MkDialog, {
+ const { dispose } = popup(MkDialog, {
...props,
actions: props.actions.map(a => ({
text: a.text,
@@ -275,7 +283,8 @@ export function actions<T extends {
done: result => {
resolve(result ? result : { canceled: true });
},
- }, 'closed');
+ closed: () => dispose(),
+ });
});
}
@@ -323,7 +332,7 @@ export function inputText(props: {
canceled: false; result: string | null;
}> {
return new Promise(resolve => {
- popup(MkDialog, {
+ const { dispose } = popup(MkDialog, {
title: props.title,
text: props.text,
input: {
@@ -338,7 +347,8 @@ export function inputText(props: {
done: result => {
resolve(result ? result : { canceled: true });
},
- }, 'closed');
+ closed: () => dispose(),
+ });
});
}
@@ -377,7 +387,7 @@ export function inputNumber(props: {
canceled: false; result: number | null;
}> {
return new Promise(resolve => {
- popup(MkDialog, {
+ const { dispose } = popup(MkDialog, {
title: props.title,
text: props.text,
input: {
@@ -390,7 +400,8 @@ export function inputNumber(props: {
done: result => {
resolve(result ? result : { canceled: true });
},
- }, 'closed');
+ closed: () => dispose(),
+ });
});
}
@@ -405,7 +416,7 @@ export function inputDate(props: {
canceled: false; result: Date;
}> {
return new Promise(resolve => {
- popup(MkDialog, {
+ const { dispose } = popup(MkDialog, {
title: props.title,
text: props.text,
input: {
@@ -417,7 +428,8 @@ export function inputDate(props: {
done: result => {
resolve(result ? { result: new Date(result.result), canceled: false } : { result: undefined, canceled: true });
},
- }, 'closed');
+ closed: () => dispose(),
+ });
});
}
@@ -427,23 +439,29 @@ export function authenticateDialog(): Promise<{
canceled: false; result: { password: string; token: string | null; };
}> {
return new Promise(resolve => {
- popup(MkPasswordDialog, {}, {
+ const { dispose } = popup(MkPasswordDialog, {}, {
done: result => {
resolve(result ? { canceled: false, result } : { canceled: true, result: undefined });
},
- }, 'closed');
+ closed: () => dispose(),
+ });
});
}
+type SelectItem<C> = {
+ value: C;
+ text: string;
+};
+
// default ãŒæŒ‡å®šã•れã¦ã„ãŸã‚‰ result 㯠null ã«ãªã‚Šå¾—ãªã„ã“ã¨ã‚’ä¿è¨¼ã™ã‚‹ overload function
export function select<C = any>(props: {
title?: string;
text?: string;
default: string;
- items: {
- value: C;
- text: string;
- }[];
+ items: (SelectItem<C> | {
+ sectionTitle: string;
+ items: SelectItem<C>[];
+ } | undefined)[];
}): Promise<{
canceled: true; result: undefined;
} | {
@@ -453,10 +471,10 @@ export function select<C = any>(props: {
title?: string;
text?: string;
default?: string | null;
- items: {
- value: C;
- text: string;
- }[];
+ items: (SelectItem<C> | {
+ sectionTitle: string;
+ items: SelectItem<C>[];
+ } | undefined)[];
}): Promise<{
canceled: true; result: undefined;
} | {
@@ -466,28 +484,29 @@ export function select<C = any>(props: {
title?: string;
text?: string;
default?: string | null;
- items: {
- value: C;
- text: string;
- }[];
+ items: (SelectItem<C> | {
+ sectionTitle: string;
+ items: SelectItem<C>[];
+ } | undefined)[];
}): Promise<{
canceled: true; result: undefined;
} | {
canceled: false; result: C | null;
}> {
return new Promise(resolve => {
- popup(MkDialog, {
+ const { dispose } = popup(MkDialog, {
title: props.title,
text: props.text,
select: {
- items: props.items,
+ items: props.items.filter(x => x !== undefined),
default: props.default ?? null,
},
}, {
done: result => {
resolve(result ? result : { canceled: true });
},
- }, 'closed');
+ closed: () => dispose(),
+ });
});
}
@@ -497,53 +516,57 @@ export function success(): Promise<void> {
window.setTimeout(() => {
showing.value = false;
}, 1000);
- popup(MkWaitingDialog, {
+ const { dispose } = popup(MkWaitingDialog, {
success: true,
showing: showing,
}, {
done: () => resolve(),
- }, 'closed');
+ closed: () => dispose(),
+ });
});
}
export function waiting(): Promise<void> {
return new Promise(resolve => {
const showing = ref(true);
- popup(MkWaitingDialog, {
+ const { dispose } = popup(MkWaitingDialog, {
success: false,
showing: showing,
}, {
done: () => resolve(),
- }, 'closed');
+ closed: () => dispose(),
+ });
});
}
export function form<F extends Form>(title: string, f: F): Promise<{ canceled: true, result?: undefined } | { canceled?: false, result: GetFormResultType<F> }> {
return new Promise(resolve => {
- popup(defineAsyncComponent(() => import('@/components/MkFormDialog.vue')), { title, form: f }, {
+ const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkFormDialog.vue')), { title, form: f }, {
done: result => {
resolve(result);
},
- }, 'closed');
+ closed: () => dispose(),
+ });
});
}
export async function selectUser(opts: { includeSelf?: boolean; localOnly?: boolean; } = {}): Promise<Misskey.entities.UserDetailed> {
return new Promise(resolve => {
- popup(defineAsyncComponent(() => import('@/components/MkUserSelectDialog.vue')), {
+ const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkUserSelectDialog.vue')), {
includeSelf: opts.includeSelf,
localOnly: opts.localOnly,
}, {
ok: user => {
resolve(user);
},
- }, 'closed');
+ closed: () => dispose(),
+ });
});
}
export async function selectDriveFile(multiple: boolean): Promise<Misskey.entities.DriveFile[]> {
return new Promise(resolve => {
- popup(defineAsyncComponent(() => import('@/components/MkDriveSelectDialog.vue')), {
+ const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkDriveSelectDialog.vue')), {
type: 'file',
multiple,
}, {
@@ -552,13 +575,14 @@ export async function selectDriveFile(multiple: boolean): Promise<Misskey.entiti
resolve(files);
}
},
- }, 'closed');
+ closed: () => dispose(),
+ });
});
}
export async function selectDriveFolder(multiple: boolean): Promise<Misskey.entities.DriveFolder[]> {
return new Promise(resolve => {
- popup(defineAsyncComponent(() => import('@/components/MkDriveSelectDialog.vue')), {
+ const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkDriveSelectDialog.vue')), {
type: 'folder',
multiple,
}, {
@@ -567,20 +591,22 @@ export async function selectDriveFolder(multiple: boolean): Promise<Misskey.enti
resolve(folders);
}
},
- }, 'closed');
+ closed: () => dispose(),
+ });
});
}
export async function pickEmoji(src: HTMLElement, opts: ComponentProps<typeof MkEmojiPickerDialog>): Promise<string> {
return new Promise(resolve => {
- popup(MkEmojiPickerDialog, {
+ const { dispose } = popup(MkEmojiPickerDialog, {
src,
...opts,
}, {
done: emoji => {
resolve(emoji);
},
- }, 'closed');
+ closed: () => dispose(),
+ });
});
}
@@ -589,7 +615,7 @@ export async function cropImage(image: Misskey.entities.DriveFile, options: {
uploadFolder?: string | null;
}): Promise<Misskey.entities.DriveFile> {
return new Promise(resolve => {
- popup(defineAsyncComponent(() => import('@/components/MkCropperDialog.vue')), {
+ const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkCropperDialog.vue')), {
file: image,
aspectRatio: options.aspectRatio,
uploadFolder: options.uploadFolder,
@@ -597,73 +623,88 @@ export async function cropImage(image: Misskey.entities.DriveFile, options: {
ok: x => {
resolve(x);
},
- }, 'closed');
+ closed: () => dispose(),
+ });
});
}
export function popupMenu(items: MenuItem[], src?: HTMLElement | EventTarget | null, options?: {
align?: string;
width?: number;
- viaKeyboard?: boolean;
onClosing?: () => void;
}): Promise<void> {
- return new Promise(resolve => {
- let dispose;
- popup(MkPopupMenu, {
+ let returnFocusTo = getHTMLElementOrNull(src) ?? getHTMLElementOrNull(document.activeElement);
+ return new Promise(resolve => nextTick(() => {
+ const { dispose } = popup(MkPopupMenu, {
items,
src,
width: options?.width,
align: options?.align,
- viaKeyboard: options?.viaKeyboard,
+ returnFocusTo,
}, {
closed: () => {
resolve();
dispose();
+ returnFocusTo = null;
},
closing: () => {
- if (options?.onClosing) options.onClosing();
+ options?.onClosing?.();
},
- }).then(res => {
- dispose = res.dispose;
});
- });
+ }));
}
export function contextMenu(items: MenuItem[], ev: MouseEvent): Promise<void> {
+ if (
+ defaultStore.state.contextMenu === 'native' ||
+ (defaultStore.state.contextMenu === 'appWithShift' && !ev.shiftKey)
+ ) {
+ return Promise.resolve();
+ }
+
+ let returnFocusTo = getHTMLElementOrNull(ev.currentTarget ?? ev.target) ?? getHTMLElementOrNull(document.activeElement);
ev.preventDefault();
- return new Promise(resolve => {
- let dispose;
- popup(MkContextMenu, {
+ return new Promise(resolve => nextTick(() => {
+ const { dispose } = popup(MkContextMenu, {
items,
ev,
}, {
closed: () => {
resolve();
dispose();
+
+ // MkModalを通ã—ã¦ã„ãªã„ã®ã§ã“ã“ã§ãƒ•ォーカスを戻ã™å‡¦ç†ã‚’行ã†
+ if (returnFocusTo != null) {
+ focusParent(returnFocusTo, true, false);
+ returnFocusTo = null;
+ }
},
- }).then(res => {
- dispose = res.dispose;
});
- });
+ }));
}
export function post(props: Record<string, any> = {}): Promise<void> {
- showMovedDialog();
+ pleaseLogin(undefined, (props.initialText || props.initialNote ? {
+ type: 'share',
+ params: {
+ text: props.initialText ?? props.initialNote.text,
+ visibility: props.initialVisibility ?? props.initialNote?.visibility,
+ localOnly: (props.initialLocalOnly || props.initialNote?.localOnly) ? '1' : '0',
+ },
+ } : undefined));
+ showMovedDialog();
return new Promise(resolve => {
// NOTE: MkPostFormDialogã‚’dynamic importã™ã‚‹ã¨iOSã§ãƒ†ã‚­ã‚¹ãƒˆã‚¨ãƒªã‚¢ã«è‡ªå‹•フォーカスã§ããªã„
// NOTE: ãŸã ã€dynamic importã—ãªã„å ´åˆã€MkPostFormDialogインスタンスãŒä½¿ã„ã¾ã‚ã•れã€
// VueãŒæ¸¡ã•れãŸã‚³ãƒ³ãƒãƒ¼ãƒãƒ³ãƒˆã«å†…部的ã«__propsã¨ã„ã†ãƒ—ロパティを生やã™å½±éŸ¿ã§ã€
// 複数ã®post formã‚’é–‹ã„ãŸã¨ãã«å ´åˆã«ã‚ˆã£ã¦ã¯ã‚¨ãƒ©ãƒ¼ã«ãªã‚‹
// ã‚‚ã¡ã‚ん複数ã®post formã‚’é–‹ã‘ã‚‹ã“ã¨è‡ªä½“Misskeyサイドã®ãƒã‚°ãªã®ã ãŒ
- let dispose;
- popup(MkPostFormDialog, props, {
+ const { dispose } = popup(MkPostFormDialog, props, {
closed: () => {
resolve();
dispose();
},
- }).then(res => {
- dispose = res.dispose;
});
});
}
diff --git a/packages/frontend/src/pages/about-misskey.vue b/packages/frontend/src/pages/about-misskey.vue
index b55ae220d8..8db71c8881 100644
--- a/packages/frontend/src/pages/about-misskey.vue
+++ b/packages/frontend/src/pages/about-misskey.vue
@@ -102,13 +102,16 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #label>Special thanks</template>
<div style="display:grid;grid-template-columns:repeat(auto-fill, minmax(130px, 1fr));grid-gap:24px;align-items:center;">
<div>
- <a style="display: inline-block;" class="masknetwork" title="Mask Network" href="https://mask.io/" target="_blank"><img style="width: 100%;" src="https://misskey-hub.net/sponsors/masknetwork.png" alt="Mask Network"></a>
+ <a style="display: inline-block;" class="masknetwork" title="Mask Network" href="https://mask.io/" target="_blank"><img style="width: 100%;" src="https://assets.misskey-hub.net/sponsors/masknetwork.png" alt="Mask Network"></a>
</div>
<div>
- <a style="display: inline-block;" class="xserver" title="XServer" href="https://www.xserver.ne.jp/" target="_blank"><img style="width: 100%;" src="https://misskey-hub.net/sponsors/xserver.png" alt="XServer"></a>
+ <a style="display: inline-block;" class="xserver" title="XServer" href="https://www.xserver.ne.jp/" target="_blank"><img style="width: 100%;" src="https://assets.misskey-hub.net/sponsors/xserver.png" alt="XServer"></a>
</div>
<div>
- <a style="display: inline-block;" class="skeb" title="Skeb" href="https://skeb.jp/" target="_blank"><img style="width: 100%;" src="https://misskey-hub.net/sponsors/skeb.svg" alt="Skeb"></a>
+ <a style="display: inline-block;" class="skeb" title="Skeb" href="https://skeb.jp/" target="_blank"><img style="width: 100%;" src="https://assets.misskey-hub.net/sponsors/skeb.svg" alt="Skeb"></a>
+ </div>
+ <div>
+ <a style="display: inline-block;" class="pepabo" title="GMO Pepabo" href="https://pepabo.com/" target="_blank"><img style="width: 100%;" src="https://assets.misskey-hub.net/sponsors/gmo_pepabo.svg" alt="GMO Pepabo"></a>
</div>
</div>
</FormSection>
@@ -240,6 +243,27 @@ const patronsWithIcon = [{
}, {
name: 'è¶Šè²é¯›ä¸¸',
icon: 'https://assets.misskey-hub.net/patrons/86c7374de37849b882d8ebbc833dc968.jpg',
+}, {
+ name: '☔ã‚ã‚ðŸ¬(ç¬Ë˜â•°â•¯Ë˜ç¬)',
+ icon: 'https://assets.misskey-hub.net/patrons/676eea72d4884d3f89aababbb62533fb.jpg',
+}, {
+ name: '貯水よã³',
+ icon: 'https://assets.misskey-hub.net/patrons/2974506d53244bbe94a67707b27099e2.jpg',
+}, {
+ name: 'ã¯ã‚‹ã‹ã•',
+ icon: 'https://assets.misskey-hub.net/patrons/26ce2432739a400aa3aa0de0ef67a107.jpg',
+}, {
+ name: '天鈴ã®ã‚',
+ icon: 'https://assets.misskey-hub.net/patrons/995cdbb00bd6421184461a883adfe1d9.jpg',
+}, {
+ name: 'ãˆã¨ã‚”ãã™',
+ icon: 'https://assets.misskey-hub.net/patrons/2578f441b82a44cfaa55ba83a318b26e.jpg',
+}, {
+ name: 'Soli',
+ icon: 'https://assets.misskey-hub.net/patrons/448070c81ebd41eda4ea2328291b2efe.jpg',
+}, {
+ name: 'ã•ã•ãれりょã†',
+ icon: 'https://assets.misskey-hub.net/patrons/cf55022cee6c41da8e70a43587aaad9a.jpg',
}];
const patrons = [
@@ -344,6 +368,7 @@ const patrons = [
'SHO SEKIGUCHI',
'塩キャベツ',
'ã¯ã¨ã½ã·ã•ã‚“',
+ '100ã®äºº (エスパー・イーシア)',
];
const thereIsTreasure = ref($i && !claimedAchievements.includes('foundTreasure'));
diff --git a/packages/frontend/src/pages/about.federation.vue b/packages/frontend/src/pages/about.federation.vue
index 24e96b4f4e..b3776c67e6 100644
--- a/packages/frontend/src/pages/about.federation.vue
+++ b/packages/frontend/src/pages/about.federation.vue
@@ -71,9 +71,9 @@ const pagination = {
sort: sort.value,
host: host.value !== '' ? host.value : null,
...(
- state.value === 'federating' ? { federating: true } :
- state.value === 'subscribing' ? { subscribing: true } :
- state.value === 'publishing' ? { publishing: true } :
+ state.value === 'federating' ? { federating: true, suspended: false, blocked: false } :
+ state.value === 'subscribing' ? { subscribing: true, suspended: false, blocked: false } :
+ state.value === 'publishing' ? { publishing: true, suspended: false, blocked: false } :
state.value === 'suspended' ? { suspended: true } :
state.value === 'blocked' ? { blocked: true } :
state.value === 'silenced' ? { silenced: true } :
diff --git a/packages/frontend/src/pages/about.overview.vue b/packages/frontend/src/pages/about.overview.vue
new file mode 100644
index 0000000000..84419b3bef
--- /dev/null
+++ b/packages/frontend/src/pages/about.overview.vue
@@ -0,0 +1,205 @@
+<!--
+SPDX-FileCopyrightText: syuilo and misskey-project
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
+<template>
+<div class="_gaps_m">
+ <div :class="$style.banner" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }">
+ <div style="overflow: clip;">
+ <img :src="instance.iconUrl ?? instance.faviconUrl ?? '/favicon.ico'" alt="" :class="$style.bannerIcon"/>
+ <div :class="$style.bannerName">
+ <b>{{ instance.name ?? host }}</b>
+ </div>
+ </div>
+ </div>
+
+ <MkKeyValue>
+ <template #key>{{ i18n.ts.description }}</template>
+ <template #value><div v-html="instance.description"></div></template>
+ </MkKeyValue>
+
+ <FormSection>
+ <div class="_gaps_m">
+ <MkKeyValue :copy="version">
+ <template #key>Misskey</template>
+ <template #value>{{ version }}</template>
+ </MkKeyValue>
+ <div v-html="i18n.tsx.poweredByMisskeyDescription({ name: instance.name ?? host })">
+ </div>
+ <FormLink to="/about-misskey">
+ <template #icon><i class="ti ti-info-circle"></i></template>
+ {{ i18n.ts.aboutMisskey }}
+ </FormLink>
+ <FormLink v-if="instance.repositoryUrl || instance.providesTarball" :to="instance.repositoryUrl || `/tarball/misskey-${version}.tar.gz`" external>
+ <template #icon><i class="ti ti-code"></i></template>
+ {{ i18n.ts.sourceCode }}
+ </FormLink>
+ <MkInfo v-else warn>
+ {{ i18n.ts.sourceCodeIsNotYetProvided }}
+ </MkInfo>
+ </div>
+ </FormSection>
+
+ <FormSection>
+ <div class="_gaps_m">
+ <FormSplit>
+ <MkKeyValue :copy="instance.maintainerName">
+ <template #key>{{ i18n.ts.administrator }}</template>
+ <template #value>
+ <template v-if="instance.maintainerName">{{ instance.maintainerName }}</template>
+ <span v-else style="opacity: 0.7;">({{ i18n.ts.none }})</span>
+ </template>
+ </MkKeyValue>
+ <MkKeyValue :copy="instance.maintainerEmail">
+ <template #key>{{ i18n.ts.contact }}</template>
+ <template #value>
+ <template v-if="instance.maintainerEmail">{{ instance.maintainerEmail }}</template>
+ <span v-else style="opacity: 0.7;">({{ i18n.ts.none }})</span>
+ </template>
+ </MkKeyValue>
+ <MkKeyValue>
+ <template #key>{{ i18n.ts.inquiry }}</template>
+ <template #value>
+ <MkLink v-if="instance.inquiryUrl" :url="instance.inquiryUrl" target="_blank">{{ instance.inquiryUrl }}</MkLink>
+ <span v-else style="opacity: 0.7;">({{ i18n.ts.none }})</span>
+ </template>
+ </MkKeyValue>
+ </FormSplit>
+ <div class="_gaps_s">
+ <FormLink v-if="instance.impressumUrl" :to="instance.impressumUrl" external>
+ <template #icon><i class="ti ti-user-shield"></i></template>
+ <template #default>{{ i18n.ts.impressum }}</template>
+ </FormLink>
+ <MkFolder v-if="instance.serverRules.length > 0">
+ <template #icon><i class="ti ti-checkup-list"></i></template>
+ <template #label>{{ i18n.ts.serverRules }}</template>
+ <ol class="_gaps_s" :class="$style.rules">
+ <li v-for="item in instance.serverRules" :key="item" :class="$style.rule">
+ <div :class="$style.ruleText" v-html="item"></div>
+ </li>
+ </ol>
+ </MkFolder>
+ <FormLink v-if="instance.tosUrl" :to="instance.tosUrl" external>
+ <template #icon><i class="ti ti-license"></i></template>
+ <template #default>{{ i18n.ts.termsOfService }}</template>
+ </FormLink>
+ <FormLink v-if="instance.privacyPolicyUrl" :to="instance.privacyPolicyUrl" external>
+ <template #icon><i class="ti ti-shield-lock"></i></template>
+ <template #default>{{ i18n.ts.privacyPolicy }}</template>
+ </FormLink>
+ <FormLink v-if="instance.feedbackUrl" :to="instance.feedbackUrl" external>
+ <template #icon><i class="ti ti-message"></i></template>
+ <template #default>{{ i18n.ts.feedback }}</template>
+ </FormLink>
+ </div>
+ </div>
+ </FormSection>
+
+ <FormSuspense v-slot="{ result: stats }" :p="initStats">
+ <FormSection>
+ <template #label>{{ i18n.ts.statistics }}</template>
+ <FormSplit>
+ <MkKeyValue>
+ <template #key>{{ i18n.ts.users }}</template>
+ <template #value>{{ number(stats.originalUsersCount) }}</template>
+ </MkKeyValue>
+ <MkKeyValue>
+ <template #key>{{ i18n.ts.notes }}</template>
+ <template #value>{{ number(stats.originalNotesCount) }}</template>
+ </MkKeyValue>
+ </FormSplit>
+ </FormSection>
+ </FormSuspense>
+
+ <FormSection>
+ <template #label>Well-known resources</template>
+ <div class="_gaps_s">
+ <FormLink to="/.well-known/host-meta" external>host-meta</FormLink>
+ <FormLink to="/.well-known/host-meta.json" external>host-meta.json</FormLink>
+ <FormLink to="/.well-known/nodeinfo" external>nodeinfo</FormLink>
+ <FormLink to="/robots.txt" external>robots.txt</FormLink>
+ <FormLink to="/manifest.json" external>manifest.json</FormLink>
+ </div>
+ </FormSection>
+</div>
+</template>
+
+<script lang="ts" setup>
+import { host, version } from '@/config.js';
+import { i18n } from '@/i18n.js';
+import { instance } from '@/instance.js';
+import number from '@/filters/number.js';
+import { misskeyApi } from '@/scripts/misskey-api.js';
+import FormLink from '@/components/form/link.vue';
+import FormSection from '@/components/form/section.vue';
+import FormSplit from '@/components/form/split.vue';
+import FormSuspense from '@/components/form/suspense.vue';
+import MkFolder from '@/components/MkFolder.vue';
+import MkKeyValue from '@/components/MkKeyValue.vue';
+import MkLink from '@/components/MkLink.vue';
+
+const initStats = () => misskeyApi('stats', {});
+</script>
+
+<style lang="scss" module>
+.banner {
+ text-align: center;
+ border-radius: 10px;
+ overflow: clip;
+ background-color: var(--panel);
+ background-size: cover;
+ background-position: center center;
+}
+
+.bannerIcon {
+ display: block;
+ margin: 16px auto 0 auto;
+ height: 64px;
+ border-radius: 8px;
+}
+
+.bannerName {
+ display: block;
+ padding: 16px;
+ color: #fff;
+ text-shadow: 0 0 8px #000;
+ background: linear-gradient(transparent, rgba(0, 0, 0, 0.7));
+}
+
+.rules {
+ counter-reset: item;
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+.rule {
+ display: flex;
+ gap: 8px;
+ word-break: break-word;
+
+ &::before {
+ flex-shrink: 0;
+ display: flex;
+ position: sticky;
+ top: calc(var(--stickyTop, 0px) + 8px);
+ counter-increment: item;
+ content: counter(item);
+ width: 32px;
+ height: 32px;
+ line-height: 32px;
+ background-color: var(--accentedBg);
+ color: var(--accent);
+ font-size: 13px;
+ font-weight: bold;
+ align-items: center;
+ justify-content: center;
+ border-radius: 999px;
+ }
+}
+
+.ruleText {
+ padding-top: 6px;
+}
+</style>
diff --git a/packages/frontend/src/pages/about.vue b/packages/frontend/src/pages/about.vue
index 324d1c11de..8dfeb6d2a7 100644
--- a/packages/frontend/src/pages/about.vue
+++ b/packages/frontend/src/pages/about.vue
@@ -8,113 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
<MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs">
<MkSpacer v-if="tab === 'overview'" :contentMax="600" :marginMin="20">
- <div class="_gaps_m">
- <div :class="$style.banner" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }">
- <div style="overflow: clip;">
- <img :src="instance.iconUrl ?? instance.faviconUrl ?? '/favicon.ico'" alt="" :class="$style.bannerIcon"/>
- <div :class="$style.bannerName">
- <b>{{ instance.name ?? host }}</b>
- </div>
- </div>
- </div>
-
- <MkKeyValue>
- <template #key>{{ i18n.ts.description }}</template>
- <template #value><div v-html="instance.description"></div></template>
- </MkKeyValue>
-
- <FormSection>
- <div class="_gaps_m">
- <MkKeyValue :copy="version">
- <template #key>Misskey</template>
- <template #value>{{ version }}</template>
- </MkKeyValue>
- <div v-html="i18n.tsx.poweredByMisskeyDescription({ name: instance.name ?? host })">
- </div>
- <FormLink to="/about-misskey">
- <template #icon><i class="ti ti-info-circle"></i></template>
- {{ i18n.ts.aboutMisskey }}
- </FormLink>
- <FormLink v-if="instance.repositoryUrl || instance.providesTarball" :to="instance.repositoryUrl || `/tarball/misskey-${version}.tar.gz`" external>
- <template #icon><i class="ti ti-code"></i></template>
- {{ i18n.ts.sourceCode }}
- </FormLink>
- <MkInfo v-else warn>
- {{ i18n.ts.sourceCodeIsNotYetProvided }}
- </MkInfo>
- </div>
- </FormSection>
-
- <FormSection>
- <div class="_gaps_m">
- <FormSplit>
- <MkKeyValue>
- <template #key>{{ i18n.ts.administrator }}</template>
- <template #value>{{ instance.maintainerName }}</template>
- </MkKeyValue>
- <MkKeyValue>
- <template #key>{{ i18n.ts.contact }}</template>
- <template #value>{{ instance.maintainerEmail }}</template>
- </MkKeyValue>
- </FormSplit>
- <FormLink v-if="instance.impressumUrl" :to="instance.impressumUrl" external>
- <template #icon><i class="ti ti-user-shield"></i></template>
- {{ i18n.ts.impressum }}
- </FormLink>
- <div class="_gaps_s">
- <MkFolder v-if="instance.serverRules.length > 0">
- <template #label>
- <i class="ti ti-checkup-list"></i>
- {{ i18n.ts.serverRules }}
- </template>
-
- <ol class="_gaps_s" :class="$style.rules">
- <li v-for="(item, index) in instance.serverRules" :key="index" :class="$style.rule"><div :class="$style.ruleText" v-html="item"></div></li>
- </ol>
- </MkFolder>
- <FormLink v-if="instance.tosUrl" :to="instance.tosUrl" external>
- <template #icon><i class="ti ti-license"></i></template>
- {{ i18n.ts.termsOfService }}
- </FormLink>
- <FormLink v-if="instance.privacyPolicyUrl" :to="instance.privacyPolicyUrl" external>
- <template #icon><i class="ti ti-shield-lock"></i></template>
- {{ i18n.ts.privacyPolicy }}
- </FormLink>
- <FormLink v-if="instance.feedbackUrl" :to="instance.feedbackUrl" external>
- <template #icon><i class="ti ti-message"></i></template>
- {{ i18n.ts.feedback }}
- </FormLink>
- </div>
- </div>
- </FormSection>
-
- <FormSuspense :p="initStats">
- <FormSection>
- <template #label>{{ i18n.ts.statistics }}</template>
- <FormSplit>
- <MkKeyValue>
- <template #key>{{ i18n.ts.users }}</template>
- <template #value>{{ number(stats.originalUsersCount) }}</template>
- </MkKeyValue>
- <MkKeyValue>
- <template #key>{{ i18n.ts.notes }}</template>
- <template #value>{{ number(stats.originalNotesCount) }}</template>
- </MkKeyValue>
- </FormSplit>
- </FormSection>
- </FormSuspense>
-
- <FormSection>
- <template #label>Well-known resources</template>
- <div class="_gaps_s">
- <FormLink :to="`/.well-known/host-meta`" external>host-meta</FormLink>
- <FormLink :to="`/.well-known/host-meta.json`" external>host-meta.json</FormLink>
- <FormLink :to="`/.well-known/nodeinfo`" external>nodeinfo</FormLink>
- <FormLink :to="`/robots.txt`" external>robots.txt</FormLink>
- <FormLink :to="`/manifest.json`" external>manifest.json</FormLink>
- </div>
- </FormSection>
- </div>
+ <XOverview/>
</MkSpacer>
<MkSpacer v-else-if="tab === 'emojis'" :contentMax="1000" :marginMin="20">
<XEmojis/>
@@ -130,26 +24,16 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { computed, watch, ref } from 'vue';
-import * as Misskey from 'misskey-js';
-import XEmojis from './about.emojis.vue';
-import XFederation from './about.federation.vue';
-import { version, host } from '@/config.js';
-import FormLink from '@/components/form/link.vue';
-import FormSection from '@/components/form/section.vue';
-import FormSuspense from '@/components/form/suspense.vue';
-import FormSplit from '@/components/form/split.vue';
-import MkFolder from '@/components/MkFolder.vue';
-import MkKeyValue from '@/components/MkKeyValue.vue';
-import MkInfo from '@/components/MkInfo.vue';
-import MkInstanceStats from '@/components/MkInstanceStats.vue';
-import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
-import { misskeyApi } from '@/scripts/misskey-api.js';
-import number from '@/filters/number.js';
+import { computed, defineAsyncComponent, ref, watch } from 'vue';
import { i18n } from '@/i18n.js';
-import { definePageMetadata } from '@/scripts/page-metadata.js';
import { claimAchievement } from '@/scripts/achievements.js';
-import { instance } from '@/instance.js';
+import { definePageMetadata } from '@/scripts/page-metadata.js';
+import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
+
+const XOverview = defineAsyncComponent(() => import('@/pages/about.overview.vue'));
+const XEmojis = defineAsyncComponent(() => import('@/pages/about.emojis.vue'));
+const XFederation = defineAsyncComponent(() => import('@/pages/about.federation.vue'));
+const MkInstanceStats = defineAsyncComponent(() => import('@/components/MkInstanceStats.vue'));
const props = withDefaults(defineProps<{
initialTab?: string;
@@ -157,7 +41,6 @@ const props = withDefaults(defineProps<{
initialTab: 'overview',
});
-const stats = ref<Misskey.entities.StatsResponse | null>(null);
const tab = ref(props.initialTab);
watch(tab, () => {
@@ -166,11 +49,6 @@ watch(tab, () => {
}
});
-const initStats = () => misskeyApi('stats', {
-}).then((res) => {
- stats.value = res;
-});
-
const headerActions = computed(() => []);
const headerTabs = computed(() => [{
@@ -195,64 +73,3 @@ definePageMetadata(() => ({
icon: 'ti ti-info-circle',
}));
</script>
-
-<style lang="scss" module>
-.banner {
- text-align: center;
- border-radius: 10px;
- overflow: clip;
- background-size: cover;
- background-position: center center;
-}
-
-.bannerIcon {
- display: block;
- margin: 16px auto 0 auto;
- height: 64px;
- border-radius: 8px;
-}
-
-.bannerName {
- display: block;
- padding: 16px;
- color: #fff;
- text-shadow: 0 0 8px #000;
- background: linear-gradient(transparent, rgba(0, 0, 0, 0.7));
-}
-
-.rules {
- counter-reset: item;
- list-style: none;
- padding: 0;
- margin: 0;
-}
-
-.rule {
- display: flex;
- gap: 8px;
- word-break: break-word;
-
- &::before {
- flex-shrink: 0;
- display: flex;
- position: sticky;
- top: calc(var(--stickyTop, 0px) + 8px);
- counter-increment: item;
- content: counter(item);
- width: 32px;
- height: 32px;
- line-height: 32px;
- background-color: var(--accentedBg);
- color: var(--accent);
- font-size: 13px;
- font-weight: bold;
- align-items: center;
- justify-content: center;
- border-radius: 999px;
- }
-}
-
-.ruleText {
- padding-top: 6px;
-}
-</style>
diff --git a/packages/frontend/src/pages/admin-user.vue b/packages/frontend/src/pages/admin-user.vue
index f57aa51b5b..1459997dcb 100644
--- a/packages/frontend/src/pages/admin-user.vue
+++ b/packages/frontend/src/pages/admin-user.vue
@@ -464,16 +464,20 @@ function toggleRoleItem(role) {
}
function createAnnouncement() {
- os.popup(defineAsyncComponent(() => import('@/components/MkUserAnnouncementEditDialog.vue')), {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkUserAnnouncementEditDialog.vue')), {
user: user.value,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
}
function editAnnouncement(announcement) {
- os.popup(defineAsyncComponent(() => import('@/components/MkUserAnnouncementEditDialog.vue')), {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkUserAnnouncementEditDialog.vue')), {
user: user.value,
announcement,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
}
watch(() => props.userId, () => {
diff --git a/packages/frontend/src/pages/admin/_header_.vue b/packages/frontend/src/pages/admin/_header_.vue
index c5a9609e6e..b88f078598 100644
--- a/packages/frontend/src/pages/admin/_header_.vue
+++ b/packages/frontend/src/pages/admin/_header_.vue
@@ -24,8 +24,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="buttons right">
<template v-if="actions">
<template v-for="action in actions">
- <MkButton v-if="action.asFullButton" class="fullButton" primary @click.stop="action.handler"><i :class="action.icon" style="margin-right: 6px;"></i>{{ action.text }}</MkButton>
- <button v-else v-tooltip.noDelay="action.text" class="_button button" :class="{ highlighted: action.highlighted }" @click.stop="action.handler" @touchstart="preventDrag"><i :class="action.icon"></i></button>
+ <MkButton v-if="action.asFullButton" class="fullButton" primary :disabled="action.disabled" @click.stop="action.handler"><i :class="action.icon" style="margin-right: 6px;"></i>{{ action.text }}</MkButton>
+ <button v-else v-tooltip.noDelay="action.text" class="_button button" :class="{ highlighted: action.highlighted }" :disabled="action.disabled" @click.stop="action.handler" @touchstart="preventDrag"><i :class="action.icon"></i></button>
</template>
</template>
</div>
@@ -56,6 +56,7 @@ const props = defineProps<{
text: string;
icon: string;
asFullButton?: boolean;
+ disabled?: boolean;
handler: (ev: MouseEvent) => void;
}[];
thin?: boolean;
diff --git a/packages/frontend/src/pages/admin/abuse-report/notification-recipient.editor.vue b/packages/frontend/src/pages/admin/abuse-report/notification-recipient.editor.vue
new file mode 100644
index 0000000000..827e22e8ae
--- /dev/null
+++ b/packages/frontend/src/pages/admin/abuse-report/notification-recipient.editor.vue
@@ -0,0 +1,321 @@
+<!--
+SPDX-FileCopyrightText: syuilo and misskey-project
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
+<template>
+<MkModalWindow
+ ref="dialogEl"
+ :width="400"
+ :height="490"
+ :withOkButton="false"
+ :okButtonDisabled="false"
+ @close="onCancelClicked"
+ @closed="emit('closed')"
+>
+ <template #header>
+ {{ mode === 'create' ? i18n.ts._abuseReport._notificationRecipient.createRecipient : i18n.ts._abuseReport._notificationRecipient.modifyRecipient }}
+ </template>
+ <div v-if="loading === 0" style="display: flex; flex-direction: column; min-height: 100%;">
+ <MkSpacer :marginMin="20" :marginMax="28" style="flex-grow: 1;">
+ <div :class="$style.root" class="_gaps_m">
+ <MkInput v-model="title">
+ <template #label>{{ i18n.ts.title }}</template>
+ </MkInput>
+ <MkSelect v-model="method">
+ <template #label>{{ i18n.ts._abuseReport._notificationRecipient.recipientType }}</template>
+ <option value="email">{{ i18n.ts._abuseReport._notificationRecipient._recipientType.mail }}</option>
+ <option value="webhook">{{ i18n.ts._abuseReport._notificationRecipient._recipientType.webhook }}</option>
+ <template #caption>
+ {{ methodCaption }}
+ </template>
+ </MkSelect>
+ <div>
+ <MkSelect v-if="method === 'email'" v-model="userId">
+ <template #label>{{ i18n.ts._abuseReport._notificationRecipient.notifiedUser }}</template>
+ <option v-for="user in moderators" :key="user.id" :value="user.id">
+ {{ user.name ? `${user.name}(${user.username})` : user.username }}
+ </option>
+ </MkSelect>
+ <div v-else-if="method === 'webhook'" :class="$style.systemWebhook">
+ <MkSelect v-model="systemWebhookId" style="flex: 1">
+ <template #label>{{ i18n.ts._abuseReport._notificationRecipient.notifiedWebhook }}</template>
+ <option v-for="webhook in systemWebhooks" :key="webhook.id ?? undefined" :value="webhook.id">
+ {{ webhook.name }}
+ </option>
+ </MkSelect>
+ <MkButton rounded :class="$style.systemWebhookEditButton" @click="onEditSystemWebhookClicked">
+ <span v-if="systemWebhookId === null" class="ti ti-plus" style="line-height: normal"/>
+ <span v-else class="ti ti-settings" style="line-height: normal"/>
+ </MkButton>
+ </div>
+ </div>
+
+ <MkDivider/>
+
+ <MkSwitch v-model="isActive">
+ <template #label>{{ i18n.ts.enable }}</template>
+ </MkSwitch>
+ </div>
+ </MkSpacer>
+
+ <div :class="$style.footer" class="_buttonsCenter">
+ <MkButton primary rounded :disabled="disableSubmitButton" @click="onSubmitClicked"><i class="ti ti-check"></i> {{ i18n.ts.ok }}</MkButton>
+ <MkButton rounded @click="onCancelClicked"><i class="ti ti-x"></i> {{ i18n.ts.cancel }}</MkButton>
+ </div>
+ </div>
+ <div v-else>
+ <MkLoading/>
+ </div>
+</MkModalWindow>
+</template>
+
+<script lang="ts" setup>
+import { computed, onMounted, ref, shallowRef, toRefs } from 'vue';
+import { entities } from 'misskey-js';
+import MkButton from '@/components/MkButton.vue';
+import MkModalWindow from '@/components/MkModalWindow.vue';
+import { i18n } from '@/i18n.js';
+import MkInput from '@/components/MkInput.vue';
+import { misskeyApi } from '@/scripts/misskey-api.js';
+import MkSelect from '@/components/MkSelect.vue';
+import { MkSystemWebhookResult, showSystemWebhookEditorDialog } from '@/components/MkSystemWebhookEditor.impl.js';
+import MkSwitch from '@/components/MkSwitch.vue';
+import MkDivider from '@/components/MkDivider.vue';
+import * as os from '@/os.js';
+
+type NotificationRecipientMethod = 'email' | 'webhook';
+
+const emit = defineEmits<{
+ (ev: 'submitted'): void;
+ (ev: 'canceled'): void;
+ (ev: 'closed'): void;
+}>();
+
+const props = defineProps<{
+ mode: 'create' | 'edit';
+ id?: string;
+}>();
+
+const { mode, id } = toRefs(props);
+
+const dialogEl = shallowRef<InstanceType<typeof MkModalWindow>>();
+
+const loading = ref<number>(0);
+
+const title = ref<string>('');
+const method = ref<NotificationRecipientMethod>('email');
+const userId = ref<string | null>(null);
+const systemWebhookId = ref<string | null>(null);
+const isActive = ref<boolean>(true);
+
+const moderators = ref<entities.User[]>([]);
+const systemWebhooks = ref<(entities.SystemWebhook | { id: null, name: string })[]>([]);
+
+const methodCaption = computed(() => {
+ switch (method.value) {
+ case 'email': {
+ return i18n.ts._abuseReport._notificationRecipient._recipientType._captions.mail;
+ }
+ case 'webhook': {
+ return i18n.ts._abuseReport._notificationRecipient._recipientType._captions.webhook;
+ }
+ default: {
+ return '';
+ }
+ }
+});
+
+const disableSubmitButton = computed(() => {
+ if (!title.value) {
+ return true;
+ }
+
+ switch (method.value) {
+ case 'email': {
+ return userId.value === null;
+ }
+ case 'webhook': {
+ return systemWebhookId.value === null;
+ }
+ default: {
+ return true;
+ }
+ }
+});
+
+async function onSubmitClicked() {
+ await loadingScope(async () => {
+ const _userId = (method.value === 'email') ? userId.value : null;
+ const _systemWebhookId = (method.value === 'webhook') ? systemWebhookId.value : null;
+ const params = {
+ isActive: isActive.value,
+ name: title.value,
+ method: method.value,
+ userId: _userId ?? undefined,
+ systemWebhookId: _systemWebhookId ?? undefined,
+ };
+
+ try {
+ switch (mode.value) {
+ case 'create': {
+ await misskeyApi('admin/abuse-report/notification-recipient/create', params);
+ break;
+ }
+ case 'edit': {
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ await misskeyApi('admin/abuse-report/notification-recipient/update', { id: id.value!, ...params });
+ break;
+ }
+ }
+
+ dialogEl.value?.close();
+ emit('submitted');
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ } catch (ex: any) {
+ const msg = ex.message ?? i18n.ts.internalServerErrorDescription;
+ await os.alert({ type: 'error', title: i18n.ts.error, text: msg });
+ dialogEl.value?.close();
+ emit('canceled');
+ }
+ });
+}
+
+function onCancelClicked() {
+ dialogEl.value?.close();
+ emit('canceled');
+}
+
+async function onEditSystemWebhookClicked() {
+ let result: MkSystemWebhookResult | null;
+ if (systemWebhookId.value === null) {
+ result = await showSystemWebhookEditorDialog({
+ mode: 'create',
+ });
+ } else {
+ result = await showSystemWebhookEditorDialog({
+ mode: 'edit',
+ id: systemWebhookId.value,
+ });
+ }
+ if (!result) {
+ return;
+ }
+
+ await fetchSystemWebhooks();
+ systemWebhookId.value = result.id ?? null;
+}
+
+async function fetchSystemWebhooks() {
+ await loadingScope(async () => {
+ systemWebhooks.value = [
+ { id: null, name: i18n.ts.createNew },
+ ...await misskeyApi('admin/system-webhook/list', { }),
+ ];
+ });
+}
+
+async function fetchModerators() {
+ await loadingScope(async () => {
+ const users = Array.of<entities.User>();
+ for (; ;) {
+ const res = await misskeyApi('admin/show-users', {
+ limit: 100,
+ state: 'adminOrModerator',
+ origin: 'local',
+ offset: users.length,
+ });
+
+ if (res.length === 0) {
+ break;
+ }
+
+ users.push(...res);
+ }
+
+ moderators.value = users;
+ });
+}
+
+async function loadingScope<T>(fn: () => Promise<T>): Promise<T> {
+ loading.value++;
+ try {
+ return await fn();
+ } finally {
+ loading.value--;
+ }
+}
+
+onMounted(async () => {
+ await loadingScope(async () => {
+ await fetchModerators();
+ await fetchSystemWebhooks();
+
+ if (mode.value === 'edit') {
+ if (!id.value) {
+ throw new Error('id is required');
+ }
+
+ try {
+ const res = await misskeyApi('admin/abuse-report/notification-recipient/show', { id: id.value });
+
+ title.value = res.name;
+ method.value = res.method;
+ userId.value = res.userId ?? null;
+ systemWebhookId.value = res.systemWebhookId ?? null;
+ isActive.value = res.isActive;
+ // eslint-disable-next-line
+ } catch (ex: any) {
+ const msg = ex.message ?? i18n.ts.internalServerErrorDescription;
+ await os.alert({ type: 'error', title: i18n.ts.error, text: msg });
+ dialogEl.value?.close();
+ emit('canceled');
+ }
+ } else {
+ userId.value = moderators.value[0]?.id ?? null;
+ systemWebhookId.value = systemWebhooks.value[0]?.id ?? null;
+ }
+ });
+});
+
+</script>
+
+<style lang="scss" module>
+.root {
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ align-items: stretch;
+}
+
+.footer {
+ position: sticky;
+ z-index: 10000;
+ bottom: 0;
+ left: 0;
+ padding: 12px;
+ border-top: solid 0.5px var(--divider);
+ background: var(--acrylicBg);
+ -webkit-backdrop-filter: var(--blur, blur(15px));
+ backdrop-filter: var(--blur, blur(15px));
+}
+
+.systemWebhook {
+ display: flex;
+ flex-direction: row;
+ justify-content: stretch;
+ align-items: flex-end;
+ gap: 8px;
+}
+
+.systemWebhookEditButton {
+ min-width: 0;
+ min-height: 0;
+ width: 34px;
+ height: 34px;
+ flex-shrink: 0;
+ box-sizing: border-box;
+ margin: 1px 0;
+ padding: 6px;
+}
+</style>
diff --git a/packages/frontend/src/pages/admin/abuse-report/notification-recipient.item.vue b/packages/frontend/src/pages/admin/abuse-report/notification-recipient.item.vue
new file mode 100644
index 0000000000..0b86808faf
--- /dev/null
+++ b/packages/frontend/src/pages/admin/abuse-report/notification-recipient.item.vue
@@ -0,0 +1,114 @@
+<!--
+SPDX-FileCopyrightText: syuilo and misskey-project
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
+<template>
+<div :class="$style.root" class="_panel _gaps_s">
+ <div :class="$style.rightDivider" style="width: 80px;"><span :class="`ti ${methodIcon}`"/> {{ methodName }}</div>
+ <div :class="$style.rightDivider" style="flex: 0.5">{{ entity.name }}</div>
+ <div :class="$style.rightDivider" style="flex: 1">
+ <div v-if="method === 'email' && user">
+ {{
+ `${i18n.ts._abuseReport._notificationRecipient.notifiedUser}: ` + ((user.name) ? `${user.name}(${user.username})` : user.username)
+ }}
+ </div>
+ <div v-if="method === 'webhook' && systemWebhook">
+ {{ `${i18n.ts._abuseReport._notificationRecipient.notifiedWebhook}: ` + systemWebhook.name }}
+ </div>
+ </div>
+ <div :class="$style.recipientButtons" style="margin-left: auto">
+ <button :class="$style.recipientButton" @click="onEditButtonClicked()">
+ <span class="ti ti-settings"/>
+ </button>
+ <button :class="$style.recipientButton" @click="onDeleteButtonClicked()">
+ <span class="ti ti-trash"/>
+ </button>
+ </div>
+</div>
+</template>
+
+<script setup lang="ts">
+import { entities } from 'misskey-js';
+import { computed, toRefs } from 'vue';
+import { i18n } from '@/i18n.js';
+
+const emit = defineEmits<{
+ (ev: 'edit', id: entities.AbuseReportNotificationRecipient['id']): void;
+ (ev: 'delete', id: entities.AbuseReportNotificationRecipient['id']): void;
+}>();
+
+const props = defineProps<{
+ entity: entities.AbuseReportNotificationRecipient;
+}>();
+
+const { entity } = toRefs(props);
+
+const method = computed(() => entity.value.method);
+const user = computed(() => entity.value.user);
+const systemWebhook = computed(() => entity.value.systemWebhook);
+const methodIcon = computed(() => {
+ switch (entity.value.method) {
+ case 'email':
+ return 'ti-mail';
+ case 'webhook':
+ return 'ti-webhook';
+ default:
+ return 'ti-help';
+ }
+});
+const methodName = computed(() => {
+ switch (entity.value.method) {
+ case 'email':
+ return i18n.ts._abuseReport._notificationRecipient._recipientType.mail;
+ case 'webhook':
+ return i18n.ts._abuseReport._notificationRecipient._recipientType.webhook;
+ default:
+ return '䏿˜Ž';
+ }
+});
+
+function onEditButtonClicked() {
+ emit('edit', entity.value.id);
+}
+
+function onDeleteButtonClicked() {
+ emit('delete', entity.value.id);
+}
+</script>
+
+<style module lang="scss">
+.root {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+ padding: 4px 8px;
+}
+
+.rightDivider {
+ border-right: 0.5px solid var(--divider);
+}
+
+.recipientButtons {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+ margin-right: -4;
+}
+
+.recipientButton {
+ background-color: transparent;
+ border: none;
+ border-radius: 9999px;
+ box-sizing: border-box;
+ margin-top: -2px;
+ margin-bottom: -2px;
+ padding: 8px;
+
+ &:hover {
+ background-color: var(--buttonBg);
+ }
+}
+</style>
diff --git a/packages/frontend/src/pages/admin/abuse-report/notification-recipient.vue b/packages/frontend/src/pages/admin/abuse-report/notification-recipient.vue
new file mode 100644
index 0000000000..f5249261be
--- /dev/null
+++ b/packages/frontend/src/pages/admin/abuse-report/notification-recipient.vue
@@ -0,0 +1,177 @@
+<!--
+SPDX-FileCopyrightText: syuilo and misskey-project
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
+<template>
+<MkStickyContainer>
+ <template #header>
+ <XHeader :actions="headerActions" :tabs="headerTabs"/>
+ </template>
+
+ <MkSpacer :contentMax="900">
+ <div :class="$style.root" class="_gaps_m">
+ <div :class="$style.addButton">
+ <MkButton primary @click="onAddButtonClicked">
+ <span class="ti ti-plus"/> {{ i18n.ts._abuseReport._notificationRecipient.createRecipient }}
+ </MkButton>
+ </div>
+ <div :class="$style.subMenus" class="_gaps_s">
+ <MkSelect v-model="filterMethod" style="flex: 1">
+ <template #label>{{ i18n.ts._abuseReport._notificationRecipient.recipientType }}</template>
+ <option :value="null">-</option>
+ <option :value="'email'">{{ i18n.ts._abuseReport._notificationRecipient._recipientType.mail }}</option>
+ <option :value="'webhook'">{{ i18n.ts._abuseReport._notificationRecipient._recipientType.webhook }}</option>
+ </MkSelect>
+ <MkInput v-model="filterText" type="search" style="flex: 1">
+ <template #label>{{ i18n.ts._abuseReport._notificationRecipient.keywords }}</template>
+ </MkInput>
+ </div>
+
+ <MkDivider/>
+
+ <div :class="$style.recipients" class="_gaps_s">
+ <XRecipient
+ v-for="r in filteredRecipients"
+ :key="r.id"
+ :entity="r"
+ @edit="onEditButtonClicked"
+ @delete="onDeleteButtonClicked"
+ />
+ </div>
+ </div>
+ </MkSpacer>
+</MkStickyContainer>
+</template>
+
+<script setup lang="ts">
+import { entities } from 'misskey-js';
+import { computed, defineAsyncComponent, onMounted, ref } from 'vue';
+import XRecipient from './notification-recipient.item.vue';
+import XHeader from '@/pages/admin/_header_.vue';
+import { misskeyApi } from '@/scripts/misskey-api.js';
+import MkInput from '@/components/MkInput.vue';
+import MkSelect from '@/components/MkSelect.vue';
+import MkButton from '@/components/MkButton.vue';
+import * as os from '@/os.js';
+import MkDivider from '@/components/MkDivider.vue';
+import { i18n } from '@/i18n.js';
+
+const recipients = ref<entities.AbuseReportNotificationRecipient[]>([]);
+
+const filterMethod = ref<string | null>(null);
+const filterText = ref<string>('');
+
+const filteredRecipients = computed(() => {
+ const method = filterMethod.value;
+ const text = filterText.value.trim().length === 0 ? null : filterText.value;
+
+ return recipients.value.filter(it => {
+ if (method ?? text) {
+ if (text) {
+ const keywords = [it.name, it.systemWebhook?.name, it.user?.name, it.user?.username];
+ if (keywords.filter(k => k?.includes(text)).length !== 0) {
+ return true;
+ }
+ }
+
+ if (method) {
+ return it.method.includes(method);
+ }
+
+ return false;
+ }
+
+ return true;
+ });
+});
+const headerActions = computed(() => []);
+const headerTabs = computed(() => []);
+
+async function onAddButtonClicked() {
+ await showEditor('create');
+}
+
+async function onEditButtonClicked(id: string) {
+ await showEditor('edit', id);
+}
+
+async function onDeleteButtonClicked(id: string) {
+ const res = await os.confirm({
+ type: 'warning',
+ title: i18n.ts._abuseReport._notificationRecipient.deleteConfirm,
+ });
+ if (!res.canceled) {
+ await misskeyApi('admin/abuse-report/notification-recipient/delete', { id: id });
+ await fetchRecipients();
+ }
+}
+
+async function showEditor(mode: 'create' | 'edit', id?: string) {
+ const { needLoad } = await new Promise<{ needLoad: boolean }>(async resolve => {
+ const { dispose } = os.popup(
+ defineAsyncComponent(() => import('./notification-recipient.editor.vue')),
+ {
+ mode,
+ id,
+ },
+ {
+ submitted: () => {
+ resolve({ needLoad: true });
+ },
+ canceled: () => {
+ resolve({ needLoad: false });
+ },
+ closed: () => {
+ dispose();
+ },
+ },
+ );
+ });
+
+ if (needLoad) {
+ await fetchRecipients();
+ }
+}
+
+async function fetchRecipients() {
+ const result = await misskeyApi('admin/abuse-report/notification-recipient/list', {
+ method: ['email', 'webhook'],
+ });
+
+ recipients.value = result.sort((a, b) => (a.method + a.id).localeCompare(b.method + b.id));
+}
+
+onMounted(async () => {
+ await fetchRecipients();
+});
+</script>
+
+<style module lang="scss">
+.root {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: stretch;
+}
+
+.addButton {
+ display: flex;
+ justify-content: flex-end;
+ gap: 8px;
+}
+
+.subMenus {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: flex-end;
+}
+
+.recipients {
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ align-items: stretch;
+}
+</style>
diff --git a/packages/frontend/src/pages/admin/abuses.vue b/packages/frontend/src/pages/admin/abuses.vue
index d2f4a4b531..9a9fa472a5 100644
--- a/packages/frontend/src/pages/admin/abuses.vue
+++ b/packages/frontend/src/pages/admin/abuses.vue
@@ -7,30 +7,33 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkStickyContainer>
<template #header><XHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="900">
- <div>
- <div class="reports">
- <div class="">
- <div class="inputs" style="display: flex;">
- <MkSelect v-model="state" style="margin: 0; flex: 1;">
- <template #label>{{ i18n.ts.state }}</template>
- <option value="all">{{ i18n.ts.all }}</option>
- <option value="unresolved">{{ i18n.ts.unresolved }}</option>
- <option value="resolved">{{ i18n.ts.resolved }}</option>
- </MkSelect>
- <MkSelect v-model="targetUserOrigin" style="margin: 0; flex: 1;">
- <template #label>{{ i18n.ts.reporteeOrigin }}</template>
- <option value="combined">{{ i18n.ts.all }}</option>
- <option value="local">{{ i18n.ts.local }}</option>
- <option value="remote">{{ i18n.ts.remote }}</option>
- </MkSelect>
- <MkSelect v-model="reporterOrigin" style="margin: 0; flex: 1;">
- <template #label>{{ i18n.ts.reporterOrigin }}</template>
- <option value="combined">{{ i18n.ts.all }}</option>
- <option value="local">{{ i18n.ts.local }}</option>
- <option value="remote">{{ i18n.ts.remote }}</option>
- </MkSelect>
- </div>
- <!-- TODO
+ <div :class="$style.root" class="_gaps">
+ <div :class="$style.subMenus" class="_gaps">
+ <MkButton link to="/admin/abuse-report-notification-recipient" primary>{{ "通知設定" }}</MkButton>
+ </div>
+
+ <div :class="$style.inputs" class="_gaps">
+ <MkSelect v-model="state" style="margin: 0; flex: 1;">
+ <template #label>{{ i18n.ts.state }}</template>
+ <option value="all">{{ i18n.ts.all }}</option>
+ <option value="unresolved">{{ i18n.ts.unresolved }}</option>
+ <option value="resolved">{{ i18n.ts.resolved }}</option>
+ </MkSelect>
+ <MkSelect v-model="targetUserOrigin" style="margin: 0; flex: 1;">
+ <template #label>{{ i18n.ts.reporteeOrigin }}</template>
+ <option value="combined">{{ i18n.ts.all }}</option>
+ <option value="local">{{ i18n.ts.local }}</option>
+ <option value="remote">{{ i18n.ts.remote }}</option>
+ </MkSelect>
+ <MkSelect v-model="reporterOrigin" style="margin: 0; flex: 1;">
+ <template #label>{{ i18n.ts.reporterOrigin }}</template>
+ <option value="combined">{{ i18n.ts.all }}</option>
+ <option value="local">{{ i18n.ts.local }}</option>
+ <option value="remote">{{ i18n.ts.remote }}</option>
+ </MkSelect>
+ </div>
+
+ <!-- TODO
<div class="inputs" style="display: flex; padding-top: 1.2em;">
<MkInput v-model="searchUsername" style="margin: 0; flex: 1;" type="text" :spellcheck="false">
<span>{{ i18n.ts.username }}</span>
@@ -41,11 +44,9 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
-->
- <MkPagination v-slot="{items}" ref="reports" :pagination="pagination" style="margin-top: var(--margin);">
- <XAbuseReport v-for="report in items" :key="report.id" :report="report" @resolved="resolved"/>
- </MkPagination>
- </div>
- </div>
+ <MkPagination v-slot="{items}" ref="reports" :pagination="pagination" style="margin-top: var(--margin);">
+ <XAbuseReport v-for="report in items" :key="report.id" :report="report" @resolved="resolved"/>
+ </MkPagination>
</div>
</MkSpacer>
</MkStickyContainer>
@@ -60,6 +61,7 @@ import MkPagination from '@/components/MkPagination.vue';
import XAbuseReport from '@/components/MkAbuseReport.vue';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
+import MkButton from '@/components/MkButton.vue';
const reports = shallowRef<InstanceType<typeof MkPagination>>();
@@ -80,7 +82,7 @@ const pagination = {
};
function resolved(reportId) {
- reports.value.removeItem(reportId);
+ reports.value?.removeItem(reportId);
}
const headerActions = computed(() => []);
@@ -92,3 +94,26 @@ definePageMetadata(() => ({
icon: 'ti ti-exclamation-circle',
}));
</script>
+
+<style module lang="scss">
+.root {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: stretch;
+}
+
+.subMenus {
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-end;
+ align-items: center;
+}
+
+.inputs {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+}
+</style>
diff --git a/packages/frontend/src/pages/admin/announcements.vue b/packages/frontend/src/pages/admin/announcements.vue
index e7fb62ec1d..b9e09c8d03 100644
--- a/packages/frontend/src/pages/admin/announcements.vue
+++ b/packages/frontend/src/pages/admin/announcements.vue
@@ -11,70 +11,83 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkInfo>{{ i18n.ts._announcement.shouldNotBeUsedToPresentPermanentInfo }}</MkInfo>
<MkInfo v-if="announcements.length > 5" warn>{{ i18n.ts._announcement.tooManyActiveAnnouncementDescription }}</MkInfo>
- <MkFolder v-for="announcement in announcements" :key="announcement.id ?? announcement._id" :defaultOpen="announcement.id == null">
- <template #label>{{ announcement.title }}</template>
- <template #icon>
- <i v-if="announcement.icon === 'info'" class="ti ti-info-circle"></i>
- <i v-else-if="announcement.icon === 'warning'" class="ti ti-alert-triangle" style="color: var(--warn);"></i>
- <i v-else-if="announcement.icon === 'error'" class="ti ti-circle-x" style="color: var(--error);"></i>
- <i v-else-if="announcement.icon === 'success'" class="ti ti-check" style="color: var(--success);"></i>
- </template>
- <template #caption>{{ announcement.text }}</template>
+ <MkSelect v-model="announcementsStatus">
+ <template #label>{{ i18n.ts.filter }}</template>
+ <option value="active">{{ i18n.ts.active }}</option>
+ <option value="archived">{{ i18n.ts.archived }}</option>
+ </MkSelect>
- <div class="_gaps_m">
- <MkInput v-model="announcement.title">
- <template #label>{{ i18n.ts.title }}</template>
- </MkInput>
- <MkTextarea v-model="announcement.text" mfmAutocomplete :mfmPreview="true">
- <template #label>{{ i18n.ts.text }}</template>
- </MkTextarea>
- <MkInput v-model="announcement.imageUrl" type="url">
- <template #label>{{ i18n.ts.imageUrl }}</template>
- </MkInput>
- <MkRadios v-model="announcement.icon">
- <template #label>{{ i18n.ts.icon }}</template>
- <option value="info"><i class="ti ti-info-circle"></i></option>
- <option value="warning"><i class="ti ti-alert-triangle" style="color: var(--warn);"></i></option>
- <option value="error"><i class="ti ti-circle-x" style="color: var(--error);"></i></option>
- <option value="success"><i class="ti ti-check" style="color: var(--success);"></i></option>
- </MkRadios>
- <MkRadios v-model="announcement.display">
- <template #label>{{ i18n.ts.display }}</template>
- <option value="normal">{{ i18n.ts.normal }}</option>
- <option value="banner">{{ i18n.ts.banner }}</option>
- <option value="dialog">{{ i18n.ts.dialog }}</option>
- </MkRadios>
- <MkInfo v-if="announcement.display === 'dialog'" warn>{{ i18n.ts._announcement.dialogAnnouncementUxWarn }}</MkInfo>
- <MkSwitch v-model="announcement.forExistingUsers" :helpText="i18n.ts._announcement.forExistingUsersDescription">
- {{ i18n.ts._announcement.forExistingUsers }}
- </MkSwitch>
- <MkSwitch v-model="announcement.silence" :helpText="i18n.ts._announcement.silenceDescription">
- {{ i18n.ts._announcement.silence }}
- </MkSwitch>
- <MkSwitch v-model="announcement.needConfirmationToRead" :helpText="i18n.ts._announcement.needConfirmationToReadDescription">
- {{ i18n.ts._announcement.needConfirmationToRead }}
- </MkSwitch>
- <p v-if="announcement.reads">{{ i18n.tsx.nUsersRead({ n: announcement.reads }) }}</p>
- <div class="buttons _buttons">
- <MkButton class="button" inline primary @click="save(announcement)"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton>
- <MkButton v-if="announcement.id != null" class="button" inline @click="archive(announcement)"><i class="ti ti-check"></i> {{ i18n.ts._announcement.end }} ({{ i18n.ts.archive }})</MkButton>
- <MkButton v-if="announcement.id != null" class="button" inline danger @click="del(announcement)"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton>
+ <MkLoading v-if="loading"/>
+
+ <template v-else>
+ <MkFolder v-for="announcement in announcements" :key="announcement.id ?? announcement._id" :defaultOpen="announcement.id == null">
+ <template #label>{{ announcement.title }}</template>
+ <template #icon>
+ <i v-if="announcement.icon === 'info'" class="ti ti-info-circle"></i>
+ <i v-else-if="announcement.icon === 'warning'" class="ti ti-alert-triangle" style="color: var(--warn);"></i>
+ <i v-else-if="announcement.icon === 'error'" class="ti ti-circle-x" style="color: var(--error);"></i>
+ <i v-else-if="announcement.icon === 'success'" class="ti ti-check" style="color: var(--success);"></i>
+ </template>
+ <template #caption>{{ announcement.text }}</template>
+
+ <div class="_gaps_m">
+ <MkInput v-model="announcement.title">
+ <template #label>{{ i18n.ts.title }}</template>
+ </MkInput>
+ <MkTextarea v-model="announcement.text" mfmAutocomplete :mfmPreview="true">
+ <template #label>{{ i18n.ts.text }}</template>
+ </MkTextarea>
+ <MkInput v-model="announcement.imageUrl" type="url">
+ <template #label>{{ i18n.ts.imageUrl }}</template>
+ </MkInput>
+ <MkRadios v-model="announcement.icon">
+ <template #label>{{ i18n.ts.icon }}</template>
+ <option value="info"><i class="ti ti-info-circle"></i></option>
+ <option value="warning"><i class="ti ti-alert-triangle" style="color: var(--warn);"></i></option>
+ <option value="error"><i class="ti ti-circle-x" style="color: var(--error);"></i></option>
+ <option value="success"><i class="ti ti-check" style="color: var(--success);"></i></option>
+ </MkRadios>
+ <MkRadios v-model="announcement.display">
+ <template #label>{{ i18n.ts.display }}</template>
+ <option value="normal">{{ i18n.ts.normal }}</option>
+ <option value="banner">{{ i18n.ts.banner }}</option>
+ <option value="dialog">{{ i18n.ts.dialog }}</option>
+ </MkRadios>
+ <MkInfo v-if="announcement.display === 'dialog'" warn>{{ i18n.ts._announcement.dialogAnnouncementUxWarn }}</MkInfo>
+ <MkSwitch v-model="announcement.forExistingUsers" :helpText="i18n.ts._announcement.forExistingUsersDescription">
+ {{ i18n.ts._announcement.forExistingUsers }}
+ </MkSwitch>
+ <MkSwitch v-model="announcement.silence" :helpText="i18n.ts._announcement.silenceDescription">
+ {{ i18n.ts._announcement.silence }}
+ </MkSwitch>
+ <MkSwitch v-model="announcement.needConfirmationToRead" :helpText="i18n.ts._announcement.needConfirmationToReadDescription">
+ {{ i18n.ts._announcement.needConfirmationToRead }}
+ </MkSwitch>
+ <p v-if="announcement.reads">{{ i18n.tsx.nUsersRead({ n: announcement.reads }) }}</p>
+ <div class="buttons _buttons">
+ <MkButton class="button" inline primary @click="save(announcement)"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton>
+ <MkButton v-if="announcement.id != null && announcement.isActive" class="button" inline @click="archive(announcement)"><i class="ti ti-check"></i> {{ i18n.ts._announcement.end }} ({{ i18n.ts.archive }})</MkButton>
+ <MkButton v-if="announcement.id != null && !announcement.isActive" class="button" inline @click="unarchive(announcement)"><i class="ti ti-restore"></i> {{ i18n.ts.unarchive }}</MkButton>
+ <MkButton v-if="announcement.id != null" class="button" inline danger @click="del(announcement)"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton>
+ </div>
</div>
- </div>
- </MkFolder>
- <MkButton class="button" @click="more()">
- <i class="ti ti-reload"></i>{{ i18n.ts.more }}
- </MkButton>
+ </MkFolder>
+ <MkLoading v-if="loadingMore"/>
+ <MkButton class="button" @click="more()">
+ <i class="ti ti-reload"></i>{{ i18n.ts.more }}
+ </MkButton>
+ </template>
</div>
</MkSpacer>
</MkStickyContainer>
</template>
<script lang="ts" setup>
-import { ref, computed } from 'vue';
+import { ref, computed, watch } from 'vue';
import XHeader from './_header_.vue';
import MkButton from '@/components/MkButton.vue';
import MkInput from '@/components/MkInput.vue';
+import MkSelect from '@/components/MkSelect.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import MkRadios from '@/components/MkRadios.vue';
import MkInfo from '@/components/MkInfo.vue';
@@ -85,11 +98,22 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
import MkFolder from '@/components/MkFolder.vue';
import MkTextarea from '@/components/MkTextarea.vue';
+const announcementsStatus = ref<'active' | 'archived'>('active');
+
+const loading = ref(true);
+const loadingMore = ref(false);
+
const announcements = ref<any[]>([]);
-misskeyApi('admin/announcements/list').then(announcementResponse => {
- announcements.value = announcementResponse;
-});
+watch(announcementsStatus, (to) => {
+ loading.value = true;
+ misskeyApi('admin/announcements/list', {
+ status: to,
+ }).then(announcementResponse => {
+ announcements.value = announcementResponse;
+ loading.value = false;
+ });
+}, { immediate: true });
function add() {
announcements.value.unshift({
@@ -125,6 +149,14 @@ async function archive(announcement) {
refresh();
}
+async function unarchive(announcement) {
+ await os.apiWithDialog('admin/announcements/update', {
+ ...announcement,
+ isActive: true,
+ });
+ refresh();
+}
+
async function save(announcement) {
if (announcement.id == null) {
await os.apiWithDialog('admin/announcements/create', announcement);
@@ -135,24 +167,32 @@ async function save(announcement) {
}
function more() {
- misskeyApi('admin/announcements/list', { untilId: announcements.value.reduce((acc, announcement) => announcement.id != null ? announcement : acc).id }).then(announcementResponse => {
+ loadingMore.value = true;
+ misskeyApi('admin/announcements/list', {
+ status: announcementsStatus.value,
+ untilId: announcements.value.reduce((acc, announcement) => announcement.id != null ? announcement : acc).id
+ }).then(announcementResponse => {
announcements.value = announcements.value.concat(announcementResponse);
+ loadingMore.value = false;
});
}
function refresh() {
- misskeyApi('admin/announcements/list').then(announcementResponse => {
+ loading.value = true;
+ misskeyApi('admin/announcements/list', {
+ status: announcementsStatus.value,
+ }).then(announcementResponse => {
announcements.value = announcementResponse;
+ loading.value = false;
});
}
-refresh();
-
const headerActions = computed(() => [{
asFullButton: true,
icon: 'ti ti-plus',
text: i18n.ts.add,
handler: add,
+ disabled: announcementsStatus.value === 'archived',
}]);
const headerTabs = computed(() => []);
diff --git a/packages/frontend/src/pages/admin/federation.vue b/packages/frontend/src/pages/admin/federation.vue
index 0aaa398584..debf684c9b 100644
--- a/packages/frontend/src/pages/admin/federation.vue
+++ b/packages/frontend/src/pages/admin/federation.vue
@@ -80,9 +80,9 @@ const pagination = {
sort: sort.value,
host: host.value !== '' ? host.value : null,
...(
- state.value === 'federating' ? { federating: true } :
- state.value === 'subscribing' ? { subscribing: true } :
- state.value === 'publishing' ? { publishing: true } :
+ state.value === 'federating' ? { federating: true, suspended: false, blocked: false } :
+ state.value === 'subscribing' ? { subscribing: true, suspended: false, blocked: false } :
+ state.value === 'publishing' ? { publishing: true, suspended: false, blocked: false } :
state.value === 'suspended' ? { suspended: true } :
state.value === 'blocked' ? { blocked: true } :
state.value === 'silenced' ? { silenced: true } :
diff --git a/packages/frontend/src/pages/admin/index.vue b/packages/frontend/src/pages/admin/index.vue
index 794feae202..292f10da1a 100644
--- a/packages/frontend/src/pages/admin/index.vue
+++ b/packages/frontend/src/pages/admin/index.vue
@@ -215,6 +215,11 @@ const menuDef = computed(() => [{
to: '/admin/external-services',
active: currentPage.value?.route.name === 'external-services',
}, {
+ icon: 'ti ti-webhook',
+ text: 'Webhook',
+ to: '/admin/system-webhook',
+ active: currentPage.value?.route.name === 'system-webhook',
+ }, {
icon: 'ti ti-adjustments',
text: i18n.ts.other,
to: '/admin/other-settings',
diff --git a/packages/frontend/src/pages/admin/instance-block.vue b/packages/frontend/src/pages/admin/instance-block.vue
index 6b14bd42c2..e090616b26 100644
--- a/packages/frontend/src/pages/admin/instance-block.vue
+++ b/packages/frontend/src/pages/admin/instance-block.vue
@@ -8,14 +8,22 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #header><XHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="32">
<FormSuspense :p="init">
- <MkTextarea v-if="tab === 'block'" v-model="blockedHosts">
- <span>{{ i18n.ts.blockedInstances }}</span>
- <template #caption>{{ i18n.ts.blockedInstancesDescription }}</template>
- </MkTextarea>
- <MkTextarea v-else-if="tab === 'silence'" v-model="silencedHosts" class="_formBlock">
- <span>{{ i18n.ts.silencedInstances }}</span>
- <template #caption>{{ i18n.ts.silencedInstancesDescription }}</template>
- </MkTextarea>
+ <template v-if="tab === 'block'">
+ <MkTextarea v-model="blockedHosts">
+ <span>{{ i18n.ts.blockedInstances }}</span>
+ <template #caption>{{ i18n.ts.blockedInstancesDescription }}</template>
+ </MkTextarea>
+ </template>
+ <template v-else-if="tab === 'silence'">
+ <MkTextarea v-model="silencedHosts" class="_formBlock">
+ <span>{{ i18n.ts.silencedInstances }}</span>
+ <template #caption>{{ i18n.ts.silencedInstancesDescription }}</template>
+ </MkTextarea>
+ <MkTextarea v-model="mediaSilencedHosts" class="_formBlock">
+ <span>{{ i18n.ts.mediaSilencedInstances }}</span>
+ <template #caption>{{ i18n.ts.mediaSilencedInstancesDescription }}</template>
+ </MkTextarea>
+ </template>
<MkButton primary @click="save"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton>
</FormSuspense>
</MkSpacer>
@@ -36,18 +44,21 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
const blockedHosts = ref<string>('');
const silencedHosts = ref<string>('');
+const mediaSilencedHosts = ref<string>('');
const tab = ref('block');
async function init() {
const meta = await misskeyApi('admin/meta');
blockedHosts.value = meta.blockedHosts.join('\n');
silencedHosts.value = meta.silencedHosts.join('\n');
+ mediaSilencedHosts.value = meta.mediaSilencedHosts.join('\n');
}
function save() {
os.apiWithDialog('admin/update-meta', {
blockedHosts: blockedHosts.value.split('\n') || [],
silencedHosts: silencedHosts.value.split('\n') || [],
+ mediaSilencedHosts: mediaSilencedHosts.value.split('\n') || [],
}).then(() => {
fetchInstance(true);
diff --git a/packages/frontend/src/pages/admin/invites.vue b/packages/frontend/src/pages/admin/invites.vue
index 95727fb14c..9cb430b0fe 100644
--- a/packages/frontend/src/pages/admin/invites.vue
+++ b/packages/frontend/src/pages/admin/invites.vue
@@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkInput v-if="!noExpirationDate" v-model="expiresAt" type="datetime-local">
<template #label>{{ i18n.ts.expirationDate }}</template>
</MkInput>
- <MkInput v-model="createCount" type="number">
+ <MkInput v-model="createCount" type="number" min="1">
<template #label>{{ i18n.ts.createCount }}</template>
</MkInput>
<MkButton primary rounded @click="createWithOptions">{{ i18n.ts.create }}</MkButton>
diff --git a/packages/frontend/src/pages/admin/modlog.ModLog.vue b/packages/frontend/src/pages/admin/modlog.ModLog.vue
index e33c882721..91f1c7c5e6 100644
--- a/packages/frontend/src/pages/admin/modlog.ModLog.vue
+++ b/packages/frontend/src/pages/admin/modlog.ModLog.vue
@@ -8,9 +8,35 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #label>
<b
:class="{
- [$style.logGreen]: ['createRole', 'addCustomEmoji', 'createGlobalAnnouncement', 'createUserAnnouncement', 'createAd', 'createInvitation', 'createAvatarDecoration'].includes(log.type),
- [$style.logYellow]: ['markSensitiveDriveFile', 'resetPassword'].includes(log.type),
- [$style.logRed]: ['suspend', 'deleteRole', 'suspendRemoteInstance', 'deleteGlobalAnnouncement', 'deleteUserAnnouncement', 'deleteCustomEmoji', 'deleteNote', 'deleteDriveFile', 'deleteAd', 'deleteAvatarDecoration'].includes(log.type)
+ [$style.logGreen]: [
+ 'createRole',
+ 'addCustomEmoji',
+ 'createGlobalAnnouncement',
+ 'createUserAnnouncement',
+ 'createAd',
+ 'createInvitation',
+ 'createAvatarDecoration',
+ 'createSystemWebhook',
+ 'createAbuseReportNotificationRecipient',
+ ].includes(log.type),
+ [$style.logYellow]: [
+ 'markSensitiveDriveFile',
+ 'resetPassword'
+ ].includes(log.type),
+ [$style.logRed]: [
+ 'suspend',
+ 'deleteRole',
+ 'suspendRemoteInstance',
+ 'deleteGlobalAnnouncement',
+ 'deleteUserAnnouncement',
+ 'deleteCustomEmoji',
+ 'deleteNote',
+ 'deleteDriveFile',
+ 'deleteAd',
+ 'deleteAvatarDecoration',
+ 'deleteSystemWebhook',
+ 'deleteAbuseReportNotificationRecipient',
+ ].includes(log.type)
}"
>{{ i18n.ts._moderationLogTypes[log.type] }}</b>
<span v-if="log.type === 'updateUserNote'">: @{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }}</span>
@@ -40,6 +66,12 @@ SPDX-License-Identifier: AGPL-3.0-only
<span v-else-if="log.type === 'createAvatarDecoration'">: {{ log.info.avatarDecoration.name }}</span>
<span v-else-if="log.type === 'updateAvatarDecoration'">: {{ log.info.before.name }}</span>
<span v-else-if="log.type === 'deleteAvatarDecoration'">: {{ log.info.avatarDecoration.name }}</span>
+ <span v-else-if="log.type === 'createSystemWebhook'">: {{ log.info.webhook.name }}</span>
+ <span v-else-if="log.type === 'updateSystemWebhook'">: {{ log.info.before.name }}</span>
+ <span v-else-if="log.type === 'deleteSystemWebhook'">: {{ log.info.webhook.name }}</span>
+ <span v-else-if="log.type === 'createAbuseReportNotificationRecipient'">: {{ log.info.recipient.name }}</span>
+ <span v-else-if="log.type === 'updateAbuseReportNotificationRecipient'">: {{ log.info.before.name }}</span>
+ <span v-else-if="log.type === 'deleteAbuseReportNotificationRecipient'">: {{ log.info.recipient.name }}</span>
</template>
<template #icon>
<MkAvatar :user="log.user" :class="$style.avatar"/>
@@ -116,6 +148,16 @@ SPDX-License-Identifier: AGPL-3.0-only
<CodeDiff :context="5" :hideHeader="true" :oldString="log.info.before ?? ''" :newString="log.info.after ?? ''" maxHeight="300px"/>
</div>
</template>
+ <template v-else-if="log.type === 'updateSystemWebhook'">
+ <div :class="$style.diff">
+ <CodeDiff :context="5" :hideHeader="true" :oldString="JSON5.stringify(log.info.before, null, '\t')" :newString="JSON5.stringify(log.info.after, null, '\t')" language="javascript" maxHeight="300px"/>
+ </div>
+ </template>
+ <template v-else-if="log.type === 'updateAbuseReportNotificationRecipient'">
+ <div :class="$style.diff">
+ <CodeDiff :context="5" :hideHeader="true" :oldString="JSON5.stringify(log.info.before, null, '\t')" :newString="JSON5.stringify(log.info.after, null, '\t')" language="javascript" maxHeight="300px"/>
+ </div>
+ </template>
<details>
<summary>raw</summary>
diff --git a/packages/frontend/src/pages/admin/roles.editor.vue b/packages/frontend/src/pages/admin/roles.editor.vue
index eb8a59b34f..3e948abdf1 100644
--- a/packages/frontend/src/pages/admin/roles.editor.vue
+++ b/packages/frontend/src/pages/admin/roles.editor.vue
@@ -378,6 +378,26 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
</MkFolder>
+ <MkFolder v-if="matchQuery([i18n.ts._role._options.canUpdateBioMedia, 'canUpdateBioMedia'])">
+ <template #label>{{ i18n.ts._role._options.canUpdateBioMedia }}</template>
+ <template #suffix>
+ <span v-if="role.policies.canUpdateBioMedia.useDefault" :class="$style.useDefaultLabel">{{ i18n.ts._role.useBaseValue }}</span>
+ <span v-else>{{ role.policies.canUpdateBioMedia.value ? i18n.ts.yes : i18n.ts.no }}</span>
+ <span :class="$style.priorityIndicator"><i :class="getPriorityIcon(role.policies.canUpdateBioMedia)"></i></span>
+ </template>
+ <div class="_gaps">
+ <MkSwitch v-model="role.policies.canUpdateBioMedia.useDefault" :readonly="readonly">
+ <template #label>{{ i18n.ts._role.useBaseValue }}</template>
+ </MkSwitch>
+ <MkSwitch v-model="role.policies.canUpdateBioMedia.value" :disabled="role.policies.canUpdateBioMedia.useDefault" :readonly="readonly">
+ <template #label>{{ i18n.ts.enable }}</template>
+ </MkSwitch>
+ <MkRange v-model="role.policies.canUpdateBioMedia.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
+ <template #label>{{ i18n.ts._role.priority }}</template>
+ </MkRange>
+ </div>
+ </MkFolder>
+
<MkFolder v-if="matchQuery([i18n.ts._role._options.pinMax, 'pinLimit'])">
<template #label>{{ i18n.ts._role._options.pinMax }}</template>
<template #suffix>
diff --git a/packages/frontend/src/pages/admin/roles.vue b/packages/frontend/src/pages/admin/roles.vue
index 9753d9f6cb..6fb950494b 100644
--- a/packages/frontend/src/pages/admin/roles.vue
+++ b/packages/frontend/src/pages/admin/roles.vue
@@ -134,6 +134,14 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkSwitch>
</MkFolder>
+ <MkFolder v-if="matchQuery([i18n.ts._role._options.canUpdateBioMedia, 'canUpdateBioMedia'])">
+ <template #label>{{ i18n.ts._role._options.canUpdateBioMedia }}</template>
+ <template #suffix>{{ policies.canUpdateBioMedia ? i18n.ts.yes : i18n.ts.no }}</template>
+ <MkSwitch v-model="policies.canUpdateBioMedia">
+ <template #label>{{ i18n.ts.enable }}</template>
+ </MkSwitch>
+ </MkFolder>
+
<MkFolder v-if="matchQuery([i18n.ts._role._options.pinMax, 'pinLimit'])">
<template #label>{{ i18n.ts._role._options.pinMax }}</template>
<template #suffix>{{ policies.pinLimit }}</template>
@@ -243,7 +251,7 @@ import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
-import { instance } from '@/instance.js';
+import { instance, fetchInstance } from '@/instance.js';
import MkFoldableSection from '@/components/MkFoldableSection.vue';
import { ROLE_POLICIES } from '@/const.js';
import { useRouter } from '@/router/supplier.js';
@@ -267,6 +275,7 @@ async function updateBaseRole() {
await os.apiWithDialog('admin/roles/update-default-policies', {
policies,
});
+ fetchInstance(true);
}
function create() {
diff --git a/packages/frontend/src/pages/admin/system-webhook.item.vue b/packages/frontend/src/pages/admin/system-webhook.item.vue
new file mode 100644
index 0000000000..0c07122af3
--- /dev/null
+++ b/packages/frontend/src/pages/admin/system-webhook.item.vue
@@ -0,0 +1,117 @@
+<!--
+SPDX-FileCopyrightText: syuilo and misskey-project
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
+<template>
+<div :class="$style.main">
+ <span :class="$style.icon">
+ <i v-if="!entity.isActive" class="ti ti-player-pause"/>
+ <i v-else-if="entity.latestStatus === null" class="ti ti-circle"/>
+ <i
+ v-else-if="[200, 201, 204].includes(entity.latestStatus)"
+ class="ti ti-check"
+ :style="{ color: 'var(--success)' }"
+ />
+ <i v-else class="ti ti-alert-triangle" :style="{ color: 'var(--error)' }"/>
+ </span>
+ <span :class="$style.text">{{ entity.name || entity.url }}</span>
+ <span :class="$style.suffix">
+ <MkTime v-if="entity.latestSentAt" :time="entity.latestSentAt" style="margin-right: 8px"/>
+ <button :class="$style.suffixButton" @click="onEditClick">
+ <i class="ti ti-settings"></i>
+ </button>
+ <button :class="$style.suffixButton" @click="onDeleteClick">
+ <i class="ti ti-trash"></i>
+ </button>
+ </span>
+</div>
+</template>
+
+<script lang="ts" setup>
+import { entities } from 'misskey-js';
+import { toRefs } from 'vue';
+
+const emit = defineEmits<{
+ (ev: 'edit', value: entities.SystemWebhook): void;
+ (ev: 'delete', value: entities.SystemWebhook): void;
+}>();
+
+const props = defineProps<{
+ entity: entities.SystemWebhook;
+}>();
+
+const { entity } = toRefs(props);
+
+function onEditClick() {
+ emit('edit', entity.value);
+}
+
+function onDeleteClick() {
+ emit('delete', entity.value);
+}
+
+</script>
+
+<style module lang="scss">
+.main {
+ display: flex;
+ align-items: center;
+ width: 100%;
+ box-sizing: border-box;
+ padding: 10px 14px;
+ background: var(--buttonBg);
+ border: none;
+ border-radius: 6px;
+ font-size: 0.9em;
+
+ &:hover {
+ text-decoration: none;
+ background: var(--buttonHoverBg);
+ }
+
+ &.active {
+ color: var(--accent);
+ background: var(--buttonHoverBg);
+ }
+}
+
+.icon {
+ margin-right: 0.75em;
+ flex-shrink: 0;
+ text-align: center;
+ color: var(--fgTransparentWeak);
+}
+
+.text {
+ flex-shrink: 1;
+ white-space: normal;
+ padding-right: 12px;
+ text-align: center;
+}
+
+.suffix {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ gaps: 4px;
+ margin-left: auto;
+ margin-right: -8px;
+ opacity: 0.7;
+ white-space: nowrap;
+}
+
+.suffixButton {
+ background: transparent;
+ border: none;
+ border-radius: 9999px;
+ margin-top: -8px;
+ margin-bottom: -8px;
+ padding: 8px;
+
+ &:hover {
+ background: var(--buttonBg);
+ }
+}
+</style>
diff --git a/packages/frontend/src/pages/admin/system-webhook.vue b/packages/frontend/src/pages/admin/system-webhook.vue
new file mode 100644
index 0000000000..7a40eec944
--- /dev/null
+++ b/packages/frontend/src/pages/admin/system-webhook.vue
@@ -0,0 +1,96 @@
+<!--
+SPDX-FileCopyrightText: syuilo and misskey-project
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
+<template>
+<MkStickyContainer>
+ <template #header>
+ <XHeader :actions="headerActions" :tabs="headerTabs"/>
+ </template>
+
+ <MkSpacer :contentMax="900">
+ <div class="_gaps_m">
+ <MkButton :class="$style.linkButton" full @click="onCreateWebhookClicked">
+ {{ i18n.ts._webhookSettings.createWebhook }}
+ </MkButton>
+
+ <FormSection>
+ <div class="_gaps">
+ <XItem v-for="item in webhooks" :key="item.id" :entity="item" @edit="onEditButtonClicked" @delete="onDeleteButtonClicked"/>
+ </div>
+ </FormSection>
+ </div>
+ </MkSpacer>
+</MkStickyContainer>
+</template>
+
+<script lang="ts" setup>
+import { computed, onMounted, ref } from 'vue';
+import { entities } from 'misskey-js';
+import XItem from './system-webhook.item.vue';
+import FormSection from '@/components/form/section.vue';
+import { definePageMetadata } from '@/scripts/page-metadata.js';
+import { i18n } from '@/i18n.js';
+import XHeader from '@/pages/admin/_header_.vue';
+import MkButton from '@/components/MkButton.vue';
+import { misskeyApi } from '@/scripts/misskey-api.js';
+import { showSystemWebhookEditorDialog } from '@/components/MkSystemWebhookEditor.impl.js';
+import * as os from '@/os.js';
+
+const webhooks = ref<entities.SystemWebhook[]>([]);
+
+const headerActions = computed(() => []);
+const headerTabs = computed(() => []);
+
+async function onCreateWebhookClicked() {
+ await showSystemWebhookEditorDialog({
+ mode: 'create',
+ });
+
+ await fetchWebhooks();
+}
+
+async function onEditButtonClicked(webhook: entities.SystemWebhook) {
+ await showSystemWebhookEditorDialog({
+ mode: 'edit',
+ id: webhook.id,
+ });
+
+ await fetchWebhooks();
+}
+
+async function onDeleteButtonClicked(webhook: entities.SystemWebhook) {
+ const result = await os.confirm({
+ type: 'warning',
+ title: i18n.ts._webhookSettings.deleteConfirm,
+ });
+ if (!result.canceled) {
+ await misskeyApi('admin/system-webhook/delete', {
+ id: webhook.id,
+ });
+ await fetchWebhooks();
+ }
+}
+
+async function fetchWebhooks() {
+ const result = await misskeyApi('admin/system-webhook/list', {});
+ webhooks.value = result.sort((a, b) => a.id.localeCompare(b.id));
+}
+
+onMounted(async () => {
+ await fetchWebhooks();
+});
+
+definePageMetadata(() => ({
+ title: 'SystemWebhook',
+ icon: 'ti ti-webhook',
+}));
+</script>
+
+<style module lang="scss">
+.linkButton {
+ text-align: left;
+ padding: 10px 18px;
+}
+</style>
diff --git a/packages/frontend/src/pages/announcement.vue b/packages/frontend/src/pages/announcement.vue
index 85ae9062d4..802a6bf399 100644
--- a/packages/frontend/src/pages/announcement.vue
+++ b/packages/frontend/src/pages/announcement.vue
@@ -109,6 +109,15 @@ definePageMetadata(() => ({
</script>
<style lang="scss" module>
+.fadeEnterActive,
+.fadeLeaveActive {
+ transition: opacity 0.125s ease;
+}
+.fadeEnterFrom,
+.fadeLeaveTo {
+ opacity: 0;
+}
+
.announcement {
padding: 16px;
}
diff --git a/packages/frontend/src/pages/antenna-timeline.vue b/packages/frontend/src/pages/antenna-timeline.vue
index 273250d1d0..ea64e457e3 100644
--- a/packages/frontend/src/pages/antenna-timeline.vue
+++ b/packages/frontend/src/pages/antenna-timeline.vue
@@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkStickyContainer>
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="800">
- <div ref="rootEl" v-hotkey.global="keymap">
+ <div ref="rootEl">
<div v-if="queue > 0" :class="$style.new"><button class="_buttonPrimary" :class="$style.newButton" @click="top()">{{ i18n.ts.newNoteRecived }}</button></div>
<div :class="$style.tl">
<MkTimeline
@@ -44,9 +44,6 @@ const antenna = ref<Misskey.entities.Antenna | null>(null);
const queue = ref(0);
const rootEl = shallowRef<HTMLElement>();
const tlEl = shallowRef<InstanceType<typeof MkTimeline>>();
-const keymap = computed(() => ({
- 't': focus,
-}));
function queueUpdated(q) {
queue.value = q;
diff --git a/packages/frontend/src/pages/channel.vue b/packages/frontend/src/pages/channel.vue
index a895df76e8..3c3ff08aee 100644
--- a/packages/frontend/src/pages/channel.vue
+++ b/packages/frontend/src/pages/channel.vue
@@ -93,7 +93,7 @@ import MkFoldableSection from '@/components/MkFoldableSection.vue';
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
import { PageHeaderItem } from '@/types/page-header.js';
import { isSupportShare } from '@/scripts/navigator.js';
-import copyToClipboard from '@/scripts/copy-to-clipboard.js';
+import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
import { miLocalStorage } from '@/local-storage.js';
import { useRouter } from '@/router/supplier.js';
diff --git a/packages/frontend/src/pages/clip.vue b/packages/frontend/src/pages/clip.vue
index fd64a55c65..fb984de368 100644
--- a/packages/frontend/src/pages/clip.vue
+++ b/packages/frontend/src/pages/clip.vue
@@ -43,7 +43,7 @@ import { url } from '@/config.js';
import MkButton from '@/components/MkButton.vue';
import { clipsCache } from '@/cache.js';
import { isSupportShare } from '@/scripts/navigator.js';
-import copyToClipboard from '@/scripts/copy-to-clipboard.js';
+import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
const props = defineProps<{
clipId: string,
diff --git a/packages/frontend/src/pages/contact.vue b/packages/frontend/src/pages/contact.vue
index bcdcf43275..1f2bee5a77 100644
--- a/packages/frontend/src/pages/contact.vue
+++ b/packages/frontend/src/pages/contact.vue
@@ -7,18 +7,26 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkStickyContainer>
<template #header><MkPageHeader/></template>
<MkSpacer :contentMax="600" :marginMin="20">
- <div class="_gaps">
- <MkKeyValue>
- <template #key>{{ i18n.ts.inquiry }}</template>
+ <div class="_gaps_m">
+ <MkKeyValue :copy="instance.maintainerName">
+ <template #key>{{ i18n.ts.administrator }}</template>
<template #value>
- <MkLink :url="instance.inquiryUrl" target="_blank">{{ instance.inquiryUrl }}</MkLink>
+ <template v-if="instance.maintainerName">{{ instance.maintainerName }}</template>
+ <span v-else style="opacity: 0.7;">({{ i18n.ts.none }})</span>
</template>
</MkKeyValue>
-
- <MkKeyValue>
- <template #key>{{ i18n.ts.email }}</template>
+ <MkKeyValue :copy="instance.maintainerEmail">
+ <template #key>{{ i18n.ts.contact }}</template>
+ <template #value>
+ <template v-if="instance.maintainerEmail">{{ instance.maintainerEmail }}</template>
+ <span v-else style="opacity: 0.7;">({{ i18n.ts.none }})</span>
+ </template>
+ </MkKeyValue>
+ <MkKeyValue :copy="instance.inquiryUrl">
+ <template #key>{{ i18n.ts.inquiry }}</template>
<template #value>
- <div>{{ instance.maintainerEmail }}</div>
+ <MkLink v-if="instance.inquiryUrl" :url="instance.inquiryUrl" target="_blank">{{ instance.inquiryUrl }}</MkLink>
+ <span v-else style="opacity: 0.7;">({{ i18n.ts.none }})</span>
</template>
</MkKeyValue>
</div>
@@ -28,8 +36,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { i18n } from '@/i18n.js';
-import { definePageMetadata } from '@/scripts/page-metadata.js';
import { instance } from '@/instance.js';
+import { definePageMetadata } from '@/scripts/page-metadata.js';
import MkKeyValue from '@/components/MkKeyValue.vue';
import MkLink from '@/components/MkLink.vue';
diff --git a/packages/frontend/src/pages/custom-emojis-manager.vue b/packages/frontend/src/pages/custom-emojis-manager.vue
index 3e2332e408..eea3f68130 100644
--- a/packages/frontend/src/pages/custom-emojis-manager.vue
+++ b/packages/frontend/src/pages/custom-emojis-manager.vue
@@ -129,18 +129,19 @@ const toggleSelect = (emoji) => {
};
const add = async (ev: MouseEvent) => {
- os.popup(defineAsyncComponent(() => import('./emoji-edit-dialog.vue')), {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('./emoji-edit-dialog.vue')), {
}, {
done: result => {
if (result.created) {
emojisPaginationComponent.value.prepend(result.created);
}
},
- }, 'closed');
+ closed: () => dispose(),
+ });
};
const edit = (emoji) => {
- os.popup(defineAsyncComponent(() => import('./emoji-edit-dialog.vue')), {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('./emoji-edit-dialog.vue')), {
emoji: emoji,
}, {
done: result => {
@@ -153,7 +154,8 @@ const edit = (emoji) => {
emojisPaginationComponent.value.removeItem(emoji.id);
}
},
- }, 'closed');
+ closed: () => dispose(),
+ });
};
const importEmoji = (emoji) => {
diff --git a/packages/frontend/src/pages/drive.file.info.vue b/packages/frontend/src/pages/drive.file.info.vue
index 8077edff5f..3026d00a2c 100644
--- a/packages/frontend/src/pages/drive.file.info.vue
+++ b/packages/frontend/src/pages/drive.file.info.vue
@@ -37,11 +37,17 @@ SPDX-License-Identifier: AGPL-3.0-only
</button>
</div>
</div>
- <div>
- <button class="_button" :class="$style.fileAltEditBtn" @click="describe()">
+ <div class="_gaps_s">
+ <button class="_button" :class="$style.kvEditBtn" @click="move()">
+ <MkKeyValue>
+ <template #key>{{ i18n.ts.folder }}</template>
+ <template #value>{{ folderHierarchy.join(' > ') }}<i class="ti ti-pencil" :class="$style.kvEditIcon"></i></template>
+ </MkKeyValue>
+ </button>
+ <button class="_button" :class="$style.kvEditBtn" @click="describe()">
<MkKeyValue>
<template #key>{{ i18n.ts.description }}</template>
- <template #value>{{ file.comment ? file.comment : `(${i18n.ts.none})` }}<i class="ti ti-pencil" :class="$style.fileAltEditIcon"></i></template>
+ <template #value>{{ file.comment ? file.comment : `(${i18n.ts.none})` }}<i class="ti ti-pencil" :class="$style.kvEditIcon"></i></template>
</MkKeyValue>
</button>
<MkKeyValue :class="$style.fileMetaDataChildren">
@@ -90,6 +96,18 @@ const props = defineProps<{
const fetching = ref(true);
const file = ref<Misskey.entities.DriveFile>();
+const folderHierarchy = computed(() => {
+ if (!file.value) return [i18n.ts.drive];
+ const folderNames = [i18n.ts.drive];
+
+ function get(folder: Misskey.entities.DriveFolder) {
+ if (folder.parent) get(folder.parent);
+ folderNames.push(folder.name);
+ }
+
+ if (file.value.folder) get(file.value.folder);
+ return folderNames;
+});
const isImage = computed(() => file.value?.type.startsWith('image/'));
async function fetch() {
@@ -122,6 +140,19 @@ function crop() {
});
}
+function move() {
+ if (!file.value) return;
+
+ os.selectDriveFolder(false).then(folder => {
+ misskeyApi('drive/files/update', {
+ fileId: file.value.id,
+ folderId: folder[0] ? folder[0].id : null,
+ }).then(async () => {
+ await fetch();
+ });
+ });
+}
+
function toggleSensitive() {
if (!file.value) return;
@@ -160,7 +191,7 @@ function rename() {
function describe() {
if (!file.value) return;
- os.popup(defineAsyncComponent(() => import('@/components/MkFileCaptionEditWindow.vue')), {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkFileCaptionEditWindow.vue')), {
default: file.value.comment ?? '',
file: file.value,
}, {
@@ -172,7 +203,8 @@ function describe() {
await fetch();
});
},
- }, 'closed');
+ closed: () => dispose(),
+ });
}
async function deleteFile() {
@@ -233,6 +265,7 @@ onMounted(async () => {
background-color: var(--accentedBg);
color: var(--accent);
text-decoration: none;
+ outline: none;
}
&.danger {
@@ -280,14 +313,14 @@ onMounted(async () => {
padding: .5rem 1rem;
}
-.fileAltEditBtn {
+.kvEditBtn {
text-align: start;
display: block;
width: 100%;
padding: .5rem 1rem;
border-radius: var(--radius);
- .fileAltEditIcon {
+ .kvEditIcon {
display: inline-block;
color: transparent;
visibility: hidden;
@@ -298,7 +331,7 @@ onMounted(async () => {
color: var(--accent);
background-color: var(--accentedBg);
- .fileAltEditIcon {
+ .kvEditIcon {
color: var(--accent);
visibility: visible;
}
diff --git a/packages/frontend/src/pages/drop-and-fusion.game.vue b/packages/frontend/src/pages/drop-and-fusion.game.vue
index eba5b92154..0f0b7e1ea8 100644
--- a/packages/frontend/src/pages/drop-and-fusion.game.vue
+++ b/packages/frontend/src/pages/drop-and-fusion.game.vue
@@ -210,7 +210,7 @@ import { apiUrl } from '@/config.js';
import { $i } from '@/account.js';
import * as sound from '@/scripts/sound.js';
import MkRange from '@/components/MkRange.vue';
-import copyToClipboard from '@/scripts/copy-to-clipboard.js';
+import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
type FrontendMonoDefinition = {
id: string;
@@ -1008,8 +1008,18 @@ function attachGameEvents() {
const domX = rect.left + (x * viewScale);
const domY = rect.top + (y * viewScale);
const scoreUnit = getScoreUnit(props.gameMode);
- os.popup(MkRippleEffect, { x: domX, y: domY }, {}, 'end');
- os.popup(MkPlusOneEffect, { x: domX, y: domY, value: scoreDelta + (scoreUnit === 'pt' ? '' : scoreUnit) }, {}, 'end');
+
+ {
+ const { dispose } = os.popup(MkRippleEffect, { x: domX, y: domY }, {
+ end: () => dispose(),
+ });
+ }
+
+ {
+ const { dispose } = os.popup(MkPlusOneEffect, { x: domX, y: domY, value: scoreDelta + (scoreUnit === 'pt' ? '' : scoreUnit) }, {
+ end: () => dispose(),
+ });
+ }
if (nextMono) {
const def = monoDefinitions.value.find(x => x.id === nextMono.id)!;
diff --git a/packages/frontend/src/pages/emoji-edit-dialog.vue b/packages/frontend/src/pages/emoji-edit-dialog.vue
index 16769ef360..853c1d6b0b 100644
--- a/packages/frontend/src/pages/emoji-edit-dialog.vue
+++ b/packages/frontend/src/pages/emoji-edit-dialog.vue
@@ -15,8 +15,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<template v-if="emoji" #header>:{{ emoji.name }}:</template>
<template v-else #header>New emoji</template>
- <div>
- <MkSpacer :marginMin="20" :marginMax="28">
+ <div style="display: flex; flex-direction: column; min-height: 100%;">
+ <MkSpacer :marginMin="20" :marginMax="28" style="flex-grow: 1;">
<div class="_gaps_m">
<div v-if="imgUrl != null" :class="$style.imgs">
<div style="background: #000;" :class="$style.imgContainer">
@@ -239,10 +239,12 @@ async function del() {
.footer {
position: sticky;
+ z-index: 10000;
bottom: 0;
left: 0;
padding: 12px;
border-top: solid 0.5px var(--divider);
+ background: var(--acrylicBg);
-webkit-backdrop-filter: var(--blur, blur(15px));
backdrop-filter: var(--blur, blur(15px));
}
diff --git a/packages/frontend/src/pages/emojis.emoji.vue b/packages/frontend/src/pages/emojis.emoji.vue
index 5301a08521..97429c29a4 100644
--- a/packages/frontend/src/pages/emojis.emoji.vue
+++ b/packages/frontend/src/pages/emojis.emoji.vue
@@ -14,10 +14,10 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import * as os from '@/os.js';
import * as Misskey from 'misskey-js';
+import * as os from '@/os.js';
import { misskeyApiGet } from '@/scripts/misskey-api.js';
-import copyToClipboard from '@/scripts/copy-to-clipboard.js';
+import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
import { i18n } from '@/i18n.js';
import MkCustomEmojiDetailedDialog from '@/components/MkCustomEmojiDetailedDialog.vue';
@@ -40,12 +40,12 @@ function menu(ev) {
text: i18n.ts.info,
icon: 'ti ti-info-circle',
action: async () => {
- os.popup(MkCustomEmojiDetailedDialog, {
+ const { dispose } = os.popup(MkCustomEmojiDetailedDialog, {
emoji: await misskeyApiGet('emoji', {
name: props.emoji.name,
- })
+ }),
}, {
- anchor: ev.target,
+ closed: () => dispose(),
});
},
}], ev.currentTarget ?? ev.target);
diff --git a/packages/frontend/src/pages/flash/flash-edit.vue b/packages/frontend/src/pages/flash/flash-edit.vue
index 3445da26a2..0b9f4dfe58 100644
--- a/packages/frontend/src/pages/flash/flash-edit.vue
+++ b/packages/frontend/src/pages/flash/flash-edit.vue
@@ -37,6 +37,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { computed, ref } from 'vue';
import * as Misskey from 'misskey-js';
+import { AISCRIPT_VERSION } from '@syuilo/aiscript';
import MkButton from '@/components/MkButton.vue';
import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
@@ -48,7 +49,7 @@ import MkInput from '@/components/MkInput.vue';
import MkSelect from '@/components/MkSelect.vue';
import { useRouter } from '@/router/supplier.js';
-const PRESET_DEFAULT = `/// @ 0.18.0
+const PRESET_DEFAULT = `/// @ ${AISCRIPT_VERSION}
var name = ""
@@ -66,7 +67,7 @@ Ui:render([
])
`;
-const PRESET_OMIKUJI = `/// @ 0.18.0
+const PRESET_OMIKUJI = `/// @ ${AISCRIPT_VERSION}
// ユーザーã”ã¨ã«æ—¥æ›¿ã‚りã®ãŠã¿ãã˜ã®ãƒ—リセット
// é¸æŠžè‚¢
@@ -109,7 +110,7 @@ Ui:render([
])
`;
-const PRESET_SHUFFLE = `/// @ 0.18.0
+const PRESET_SHUFFLE = `/// @ ${AISCRIPT_VERSION}
// å·»ãæˆ»ã—å¯èƒ½ãªæ–‡å­—シャッフルã®ãƒ—リセット
let string = "ペペロンãƒãƒ¼ãƒŽ"
@@ -188,7 +189,7 @@ var cursor = 0
do()
`;
-const PRESET_QUIZ = `/// @ 0.18.0
+const PRESET_QUIZ = `/// @ ${AISCRIPT_VERSION}
let title = '地ç†ã‚¯ã‚¤ã‚º'
let qas = [{
@@ -301,7 +302,7 @@ qaEls.push(Ui:C:container({
Ui:render(qaEls)
`;
-const PRESET_TIMELINE = `/// @ 0.18.0
+const PRESET_TIMELINE = `/// @ ${AISCRIPT_VERSION}
// APIリクエストを行ã„ローカルタイムラインを表示ã™ã‚‹ãƒ—リセット
@fetch() {
diff --git a/packages/frontend/src/pages/flash/flash.vue b/packages/frontend/src/pages/flash/flash.vue
index 40499fde0e..020463a133 100644
--- a/packages/frontend/src/pages/flash/flash.vue
+++ b/packages/frontend/src/pages/flash/flash.vue
@@ -78,7 +78,8 @@ import MkCode from '@/components/MkCode.vue';
import { defaultStore } from '@/store.js';
import { $i } from '@/account.js';
import { isSupportShare } from '@/scripts/navigator.js';
-import copyToClipboard from '@/scripts/copy-to-clipboard.js';
+import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
+import { pleaseLogin } from '@/scripts/please-login.js';
const props = defineProps<{
id: string;
@@ -143,6 +144,7 @@ function shareWithNote() {
function like() {
if (!flash.value) return;
+ pleaseLogin();
os.apiWithDialog('flash/like', {
flashId: flash.value.id,
@@ -154,6 +156,7 @@ function like() {
async function unlike() {
if (!flash.value) return;
+ pleaseLogin();
const confirm = await os.confirm({
type: 'warning',
diff --git a/packages/frontend/src/pages/follow.vue b/packages/frontend/src/pages/follow.vue
deleted file mode 100644
index 247b0ac639..0000000000
--- a/packages/frontend/src/pages/follow.vue
+++ /dev/null
@@ -1,71 +0,0 @@
-<!--
-SPDX-FileCopyrightText: syuilo and misskey-project
-SPDX-License-Identifier: AGPL-3.0-only
--->
-
-<template>
-<div>
-</div>
-</template>
-
-<script lang="ts" setup>
-import { } from 'vue';
-import * as Misskey from 'misskey-js';
-import * as os from '@/os.js';
-import { misskeyApi } from '@/scripts/misskey-api.js';
-import { i18n } from '@/i18n.js';
-import { defaultStore } from '@/store.js';
-import { mainRouter } from '@/router/main.js';
-
-async function follow(user): Promise<void> {
- const { canceled } = await os.confirm({
- type: 'question',
- text: i18n.tsx.followConfirm({ name: user.name || user.username }),
- });
-
- if (canceled) {
- window.close();
- return;
- }
-
- os.apiWithDialog('following/create', {
- userId: user.id,
- withReplies: defaultStore.state.defaultWithReplies,
- });
- user.withReplies = defaultStore.state.defaultWithReplies;
-}
-
-const acct = new URL(location.href).searchParams.get('acct');
-if (acct == null) {
- throw new Error('acct required');
-}
-
-let promise;
-
-if (acct.startsWith('https://')) {
- promise = misskeyApi('ap/show', {
- uri: acct,
- });
- promise.then(res => {
- if (res.type === 'User') {
- follow(res.object);
- } else if (res.type === 'Note') {
- mainRouter.push(`/notes/${res.object.id}`);
- } else {
- os.alert({
- type: 'error',
- text: 'Not a user',
- }).then(() => {
- window.close();
- });
- }
- });
-} else {
- promise = misskeyApi('users/show', Misskey.acct.parse(acct));
- promise.then(user => {
- follow(user);
- });
-}
-
-os.promiseDialog(promise, null, null, i18n.ts.fetchingAsApObject);
-</script>
diff --git a/packages/frontend/src/pages/gallery/post.vue b/packages/frontend/src/pages/gallery/post.vue
index 615675225d..fc2b5f810c 100644
--- a/packages/frontend/src/pages/gallery/post.vue
+++ b/packages/frontend/src/pages/gallery/post.vue
@@ -77,7 +77,7 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
import { defaultStore } from '@/store.js';
import { $i } from '@/account.js';
import { isSupportShare } from '@/scripts/navigator.js';
-import copyToClipboard from '@/scripts/copy-to-clipboard.js';
+import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
import { useRouter } from '@/router/supplier.js';
const router = useRouter();
diff --git a/packages/frontend/src/pages/games.vue b/packages/frontend/src/pages/games.vue
index afd6df1ad9..b52f4decaa 100644
--- a/packages/frontend/src/pages/games.vue
+++ b/packages/frontend/src/pages/games.vue
@@ -8,12 +8,12 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #header><MkPageHeader/></template>
<MkSpacer :contentMax="800">
<div class="_gaps">
- <div class="_panel">
+ <div class="_panel" :class="$style.link">
<MkA to="/bubble-game">
<img src="/client-assets/drop-and-fusion/logo.png" style="display: block; max-width: 100%; max-height: 200px; margin: auto;"/>
</MkA>
</div>
- <div class="_panel">
+ <div class="_panel" :class="$style.link">
<MkA to="/reversi">
<img src="/client-assets/reversi/logo.png" style="display: block; max-width: 100%; max-height: 200px; margin: auto;"/>
</MkA>
@@ -32,3 +32,10 @@ definePageMetadata(() => ({
icon: 'ti ti-device-gamepad',
}));
</script>
+
+<style module>
+.link:focus-within {
+ outline: 2px solid var(--focus);
+ outline-offset: -2px;
+}
+</style>
diff --git a/packages/frontend/src/pages/instance-info.vue b/packages/frontend/src/pages/instance-info.vue
index 26797ba85e..4ba428d536 100644
--- a/packages/frontend/src/pages/instance-info.vue
+++ b/packages/frontend/src/pages/instance-info.vue
@@ -47,6 +47,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkButton v-if="suspensionState !== 'none'" :disabled="!instance" @click="resumeDelivery">{{ i18n.ts._delivery.resume }}</MkButton>
<MkSwitch v-model="isBlocked" :disabled="!meta || !instance" @update:modelValue="toggleBlock">{{ i18n.ts.blockThisInstance }}</MkSwitch>
<MkSwitch v-model="isSilenced" :disabled="!meta || !instance" @update:modelValue="toggleSilenced">{{ i18n.ts.silenceThisInstance }}</MkSwitch>
+ <MkSwitch v-model="isMediaSilenced" :disabled="!meta || !instance" @update:modelValue="toggleMediaSilenced">{{ i18n.ts.mediaSilenceThisInstance }}</MkSwitch>
<MkButton @click="refreshMetadata"><i class="ti ti-refresh"></i> Refresh metadata</MkButton>
<MkTextarea v-model="moderationNote" manualSave>
<template #label>{{ i18n.ts.moderationNote }}</template>
@@ -167,6 +168,7 @@ const instance = ref<Misskey.entities.FederationInstance | null>(null);
const suspensionState = ref<'none' | 'manuallySuspended' | 'goneSuspended' | 'autoSuspendedForNotResponding'>('none');
const isBlocked = ref(false);
const isSilenced = ref(false);
+const isMediaSilenced = ref(false);
const faviconUrl = ref<string | null>(null);
const moderationNote = ref('');
@@ -195,8 +197,9 @@ async function fetch(): Promise<void> {
suspensionState.value = instance.value?.suspensionState ?? 'none';
isBlocked.value = instance.value?.isBlocked ?? false;
isSilenced.value = instance.value?.isSilenced ?? false;
+ isMediaSilenced.value = instance.value?.isMediaSilenced ?? false;
faviconUrl.value = getProxiedImageUrlNullable(instance.value?.faviconUrl, 'preview') ?? getProxiedImageUrlNullable(instance.value?.iconUrl, 'preview');
- moderationNote.value = instance.value?.moderationNote;
+ moderationNote.value = instance.value?.moderationNote ?? '';
}
async function toggleBlock(): Promise<void> {
@@ -218,6 +221,16 @@ async function toggleSilenced(): Promise<void> {
});
}
+async function toggleMediaSilenced(): Promise<void> {
+ if (!meta.value) throw new Error('No meta?');
+ if (!instance.value) throw new Error('No instance?');
+ const { host } = instance.value;
+ const mediaSilencedHosts = meta.value.mediaSilencedHosts ?? [];
+ await misskeyApi('admin/update-meta', {
+ mediaSilencedHosts: isMediaSilenced.value ? mediaSilencedHosts.concat([host]) : mediaSilencedHosts.filter(x => x !== host),
+ });
+}
+
async function stopDelivery(): Promise<void> {
if (!instance.value) throw new Error('No instance?');
suspensionState.value = 'manuallySuspended';
diff --git a/packages/frontend/src/pages/lookup.vue b/packages/frontend/src/pages/lookup.vue
new file mode 100644
index 0000000000..3233953942
--- /dev/null
+++ b/packages/frontend/src/pages/lookup.vue
@@ -0,0 +1,97 @@
+<!--
+SPDX-FileCopyrightText: syuilo and other misskey contributors
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
+<template>
+<MkStickyContainer>
+ <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
+ <MkSpacer :contentMax="800">
+ <div v-if="state === 'done'" class="_buttonsCenter">
+ <MkButton @click="close">{{ i18n.ts.close }}</MkButton>
+ <MkButton @click="goToMisskey">{{ i18n.ts.goToMisskey }}</MkButton>
+ </div>
+ <div v-else class="_fullInfo">
+ <MkLoading/>
+ </div>
+ </MkSpacer>
+</MkStickyContainer>
+</template>
+
+<script lang="ts" setup>
+import { computed, ref } from 'vue';
+import * as Misskey from 'misskey-js';
+import * as os from '@/os.js';
+import { misskeyApi } from '@/scripts/misskey-api.js';
+import { i18n } from '@/i18n.js';
+import { definePageMetadata } from '@/scripts/page-metadata.js';
+import { mainRouter } from '@/router/main.js';
+import MkButton from '@/components/MkButton.vue';
+
+const state = ref<'fetching' | 'done'>('fetching');
+
+function fetch() {
+ const params = new URL(location.href).searchParams;
+
+ // acctã®ã»ã†ã¯deprecated
+ let uri = params.get('uri') ?? params.get('acct');
+ if (uri == null) {
+ state.value = 'done';
+ return;
+ }
+
+ let promise: Promise<any>;
+
+ if (uri.startsWith('https://')) {
+ promise = misskeyApi('ap/show', {
+ uri,
+ });
+ promise.then(res => {
+ if (res.type === 'User') {
+ mainRouter.replace(res.object.host ? `/@${res.object.username}@${res.object.host}` : `/@${res.object.username}`);
+ } else if (res.type === 'Note') {
+ mainRouter.replace(`/notes/${res.object.id}`);
+ } else {
+ os.alert({
+ type: 'error',
+ text: 'Not a user',
+ });
+ }
+ });
+ } else {
+ if (uri.startsWith('acct:')) {
+ uri = uri.slice(5);
+ }
+ promise = misskeyApi('users/show', Misskey.acct.parse(uri));
+ promise.then(user => {
+ mainRouter.replace(user.host ? `/@${user.username}@${user.host}` : `/@${user.username}`);
+ });
+ }
+
+ os.promiseDialog(promise, null, null, i18n.ts.fetchingAsApObject);
+}
+
+function close(): void {
+ window.close();
+
+ // é–‰ã˜ãªã‘れã°100ms後タイムラインã«
+ window.setTimeout(() => {
+ location.href = '/';
+ }, 100);
+}
+
+function goToMisskey(): void {
+ location.href = '/';
+}
+
+fetch();
+
+const headerActions = computed(() => []);
+
+const headerTabs = computed(() => []);
+
+definePageMetadata({
+ title: i18n.ts.lookup,
+ icon: 'ti ti-world-search',
+});
+</script>
diff --git a/packages/frontend/src/pages/my-antennas/create.vue b/packages/frontend/src/pages/my-antennas/create.vue
index 2d026d2fa9..2b8518747f 100644
--- a/packages/frontend/src/pages/my-antennas/create.vue
+++ b/packages/frontend/src/pages/my-antennas/create.vue
@@ -4,43 +4,33 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
-<div>
- <XAntenna :antenna="draft" @created="onAntennaCreated"/>
-</div>
+<MkStickyContainer>
+ <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
+
+ <MkAntennaEditor @created="onAntennaCreated"/>
+</MkStickyContainer>
</template>
<script lang="ts" setup>
-import { ref } from 'vue';
-import XAntenna from './editor.vue';
+import { computed } from 'vue';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { antennasCache } from '@/cache.js';
import { useRouter } from '@/router/supplier.js';
+import MkAntennaEditor from '@/components/MkAntennaEditor.vue';
const router = useRouter();
-const draft = ref({
- name: '',
- src: 'all',
- userListId: null,
- users: [],
- keywords: [],
- excludeKeywords: [],
- excludeBots: false,
- withReplies: false,
- caseSensitive: false,
- localOnly: false,
- withFile: false,
- notify: false,
-});
-
function onAntennaCreated() {
antennasCache.delete();
router.push('/my/antennas');
}
+const headerActions = computed(() => []);
+const headerTabs = computed(() => []);
+
definePageMetadata(() => ({
- title: i18n.ts.manageAntennas,
+ title: i18n.ts.createAntenna,
icon: 'ti ti-antenna',
}));
</script>
diff --git a/packages/frontend/src/pages/my-antennas/edit.vue b/packages/frontend/src/pages/my-antennas/edit.vue
index 9471be8575..9f927cd1a0 100644
--- a/packages/frontend/src/pages/my-antennas/edit.vue
+++ b/packages/frontend/src/pages/my-antennas/edit.vue
@@ -4,15 +4,17 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
-<div class="">
- <XAntenna v-if="antenna" :antenna="antenna" @updated="onAntennaUpdated"/>
-</div>
+<MkStickyContainer>
+ <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
+
+ <MkAntennaEditor v-if="antenna" :antenna="antenna" @updated="onAntennaUpdated"/>
+</MkStickyContainer>
</template>
<script lang="ts" setup>
-import { ref } from 'vue';
+import { ref, computed } from 'vue';
import * as Misskey from 'misskey-js';
-import XAntenna from './editor.vue';
+import MkAntennaEditor from '@/components/MkAntennaEditor.vue';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
@@ -36,8 +38,11 @@ misskeyApi('antennas/show', { antennaId: props.antennaId }).then((antennaRespons
antenna.value = antennaResponse;
});
+const headerActions = computed(() => []);
+const headerTabs = computed(() => []);
+
definePageMetadata(() => ({
- title: i18n.ts.manageAntennas,
+ title: i18n.ts.editAntenna,
icon: 'ti ti-antenna',
}));
</script>
diff --git a/packages/frontend/src/pages/my-clips/index.vue b/packages/frontend/src/pages/my-clips/index.vue
index 1a0d7177fc..ece998a7a5 100644
--- a/packages/frontend/src/pages/my-clips/index.vue
+++ b/packages/frontend/src/pages/my-clips/index.vue
@@ -12,7 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkButton primary rounded class="add" @click="create"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton>
<MkPagination v-slot="{ items }" ref="pagingComponent" :pagination="pagination" class="_gaps">
- <MkClipPreview v-for="item in items" :key="item.id" :clip="item"/>
+ <MkClipPreview v-for="item in items" :key="item.id" :clip="item" :noUserInfo="true"/>
</MkPagination>
</div>
<div v-else-if="tab === 'favorites'" key="favorites" class="_gaps">
diff --git a/packages/frontend/src/pages/my-lists/list.vue b/packages/frontend/src/pages/my-lists/list.vue
index 7492b099ea..a2ceb222fe 100644
--- a/packages/frontend/src/pages/my-lists/list.vue
+++ b/packages/frontend/src/pages/my-lists/list.vue
@@ -133,22 +133,25 @@ async function removeUser(item, ev) {
}
async function showMembershipMenu(item, ev) {
+ const withRepliesRef = ref(item.withReplies);
os.popupMenu([{
- text: item.withReplies ? i18n.ts.hideRepliesToOthersInTimeline : i18n.ts.showRepliesToOthersInTimeline,
- icon: item.withReplies ? 'ti ti-messages-off' : 'ti ti-messages',
- action: async () => {
- misskeyApi('users/lists/update-membership', {
- listId: list.value.id,
- userId: item.userId,
- withReplies: !item.withReplies,
- }).then(() => {
- paginationEl.value.updateItem(item.id, (old) => ({
- ...old,
- withReplies: !item.withReplies,
- }));
- });
- },
+ type: 'switch',
+ text: i18n.ts.showRepliesToOthersInTimeline,
+ icon: 'ti ti-messages',
+ ref: withRepliesRef,
}], ev.currentTarget ?? ev.target);
+ watch(withRepliesRef, withReplies => {
+ misskeyApi('users/lists/update-membership', {
+ listId: list.value!.id,
+ userId: item.userId,
+ withReplies,
+ }).then(() => {
+ paginationEl.value!.updateItem(item.id, (old) => ({
+ ...old,
+ withReplies,
+ }));
+ });
+ });
}
async function deleteList() {
diff --git a/packages/frontend/src/pages/page.vue b/packages/frontend/src/pages/page.vue
index e73d032000..20b776aaa2 100644
--- a/packages/frontend/src/pages/page.vue
+++ b/packages/frontend/src/pages/page.vue
@@ -125,7 +125,7 @@ import { $i } from '@/account.js';
import { isSupportShare } from '@/scripts/navigator.js';
import { instance } from '@/instance.js';
import { getStaticImageUrl } from '@/scripts/media-proxy.js';
-import copyToClipboard from '@/scripts/copy-to-clipboard.js';
+import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
const props = defineProps<{
pageName: string;
@@ -286,6 +286,7 @@ definePageMetadata(() => ({
background-color: var(--accentedBg);
color: var(--accent);
text-decoration: none;
+ outline: none;
}
}
diff --git a/packages/frontend/src/pages/preview.vue b/packages/frontend/src/pages/preview.vue
new file mode 100644
index 0000000000..8e07b190aa
--- /dev/null
+++ b/packages/frontend/src/pages/preview.vue
@@ -0,0 +1,26 @@
+<!--
+SPDX-FileCopyrightText: syuilo and misskey-project
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
+<template>
+<div>
+ <MkSample/>
+</div>
+</template>
+
+<script lang="ts" setup>
+import { computed } from 'vue';
+import MkSample from '@/components/MkPreview.vue';
+import { i18n } from '@/i18n.js';
+import { definePageMetadata } from '@/scripts/page-metadata.js';
+
+const headerActions = computed(() => []);
+
+const headerTabs = computed(() => []);
+
+definePageMetadata(computed(() => ({
+ title: i18n.ts.preview,
+ icon: 'ti ti-eye',
+})));
+</script>
diff --git a/packages/frontend/src/pages/reset-password.vue b/packages/frontend/src/pages/reset-password.vue
index 6b67a9cc87..6d24029535 100644
--- a/packages/frontend/src/pages/reset-password.vue
+++ b/packages/frontend/src/pages/reset-password.vue
@@ -44,7 +44,9 @@ async function save() {
onMounted(() => {
if (props.token == null) {
- os.popup(defineAsyncComponent(() => import('@/components/MkForgotPassword.vue')), {}, {}, 'closed');
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkForgotPassword.vue')), {}, {
+ closed: () => dispose(),
+ });
mainRouter.push('/');
}
});
diff --git a/packages/frontend/src/pages/reversi/game.board.vue b/packages/frontend/src/pages/reversi/game.board.vue
index 175ea62411..7d9cefa5c9 100644
--- a/packages/frontend/src/pages/reversi/game.board.vue
+++ b/packages/frontend/src/pages/reversi/game.board.vue
@@ -169,7 +169,7 @@ const props = defineProps<{
const showBoardLabels = ref<boolean>(false);
const useAvatarAsStone = ref<boolean>(true);
const autoplaying = ref<boolean>(false);
-// eslint-disable-next-line vue/no-setup-props-destructure
+// eslint-disable-next-line vue/no-setup-props-reactivity-loss
const game = ref<Misskey.entities.ReversiGameDetailed & { logs: Reversi.Serializer.SerializedLog[] }>(deepClone(props.game));
const logPos = ref<number>(game.value.logs.length);
const engine = shallowRef<Reversi.Game>(Reversi.Serializer.restoreGame({
diff --git a/packages/frontend/src/pages/reversi/game.vue b/packages/frontend/src/pages/reversi/game.vue
index eadc51881c..97a793753d 100644
--- a/packages/frontend/src/pages/reversi/game.vue
+++ b/packages/frontend/src/pages/reversi/game.vue
@@ -20,6 +20,7 @@ import { useStream } from '@/stream.js';
import { signinRequired } from '@/account.js';
import { useRouter } from '@/router/supplier.js';
import * as os from '@/os.js';
+import { url } from '@/config.js';
import { i18n } from '@/i18n.js';
import { useInterval } from '@/scripts/use-interval.js';
@@ -44,7 +45,7 @@ function start(_game: Misskey.entities.ReversiGameDetailed) {
if (shareWhenStart.value) {
misskeyApi('notes/create', {
- text: i18n.ts._reversi.iStartedAGame + '\n' + location.href,
+ text: `${i18n.ts._reversi.iStartedAGame}\n${url}/reversi/g/${props.gameId}`,
visibility: 'home',
});
}
diff --git a/packages/frontend/src/pages/search.note.vue b/packages/frontend/src/pages/search.note.vue
index d68bbaeeca..9cf7fbe8d8 100644
--- a/packages/frontend/src/pages/search.note.vue
+++ b/packages/frontend/src/pages/search.note.vue
@@ -6,29 +6,38 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<div class="_gaps">
<div class="_gaps">
- <MkInput v-model="searchQuery" :large="true" :autofocus="true" type="search" @enter="search">
+ <MkInput v-model="searchQuery" :large="true" :autofocus="true" type="search" @enter.prevent="search">
<template #prefix><i class="ti ti-search"></i></template>
</MkInput>
- <MkFolder>
- <template #label>{{ i18n.ts.options }}</template>
+ <MkFoldableSection :expanded="true">
+ <template #header>{{ i18n.ts.options }}</template>
<div class="_gaps_m">
- <MkSwitch v-model="isLocalOnly">{{ i18n.ts.localOnly }}</MkSwitch>
+ <MkRadios v-model="hostSelect">
+ <template #label>{{ i18n.ts.host }}</template>
+ <option value="all" default>{{ i18n.ts.all }}</option>
+ <option value="local">{{ i18n.ts.local }}</option>
+ <option v-if="noteSearchableScope === 'global'" value="specified">{{ i18n.ts.specifyHost }}</option>
+ </MkRadios>
+ <MkInput v-if="noteSearchableScope === 'global'" v-model="hostInput" :disabled="hostSelect !== 'specified'" :large="true" type="search">
+ <template #prefix><i class="ti ti-server"></i></template>
+ </MkInput>
<MkFolder :defaultOpen="true">
<template #label>{{ i18n.ts.specifyUser }}</template>
- <template v-if="user" #suffix>@{{ user.username }}</template>
+ <template v-if="user" #suffix>@{{ user.username }}{{ user.host ? `@${user.host}` : "" }}</template>
- <div style="text-align: center;" class="_gaps">
- <div v-if="user">@{{ user.username }}</div>
- <div>
- <MkButton v-if="user == null" primary rounded inline @click="selectUser">{{ i18n.ts.selectUser }}</MkButton>
- <MkButton v-else danger rounded inline @click="user = null">{{ i18n.ts.remove }}</MkButton>
+ <div class="_gaps">
+ <div :class="$style.userItem">
+ <MkUserCardMini v-if="user" :class="$style.userCard" :user="user" :withChart="false"/>
+ <MkButton v-if="user == null && $i != null" transparent :class="$style.addMeButton" @click="selectSelf"><div :class="$style.addUserButtonInner"><span><i class="ti ti-plus"></i><i class="ti ti-user"></i></span><span>{{ i18n.ts.selectSelf }}</span></div></MkButton>
+ <MkButton v-if="user == null" transparent :class="$style.addUserButton" @click="selectUser"><div :class="$style.addUserButtonInner"><i class="ti ti-plus"></i><span>{{ i18n.ts.selectUser }}</span></div></MkButton>
+ <button class="_button" :class="$style.remove" :disabled="user == null" @click="removeUser"><i class="ti ti-x"></i></button>
</div>
</div>
</MkFolder>
</div>
- </MkFolder>
+ </MkFoldableSection>
<div>
<MkButton large primary gradate rounded style="margin: 0 auto;" @click="search">{{ i18n.ts.search }}</MkButton>
</div>
@@ -42,54 +51,145 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { ref } from 'vue';
+import { computed, ref, toRef, watch } from 'vue';
+import type { UserDetailed } from 'misskey-js/entities.js';
+import type { Paging } from '@/components/MkPagination.vue';
import MkNotes from '@/components/MkNotes.vue';
import MkInput from '@/components/MkInput.vue';
import MkButton from '@/components/MkButton.vue';
-import MkSwitch from '@/components/MkSwitch.vue';
import { i18n } from '@/i18n.js';
import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import MkFoldableSection from '@/components/MkFoldableSection.vue';
import MkFolder from '@/components/MkFolder.vue';
import { useRouter } from '@/router/supplier.js';
+import MkUserCardMini from '@/components/MkUserCardMini.vue';
+import MkRadios from '@/components/MkRadios.vue';
+import { $i } from '@/account.js';
+import { instance } from '@/instance.js';
-const router = useRouter();
+const props = withDefaults(defineProps<{
+ query?: string;
+ userId?: string;
+ username?: string;
+ host?: string | null;
+}>(), {
+ query: '',
+ userId: undefined,
+ username: undefined,
+ host: '',
+});
+const router = useRouter();
const key = ref(0);
-const searchQuery = ref('');
-const searchOrigin = ref('combined');
-const notePagination = ref();
-const user = ref<any>(null);
-const isLocalOnly = ref(false);
+const searchQuery = ref(toRef(props, 'query').value);
+const notePagination = ref<Paging>();
+const user = ref<UserDetailed | null>(null);
+const hostInput = ref(toRef(props, 'host').value);
+
+const noteSearchableScope = instance.noteSearchableScope ?? 'local';
+
+const hostSelect = ref<'all' | 'local' | 'specified'>('all');
+
+const setHostSelectWithInput = (after:string|undefined|null, before:string|undefined|null) => {
+ if (before === after) return;
+ if (after === '') hostSelect.value = 'all';
+ else hostSelect.value = 'specified';
+};
+
+setHostSelectWithInput(hostInput.value, undefined);
+
+watch(hostInput, setHostSelectWithInput);
+
+const searchHost = computed(() => {
+ if (hostSelect.value === 'local') return '.';
+ if (hostSelect.value === 'specified') return hostInput.value;
+ return null;
+});
+
+if (props.userId != null) {
+ misskeyApi('users/show', { userId: props.userId }).then(_user => {
+ user.value = _user;
+ });
+} else if (props.username != null) {
+ misskeyApi('users/show', {
+ username: props.username,
+ ...(props.host != null && props.host !== '') ? { host: props.host } : {},
+ }).then(_user => {
+ user.value = _user;
+ });
+}
function selectUser() {
- os.selectUser({ includeSelf: true }).then(_user => {
+ os.selectUser({ includeSelf: true, localOnly: instance.noteSearchableScope === 'local' }).then(_user => {
user.value = _user;
+ hostInput.value = _user.host ?? '';
});
}
+function selectSelf() {
+ user.value = $i as UserDetailed | null;
+ hostInput.value = null;
+}
+
+function removeUser() {
+ user.value = null;
+ hostInput.value = '';
+}
+
async function search() {
const query = searchQuery.value.toString().trim();
if (query == null || query === '') return;
- if (query.startsWith('https://')) {
- const promise = misskeyApi('ap/show', {
- uri: query,
+ //#region AP lookup
+ if (query.startsWith('https://') && !query.includes(' ')) {
+ const confirm = await os.confirm({
+ type: 'info',
+ text: i18n.ts.lookupConfirm,
});
+ if (!confirm.canceled) {
+ const promise = misskeyApi('ap/show', {
+ uri: query,
+ });
+
+ os.promiseDialog(promise, null, null, i18n.ts.fetchingAsApObject);
+
+ const res = await promise;
- os.promiseDialog(promise, null, null, i18n.ts.fetchingAsApObject);
+ if (res.type === 'User') {
+ router.push(`/@${res.object.username}@${res.object.host}`);
+ } else if (res.type === 'Note') {
+ router.push(`/notes/${res.object.id}`);
+ }
- const res = await promise;
+ return;
+ }
+ }
+ //#endregion
- if (res.type === 'User') {
- router.push(`/@${res.object.username}@${res.object.host}`);
- } else if (res.type === 'Note') {
- router.push(`/notes/${res.object.id}`);
+ if (query.length > 1 && !query.includes(' ')) {
+ if (query.startsWith('@')) {
+ const confirm = await os.confirm({
+ type: 'info',
+ text: i18n.ts.lookupConfirm,
+ });
+ if (!confirm.canceled) {
+ router.push(`/${query}`);
+ return;
+ }
}
- return;
+ if (query.startsWith('#')) {
+ const confirm = await os.confirm({
+ type: 'info',
+ text: i18n.ts.openTagPageConfirm,
+ });
+ if (!confirm.canceled) {
+ router.push(`/tags/${encodeURIComponent(query.substring(1))}`);
+ return;
+ }
+ }
}
notePagination.value = {
@@ -98,11 +198,49 @@ async function search() {
params: {
query: searchQuery.value,
userId: user.value ? user.value.id : null,
+ ...(searchHost.value ? { host: searchHost.value } : {}),
},
};
- if (isLocalOnly.value) notePagination.value.params.host = '.';
-
key.value++;
}
</script>
+<style lang="scss" module>
+.userItem {
+ display: flex;
+ justify-content: center;
+}
+.addMeButton {
+ border: 2px dashed var(--fgTransparent);
+ padding: 12px;
+ margin-right: 16px;
+}
+.addUserButton {
+ border: 2px dashed var(--fgTransparent);
+ padding: 12px;
+ flex-grow: 1;
+}
+.addUserButtonInner {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: space-between;
+ min-height: 38px;
+}
+.userCard {
+ flex-grow: 1;
+}
+.remove {
+ width: 32px;
+ height: 32px;
+ align-self: center;
+
+ & > i:before {
+ color: #ff2a2a;
+ }
+
+ &:disabled {
+ opacity: 0;
+ }
+}
+</style>
diff --git a/packages/frontend/src/pages/search.stories.impl.ts b/packages/frontend/src/pages/search.stories.impl.ts
new file mode 100644
index 0000000000..0110a7ab8e
--- /dev/null
+++ b/packages/frontend/src/pages/search.stories.impl.ts
@@ -0,0 +1,88 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { StoryObj } from '@storybook/vue3';
+import { HttpResponse, http } from 'msw';
+import search_ from './search.vue';
+import { userDetailed } from '@/../.storybook/fakes.js';
+import { commonHandlers } from '@/../.storybook/mocks.js';
+
+const localUser = userDetailed('someuserid', 'miskist', null, 'Local Misskey User');
+
+export const Default = {
+ render(args) {
+ return {
+ components: {
+ search_,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ },
+ template: '<search_ v-bind="props" />',
+ };
+ },
+ args: {
+ ignoreNotesSearchAvailable: true,
+ },
+ parameters: {
+ layout: 'fullscreen',
+ msw: {
+ handlers: [
+ ...commonHandlers,
+ http.post('/api/users/show', () => {
+ return HttpResponse.json(userDetailed());
+ }),
+ http.post('/api/users/search', () => {
+ return HttpResponse.json([userDetailed(), localUser]);
+ }),
+ ],
+ },
+ },
+} satisfies StoryObj<typeof search_>;
+
+export const NoteSearchDisabled = {
+ ...Default,
+ args: {},
+} satisfies StoryObj<typeof search_>;
+
+export const WithUsernameLocal = {
+ ...Default,
+
+ args: {
+ ...Default.args,
+ username: localUser.username,
+ host: localUser.host,
+ },
+ parameters: {
+ layout: 'fullscreen',
+ msw: {
+ handlers: [
+ ...commonHandlers,
+ http.post('/api/users/show', () => {
+ return HttpResponse.json(localUser);
+ }),
+ http.post('/api/users/search', () => {
+ return HttpResponse.json([userDetailed(), localUser]);
+ }),
+ ],
+ },
+ },
+} satisfies StoryObj<typeof search_>;
+
+export const WithUserType = {
+ ...Default,
+ args: {
+ type: 'user',
+ },
+} satisfies StoryObj<typeof search_>;
diff --git a/packages/frontend/src/pages/search.user.vue b/packages/frontend/src/pages/search.user.vue
index b9c2704bc7..724fbfdfbd 100644
--- a/packages/frontend/src/pages/search.user.vue
+++ b/packages/frontend/src/pages/search.user.vue
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<div class="_gaps">
<div class="_gaps">
- <MkInput v-model="searchQuery" :large="true" :autofocus="true" type="search" @enter="search">
+ <MkInput v-model="searchQuery" :large="true" :autofocus="true" type="search" @enter.prevent="search">
<template #prefix><i class="ti ti-search"></i></template>
</MkInput>
<MkRadios v-model="searchOrigin" @update:modelValue="search()">
@@ -25,7 +25,9 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { ref } from 'vue';
+import { ref, toRef } from 'vue';
+import type { Endpoints } from 'misskey-js';
+import type { Paging } from '@/components/MkPagination.vue';
import MkUserList from '@/components/MkUserList.vue';
import MkInput from '@/components/MkInput.vue';
import MkRadios from '@/components/MkRadios.vue';
@@ -36,34 +38,74 @@ import MkFoldableSection from '@/components/MkFoldableSection.vue';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { useRouter } from '@/router/supplier.js';
+const props = withDefaults(defineProps<{
+ query?: string,
+ origin?: Endpoints['users/search']['req']['origin'],
+}>(), {
+ query: '',
+ origin: 'combined',
+});
+
const router = useRouter();
const key = ref('');
-const searchQuery = ref('');
-const searchOrigin = ref('combined');
-const userPagination = ref();
+const searchQuery = ref(toRef(props, 'query').value);
+const searchOrigin = ref(toRef(props, 'origin').value);
+const userPagination = ref<Paging>();
async function search() {
const query = searchQuery.value.toString().trim();
if (query == null || query === '') return;
- if (query.startsWith('https://')) {
- const promise = misskeyApi('ap/show', {
- uri: query,
+ //#region AP lookup
+ if (query.startsWith('https://') && !query.includes(' ')) {
+ const confirm = await os.confirm({
+ type: 'info',
+ text: i18n.ts.lookupConfirm,
});
+ if (!confirm.canceled) {
+ const promise = misskeyApi('ap/show', {
+ uri: query,
+ });
+
+ os.promiseDialog(promise, null, null, i18n.ts.fetchingAsApObject);
+
+ const res = await promise;
- os.promiseDialog(promise, null, null, i18n.ts.fetchingAsApObject);
+ if (res.type === 'User') {
+ router.push(`/@${res.object.username}@${res.object.host}`);
+ } else if (res.type === 'Note') {
+ router.push(`/notes/${res.object.id}`);
+ }
- const res = await promise;
+ return;
+ }
+ }
+ //#endregion
- if (res.type === 'User') {
- router.push(`/@${res.object.username}@${res.object.host}`);
- } else if (res.type === 'Note') {
- router.push(`/notes/${res.object.id}`);
+ if (query.length > 1 && !query.includes(' ')) {
+ if (query.startsWith('@')) {
+ const confirm = await os.confirm({
+ type: 'info',
+ text: i18n.ts.lookupConfirm,
+ });
+ if (!confirm.canceled) {
+ router.push(`/${query}`);
+ return;
+ }
}
- return;
+ if (query.startsWith('#')) {
+ const confirm = await os.confirm({
+ type: 'info',
+ text: i18n.ts.openTagPageConfirm,
+ });
+ if (!confirm.canceled) {
+ router.push(`/user-tags/${encodeURIComponent(query.substring(1))}`);
+ return;
+ }
+ }
}
userPagination.value = {
diff --git a/packages/frontend/src/pages/search.vue b/packages/frontend/src/pages/search.vue
index a3dcda77be..38d7548fa8 100644
--- a/packages/frontend/src/pages/search.vue
+++ b/packages/frontend/src/pages/search.vue
@@ -9,8 +9,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs">
<MkSpacer v-if="tab === 'note'" key="note" :contentMax="800">
- <div v-if="notesSearchAvailable">
- <XNote/>
+ <div v-if="notesSearchAvailable || ignoreNotesSearchAvailable">
+ <XNote v-bind="props"/>
</div>
<div v-else>
<MkInfo warn>{{ i18n.ts.notesSearchNotAvailable }}</MkInfo>
@@ -18,27 +18,43 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkSpacer>
<MkSpacer v-else-if="tab === 'user'" key="user" :contentMax="800">
- <XUser/>
+ <XUser v-bind="props"/>
</MkSpacer>
</MkHorizontalSwipe>
</MkStickyContainer>
</template>
<script lang="ts" setup>
-import { computed, defineAsyncComponent, ref } from 'vue';
+import { computed, defineAsyncComponent, ref, toRef } from 'vue';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
-import { $i } from '@/account.js';
-import { instance } from '@/instance.js';
+import { notesSearchAvailable } from '@/scripts/check-permissions.js';
import MkInfo from '@/components/MkInfo.vue';
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
+const props = withDefaults(defineProps<{
+ query?: string,
+ userId?: string,
+ username?: string,
+ host?: string | null,
+ type?: 'note' | 'user',
+ origin?: 'combined' | 'local' | 'remote',
+ // For storybook only
+ ignoreNotesSearchAvailable?: boolean,
+}>(), {
+ query: '',
+ userId: undefined,
+ username: undefined,
+ host: undefined,
+ type: 'note',
+ origin: 'combined',
+ ignoreNotesSearchAvailable: false,
+});
+
const XNote = defineAsyncComponent(() => import('./search.note.vue'));
const XUser = defineAsyncComponent(() => import('./search.user.vue'));
-const tab = ref('note');
-
-const notesSearchAvailable = (($i == null && instance.policies.canSearchNotes) || ($i != null && $i.policies.canSearchNotes));
+const tab = ref(toRef(props, 'type').value);
const headerActions = computed(() => []);
diff --git a/packages/frontend/src/pages/settings/2fa.vue b/packages/frontend/src/pages/settings/2fa.vue
index b7d648c1a4..6a9a1e16e2 100644
--- a/packages/frontend/src/pages/settings/2fa.vue
+++ b/packages/frontend/src/pages/settings/2fa.vue
@@ -108,9 +108,11 @@ async function registerTOTP(): Promise<void> {
token: auth.result.token,
});
- os.popup(defineAsyncComponent(() => import('./2fa.qrdialog.vue')), {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('./2fa.qrdialog.vue')), {
twoFactorData,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
}
async function unregisterTOTP(): Promise<void> {
diff --git a/packages/frontend/src/pages/settings/accounts.vue b/packages/frontend/src/pages/settings/accounts.vue
index 1182346de9..08c9261dcf 100644
--- a/packages/frontend/src/pages/settings/accounts.vue
+++ b/packages/frontend/src/pages/settings/accounts.vue
@@ -74,22 +74,24 @@ async function removeAccount(account) {
}
function addExistingAccount() {
- os.popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), {}, {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), {}, {
done: async res => {
await addAccounts(res.id, res.i);
os.success();
init();
},
- }, 'closed');
+ closed: () => dispose(),
+ });
}
function createAccount() {
- os.popup(defineAsyncComponent(() => import('@/components/MkSignupDialog.vue')), {}, {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkSignupDialog.vue')), {}, {
done: async res => {
await addAccounts(res.id, res.i);
switchAccountWithToken(res.i);
},
- }, 'closed');
+ closed: () => dispose(),
+ });
}
async function switchAccount(account: any) {
diff --git a/packages/frontend/src/pages/settings/api.vue b/packages/frontend/src/pages/settings/api.vue
index d9596b4e45..b35d406a98 100644
--- a/packages/frontend/src/pages/settings/api.vue
+++ b/packages/frontend/src/pages/settings/api.vue
@@ -23,7 +23,7 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
const isDesktop = ref(window.innerWidth >= 1100);
function generateToken() {
- os.popup(defineAsyncComponent(() => import('@/components/MkTokenGenerateWindow.vue')), {}, {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkTokenGenerateWindow.vue')), {}, {
done: async result => {
const { name, permissions } = result;
const { token } = await misskeyApi('miauth/gen-token', {
@@ -38,7 +38,8 @@ function generateToken() {
text: token,
});
},
- }, 'closed');
+ closed: () => dispose(),
+ });
}
const headerActions = computed(() => []);
diff --git a/packages/frontend/src/pages/settings/avatar-decoration.vue b/packages/frontend/src/pages/settings/avatar-decoration.vue
index 3cc911c014..77229d3349 100644
--- a/packages/frontend/src/pages/settings/avatar-decoration.vue
+++ b/packages/frontend/src/pages/settings/avatar-decoration.vue
@@ -67,7 +67,7 @@ misskeyApi('get-avatar-decorations').then(_avatarDecorations => {
});
function openDecoration(avatarDecoration, index?: number) {
- os.popup(defineAsyncComponent(() => import('./avatar-decoration.dialog.vue')), {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('./avatar-decoration.dialog.vue')), {
decoration: avatarDecoration,
usingIndex: index,
}, {
@@ -108,7 +108,8 @@ function openDecoration(avatarDecoration, index?: number) {
});
$i.avatarDecorations = update;
},
- }, 'closed');
+ closed: () => dispose(),
+ });
}
function detachAllDecorations() {
diff --git a/packages/frontend/src/pages/settings/drive-cleaner.vue b/packages/frontend/src/pages/settings/drive-cleaner.vue
index b20774c4ec..8d2946db63 100644
--- a/packages/frontend/src/pages/settings/drive-cleaner.vue
+++ b/packages/frontend/src/pages/settings/drive-cleaner.vue
@@ -48,7 +48,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script setup lang="ts">
-import { computed, ref, watch } from 'vue';
+import { computed, ref, watch, type StyleValue } from 'vue';
import tinycolor from 'tinycolor2';
import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
@@ -102,10 +102,10 @@ function fetchDriveInfo(): void {
});
}
-function genUsageBar(fsize: number): object {
+function genUsageBar(fsize: number): StyleValue {
return {
width: `${fsize / usage.value * 100}%`,
- background: tinycolor({ h: 180 - (fsize / usage.value * 180), s: 0.7, l: 0.5 }),
+ background: tinycolor({ h: 180 - (fsize / usage.value * 180), s: 0.7, l: 0.5 }).toHslString(),
};
}
diff --git a/packages/frontend/src/pages/settings/drive.vue b/packages/frontend/src/pages/settings/drive.vue
index 81a8d474d2..0e66b93f1c 100644
--- a/packages/frontend/src/pages/settings/drive.vue
+++ b/packages/frontend/src/pages/settings/drive.vue
@@ -95,7 +95,7 @@ const meterStyle = computed(() => {
h: 180 - (usage.value / capacity.value * 180),
s: 0.7,
l: 0.5,
- }),
+ }).toHslString(),
};
});
diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue
index cfc63f2a08..94ef3b8485 100644
--- a/packages/frontend/src/pages/settings/general.vue
+++ b/packages/frontend/src/pages/settings/general.vue
@@ -169,6 +169,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkSwitch v-model="disableStreamingTimeline">{{ i18n.ts.disableStreamingTimeline }}</MkSwitch>
<MkSwitch v-model="enableHorizontalSwipe">{{ i18n.ts.enableHorizontalSwipe }}</MkSwitch>
<MkSwitch v-model="alwaysConfirmFollow">{{ i18n.ts.alwaysConfirmFollow }}</MkSwitch>
+ <MkSwitch v-model="confirmWhenRevealingSensitiveMedia">{{ i18n.ts.confirmWhenRevealingSensitiveMedia }}</MkSwitch>
</div>
<MkSelect v-model="serverDisconnectedBehavior">
<template #label>{{ i18n.ts.whenServerDisconnected }}</template>
@@ -176,6 +177,12 @@ SPDX-License-Identifier: AGPL-3.0-only
<option value="dialog">{{ i18n.ts._serverDisconnectedBehavior.dialog }}</option>
<option value="quiet">{{ i18n.ts._serverDisconnectedBehavior.quiet }}</option>
</MkSelect>
+ <MkSelect v-model="contextMenu">
+ <template #label>{{ i18n.ts._contextMenu.title }}</template>
+ <option value="app">{{ i18n.ts._contextMenu.app }}</option>
+ <option value="appWithShift">{{ i18n.ts._contextMenu.appWithShift }}</option>
+ <option value="native">{{ i18n.ts._contextMenu.native }}</option>
+ </MkSelect>
<MkRange v-model="numberOfPageCache" :min="1" :max="10" :step="1" easing>
<template #label>{{ i18n.ts.numberOfPageCache }}</template>
<template #caption>{{ i18n.ts.numberOfPageCacheDescription }}</template>
@@ -315,6 +322,8 @@ const enableSeasonalScreenEffect = computed(defaultStore.makeGetterSetter('enabl
const enableHorizontalSwipe = computed(defaultStore.makeGetterSetter('enableHorizontalSwipe'));
const useNativeUIForVideoAudioPlayer = computed(defaultStore.makeGetterSetter('useNativeUIForVideoAudioPlayer'));
const alwaysConfirmFollow = computed(defaultStore.makeGetterSetter('alwaysConfirmFollow'));
+const confirmWhenRevealingSensitiveMedia = computed(defaultStore.makeGetterSetter('confirmWhenRevealingSensitiveMedia'));
+const contextMenu = computed(defaultStore.makeGetterSetter('contextMenu'));
watch(lang, () => {
miLocalStorage.setItem('lang', lang.value as string);
@@ -357,6 +366,8 @@ watch([
disableStreamingTimeline,
enableSeasonalScreenEffect,
alwaysConfirmFollow,
+ confirmWhenRevealingSensitiveMedia,
+ contextMenu,
], async () => {
await reloadAsk();
});
diff --git a/packages/frontend/src/pages/settings/plugin.vue b/packages/frontend/src/pages/settings/plugin.vue
index 9804454e66..3c3dcfe41e 100644
--- a/packages/frontend/src/pages/settings/plugin.vue
+++ b/packages/frontend/src/pages/settings/plugin.vue
@@ -82,7 +82,7 @@ import MkCode from '@/components/MkCode.vue';
import MkFolder from '@/components/MkFolder.vue';
import MkKeyValue from '@/components/MkKeyValue.vue';
import * as os from '@/os.js';
-import copyToClipboard from '@/scripts/copy-to-clipboard.js';
+import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
import { ColdDeviceStorage } from '@/store.js';
import { unisonReload } from '@/scripts/unison-reload.js';
import { i18n } from '@/i18n.js';
diff --git a/packages/frontend/src/pages/settings/preferences-backups.vue b/packages/frontend/src/pages/settings/preferences-backups.vue
index b6f1043154..dace2cd847 100644
--- a/packages/frontend/src/pages/settings/preferences-backups.vue
+++ b/packages/frontend/src/pages/settings/preferences-backups.vue
@@ -113,8 +113,6 @@ const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [
'sound_note',
'sound_noteMy',
'sound_notification',
- 'sound_antenna',
- 'sound_channel',
];
const coldDeviceStorageSaveKeys: (keyof typeof ColdDeviceStorage.default)[] = [
'lightTheme',
diff --git a/packages/frontend/src/pages/settings/profile.vue b/packages/frontend/src/pages/settings/profile.vue
index 60bf9b4d3d..a328933686 100644
--- a/packages/frontend/src/pages/settings/profile.vue
+++ b/packages/frontend/src/pages/settings/profile.vue
@@ -342,6 +342,7 @@ definePageMetadata(() => ({
&:hover, &:focus {
opacity: .7;
}
+
&:active {
cursor: pointer;
}
diff --git a/packages/frontend/src/pages/settings/sounds.sound.vue b/packages/frontend/src/pages/settings/sounds.sound.vue
index 113abd708b..81478fede5 100644
--- a/packages/frontend/src/pages/settings/sounds.sound.vue
+++ b/packages/frontend/src/pages/settings/sounds.sound.vue
@@ -9,7 +9,13 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #label>{{ i18n.ts.sound }}</template>
<option v-for="x in soundsTypes" :key="x ?? 'null'" :value="x">{{ getSoundTypeName(x) }}</option>
</MkSelect>
- <div v-if="type === '_driveFile_'" :class="$style.fileSelectorRoot">
+ <div v-if="type === '_driveFile_' && driveFileError === true" :class="$style.fileSelectorRoot">
+ <MkButton :class="$style.fileSelectorButton" inline rounded primary @click="selectSound">{{ i18n.ts.selectFile }}</MkButton>
+ <div :class="$style.fileErrorRoot">
+ <MkCondensedLine>{{ i18n.ts._soundSettings.driveFileError }}</MkCondensedLine>
+ </div>
+ </div>
+ <div v-else-if="type === '_driveFile_'" :class="$style.fileSelectorRoot">
<MkButton :class="$style.fileSelectorButton" inline rounded primary @click="selectSound">{{ i18n.ts.selectFile }}</MkButton>
<div :class="['_nowrap', !fileUrl && $style.fileNotSelected]">{{ friendlyFileName }}</div>
</div>
@@ -19,13 +25,13 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_buttons">
<MkButton inline @click="listen"><i class="ti ti-player-play"></i> {{ i18n.ts.listen }}</MkButton>
- <MkButton inline primary @click="save"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton>
+ <MkButton inline primary :disabled="!hasChanged || driveFileError" @click="save"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton>
</div>
</div>
</template>
<script lang="ts" setup>
-import { ref, computed } from 'vue';
+import { ref, computed, watch } from 'vue';
import type { SoundType } from '@/scripts/sound.js';
import MkSelect from '@/components/MkSelect.vue';
import MkButton from '@/components/MkButton.vue';
@@ -51,13 +57,18 @@ const type = ref<SoundType>(props.type);
const fileId = ref(props.fileId);
const fileUrl = ref(props.fileUrl);
const fileName = ref<string>('');
+const driveFileError = ref(false);
+const hasChanged = ref(false);
const volume = ref(props.volume);
if (type.value === '_driveFile_' && fileId.value) {
- const apiRes = await misskeyApi('drive/files/show', {
+ await misskeyApi('drive/files/show', {
fileId: fileId.value,
+ }).then((res) => {
+ fileName.value = res.name;
+ }).catch((res) => {
+ driveFileError.value = true;
});
- fileName.value = apiRes.name;
}
function getSoundTypeName(f: SoundType): string {
@@ -107,9 +118,21 @@ function selectSound(ev) {
fileUrl.value = file.url;
fileName.value = file.name;
fileId.value = file.id;
+ driveFileError.value = false;
+ hasChanged.value = true;
});
}
+watch([type, volume], ([typeTo, volumeTo], [typeFrom, volumeFrom]) => {
+ if (typeFrom !== typeTo && typeTo !== '_driveFile_') {
+ fileUrl.value = undefined;
+ fileName.value = '';
+ fileId.value = undefined;
+ driveFileError.value = false;
+ }
+ hasChanged.value = true;
+});
+
function listen() {
if (type.value === '_driveFile_' && (!fileUrl.value || !fileId.value)) {
os.alert({
@@ -131,6 +154,10 @@ function listen() {
}
function save() {
+ if (hasChanged.value === false || driveFileError.value === true) {
+ return;
+ }
+
if (type.value === '_driveFile_' && !fileUrl.value) {
os.alert({
type: 'warning',
@@ -163,6 +190,13 @@ function save() {
gap: 8px;
}
+.fileErrorRoot {
+ flex-grow: 1;
+ min-width: 0;
+ font-weight: 700;
+ color: var(--error);
+}
+
.fileSelectorButton {
flex-shrink: 0;
}
diff --git a/packages/frontend/src/pages/settings/sounds.vue b/packages/frontend/src/pages/settings/sounds.vue
index 090f0cf14c..9fcf564e55 100644
--- a/packages/frontend/src/pages/settings/sounds.vue
+++ b/packages/frontend/src/pages/settings/sounds.vue
@@ -21,8 +21,14 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkFolder v-for="type in operationTypes" :key="type">
<template #label>{{ i18n.ts._sfx[type] }}</template>
<template #suffix>{{ getSoundTypeName(sounds[type].type) }}</template>
-
- <XSound :type="sounds[type].type" :volume="sounds[type].volume" :fileId="sounds[type].fileId" :fileUrl="sounds[type].fileUrl" @update="(res) => updated(type, res)"/>
+ <Suspense>
+ <template #default>
+ <XSound :type="sounds[type].type" :volume="sounds[type].volume" :fileId="sounds[type].fileId" :fileUrl="sounds[type].fileUrl" @update="(res) => updated(type, res)"/>
+ </template>
+ <template #fallback>
+ <MkLoading/>
+ </template>
+ </Suspense>
</MkFolder>
</div>
</FormSection>
@@ -54,8 +60,6 @@ const sounds = ref<Record<OperationType, Ref<SoundStore>>>({
note: defaultStore.reactiveState.sound_note,
noteMy: defaultStore.reactiveState.sound_noteMy,
notification: defaultStore.reactiveState.sound_notification,
- antenna: defaultStore.reactiveState.sound_antenna,
- channel: defaultStore.reactiveState.sound_channel,
reaction: defaultStore.reactiveState.sound_reaction,
});
diff --git a/packages/frontend/src/pages/settings/statusbar.statusbar.vue b/packages/frontend/src/pages/settings/statusbar.statusbar.vue
index 92e389a288..67943524ef 100644
--- a/packages/frontend/src/pages/settings/statusbar.statusbar.vue
+++ b/packages/frontend/src/pages/settings/statusbar.statusbar.vue
@@ -36,7 +36,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkSwitch v-model="statusbar.props.shuffle">
<template #label>{{ i18n.ts.shuffle }}</template>
</MkSwitch>
- <MkInput v-model="statusbar.props.refreshIntervalSec" manualSave type="number">
+ <MkInput v-model="statusbar.props.refreshIntervalSec" manualSave type="number" min="1">
<template #label>{{ i18n.ts.refreshInterval }}</template>
</MkInput>
<MkRange v-model="statusbar.props.marqueeDuration" :min="5" :max="150" :step="1">
@@ -48,7 +48,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkSwitch>
</template>
<template v-else-if="statusbar.type === 'federation'">
- <MkInput v-model="statusbar.props.refreshIntervalSec" manualSave type="number">
+ <MkInput v-model="statusbar.props.refreshIntervalSec" manualSave type="number" min="1">
<template #label>{{ i18n.ts.refreshInterval }}</template>
</MkInput>
<MkRange v-model="statusbar.props.marqueeDuration" :min="5" :max="150" :step="1">
diff --git a/packages/frontend/src/pages/settings/theme.manage.vue b/packages/frontend/src/pages/settings/theme.manage.vue
index 8a94d7388b..579ca6b20b 100644
--- a/packages/frontend/src/pages/settings/theme.manage.vue
+++ b/packages/frontend/src/pages/settings/theme.manage.vue
@@ -38,7 +38,7 @@ import MkSelect from '@/components/MkSelect.vue';
import MkInput from '@/components/MkInput.vue';
import MkButton from '@/components/MkButton.vue';
import { Theme, getBuiltinThemesRef } from '@/scripts/theme.js';
-import copyToClipboard from '@/scripts/copy-to-clipboard.js';
+import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
import * as os from '@/os.js';
import { getThemes, removeTheme } from '@/theme-store.js';
import { i18n } from '@/i18n.js';
diff --git a/packages/frontend/src/pages/settings/theme.vue b/packages/frontend/src/pages/settings/theme.vue
index 0a4bd4b826..7d192bcbea 100644
--- a/packages/frontend/src/pages/settings/theme.vue
+++ b/packages/frontend/src/pages/settings/theme.vue
@@ -213,12 +213,18 @@ definePageMetadata(() => ({
}
}
+ .dn:focus-visible ~ .toggle {
+ outline: 2px solid var(--focus);
+ outline-offset: 2px;
+ }
+
.toggle {
cursor: pointer;
display: inline-block;
position: relative;
width: 90px;
height: 50px;
+ margin: 4px; // focus用ã®ã‚¢ã‚¦ãƒˆãƒ©ã‚¤ãƒ³
background-color: #83D8FF;
border-radius: 90px - 6;
transition: background-color 200ms cubic-bezier(0.445, 0.05, 0.55, 0.95) !important;
diff --git a/packages/frontend/src/pages/settings/webhook.edit.vue b/packages/frontend/src/pages/settings/webhook.edit.vue
index e9fb1e471e..058ef69c35 100644
--- a/packages/frontend/src/pages/settings/webhook.edit.vue
+++ b/packages/frontend/src/pages/settings/webhook.edit.vue
@@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkInput>
<FormSection>
- <template #label>{{ i18n.ts._webhookSettings.events }}</template>
+ <template #label>{{ i18n.ts._webhookSettings.trigger }}</template>
<div class="_gaps_s">
<MkSwitch v-model="event_follow">{{ i18n.ts._webhookSettings._events.follow }}</MkSwitch>
diff --git a/packages/frontend/src/pages/settings/webhook.new.vue b/packages/frontend/src/pages/settings/webhook.new.vue
index 5bf85e48f4..d62357caaf 100644
--- a/packages/frontend/src/pages/settings/webhook.new.vue
+++ b/packages/frontend/src/pages/settings/webhook.new.vue
@@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkInput>
<FormSection>
- <template #label>{{ i18n.ts._webhookSettings.events }}</template>
+ <template #label>{{ i18n.ts._webhookSettings.trigger }}</template>
<div class="_gaps_s">
<MkSwitch v-model="event_follow">{{ i18n.ts._webhookSettings._events.follow }}</MkSwitch>
diff --git a/packages/frontend/src/pages/timeline.vue b/packages/frontend/src/pages/timeline.vue
index 98744c6318..32f6dd0e5a 100644
--- a/packages/frontend/src/pages/timeline.vue
+++ b/packages/frontend/src/pages/timeline.vue
@@ -8,8 +8,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #header><MkPageHeader v-model:tab="src" :actions="headerActions" :tabs="$i ? headerTabs : headerTabsWhenNotLogin" :displayMyAvatar="true"/></template>
<MkSpacer :contentMax="800">
<MkHorizontalSwipe v-model:tab="src" :tabs="$i ? headerTabs : headerTabsWhenNotLogin">
- <div :key="src" ref="rootEl" v-hotkey.global="keymap">
- <MkInfo v-if="['home', 'local', 'social', 'global'].includes(src) && !defaultStore.reactiveState.timelineTutorials.value[src]" style="margin-bottom: var(--margin);" closable @close="closeTutorial()">
+ <div :key="src" ref="rootEl">
+ <MkInfo v-if="isBasicTimeline(src) && !defaultStore.reactiveState.timelineTutorials.value[src]" style="margin-bottom: var(--margin);" closable @close="closeTutorial()">
{{ i18n.ts._timelineDescription[src] }}
</MkInfo>
<MkPostForm v-if="defaultStore.reactiveState.showFixedPostForm.value" :class="$style.postForm" class="post-form _panel" fixed style="margin-bottom: var(--margin);"/>
@@ -45,7 +45,6 @@ import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { defaultStore } from '@/store.js';
import { i18n } from '@/i18n.js';
-import { instance } from '@/instance.js';
import { $i } from '@/account.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { antennasCache, userListsCache, favoritedChannelsCache } from '@/cache.js';
@@ -53,20 +52,15 @@ import { deviceKind } from '@/scripts/device-kind.js';
import { deepMerge } from '@/scripts/merge.js';
import { MenuItem } from '@/types/menu.js';
import { miLocalStorage } from '@/local-storage.js';
+import { availableBasicTimelines, hasWithReplies, isAvailableBasicTimeline, isBasicTimeline, basicTimelineIconClass } from '@/timelines.js';
provide('shouldOmitHeaderTitle', true);
-const isLocalTimelineAvailable = ($i == null && instance.policies.ltlAvailable) || ($i != null && $i.policies.ltlAvailable);
-const isGlobalTimelineAvailable = ($i == null && instance.policies.gtlAvailable) || ($i != null && $i.policies.gtlAvailable);
-const keymap = {
- 't': focus,
-};
-
const tlComponent = shallowRef<InstanceType<typeof MkTimeline>>();
const rootEl = shallowRef<HTMLElement>();
const queue = ref(0);
-const srcWhenNotSignin = ref<'local' | 'global'>(isLocalTimelineAvailable ? 'local' : 'global');
+const srcWhenNotSignin = ref<'local' | 'global'>(isAvailableBasicTimeline('local') ? 'local' : 'global');
const src = computed<'home' | 'local' | 'social' | 'global' | `list:${string}`>({
get: () => ($i ? defaultStore.reactiveState.tl.value.src : srcWhenNotSignin.value),
set: (x) => saveSrc(x),
@@ -77,7 +71,11 @@ const withRenotes = computed<boolean>({
});
// computed内ã§ã®ç„¡é™ãƒ«ãƒ¼ãƒ—を防ããŸã‚ã®ãƒ•ラグ
-const localSocialTLFilterSwitchStore = ref<'withReplies' | 'onlyFiles' | false>('withReplies');
+const localSocialTLFilterSwitchStore = ref<'withReplies' | 'onlyFiles' | false>(
+ defaultStore.reactiveState.tl.value.filter.withReplies ? 'withReplies' :
+ defaultStore.reactiveState.tl.value.filter.onlyFiles ? 'onlyFiles' :
+ false,
+);
const withReplies = computed<boolean>({
get: () => {
@@ -232,7 +230,7 @@ function focus(): void {
}
function closeTutorial(): void {
- if (!['home', 'local', 'social', 'global'].includes(src.value)) return;
+ if (!isBasicTimeline(src.value)) return;
const before = defaultStore.state.timelineTutorials;
before[src.value] = true;
defaultStore.set('timelineTutorials', before);
@@ -248,7 +246,7 @@ const headerActions = computed(() => {
type: 'switch',
text: i18n.ts.showRenotes,
ref: withRenotes,
- }, src.value === 'local' || src.value === 'social' ? {
+ }, isBasicTimeline(src.value) && hasWithReplies(src.value) ? {
type: 'switch',
text: i18n.ts.showRepliesToOthersInTimeline,
ref: withReplies,
@@ -261,7 +259,7 @@ const headerActions = computed(() => {
type: 'switch',
text: i18n.ts.fileAttachedOnly,
ref: onlyFiles,
- disabled: src.value === 'local' || src.value === 'social' ? withReplies : false,
+ disabled: isBasicTimeline(src.value) && hasWithReplies(src.value) ? withReplies : false,
}], ev.currentTarget ?? ev.target);
},
},
@@ -283,27 +281,12 @@ const headerTabs = computed(() => [...(defaultStore.reactiveState.pinnedUserList
title: l.name,
icon: 'ti ti-star',
iconOnly: true,
-}))), {
- key: 'home',
- title: i18n.ts._timelines.home,
- icon: 'ti ti-home',
- iconOnly: true,
-}, ...(isLocalTimelineAvailable ? [{
- key: 'local',
- title: i18n.ts._timelines.local,
- icon: 'ti ti-planet',
- iconOnly: true,
-}, {
- key: 'social',
- title: i18n.ts._timelines.social,
- icon: 'ti ti-universe',
- iconOnly: true,
-}] : []), ...(isGlobalTimelineAvailable ? [{
- key: 'global',
- title: i18n.ts._timelines.global,
- icon: 'ti ti-whirl',
+}))), ...availableBasicTimelines().map(tl => ({
+ key: tl,
+ title: i18n.ts._timelines[tl],
+ icon: basicTimelineIconClass(tl),
iconOnly: true,
-}] : []), {
+})), {
icon: 'ti ti-list',
title: i18n.ts.lists,
iconOnly: true,
@@ -320,24 +303,16 @@ const headerTabs = computed(() => [...(defaultStore.reactiveState.pinnedUserList
onClick: chooseChannel,
}] as Tab[]);
-const headerTabsWhenNotLogin = computed(() => [
- ...(isLocalTimelineAvailable ? [{
- key: 'local',
- title: i18n.ts._timelines.local,
- icon: 'ti ti-planet',
- iconOnly: true,
- }] : []),
- ...(isGlobalTimelineAvailable ? [{
- key: 'global',
- title: i18n.ts._timelines.global,
- icon: 'ti ti-whirl',
- iconOnly: true,
- }] : []),
-] as Tab[]);
+const headerTabsWhenNotLogin = computed(() => [...availableBasicTimelines().map(tl => ({
+ key: tl,
+ title: i18n.ts._timelines[tl],
+ icon: basicTimelineIconClass(tl),
+ iconOnly: true,
+}))] as Tab[]);
definePageMetadata(() => ({
title: i18n.ts.timeline,
- icon: src.value === 'local' ? 'ti ti-planet' : src.value === 'social' ? 'ti ti-universe' : src.value === 'global' ? 'ti ti-whirl' : 'ti ti-home',
+ icon: isBasicTimeline(src.value) ? basicTimelineIconClass(src.value) : 'ti ti-home',
}));
</script>
diff --git a/packages/frontend/src/pages/user/home.vue b/packages/frontend/src/pages/user/home.vue
index 4e3e383e33..3039ec7499 100644
--- a/packages/frontend/src/pages/user/home.vue
+++ b/packages/frontend/src/pages/user/home.vue
@@ -32,9 +32,9 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
</div>
<span v-if="$i && $i.id != user.id && user.isFollowed" class="followed">{{ i18n.ts.followsYou }}</span>
- <div v-if="$i" class="actions">
+ <div class="actions">
<button class="menu _button" @click="menu"><i class="ti ti-dots"></i></button>
- <MkFollowButton v-if="$i.id != user.id" v-model:user="user" :inline="true" :transparent="false" :full="true" class="koudoku"/>
+ <MkFollowButton v-if="$i?.id != user.id" v-model:user="user" :inline="true" :transparent="false" :full="true" class="koudoku"/>
</div>
</div>
<MkAvatar class="avatar" :user="user" indicator/>
@@ -97,7 +97,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="user.fields.length > 0" class="fields">
<dl v-for="(field, i) in user.fields" :key="i" class="field">
<dt class="name">
- <Mfm :text="field.name" :plain="true" :colored="false"/>
+ <Mfm :text="field.name" :author="user" :plain="true" :colored="false"/>
</dt>
<dd class="value">
<Mfm :text="field.value" :author="user" :colored="false"/>
@@ -167,12 +167,14 @@ import number from '@/filters/number.js';
import { userPage } from '@/filters/user.js';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
+import { defaultStore } from '@/store.js';
import { $i, iAmModerator } from '@/account.js';
import { dateString } from '@/filters/date.js';
import { confetti } from '@/scripts/confetti.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { isFollowingVisibleForMe, isFollowersVisibleForMe } from '@/scripts/isFfVisibleForMe.js';
import { useRouter } from '@/router/supplier.js';
+import { getStaticImageUrl } from '@/scripts/media-proxy.js';
function calcAge(birthdate: string): number {
const date = new Date(birthdate);
@@ -220,8 +222,14 @@ watch(moderationNote, async () => {
const style = computed(() => {
if (props.user.bannerUrl == null) return {};
- return {
- backgroundImage: `url(${ props.user.bannerUrl })`,
+ if (defaultStore.state.disableShowingAnimatedImages) {
+ return {
+ backgroundImage: `url(${ getStaticImageUrl(props.user.bannerUrl) })`,
+ };
+ } else {
+ return {
+ backgroundImage: `url(${ props.user.bannerUrl })`,
+ };
};
});
@@ -392,11 +400,12 @@ onUnmounted(() => {
> .name {
display: block;
- margin: 0;
+ margin: -10px;
+ padding: 10px;
line-height: 32px;
font-weight: bold;
font-size: 1.8em;
- text-shadow: 0 0 8px #000;
+ filter: drop-shadow(0 0 4px #000);
}
> .bottom {
diff --git a/packages/frontend/src/pages/welcome.timeline.note.vue b/packages/frontend/src/pages/welcome.timeline.note.vue
new file mode 100644
index 0000000000..f385938343
--- /dev/null
+++ b/packages/frontend/src/pages/welcome.timeline.note.vue
@@ -0,0 +1,109 @@
+<!--
+SPDX-FileCopyrightText: syuilo and misskey-project
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
+<template>
+<div :key="note.id" :class="$style.note">
+ <div class="_panel _gaps_s" :class="$style.content">
+ <div v-if="note.cw != null" :class="$style.richcontent">
+ <div><Mfm :text="note.cw" :author="note.user"/></div>
+ <MkCwButton v-model="showContent" :text="note.text" :renote="note.renote" :files="note.files" :poll="note.poll" style="margin: 4px 0;"/>
+ <div v-if="showContent">
+ <MkA v-if="note.replyId" class="reply" :to="`/notes/${note.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA>
+ <Mfm v-if="note.text" :text="note.text" :author="note.user"/>
+ <MkA v-if="note.renoteId" class="rp" :to="`/notes/${note.renoteId}`">RN: ...</MkA>
+ </div>
+ </div>
+ <div v-else ref="noteTextEl" :class="[$style.text, { [$style.collapsed]: shouldCollapse }]">
+ <MkA v-if="note.replyId" class="reply" :to="`/notes/${note.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA>
+ <Mfm v-if="note.text" :text="note.text" :author="note.user"/>
+ <MkA v-if="note.renoteId" class="rp" :to="`/notes/${note.renoteId}`">RN: ...</MkA>
+ </div>
+ <div v-if="note.files && note.files.length > 0" :class="$style.richcontent">
+ <MkMediaList :mediaList="note.files.slice(0, 4)"/>
+ </div>
+ <div v-if="note.poll">
+ <MkPoll :noteId="note.id" :poll="note.poll" :readOnly="true"/>
+ </div>
+ <div v-if="note.reactionCount > 0" :class="$style.reactions">
+ <MkReactionsViewer :note="note" :maxNumber="16"/>
+ </div>
+ </div>
+</div>
+</template>
+
+<script lang="ts" setup>
+import { ref, shallowRef, onUpdated, onMounted } from 'vue';
+import * as Misskey from 'misskey-js';
+import MkReactionsViewer from '@/components/MkReactionsViewer.vue';
+import MkMediaList from '@/components/MkMediaList.vue';
+import MkPoll from '@/components/MkPoll.vue';
+import MkCwButton from '@/components/MkCwButton.vue';
+
+defineProps<{
+ note: Misskey.entities.Note;
+}>();
+
+const noteTextEl = shallowRef<HTMLDivElement>();
+const shouldCollapse = ref(false);
+const showContent = ref(false);
+
+function calcCollapse() {
+ if (noteTextEl.value) {
+ const height = noteTextEl.value.scrollHeight;
+ if (height > 200) {
+ shouldCollapse.value = true;
+ }
+ }
+}
+
+onMounted(() => {
+ calcCollapse();
+});
+
+onUpdated(() => {
+ calcCollapse();
+});
+</script>
+
+<style lang="scss" module>
+.note {
+ margin-left: auto;
+}
+
+.text {
+ position: relative;
+ max-height: 200px;
+ overflow: hidden;
+
+ &.collapsed::after {
+ content: '';
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ height: 64px;
+ background: linear-gradient(0deg, var(--panel), var(--X15));
+ }
+}
+
+.content {
+ padding: 16px;
+ margin: 0 0 0 auto;
+ max-width: max-content;
+ border-radius: 16px;
+}
+
+.reactions {
+ box-sizing: border-box;
+ margin: 8px -16px -8px;
+ padding: 8px 16px 0;
+ width: calc(100% + 32px);
+ border-top: 1px solid var(--divider);
+}
+
+.richcontent {
+ min-width: 250px;
+}
+</style>
diff --git a/packages/frontend/src/pages/welcome.timeline.vue b/packages/frontend/src/pages/welcome.timeline.vue
index 139b2e0a07..db326f9e6c 100644
--- a/packages/frontend/src/pages/welcome.timeline.vue
+++ b/packages/frontend/src/pages/welcome.timeline.vue
@@ -4,24 +4,17 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
-<div :class="$style.root">
- <div ref="scrollEl" :class="[$style.scrollbox, { [$style.scroll]: isScrolling }]">
- <div v-for="note in notes" :key="note.id" :class="$style.note">
- <div class="_panel" :class="$style.content">
- <div>
- <MkA v-if="note.replyId" class="reply" :to="`/notes/${note.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA>
- <Mfm v-if="note.text" :text="note.text" :author="note.user"/>
- <MkA v-if="note.renoteId" class="rp" :to="`/notes/${note.renoteId}`">RN: ...</MkA>
- </div>
- <div v-if="note.files.length > 0" :class="$style.richcontent">
- <MkMediaList :mediaList="note.files"/>
- </div>
- <div v-if="note.poll">
- <MkPoll :noteId="note.id" :poll="note.poll" :readOnly="true"/>
- </div>
- </div>
- <MkReactionsViewer ref="reactionsViewer" :note="note"/>
- </div>
+<div :class="$style.root" class="_gaps">
+ <div
+ ref="notesMainContainerEl"
+ class="_gaps"
+ :class="[$style.scrollBoxMain, { [$style.scrollIntro]: (scrollState === 'intro'), [$style.scrollLoop]: (scrollState === 'loop') }]"
+ @animationend="changeScrollState"
+ >
+ <XNote v-for="note in notes" :key="`${note.id}_1`" :class="$style.note" :note="note"/>
+ </div>
+ <div v-if="isScrolling" class="_gaps" :class="[$style.scrollBoxSub, { [$style.scrollIntro]: (scrollState === 'intro'), [$style.scrollLoop]: (scrollState === 'loop') }]">
+ <XNote v-for="note in notes" :key="`${note.id}_2`" :class="$style.note" :note="note"/>
</div>
</div>
</template>
@@ -29,43 +22,54 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import * as Misskey from 'misskey-js';
import { onUpdated, ref, shallowRef } from 'vue';
-import MkReactionsViewer from '@/components/MkReactionsViewer.vue';
-import MkMediaList from '@/components/MkMediaList.vue';
-import MkPoll from '@/components/MkPoll.vue';
+import XNote from '@/pages/welcome.timeline.note.vue';
import { misskeyApiGet } from '@/scripts/misskey-api.js';
import { getScrollContainer } from '@/scripts/scroll.js';
const notes = ref<Misskey.entities.Note[]>([]);
const isScrolling = ref(false);
-const scrollEl = shallowRef<HTMLElement>();
+const scrollState = ref<null | 'intro' | 'loop'>(null);
+const notesMainContainerEl = shallowRef<HTMLElement>();
misskeyApiGet('notes/featured').then(_notes => {
notes.value = _notes;
});
+function changeScrollState() {
+ if (scrollState.value !== 'loop') {
+ scrollState.value = 'loop';
+ }
+}
+
onUpdated(() => {
- if (!scrollEl.value) return;
- const container = getScrollContainer(scrollEl.value);
+ if (!notesMainContainerEl.value) return;
+ const container = getScrollContainer(notesMainContainerEl.value);
const containerHeight = container ? container.clientHeight : window.innerHeight;
- if (scrollEl.value.offsetHeight > containerHeight) {
+ if (notesMainContainerEl.value.offsetHeight > containerHeight) {
+ if (scrollState.value === null) {
+ scrollState.value = 'intro';
+ }
isScrolling.value = true;
}
});
</script>
<style lang="scss" module>
-@keyframes scroll {
+@keyframes scrollIntro {
0% {
transform: translate3d(0, 0, 0);
}
- 5% {
- transform: translate3d(0, 0, 0);
+ 100% {
+ transform: translate3d(0, calc(calc(-100% - 128px) - var(--margin)), 0);
}
- 75% {
- transform: translate3d(0, calc(-100% + 90vh), 0);
+}
+
+@keyframes scrollConstant {
+ 0% {
+ transform: translate3d(0, -128px, 0);
}
- 90% {
- transform: translate3d(0, calc(-100% + 90vh), 0);
+ 100% {
+ transform: translate3d(0, calc(calc(-100% - 128px) - var(--margin)), 0);
}
}
@@ -73,24 +77,26 @@ onUpdated(() => {
text-align: right;
}
-.scrollbox {
- &.scroll {
- animation: scroll 45s linear infinite;
+.scrollBoxMain {
+ &.scrollIntro {
+ animation: scrollIntro 30s linear forwards;
+ }
+ &.scrollLoop {
+ animation: scrollConstant 30s linear infinite;
}
}
-.note {
- margin: 16px 0 16px auto;
-}
-
-.content {
- padding: 16px;
- margin: 0 0 0 auto;
- max-width: max-content;
- border-radius: 16px;
+.scrollBoxSub {
+ &.scrollIntro {
+ animation: scrollIntro 30s linear forwards;
+ }
+ &.scrollLoop {
+ animation: scrollConstant 30s linear infinite;
+ }
}
-.richcontent {
- min-width: 250px;
+.root:has(.note:hover) .scrollBoxMain,
+.root:has(.note:hover) .scrollBoxSub {
+ animation-play-state: paused;
}
</style>
diff --git a/packages/frontend/src/router/definition.ts b/packages/frontend/src/router/definition.ts
index c12ae0fa57..995a2055b8 100644
--- a/packages/frontend/src/router/definition.ts
+++ b/packages/frontend/src/router/definition.ts
@@ -232,13 +232,26 @@ const routes: RouteDef[] = [{
component: page(() => import('@/pages/search.vue')),
query: {
q: 'query',
+ userId: 'userId',
+ username: 'username',
+ host: 'host',
channel: 'channel',
type: 'type',
origin: 'origin',
},
}, {
+ // Legacy Compatibility
path: '/authorize-follow',
- component: page(() => import('@/pages/follow.vue')),
+ redirect: '/lookup',
+ loginRequired: true,
+}, {
+ // Mastodon Compatibility
+ path: '/authorize_interaction',
+ redirect: '/lookup',
+ loginRequired: true,
+}, {
+ path: '/lookup',
+ component: page(() => import('@/pages/lookup.vue')),
loginRequired: true,
}, {
path: '/share',
@@ -252,6 +265,9 @@ const routes: RouteDef[] = [{
path: '/scratchpad',
component: page(() => import('@/pages/scratchpad.vue')),
}, {
+ path: '/preview',
+ component: page(() => import('@/pages/preview.vue')),
+}, {
path: '/auth/:token',
component: page(() => import('@/pages/auth.vue')),
}, {
@@ -472,6 +488,14 @@ const routes: RouteDef[] = [{
name: 'invites',
component: page(() => import('@/pages/admin/invites.vue')),
}, {
+ path: '/abuse-report-notification-recipient',
+ name: 'abuse-report-notification-recipient',
+ component: page(() => import('@/pages/admin/abuse-report/notification-recipient.vue')),
+ }, {
+ path: '/system-webhook',
+ name: 'system-webhook',
+ component: page(() => import('@/pages/admin/system-webhook.vue')),
+ }, {
path: '/',
component: page(() => import('@/pages/_empty_.vue')),
}],
diff --git a/packages/frontend/src/scripts/array.ts b/packages/frontend/src/scripts/array.ts
index b3d76e149f..f2feb29dfc 100644
--- a/packages/frontend/src/scripts/array.ts
+++ b/packages/frontend/src/scripts/array.ts
@@ -78,44 +78,6 @@ export function maximum(xs: number[]): number {
}
/**
- * Splits an array based on the equivalence relation.
- * The concatenation of the result is equal to the argument.
- */
-export function groupBy<T>(f: EndoRelation<T>, xs: T[]): T[][] {
- const groups = [] as T[][];
- for (const x of xs) {
- const lastGroup = groups.at(-1);
- if (lastGroup !== undefined && f(lastGroup[0], x)) {
- lastGroup.push(x);
- } else {
- groups.push([x]);
- }
- }
- return groups;
-}
-
-/**
- * Splits an array based on the equivalence relation induced by the function.
- * The concatenation of the result is equal to the argument.
- */
-export function groupOn<T, S>(f: (x: T) => S, xs: T[]): T[][] {
- return groupBy((a, b) => f(a) === f(b), xs);
-}
-
-export function groupByX<T>(collections: T[], keySelector: (x: T) => string) {
- return collections.reduce((obj: Record<string, T[]>, item: T) => {
- const key = keySelector(item);
- if (typeof obj[key] === 'undefined') {
- obj[key] = [];
- }
-
- obj[key].push(item);
-
- return obj;
- }, {});
-}
-
-/**
* Compare two arrays by lexicographical order
*/
export function lessThan(xs: number[], ys: number[]): boolean {
diff --git a/packages/frontend/src/scripts/check-permissions.ts b/packages/frontend/src/scripts/check-permissions.ts
new file mode 100644
index 0000000000..ed86529d5b
--- /dev/null
+++ b/packages/frontend/src/scripts/check-permissions.ts
@@ -0,0 +1,19 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { instance } from '@/instance.js';
+import { $i } from '@/account.js';
+
+export const notesSearchAvailable = (
+ // FIXME: instance.policies would be null in Vitest
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
+ ($i == null && instance.policies != null && instance.policies.canSearchNotes) ||
+ ($i != null && $i.policies.canSearchNotes) ||
+ false
+) as boolean;
+
+export const canSearchNonLocalNotes = (
+ instance.noteSearchableScope === 'global'
+);
diff --git a/packages/frontend/src/scripts/copy-to-clipboard.ts b/packages/frontend/src/scripts/copy-to-clipboard.ts
index 216c0464b3..7e0bb25606 100644
--- a/packages/frontend/src/scripts/copy-to-clipboard.ts
+++ b/packages/frontend/src/scripts/copy-to-clipboard.ts
@@ -6,33 +6,6 @@
/**
* Clipboardã«å€¤ã‚’コピー(TODO: 文字列以外も対応)
*/
-export default val => {
- // 空div 生æˆ
- const tmp = document.createElement('div');
- // é¸æŠžç”¨ã®ã‚¿ã‚°ç”Ÿæˆ
- const pre = document.createElement('pre');
-
- // 親è¦ç´ ã®CSSã§ user-select: none ã ã¨ã‚³ãƒ”ーã§ããªã„ã®ã§æ›¸ãæ›ãˆã‚‹
- pre.style.webkitUserSelect = 'auto';
- pre.style.userSelect = 'auto';
-
- tmp.appendChild(pre).textContent = val;
-
- // è¦ç´ ã‚’ç”»é¢å¤–ã¸
- const s = tmp.style;
- s.position = 'fixed';
- s.right = '200%';
-
- // body ã«è¿½åŠ 
- document.body.appendChild(tmp);
- // è¦ç´ ã‚’é¸æŠž
- document.getSelection().selectAllChildren(tmp);
-
- // クリップボードã«ã‚³ãƒ”ー
- const result = document.execCommand('copy');
-
- // è¦ç´ å‰Šé™¤
- document.body.removeChild(tmp);
-
- return result;
+export function copyToClipboard(input: string | null) {
+ if (input) navigator.clipboard.writeText(input);
};
diff --git a/packages/frontend/src/scripts/focus-trap.ts b/packages/frontend/src/scripts/focus-trap.ts
new file mode 100644
index 0000000000..a5df36f520
--- /dev/null
+++ b/packages/frontend/src/scripts/focus-trap.ts
@@ -0,0 +1,78 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+import { getHTMLElementOrNull } from '@/scripts/get-dom-node-or-null.js';
+
+const focusTrapElements = new Set<HTMLElement>();
+const ignoreElements = [
+ 'script',
+ 'style',
+];
+
+function containsFocusTrappedElements(el: HTMLElement): boolean {
+ return Array.from(focusTrapElements).some((focusTrapElement) => {
+ return el.contains(focusTrapElement);
+ });
+}
+
+function releaseFocusTrap(el: HTMLElement): void {
+ focusTrapElements.delete(el);
+ if (el.inert === true) {
+ el.inert = false;
+ }
+ if (el.parentElement != null && el !== document.body) {
+ el.parentElement.childNodes.forEach((siblingNode) => {
+ const siblingEl = getHTMLElementOrNull(siblingNode);
+ if (!siblingEl) return;
+ if (siblingEl !== el && (focusTrapElements.has(siblingEl) || containsFocusTrappedElements(siblingEl) || focusTrapElements.size === 0)) {
+ siblingEl.inert = false;
+ } else if (
+ focusTrapElements.size > 0 &&
+ !containsFocusTrappedElements(siblingEl) &&
+ !focusTrapElements.has(siblingEl) &&
+ !ignoreElements.includes(siblingEl.tagName.toLowerCase())
+ ) {
+ siblingEl.inert = true;
+ } else {
+ siblingEl.inert = false;
+ }
+ });
+ releaseFocusTrap(el.parentElement);
+ }
+}
+
+export function focusTrap(el: HTMLElement, hasInteractionWithOtherFocusTrappedEls: boolean, parent: true): void;
+export function focusTrap(el: HTMLElement, hasInteractionWithOtherFocusTrappedEls?: boolean, parent?: false): { release: () => void; };
+export function focusTrap(el: HTMLElement, hasInteractionWithOtherFocusTrappedEls = false, parent = false): { release: () => void; } | void {
+ if (el.inert === true) {
+ el.inert = false;
+ }
+ if (el.parentElement != null && el !== document.body) {
+ el.parentElement.childNodes.forEach((siblingNode) => {
+ const siblingEl = getHTMLElementOrNull(siblingNode);
+ if (!siblingEl) return;
+ if (
+ siblingEl !== el &&
+ (
+ hasInteractionWithOtherFocusTrappedEls === false ||
+ (!focusTrapElements.has(siblingEl) && !containsFocusTrappedElements(siblingEl))
+ ) &&
+ !ignoreElements.includes(siblingEl.tagName.toLowerCase())
+ ) {
+ siblingEl.inert = true;
+ }
+ });
+ focusTrap(el.parentElement, hasInteractionWithOtherFocusTrappedEls, true);
+ }
+
+ if (!parent) {
+ focusTrapElements.add(el);
+
+ return {
+ release: () => {
+ releaseFocusTrap(el);
+ },
+ };
+ }
+}
diff --git a/packages/frontend/src/scripts/focus.ts b/packages/frontend/src/scripts/focus.ts
index ea6ee61c88..eb2da5ad86 100644
--- a/packages/frontend/src/scripts/focus.ts
+++ b/packages/frontend/src/scripts/focus.ts
@@ -3,30 +3,78 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
-export function focusPrev(el: Element | null, self = false, scroll = true) {
- if (el == null) return;
- if (!self) el = el.previousElementSibling;
- if (el) {
- if (el.hasAttribute('tabindex')) {
- (el as HTMLElement).focus({
- preventScroll: !scroll,
- });
- } else {
- focusPrev(el.previousElementSibling, true);
- }
+import { getScrollPosition, getScrollContainer, getStickyBottom, getStickyTop } from '@/scripts/scroll.js';
+import { getElementOrNull, getNodeOrNull } from '@/scripts/get-dom-node-or-null.js';
+
+type MaybeHTMLElement = EventTarget | Node | Element | HTMLElement;
+
+export const isFocusable = (input: MaybeHTMLElement | null | undefined): input is HTMLElement => {
+ if (input == null || !(input instanceof HTMLElement)) return false;
+
+ if (input.tabIndex < 0) return false;
+ if ('disabled' in input && input.disabled === true) return false;
+ if ('readonly' in input && input.readonly === true) return false;
+
+ if (!input.ownerDocument.contains(input)) return false;
+
+ const style = window.getComputedStyle(input);
+ if (style.display === 'none') return false;
+ if (style.visibility === 'hidden') return false;
+ if (style.opacity === '0') return false;
+ if (style.pointerEvents === 'none') return false;
+
+ return true;
+};
+
+export const focusPrev = (input: MaybeHTMLElement | null | undefined, self = false, scroll = true) => {
+ const element = self ? input : getElementOrNull(input)?.previousElementSibling;
+ if (element == null) return;
+ if (isFocusable(element)) {
+ focusOrScroll(element, scroll);
+ } else {
+ focusPrev(element, false, scroll);
}
-}
+};
-export function focusNext(el: Element | null, self = false, scroll = true) {
- if (el == null) return;
- if (!self) el = el.nextElementSibling;
- if (el) {
- if (el.hasAttribute('tabindex')) {
- (el as HTMLElement).focus({
- preventScroll: !scroll,
- });
- } else {
- focusPrev(el.nextElementSibling, true);
+export const focusNext = (input: MaybeHTMLElement | null | undefined, self = false, scroll = true) => {
+ const element = self ? input : getElementOrNull(input)?.nextElementSibling;
+ if (element == null) return;
+ if (isFocusable(element)) {
+ focusOrScroll(element, scroll);
+ } else {
+ focusNext(element, false, scroll);
+ }
+};
+
+export const focusParent = (input: MaybeHTMLElement | null | undefined, self = false, scroll = true) => {
+ const element = self ? input : getNodeOrNull(input)?.parentElement;
+ if (element == null) return;
+ if (isFocusable(element)) {
+ focusOrScroll(element, scroll);
+ } else {
+ focusParent(element, false, scroll);
+ }
+};
+
+const focusOrScroll = (element: HTMLElement, scroll: boolean) => {
+ if (scroll) {
+ const scrollContainer = getScrollContainer(element) ?? document.documentElement;
+ const scrollContainerTop = getScrollPosition(scrollContainer);
+ const stickyTop = getStickyTop(element, scrollContainer);
+ const stickyBottom = getStickyBottom(element, scrollContainer);
+ const top = element.getBoundingClientRect().top;
+ const bottom = element.getBoundingClientRect().bottom;
+
+ let scrollTo = scrollContainerTop;
+ if (top < stickyTop) {
+ scrollTo += top - stickyTop;
+ } else if (bottom > window.innerHeight - stickyBottom) {
+ scrollTo += bottom - window.innerHeight + stickyBottom;
}
+ scrollContainer.scrollTo({ top: scrollTo, behavior: 'instant' });
+ }
+
+ if (document.activeElement !== element) {
+ element.focus({ preventScroll: true });
}
-}
+};
diff --git a/packages/frontend/src/scripts/get-dom-node-or-null.ts b/packages/frontend/src/scripts/get-dom-node-or-null.ts
new file mode 100644
index 0000000000..fbf54675fd
--- /dev/null
+++ b/packages/frontend/src/scripts/get-dom-node-or-null.ts
@@ -0,0 +1,19 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export const getNodeOrNull = (input: unknown): Node | null => {
+ if (input instanceof Node) return input;
+ return null;
+};
+
+export const getElementOrNull = (input: unknown): Element | null => {
+ if (input instanceof Element) return input;
+ return null;
+};
+
+export const getHTMLElementOrNull = (input: unknown): HTMLElement | null => {
+ if (input instanceof HTMLElement) return input;
+ return null;
+};
diff --git a/packages/frontend/src/scripts/get-drive-file-menu.ts b/packages/frontend/src/scripts/get-drive-file-menu.ts
index 7aca5f83b2..108648d640 100644
--- a/packages/frontend/src/scripts/get-drive-file-menu.ts
+++ b/packages/frontend/src/scripts/get-drive-file-menu.ts
@@ -6,7 +6,7 @@
import * as Misskey from 'misskey-js';
import { defineAsyncComponent } from 'vue';
import { i18n } from '@/i18n.js';
-import copyToClipboard from '@/scripts/copy-to-clipboard.js';
+import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { MenuItem } from '@/types/menu.js';
@@ -27,7 +27,7 @@ function rename(file: Misskey.entities.DriveFile) {
}
function describe(file: Misskey.entities.DriveFile) {
- os.popup(defineAsyncComponent(() => import('@/components/MkFileCaptionEditWindow.vue')), {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkFileCaptionEditWindow.vue')), {
default: file.comment ?? '',
file: file,
}, {
@@ -37,7 +37,17 @@ function describe(file: Misskey.entities.DriveFile) {
comment: caption.length === 0 ? null : caption,
});
},
- }, 'closed');
+ closed: () => dispose(),
+ });
+}
+
+function move(file: Misskey.entities.DriveFile) {
+ os.selectDriveFolder(false).then(folder => {
+ misskeyApi('drive/files/update', {
+ fileId: file.id,
+ folderId: folder[0] ? folder[0].id : null,
+ });
+ });
}
function toggleSensitive(file: Misskey.entities.DriveFile) {
@@ -88,6 +98,10 @@ export function getDriveFileMenu(file: Misskey.entities.DriveFile, folder?: Miss
icon: 'ti ti-forms',
action: () => rename(file),
}, {
+ text: i18n.ts.move,
+ icon: 'ti ti-folder-symlink',
+ action: () => move(file),
+ }, {
text: file.isSensitive ? i18n.ts.unmarkAsSensitive : i18n.ts.markAsSensitive,
icon: file.isSensitive ? 'ti ti-eye' : 'ti ti-eye-exclamation',
action: () => toggleSensitive(file),
diff --git a/packages/frontend/src/scripts/get-note-menu.ts b/packages/frontend/src/scripts/get-note-menu.ts
index 71ad299f50..ebb96d1746 100644
--- a/packages/frontend/src/scripts/get-note-menu.ts
+++ b/packages/frontend/src/scripts/get-note-menu.ts
@@ -11,7 +11,7 @@ import { i18n } from '@/i18n.js';
import { instance } from '@/instance.js';
import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
-import copyToClipboard from '@/scripts/copy-to-clipboard.js';
+import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
import { url } from '@/config.js';
import { defaultStore, noteActions } from '@/store.js';
import { miLocalStorage } from '@/local-storage.js';
@@ -136,10 +136,12 @@ export function getAbuseNoteMenu(note: Misskey.entities.Note, text: string): Men
let noteInfo = '';
if (note.url ?? note.uri != null) noteInfo = `Note: ${note.url ?? note.uri}\n`;
noteInfo += `Local Note: ${localUrl}\n`;
- os.popup(defineAsyncComponent(() => import('@/components/MkAbuseReportWindow.vue')), {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkAbuseReportWindow.vue')), {
user: note.user,
initialComment: `${noteInfo}-----\n`,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
},
};
}
@@ -530,7 +532,9 @@ export function getRenoteMenu(props: {
const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2);
- os.popup(MkRippleEffect, { x, y }, {}, 'end');
+ const { dispose } = os.popup(MkRippleEffect, { x, y }, {
+ end: () => dispose(),
+ });
}
if (!props.mock) {
@@ -566,7 +570,9 @@ export function getRenoteMenu(props: {
const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2);
- os.popup(MkRippleEffect, { x, y }, {}, 'end');
+ const { dispose } = os.popup(MkRippleEffect, { x, y }, {
+ end: () => dispose(),
+ });
}
const configuredVisibility = defaultStore.state.rememberNoteVisibility ? defaultStore.state.visibility : defaultStore.state.defaultNoteVisibility;
@@ -615,7 +621,9 @@ export function getRenoteMenu(props: {
const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2);
- os.popup(MkRippleEffect, { x, y }, {}, 'end');
+ const { dispose } = os.popup(MkRippleEffect, { x, y }, {
+ end: () => dispose(),
+ });
}
if (!props.mock) {
diff --git a/packages/frontend/src/scripts/get-user-menu.ts b/packages/frontend/src/scripts/get-user-menu.ts
index 3e031d232f..33f16a68aa 100644
--- a/packages/frontend/src/scripts/get-user-menu.ts
+++ b/packages/frontend/src/scripts/get-user-menu.ts
@@ -7,15 +7,17 @@ import { toUnicode } from 'punycode';
import { defineAsyncComponent, ref, watch } from 'vue';
import * as Misskey from 'misskey-js';
import { i18n } from '@/i18n.js';
-import copyToClipboard from '@/scripts/copy-to-clipboard.js';
+import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
import { host, url } from '@/config.js';
import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { defaultStore, userActions } from '@/store.js';
import { $i, iAmModerator } from '@/account.js';
+import { notesSearchAvailable, canSearchNonLocalNotes } from '@/scripts/check-permissions.js';
import { IRouter } from '@/nirax.js';
import { antennasCache, rolesCache, userListsCache } from '@/cache.js';
import { mainRouter } from '@/router/main.js';
+import { MenuItem } from '@/types/menu.js';
export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter = mainRouter) {
const meId = $i ? $i.id : null;
@@ -81,15 +83,6 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter
});
}
- async function toggleWithReplies() {
- os.apiWithDialog('following/update', {
- userId: user.id,
- withReplies: !user.withReplies,
- }).then(() => {
- user.withReplies = !user.withReplies;
- });
- }
-
async function toggleNotify() {
os.apiWithDialog('following/update', {
userId: user.id,
@@ -100,9 +93,11 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter
}
function reportAbuse() {
- os.popup(defineAsyncComponent(() => import('@/components/MkAbuseReportWindow.vue')), {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkAbuseReportWindow.vue')), {
user: user,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
}
async function getConfirmed(text: string): Promise<boolean> {
@@ -152,13 +147,20 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter
});
}
- let menu = [{
+ let menu: MenuItem[] = [{
icon: 'ti ti-at',
text: i18n.ts.copyUsername,
action: () => {
copyToClipboard(`@${user.username}@${user.host ?? host}`);
},
- }, ...(iAmModerator ? [{
+ }, ...( notesSearchAvailable && (user.host == null || canSearchNonLocalNotes) ? [{
+ icon: 'ti ti-search',
+ text: i18n.ts.searchThisUsersNotes,
+ action: () => {
+ router.push(`/search?username=${encodeURIComponent(user.username)}${user.host != null ? '&host=' + encodeURIComponent(user.host) : ''}`);
+ },
+ }] : [])
+ , ...(iAmModerator ? [{
icon: 'ti ti-user-exclamation',
text: i18n.ts.moderation,
action: () => {
@@ -184,7 +186,7 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter
const canonical = user.host === null ? `@${user.username}` : `@${user.username}@${toUnicode(user.host)}`;
copyToClipboard(`${url}/${canonical}`);
},
- }, {
+ }, ...($i ? [{
icon: 'ti ti-mail',
text: i18n.ts.sendMessage,
action: () => {
@@ -257,7 +259,7 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter
},
}));
},
- }] as any;
+ }] : [])] as any;
if ($i && meId !== user.id) {
if (iAmModerator) {
@@ -304,15 +306,25 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter
// フォローã—ãŸã¨ã—ã¦ã‚‚ user.isFollowing ã¯ãƒªã‚¢ãƒ«ã‚¿ã‚¤ãƒ æ›´æ–°ã•れãªã„ã®ã§ä¸ä¾¿ãªãŸã‚
//if (user.isFollowing) {
+ const withRepliesRef = ref(user.withReplies);
menu = menu.concat([{
- icon: user.withReplies ? 'ti ti-messages-off' : 'ti ti-messages',
- text: user.withReplies ? i18n.ts.hideRepliesToOthersInTimeline : i18n.ts.showRepliesToOthersInTimeline,
- action: toggleWithReplies,
+ type: 'switch',
+ icon: 'ti ti-messages',
+ text: i18n.ts.showRepliesToOthersInTimeline,
+ ref: withRepliesRef,
}, {
icon: user.notify === 'none' ? 'ti ti-bell' : 'ti ti-bell-off',
text: user.notify === 'none' ? i18n.ts.notifyNotes : i18n.ts.unnotifyNotes,
action: toggleNotify,
}]);
+ watch(withRepliesRef, (withReplies) => {
+ misskeyApi('following/update', {
+ userId: user.id,
+ withReplies,
+ }).then(() => {
+ user.withReplies = withReplies;
+ });
+ });
//}
menu = menu.concat([{ type: 'divider' }, {
diff --git a/packages/frontend/src/scripts/hotkey.ts b/packages/frontend/src/scripts/hotkey.ts
index 0600bff893..04fb235694 100644
--- a/packages/frontend/src/scripts/hotkey.ts
+++ b/packages/frontend/src/scripts/hotkey.ts
@@ -2,94 +2,171 @@
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
+import { getHTMLElementOrNull } from "@/scripts/get-dom-node-or-null.js";
-import keyCode from './keycode.js';
+//#region types
+export type Keymap = Record<string, CallbackFunction | CallbackObject>;
-type Callback = (ev: KeyboardEvent) => void;
+type CallbackFunction = (ev: KeyboardEvent) => unknown;
-type Keymap = Record<string, Callback>;
+type CallbackObject = {
+ callback: CallbackFunction;
+ allowRepeat?: boolean;
+};
type Pattern = {
which: string[];
- ctrl?: boolean;
- shift?: boolean;
- alt?: boolean;
+ ctrl: boolean;
+ alt: boolean;
+ shift: boolean;
};
type Action = {
patterns: Pattern[];
- callback: Callback;
- allowRepeat: boolean;
+ callback: CallbackFunction;
+ options: Required<Omit<CallbackObject, 'callback'>>;
};
+//#endregion
-const parseKeymap = (keymap: Keymap) => Object.entries(keymap).map(([patterns, callback]): Action => {
- const result = {
- patterns: [],
- callback,
- allowRepeat: true,
- } as Action;
+//#region consts
+const KEY_ALIASES = {
+ 'esc': 'Escape',
+ 'enter': 'Enter',
+ 'space': ' ',
+ 'up': 'ArrowUp',
+ 'down': 'ArrowDown',
+ 'left': 'ArrowLeft',
+ 'right': 'ArrowRight',
+ 'plus': ['+', ';'],
+};
- if (patterns.match(/^\(.*\)$/) !== null) {
- result.allowRepeat = false;
- patterns = patterns.slice(1, -1);
- }
+const MODIFIER_KEYS = ['ctrl', 'alt', 'shift'];
+
+const IGNORE_ELEMENTS = ['input', 'textarea'];
+//#endregion
- result.patterns = patterns.split('|').map(part => {
- const pattern = {
- which: [],
- ctrl: false,
- alt: false,
- shift: false,
- } as Pattern;
+//#region store
+let latestHotkey: Pattern & { callback: CallbackFunction } | null = null;
+//#endregion
- const keys = part.trim().split('+').map(x => x.trim().toLowerCase());
- for (const key of keys) {
- switch (key) {
- case 'ctrl': pattern.ctrl = true; break;
- case 'alt': pattern.alt = true; break;
- case 'shift': pattern.shift = true; break;
- default: pattern.which = keyCode(key).map(k => k.toLowerCase());
+//#region impl
+export const makeHotkey = (keymap: Keymap) => {
+ const actions = parseKeymap(keymap);
+ return (ev: KeyboardEvent) => {
+ if ('pswp' in window && window.pswp != null) return;
+ if (document.activeElement != null) {
+ if (IGNORE_ELEMENTS.includes(document.activeElement.tagName.toLowerCase())) return;
+ if (getHTMLElementOrNull(document.activeElement)?.isContentEditable) return;
+ }
+ for (const action of actions) {
+ if (matchPatterns(ev, action)) {
+ ev.preventDefault();
+ ev.stopPropagation();
+ action.callback(ev);
+ storePattern(ev, action.callback);
}
}
+ };
+};
- return pattern;
+const parseKeymap = (keymap: Keymap) => {
+ return Object.entries(keymap).map(([rawPatterns, rawCallback]) => {
+ const patterns = parsePatterns(rawPatterns);
+ const callback = parseCallback(rawCallback);
+ const options = parseOptions(rawCallback);
+ return { patterns, callback, options } as const satisfies Action;
});
+};
- return result;
-});
-
-const ignoreElements = ['input', 'textarea'];
+const parsePatterns = (rawPatterns: keyof Keymap) => {
+ return rawPatterns.split('|').map(part => {
+ const keys = part.split('+').map(trimLower);
+ const which = parseKeyCode(keys.findLast(x => !MODIFIER_KEYS.includes(x)));
+ const ctrl = keys.includes('ctrl');
+ const alt = keys.includes('alt');
+ const shift = keys.includes('shift');
+ return { which, ctrl, alt, shift } as const satisfies Pattern;
+ });
+};
-function match(ev: KeyboardEvent, patterns: Action['patterns']): boolean {
- const key = ev.key.toLowerCase();
- return patterns.some(pattern => pattern.which.includes(key) &&
- pattern.ctrl === ev.ctrlKey &&
- pattern.shift === ev.shiftKey &&
- pattern.alt === ev.altKey &&
- !ev.metaKey,
- );
-}
+const parseCallback = (rawCallback: Keymap[keyof Keymap]) => {
+ if (typeof rawCallback === 'object') {
+ return rawCallback.callback;
+ }
+ return rawCallback;
+};
-export const makeHotkey = (keymap: Keymap) => {
- const actions = parseKeymap(keymap);
+const parseOptions = (rawCallback: Keymap[keyof Keymap]) => {
+ const defaultOptions = {
+ allowRepeat: false,
+ } as const satisfies Action['options'];
+ if (typeof rawCallback === 'object') {
+ const { callback, ...rawOptions } = rawCallback;
+ const options = { ...defaultOptions, ...rawOptions };
+ return { ...options } as const satisfies Action['options'];
+ }
+ return { ...defaultOptions } as const satisfies Action['options'];
+};
- return (ev: KeyboardEvent) => {
- if (document.activeElement) {
- if (ignoreElements.some(el => document.activeElement!.matches(el))) return;
- if (document.activeElement.attributes['contenteditable']) return;
+const matchPatterns = (ev: KeyboardEvent, action: Action) => {
+ const { patterns, options, callback } = action;
+ if (ev.repeat && !options.allowRepeat) return false;
+ const key = ev.key.toLowerCase();
+ return patterns.some(({ which, ctrl, shift, alt }) => {
+ if (
+ options.allowRepeat === false &&
+ latestHotkey != null &&
+ latestHotkey.which.includes(key) &&
+ latestHotkey.ctrl === ctrl &&
+ latestHotkey.alt === alt &&
+ latestHotkey.shift === shift &&
+ latestHotkey.callback === callback
+ ) {
+ return false;
}
+ if (!which.includes(key)) return false;
+ if (ctrl !== (ev.ctrlKey || ev.metaKey)) return false;
+ if (alt !== ev.altKey) return false;
+ if (shift !== ev.shiftKey) return false;
+ return true;
+ });
+};
- for (const action of actions) {
- const matched = match(ev, action.patterns);
+let lastHotKeyStoreTimer: number | null = null;
- if (matched) {
- if (!action.allowRepeat && ev.repeat) return;
+const storePattern = (ev: KeyboardEvent, callback: CallbackFunction) => {
+ if (lastHotKeyStoreTimer != null) {
+ clearTimeout(lastHotKeyStoreTimer);
+ }
- ev.preventDefault();
- ev.stopPropagation();
- action.callback(ev);
- break;
- }
- }
+ latestHotkey = {
+ which: [ev.key.toLowerCase()],
+ ctrl: ev.ctrlKey || ev.metaKey,
+ alt: ev.altKey,
+ shift: ev.shiftKey,
+ callback,
};
+
+ lastHotKeyStoreTimer = window.setTimeout(() => {
+ latestHotkey = null;
+ }, 500);
};
+
+const parseKeyCode = (input?: string | null) => {
+ if (input == null) return [];
+ const raw = getValueByKey(KEY_ALIASES, input);
+ if (raw == null) return [input];
+ if (typeof raw === 'string') return [trimLower(raw)];
+ return raw.map(trimLower);
+};
+
+const getValueByKey = <
+ T extends Record<keyof any, unknown>,
+ K extends keyof T | keyof any,
+ R extends K extends keyof T ? T[K] : T[keyof T] | undefined,
+>(obj: T, key: K) => {
+ return obj[key] as R;
+};
+
+const trimLower = (str: string) => str.trim().toLowerCase();
+//#endregion
diff --git a/packages/frontend/src/scripts/install-plugin.ts b/packages/frontend/src/scripts/install-plugin.ts
index d0a8675b19..37f473b6de 100644
--- a/packages/frontend/src/scripts/install-plugin.ts
+++ b/packages/frontend/src/scripts/install-plugin.ts
@@ -103,7 +103,7 @@ export async function installPlugin(code: string, meta?: AiScriptPluginMeta) {
}
const token = realMeta.permissions == null || realMeta.permissions.length === 0 ? null : await new Promise((res, rej) => {
- os.popup(defineAsyncComponent(() => import('@/components/MkTokenGenerateWindow.vue')), {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkTokenGenerateWindow.vue')), {
title: i18n.ts.tokenRequested,
information: i18n.ts.pluginTokenRequestedDescription,
initialName: realMeta.name,
@@ -118,7 +118,8 @@ export async function installPlugin(code: string, meta?: AiScriptPluginMeta) {
});
res(token);
},
- }, 'closed');
+ closed: () => dispose(),
+ });
});
savePlugin({
diff --git a/packages/frontend/src/scripts/keycode.ts b/packages/frontend/src/scripts/keycode.ts
deleted file mode 100644
index 7ffceafada..0000000000
--- a/packages/frontend/src/scripts/keycode.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export default (input: string): string[] => {
- if (Object.keys(aliases).some(a => a.toLowerCase() === input.toLowerCase())) {
- const codes = aliases[input];
- return Array.isArray(codes) ? codes : [codes];
- } else {
- return [input];
- }
-};
-
-export const aliases = {
- 'esc': 'Escape',
- 'enter': ['Enter', 'NumpadEnter'],
- 'space': [' ', 'Spacebar'],
- 'up': 'ArrowUp',
- 'down': 'ArrowDown',
- 'left': 'ArrowLeft',
- 'right': 'ArrowRight',
- 'plus': ['NumpadAdd', 'Semicolon'],
-};
diff --git a/packages/frontend/src/scripts/lookup.ts b/packages/frontend/src/scripts/lookup.ts
index 7f020b15cc..a261ec0669 100644
--- a/packages/frontend/src/scripts/lookup.ts
+++ b/packages/frontend/src/scripts/lookup.ts
@@ -16,7 +16,7 @@ export async function lookup(router?: Router) {
title: i18n.ts.lookup,
});
const query = temp ? temp.trim() : '';
- if (canceled) return;
+ if (canceled || query.length <= 1) return;
if (query.startsWith('@') && !query.includes(' ')) {
_router.push(`/${query}`);
diff --git a/packages/frontend/src/scripts/merge.ts b/packages/frontend/src/scripts/merge.ts
index 4e39a0fa06..9794a300da 100644
--- a/packages/frontend/src/scripts/merge.ts
+++ b/packages/frontend/src/scripts/merge.ts
@@ -6,7 +6,7 @@
import { deepClone } from './clone.js';
import type { Cloneable } from './clone.js';
-type DeepPartial<T> = {
+export type DeepPartial<T> = {
[P in keyof T]?: T[P] extends Record<string | number | symbol, unknown> ? DeepPartial<T[P]> : T[P];
};
diff --git a/packages/frontend/src/scripts/mfm-function-picker.ts b/packages/frontend/src/scripts/mfm-function-picker.ts
index 8867a8c50f..9938e534c1 100644
--- a/packages/frontend/src/scripts/mfm-function-picker.ts
+++ b/packages/frontend/src/scripts/mfm-function-picker.ts
@@ -7,29 +7,24 @@ import { Ref, nextTick } from 'vue';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { MFM_TAGS } from '@/const.js';
+import type { MenuItem } from '@/types/menu.js';
/**
* MFMã®è£…飾ã®ãƒªã‚¹ãƒˆã‚’表示ã™ã‚‹
*/
-export function mfmFunctionPicker(src: any, textArea: HTMLInputElement | HTMLTextAreaElement, textRef: Ref<string>) {
- return new Promise((res, rej) => {
- os.popupMenu([{
- text: i18n.ts.addMfmFunction,
- type: 'label',
- }, ...getFunctionList(textArea, textRef)], src);
- });
+export function mfmFunctionPicker(src: HTMLElement | EventTarget | null, textArea: HTMLInputElement | HTMLTextAreaElement, textRef: Ref<string>) {
+ os.popupMenu([{
+ text: i18n.ts.addMfmFunction,
+ type: 'label',
+ }, ...getFunctionList(textArea, textRef)], src);
}
-function getFunctionList(textArea: HTMLInputElement | HTMLTextAreaElement, textRef: Ref<string>) : object[] {
- const ret: object[] = [];
- MFM_TAGS.forEach(tag => {
- ret.push({
- text: tag,
- icon: 'ti ti-icons',
- action: () => add(textArea, textRef, tag),
- });
- });
- return ret;
+function getFunctionList(textArea: HTMLInputElement | HTMLTextAreaElement, textRef: Ref<string>): MenuItem[] {
+ return MFM_TAGS.map(tag => ({
+ text: tag,
+ icon: 'ti ti-icons',
+ action: () => add(textArea, textRef, tag),
+ }));
}
function add(textArea: HTMLInputElement | HTMLTextAreaElement, textRef: Ref<string>, type: string) {
diff --git a/packages/frontend/src/scripts/player-url-transform.ts b/packages/frontend/src/scripts/player-url-transform.ts
new file mode 100644
index 0000000000..53b2a9e441
--- /dev/null
+++ b/packages/frontend/src/scripts/player-url-transform.ts
@@ -0,0 +1,26 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+import { hostname } from '@/config.js';
+
+export function transformPlayerUrl(url: string): string {
+ const urlObj = new URL(url);
+ if (!['https:', 'http:'].includes(urlObj.protocol)) throw new Error('Invalid protocol');
+
+ const urlParams = new URLSearchParams(urlObj.search);
+
+ if (urlObj.hostname === 'player.twitch.tv') {
+ // Twitchã¯CSPã®åˆ¶ç´„ã‚り
+ // https://dev.twitch.tv/docs/embed/video-and-clips/
+ urlParams.set('parent', hostname);
+ urlParams.set('allowfullscreen', '');
+ urlParams.set('autoplay', 'true');
+ } else {
+ urlParams.set('autoplay', '1');
+ urlParams.set('auto_play', '1');
+ }
+ urlObj.search = urlParams.toString();
+
+ return urlObj.toString();
+}
diff --git a/packages/frontend/src/scripts/please-login.ts b/packages/frontend/src/scripts/please-login.ts
index 9e51272791..18f05bc7f4 100644
--- a/packages/frontend/src/scripts/please-login.ts
+++ b/packages/frontend/src/scripts/please-login.ts
@@ -8,19 +8,57 @@ import { $i } from '@/account.js';
import { i18n } from '@/i18n.js';
import { popup } from '@/os.js';
-export function pleaseLogin(path?: string) {
+export type OpenOnRemoteOptions = {
+ /**
+ * 外部ã®Misskey Webã§ç‰¹å®šã®ãƒ‘スを開ã
+ */
+ type: 'web';
+
+ /**
+ * 内部パス(例: `/settings`)
+ */
+ path: string;
+} | {
+ /**
+ * 外部ã®Misskey Webã§ç…§ä¼šã™ã‚‹
+ */
+ type: 'lookup';
+
+ /**
+ * 照会ã—ãŸã„エンティティã®URL
+ *
+ * (例: `https://misskey.example.com/notes/abcdexxxxyz`)
+ */
+ url: string;
+} | {
+ /**
+ * 外部ã®Misskeyã§ãƒŽãƒ¼ãƒˆã™ã‚‹
+ */
+ type: 'share';
+
+ /**
+ * `/share` ãƒšãƒ¼ã‚¸ã«æ¸¡ã™ã‚¯ã‚¨ãƒªã‚¹ãƒˆãƒªãƒ³ã‚°
+ *
+ * @see https://go.misskey-hub.net/spec/share/
+ */
+ params: Record<string, string>;
+};
+
+export function pleaseLogin(path?: string, openOnRemote?: OpenOnRemoteOptions) {
if ($i) return;
- popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), {
+ const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), {
autoSet: true,
- message: i18n.ts.signinRequired,
+ message: openOnRemote ? i18n.ts.signinOrContinueOnRemote : i18n.ts.signinRequired,
+ openOnRemote,
}, {
cancelled: () => {
if (path) {
window.location.href = path;
}
},
- }, 'closed');
+ closed: () => dispose(),
+ });
throw new Error('signin required');
}
diff --git a/packages/frontend/src/scripts/scroll.ts b/packages/frontend/src/scripts/scroll.ts
index 8edb6fca05..f0274034b5 100644
--- a/packages/frontend/src/scripts/scroll.ts
+++ b/packages/frontend/src/scripts/scroll.ts
@@ -23,6 +23,14 @@ export function getStickyTop(el: HTMLElement, container: HTMLElement | null = nu
return getStickyTop(el.parentElement, container, newTop);
}
+export function getStickyBottom(el: HTMLElement, container: HTMLElement | null = null, bottom = 0) {
+ if (!el.parentElement) return bottom;
+ const data = el.dataset.stickyContainerFooterHeight;
+ const newBottom = data ? Number(data) + bottom : bottom;
+ if (el === container) return newBottom;
+ return getStickyBottom(el.parentElement, container, newBottom);
+}
+
export function getScrollPosition(el: HTMLElement | null): number {
const container = getScrollContainer(el);
return container == null ? window.scrollY : container.scrollTop;
diff --git a/packages/frontend/src/scripts/sound.ts b/packages/frontend/src/scripts/sound.ts
index fcd59510df..05f82fce7d 100644
--- a/packages/frontend/src/scripts/sound.ts
+++ b/packages/frontend/src/scripts/sound.ts
@@ -74,8 +74,6 @@ export const soundsTypes = [
export const operationTypes = [
'noteMy',
'note',
- 'antenna',
- 'channel',
'notification',
'reaction',
] as const;
@@ -126,10 +124,33 @@ export async function loadAudio(url: string, options?: { useCache?: boolean; })
*/
export function playMisskeySfx(operationType: OperationType) {
const sound = defaultStore.state[`sound_${operationType}`];
- if (sound.type == null || !canPlay || ('userActivation' in navigator && !navigator.userActivation.hasBeenActive)) return;
+ playMisskeySfxFile(sound).then((succeed) => {
+ if (!succeed && sound.type === '_driveFile_') {
+ // ドライブファイルãŒå­˜åœ¨ã—ãªã„å ´åˆã¯ãƒ‡ãƒ•ォルトã®ã‚µã‚¦ãƒ³ãƒ‰ã‚’å†ç”Ÿã™ã‚‹
+ const soundName = defaultStore.def[`sound_${operationType}`].default.type as Exclude<SoundType, '_driveFile_'>;
+ if (_DEV_) console.log(`Failed to play sound: ${sound.fileUrl}, so play default sound: ${soundName}`);
+ playMisskeySfxFileInternal({
+ type: soundName,
+ volume: sound.volume,
+ });
+ }
+ });
+}
+
+/**
+ * サウンド設定形å¼ã§æŒ‡å®šã•れãŸéŸ³å£°ã‚’å†ç”Ÿã™ã‚‹
+ * @param soundStore サウンド設定
+ */
+export async function playMisskeySfxFile(soundStore: SoundStore): Promise<boolean> {
+ // 連続ã—ã¦å†ç”Ÿã—ãªã„
+ if (!canPlay) return false;
+ // ユーザーアクティベーションãŒå¿…è¦ãªå ´åˆã¯ãれãŒãªã„å ´åˆã¯å†ç”Ÿã—ãªã„
+ if ('userActivation' in navigator && !navigator.userActivation.hasBeenActive) return false;
+ // サウンドãŒãªã„å ´åˆã¯å†ç”Ÿã—ãªã„
+ if (soundStore.type === null || soundStore.type === '_driveFile_' && !soundStore.fileUrl) return false;
canPlay = false;
- playMisskeySfxFile(sound).finally(() => {
+ return await playMisskeySfxFileInternal(soundStore).finally(() => {
// ã”ã短時間ã«éŸ³ãŒé‡è¤‡ã—ãªã„よã†ã«
setTimeout(() => {
canPlay = true;
@@ -137,23 +158,22 @@ export function playMisskeySfx(operationType: OperationType) {
});
}
-/**
- * サウンド設定形å¼ã§æŒ‡å®šã•れãŸéŸ³å£°ã‚’å†ç”Ÿã™ã‚‹
- * @param soundStore サウンド設定
- */
-export async function playMisskeySfxFile(soundStore: SoundStore) {
+async function playMisskeySfxFileInternal(soundStore: SoundStore): Promise<boolean> {
if (soundStore.type === null || (soundStore.type === '_driveFile_' && !soundStore.fileUrl)) {
- return;
+ return false;
}
const masterVolume = defaultStore.state.sound_masterVolume;
if (isMute() || masterVolume === 0 || soundStore.volume === 0) {
- return;
+ return true; // ãƒŸãƒ¥ãƒ¼ãƒˆæ™‚ã¯æˆåŠŸã¨ã—ã¦æ‰±ã†
}
const url = soundStore.type === '_driveFile_' ? soundStore.fileUrl : `/client-assets/sounds/${soundStore.type}.mp3`;
- const buffer = await loadAudio(url);
- if (!buffer) return;
+ const buffer = await loadAudio(url).catch(() => {
+ return undefined;
+ });
+ if (!buffer) return false;
const volume = soundStore.volume * masterVolume;
createSourceNode(buffer, { volume }).soundSource.start();
+ return true;
}
export async function playUrl(url: string, opts: {
diff --git a/packages/frontend/src/scripts/url.ts b/packages/frontend/src/scripts/url.ts
index e3072b3b7d..5a8265af9e 100644
--- a/packages/frontend/src/scripts/url.ts
+++ b/packages/frontend/src/scripts/url.ts
@@ -21,3 +21,8 @@ export function query(obj: Record<string, any>): string {
export function appendQuery(url: string, query: string): string {
return `${url}${/\?/.test(url) ? url.endsWith('?') ? '' : '&' : '?'}${query}`;
}
+
+export function extractDomain(url: string) {
+ const match = url.match(/^(?:https?:)?(?:\/\/)?(?:[^@\n]+@)?([^:\/\n]+)/im);
+ return match ? match[1] : null;
+}
diff --git a/packages/frontend/src/scripts/use-chart-tooltip.ts b/packages/frontend/src/scripts/use-chart-tooltip.ts
index bed221a622..bba64fc6ee 100644
--- a/packages/frontend/src/scripts/use-chart-tooltip.ts
+++ b/packages/frontend/src/scripts/use-chart-tooltip.ts
@@ -17,20 +17,16 @@ export function useChartTooltip(opts: { position: 'top' | 'middle' } = { positio
borderColor: string;
text: string;
}[] | null>(null);
- let disposeTooltipComponent;
-
- os.popup(MkChartTooltip, {
+ const { dispose: disposeTooltipComponent } = os.popup(MkChartTooltip, {
showing: tooltipShowing,
x: tooltipX,
y: tooltipY,
title: tooltipTitle,
series: tooltipSeries,
- }, {}).then(({ dispose }) => {
- disposeTooltipComponent = dispose;
- });
+ }, {});
onUnmounted(() => {
- if (disposeTooltipComponent) disposeTooltipComponent();
+ disposeTooltipComponent();
});
onDeactivated(() => {
diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts
index e8eb5a1ed7..437314074a 100644
--- a/packages/frontend/src/store.ts
+++ b/packages/frontend/src/store.ts
@@ -454,6 +454,14 @@ export const defaultStore = markRaw(new Storage('base', {
where: 'device',
default: true,
},
+ confirmWhenRevealingSensitiveMedia: {
+ where: 'device',
+ default: false,
+ },
+ contextMenu: {
+ where: 'device',
+ default: 'app' as 'app' | 'appWithShift' | 'native',
+ },
sound_masterVolume: {
where: 'device',
@@ -479,14 +487,6 @@ export const defaultStore = markRaw(new Storage('base', {
where: 'device',
default: { type: 'syuilo/n-ea', volume: 1 } as SoundStore,
},
- sound_antenna: {
- where: 'device',
- default: { type: 'syuilo/triple', volume: 1 } as SoundStore,
- },
- sound_channel: {
- where: 'device',
- default: { type: 'syuilo/square-pico', volume: 1 } as SoundStore,
- },
sound_reaction: {
where: 'device',
default: { type: 'syuilo/bubble2', volume: 1 } as SoundStore,
diff --git a/packages/frontend/src/style.scss b/packages/frontend/src/style.scss
index 250a2616a7..2feb79ef81 100644
--- a/packages/frontend/src/style.scss
+++ b/packages/frontend/src/style.scss
@@ -113,6 +113,10 @@ a {
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
+ &:focus-visible {
+ outline-offset: 2px;
+ }
+
&:hover {
text-decoration: underline;
}
@@ -143,12 +147,21 @@ rt {
white-space: initial;
}
+:focus-visible {
+ outline: var(--focus) solid 2px;
+ outline-offset: -2px;
+
+ &:hover {
+ text-decoration: none;
+ }
+}
+
.ti {
width: 1.28em;
vertical-align: -12%;
line-height: 1em;
- &:before {
+ &::before {
font-size: 128%;
}
}
@@ -230,10 +243,6 @@ rt {
line-height: inherit;
max-width: 100%;
- &:focus-visible {
- outline: none;
- }
-
&:disabled {
opacity: 0.5;
cursor: default;
@@ -270,13 +279,17 @@ rt {
._help {
color: var(--accent);
- cursor: help
+ cursor: help;
}
._textButton {
@extend ._button;
color: var(--accent);
+ &:focus-visible {
+ outline-offset: 2px;
+ }
+
&:not(:disabled):hover {
text-decoration: underline;
}
diff --git a/packages/frontend/src/timelines.ts b/packages/frontend/src/timelines.ts
new file mode 100644
index 0000000000..94eda3545e
--- /dev/null
+++ b/packages/frontend/src/timelines.ts
@@ -0,0 +1,56 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { $i } from '@/account.js';
+import { instance } from '@/instance.js';
+
+export const basicTimelineTypes = [
+ 'home',
+ 'local',
+ 'social',
+ 'global',
+] as const;
+
+export type BasicTimelineType = typeof basicTimelineTypes[number];
+
+export function isBasicTimeline(timeline: string): timeline is BasicTimelineType {
+ return basicTimelineTypes.includes(timeline as BasicTimelineType);
+}
+
+export function basicTimelineIconClass(timeline: BasicTimelineType): string {
+ switch (timeline) {
+ case 'home':
+ return 'ti ti-home';
+ case 'local':
+ return 'ti ti-planet';
+ case 'social':
+ return 'ti ti-universe';
+ case 'global':
+ return 'ti ti-whirl';
+ }
+}
+
+export function isAvailableBasicTimeline(timeline: BasicTimelineType | undefined | null): boolean {
+ switch (timeline) {
+ case 'home':
+ return $i != null;
+ case 'local':
+ return ($i == null && instance.policies.ltlAvailable) || ($i != null && $i.policies.ltlAvailable);
+ case 'social':
+ return $i != null && $i.policies.ltlAvailable;
+ case 'global':
+ return ($i == null && instance.policies.gtlAvailable) || ($i != null && $i.policies.gtlAvailable);
+ default:
+ return false;
+ }
+}
+
+export function availableBasicTimelines(): BasicTimelineType[] {
+ return basicTimelineTypes.filter(isAvailableBasicTimeline);
+}
+
+export function hasWithReplies(timeline: BasicTimelineType | undefined | null): boolean {
+ return timeline === 'local' || timeline === 'social';
+}
diff --git a/packages/frontend/src/ui/_common_/common.ts b/packages/frontend/src/ui/_common_/common.ts
index 839fa5faf8..74c3028745 100644
--- a/packages/frontend/src/ui/_common_/common.ts
+++ b/packages/frontend/src/ui/_common_/common.ts
@@ -85,34 +85,36 @@ export function openInstanceMenu(ev: MouseEvent) {
icon: 'ti ti-help-circle',
to: '/contact',
}, (instance.impressumUrl) ? {
+ type: 'a',
text: i18n.ts.impressum,
icon: 'ti ti-file-invoice',
- action: () => {
- window.open(instance.impressumUrl, '_blank', 'noopener');
- },
+ href: instance.impressumUrl,
+ target: '_blank',
} : undefined, (instance.tosUrl) ? {
+ type: 'a',
text: i18n.ts.termsOfService,
icon: 'ti ti-notebook',
- action: () => {
- window.open(instance.tosUrl, '_blank', 'noopener');
- },
+ href: instance.tosUrl,
+ target: '_blank',
} : undefined, (instance.privacyPolicyUrl) ? {
+ type: 'a',
text: i18n.ts.privacyPolicy,
icon: 'ti ti-shield-lock',
- action: () => {
- window.open(instance.privacyPolicyUrl, '_blank', 'noopener');
- },
+ href: instance.privacyPolicyUrl,
+ target: '_blank',
} : undefined, (!instance.impressumUrl && !instance.tosUrl && !instance.privacyPolicyUrl) ? undefined : { type: 'divider' }, {
+ type: 'a',
text: i18n.ts.document,
icon: 'ti ti-bulb',
- action: () => {
- window.open('https://misskey-hub.net/docs/for-users/', '_blank', 'noopener');
- },
+ href: 'https://misskey-hub.net/docs/for-users/',
+ target: '_blank',
}, ($i) ? {
text: i18n.ts._initialTutorial.launchTutorial,
icon: 'ti ti-presentation',
action: () => {
- os.popup(defineAsyncComponent(() => import('@/components/MkTutorialDialog.vue')), {}, {}, 'closed');
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkTutorialDialog.vue')), {}, {
+ closed: () => dispose(),
+ });
},
} : undefined, {
type: 'link',
diff --git a/packages/frontend/src/ui/_common_/common.vue b/packages/frontend/src/ui/_common_/common.vue
index 822b552837..d7df2d10f9 100644
--- a/packages/frontend/src/ui/_common_/common.vue
+++ b/packages/frontend/src/ui/_common_/common.vue
@@ -227,7 +227,7 @@ if ($i) {
right: 15px;
pointer-events: none;
- &:before {
+ &::before {
content: "";
display: block;
width: 18px;
diff --git a/packages/frontend/src/ui/_common_/navbar-for-mobile.vue b/packages/frontend/src/ui/_common_/navbar-for-mobile.vue
index 5d0e065f09..87e9e45e63 100644
--- a/packages/frontend/src/ui/_common_/navbar-for-mobile.vue
+++ b/packages/frontend/src/ui/_common_/navbar-for-mobile.vue
@@ -74,8 +74,9 @@ function openAccountMenu(ev: MouseEvent) {
}
function more() {
- os.popup(defineAsyncComponent(() => import('@/components/MkLaunchPad.vue')), {}, {
- }, 'closed');
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkLaunchPad.vue')), {}, {
+ closed: () => dispose(),
+ });
}
</script>
@@ -138,7 +139,7 @@ function more() {
font-weight: bold;
text-align: left;
- &:before {
+ &::before {
content: "";
display: block;
width: calc(100% - 38px);
@@ -154,7 +155,7 @@ function more() {
}
&:hover, &.active {
- &:before {
+ &::before {
background: var(--accentLighten);
}
}
@@ -225,7 +226,7 @@ function more() {
}
&:hover, &.active {
- &:before {
+ &::before {
content: "";
display: block;
width: calc(100% - 24px);
diff --git a/packages/frontend/src/ui/_common_/navbar.vue b/packages/frontend/src/ui/_common_/navbar.vue
index fa1f0eb8c7..8307da0d42 100644
--- a/packages/frontend/src/ui/_common_/navbar.vue
+++ b/packages/frontend/src/ui/_common_/navbar.vue
@@ -99,10 +99,11 @@ function openAccountMenu(ev: MouseEvent) {
}
function more(ev: MouseEvent) {
- os.popup(defineAsyncComponent(() => import('@/components/MkLaunchPad.vue')), {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkLaunchPad.vue')), {
src: ev.currentTarget ?? ev.target,
}, {
- }, 'closed');
+ closed: () => dispose(),
+ });
}
</script>
@@ -165,6 +166,15 @@ function more(ev: MouseEvent) {
display: block;
text-align: center;
width: 100%;
+
+ &:focus-visible {
+ outline: none;
+
+ > .instanceIcon {
+ outline: 2px solid var(--focus);
+ outline-offset: 2px;
+ }
+ }
}
.instanceIcon {
@@ -191,7 +201,7 @@ function more(ev: MouseEvent) {
font-weight: bold;
text-align: left;
- &:before {
+ &::before {
content: "";
display: block;
width: calc(100% - 38px);
@@ -206,8 +216,17 @@ function more(ev: MouseEvent) {
background: linear-gradient(90deg, var(--buttonGradateA), var(--buttonGradateB));
}
+ &:focus-visible {
+ outline: none;
+
+ &::before {
+ outline: 2px solid var(--fgOnAccent);
+ outline-offset: -4px;
+ }
+ }
+
&:hover, &.active {
- &:before {
+ &::before {
background: var(--accentLighten);
}
}
@@ -233,6 +252,14 @@ function more(ev: MouseEvent) {
text-align: left;
box-sizing: border-box;
overflow: clip;
+
+ &:focus-visible {
+ outline: none;
+
+ > .avatar {
+ box-shadow: 0 0 0 4px var(--focus);
+ }
+ }
}
.avatar {
@@ -281,10 +308,19 @@ function more(ev: MouseEvent) {
color: var(--navActive);
}
- &:hover, &.active {
+ &:focus-visible {
+ outline: none;
+
+ &::before {
+ outline: 2px solid var(--focus);
+ outline-offset: -2px;
+ }
+ }
+
+ &:hover, &.active, &:focus {
color: var(--accent);
- &:before {
+ &::before {
content: "";
display: block;
width: calc(100% - 34px);
@@ -351,6 +387,15 @@ function more(ev: MouseEvent) {
display: block;
text-align: center;
width: 100%;
+
+ &:focus-visible {
+ outline: none;
+
+ > .instanceIcon {
+ outline: 2px solid var(--focus);
+ outline-offset: 2px;
+ }
+ }
}
.instanceIcon {
@@ -375,7 +420,7 @@ function more(ev: MouseEvent) {
height: 52px;
text-align: center;
- &:before {
+ &::before {
content: "";
display: block;
position: absolute;
@@ -390,8 +435,17 @@ function more(ev: MouseEvent) {
background: linear-gradient(90deg, var(--buttonGradateA), var(--buttonGradateB));
}
+ &:focus-visible {
+ outline: none;
+
+ &::before {
+ outline: 2px solid var(--fgOnAccent);
+ outline-offset: -4px;
+ }
+ }
+
&:hover, &.active {
- &:before {
+ &::before {
background: var(--accentLighten);
}
}
@@ -412,6 +466,14 @@ function more(ev: MouseEvent) {
padding: 20px 0;
width: 100%;
overflow: clip;
+
+ &:focus-visible {
+ outline: none;
+
+ > .avatar {
+ box-shadow: 0 0 0 4px var(--focus);
+ }
+ }
}
.avatar {
@@ -441,11 +503,20 @@ function more(ev: MouseEvent) {
width: 100%;
text-align: center;
- &:hover, &.active {
+ &:focus-visible {
+ outline: none;
+
+ &::before {
+ outline: 2px solid var(--focus);
+ outline-offset: -2px;
+ }
+ }
+
+ &:hover, &.active, &:focus {
text-decoration: none;
color: var(--accent);
- &:before {
+ &::before {
content: "";
display: block;
height: 100%;
diff --git a/packages/frontend/src/ui/classic.header.vue b/packages/frontend/src/ui/classic.header.vue
index ee5176b558..c03afd6cd6 100644
--- a/packages/frontend/src/ui/classic.header.vue
+++ b/packages/frontend/src/ui/classic.header.vue
@@ -71,11 +71,12 @@ const otherNavItemIndicated = computed<boolean>(() => {
});
function more(ev: MouseEvent) {
- os.popup(defineAsyncComponent(() => import('@/components/MkLaunchPad.vue')), {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkLaunchPad.vue')), {
src: ev.currentTarget ?? ev.target,
anchor: { x: 'center', y: 'bottom' },
}, {
- }, 'closed');
+ closed: () => dispose(),
+ });
}
function openAccountMenu(ev: MouseEvent) {
diff --git a/packages/frontend/src/ui/classic.sidebar.vue b/packages/frontend/src/ui/classic.sidebar.vue
index 19672ef87f..d8574a915f 100644
--- a/packages/frontend/src/ui/classic.sidebar.vue
+++ b/packages/frontend/src/ui/classic.sidebar.vue
@@ -86,9 +86,11 @@ function calcViewState() {
}
function more(ev: MouseEvent) {
- os.popup(defineAsyncComponent(() => import('@/components/MkLaunchPad.vue')), {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkLaunchPad.vue')), {
src: ev.currentTarget ?? ev.target,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
}
function openAccountMenu(ev: MouseEvent) {
diff --git a/packages/frontend/src/ui/deck.vue b/packages/frontend/src/ui/deck.vue
index bdb62dca15..af46b0641d 100644
--- a/packages/frontend/src/ui/deck.vue
+++ b/packages/frontend/src/ui/deck.vue
@@ -24,7 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:ref="id"
:key="id"
:class="$style.column"
- :column="columns.find(c => c.id === id)"
+ :column="columns.find(c => c.id === id)!"
:isStacked="ids.length > 1"
@headerWheel="onWheel"
/>
@@ -95,7 +95,8 @@ SPDX-License-Identifier: AGPL-3.0-only
import { computed, defineAsyncComponent, ref, watch, shallowRef } from 'vue';
import { v4 as uuid } from 'uuid';
import XCommon from './_common_/common.vue';
-import { deckStore, addColumn as addColumnToStore, loadDeck, getProfiles, deleteProfile as deleteProfile_ } from './deck/deck-store.js';
+import { deckStore, columnTypes, addColumn as addColumnToStore, loadDeck, getProfiles, deleteProfile as deleteProfile_ } from './deck/deck-store.js';
+import type { ColumnType } from './deck/deck-store.js';
import XSidebar from '@/ui/_common_/navbar.vue';
import XDrawerMenu from '@/ui/_common_/navbar-for-mobile.vue';
import MkButton from '@/components/MkButton.vue';
@@ -152,10 +153,12 @@ window.addEventListener('resize', () => {
const snapScroll = deviceKind === 'smartphone' || deviceKind === 'tablet';
const drawerMenuShowing = ref(false);
+/*
const route = 'TODO';
watch(route, () => {
drawerMenuShowing.value = false;
});
+*/
const columns = deckStore.reactiveState.columns;
const layout = deckStore.reactiveState.layout;
@@ -174,32 +177,20 @@ function showSettings() {
const columnsEl = shallowRef<HTMLElement>();
const addColumn = async (ev) => {
- const columns = [
- 'main',
- 'widgets',
- 'notifications',
- 'tl',
- 'antenna',
- 'list',
- 'channel',
- 'mentions',
- 'direct',
- 'roleTimeline',
- ];
-
const { canceled, result: column } = await os.select({
title: i18n.ts._deck.addColumn,
- items: columns.map(column => ({
+ items: columnTypes.map(column => ({
value: column, text: i18n.ts._deck._columns[column],
})),
});
- if (canceled) return;
+ if (canceled || column == null) return;
addColumnToStore({
type: column,
id: uuid(),
name: i18n.ts._deck._columns[column],
width: 330,
+ soundSetting: { type: null, volume: 1 },
});
};
@@ -211,7 +202,7 @@ const onContextmenu = (ev) => {
};
function onWheel(ev: WheelEvent) {
- if (ev.deltaX === 0) {
+ if (ev.deltaX === 0 && columnsEl.value != null) {
columnsEl.value.scrollLeft += ev.deltaY;
}
}
@@ -242,7 +233,7 @@ function changeProfile(ev: MouseEvent) {
title: i18n.ts._deck.profile,
minLength: 1,
});
- if (canceled) return;
+ if (canceled || name == null) return;
deckStore.set('profile', name);
unisonReload();
diff --git a/packages/frontend/src/ui/deck/antenna-column.vue b/packages/frontend/src/ui/deck/antenna-column.vue
index c3dc1e4fce..987bd4db55 100644
--- a/packages/frontend/src/ui/deck/antenna-column.vue
+++ b/packages/frontend/src/ui/deck/antenna-column.vue
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
-<XColumn :menu="menu" :column="column" :isStacked="isStacked" :refresher="() => timeline.reloadTimeline()">
+<XColumn :menu="menu" :column="column" :isStacked="isStacked" :refresher="async () => { await timeline?.reloadTimeline() }">
<template #header>
<i class="ti ti-antenna"></i><span style="margin-left: 8px;">{{ column.name }}</span>
</template>
@@ -14,7 +14,8 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { onMounted, ref, shallowRef, watch } from 'vue';
+import { onMounted, ref, shallowRef, watch, defineAsyncComponent } from 'vue';
+import type { entities as MisskeyEntities } from 'misskey-js';
import XColumn from './column.vue';
import { updateColumn, Column } from './deck-store.js';
import MkTimeline from '@/components/MkTimeline.vue';
@@ -22,6 +23,7 @@ import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { i18n } from '@/i18n.js';
import { MenuItem } from '@/types/menu.js';
+import { antennasCache } from '@/cache.js';
import { SoundStore } from '@/store.js';
import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
import * as sound from '@/scripts/sound.js';
@@ -46,14 +48,36 @@ watch(soundSetting, v => {
async function setAntenna() {
const antennas = await misskeyApi('antennas/list');
- const { canceled, result: antenna } = await os.select({
+ const { canceled, result: antenna } = await os.select<MisskeyEntities.Antenna | '_CREATE_'>({
title: i18n.ts.selectAntenna,
- items: antennas.map(x => ({
- value: x, text: x.name,
- })),
+ items: [
+ { value: '_CREATE_', text: i18n.ts.createNew },
+ (antennas.length > 0 ? {
+ sectionTitle: i18n.ts.createdAntennas,
+ items: antennas.map(x => ({
+ value: x, text: x.name,
+ })),
+ } : undefined),
+ ],
default: props.column.antennaId,
});
- if (canceled) return;
+ if (canceled || antenna == null) return;
+
+ if (antenna === '_CREATE_') {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkAntennaEditorDialog.vue')), {}, {
+ created: (newAntenna: MisskeyEntities.Antenna) => {
+ antennasCache.delete();
+ updateColumn(props.column.id, {
+ antennaId: newAntenna.id,
+ });
+ },
+ closed: () => {
+ dispose();
+ },
+ });
+ return;
+ }
+
updateColumn(props.column.id, {
antennaId: antenna.id,
});
diff --git a/packages/frontend/src/ui/deck/channel-column.vue b/packages/frontend/src/ui/deck/channel-column.vue
index 7c5b13eaf1..42c07056e7 100644
--- a/packages/frontend/src/ui/deck/channel-column.vue
+++ b/packages/frontend/src/ui/deck/channel-column.vue
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
-<XColumn :menu="menu" :column="column" :isStacked="isStacked" :refresher="() => timeline.reloadTimeline()">
+<XColumn :menu="menu" :column="column" :isStacked="isStacked" :refresher="async () => { await timeline?.reloadTimeline() }">
<template #header>
<i class="ti ti-device-tv"></i><span style="margin-left: 8px;">{{ column.name }}</span>
</template>
@@ -68,6 +68,7 @@ async function setChannel() {
}
async function post() {
+ if (props.column.channelId == null) return;
if (!channel.value || channel.value.id !== props.column.channelId) {
channel.value = await misskeyApi('channels/show', {
channelId: props.column.channelId,
diff --git a/packages/frontend/src/ui/deck/column.vue b/packages/frontend/src/ui/deck/column.vue
index 07845bacbb..e96402d13b 100644
--- a/packages/frontend/src/ui/deck/column.vue
+++ b/packages/frontend/src/ui/deck/column.vue
@@ -271,7 +271,7 @@ function onDrop(ev) {
border-radius: 10px;
&.draghover {
- &:after {
+ &::after {
content: "";
display: block;
position: absolute;
@@ -285,7 +285,7 @@ function onDrop(ev) {
}
&.dragging {
- &:after {
+ &::after {
content: "";
display: block;
position: absolute;
diff --git a/packages/frontend/src/ui/deck/deck-store.ts b/packages/frontend/src/ui/deck/deck-store.ts
index bb3c04cd5c..eb587554b9 100644
--- a/packages/frontend/src/ui/deck/deck-store.ts
+++ b/packages/frontend/src/ui/deck/deck-store.ts
@@ -6,6 +6,7 @@
import { throttle } from 'throttle-debounce';
import { markRaw } from 'vue';
import { notificationTypes } from 'misskey-js';
+import type { BasicTimelineType } from '@/timelines.js';
import { Storage } from '@/pizzax.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { deepClone } from '@/scripts/clone.js';
@@ -17,9 +18,24 @@ type ColumnWidget = {
data: Record<string, any>;
};
+export const columnTypes = [
+ 'main',
+ 'widgets',
+ 'notifications',
+ 'tl',
+ 'antenna',
+ 'list',
+ 'channel',
+ 'mentions',
+ 'direct',
+ 'roleTimeline',
+] as const;
+
+export type ColumnType = typeof columnTypes[number];
+
export type Column = {
id: string;
- type: 'main' | 'widgets' | 'notifications' | 'tl' | 'antenna' | 'channel' | 'list' | 'mentions' | 'direct';
+ type: ColumnType;
name: string | null;
width: number;
widgets?: ColumnWidget[];
@@ -30,7 +46,7 @@ export type Column = {
channelId?: string;
roleId?: string;
excludeTypes?: typeof notificationTypes[number][];
- tl?: 'home' | 'local' | 'social' | 'global';
+ tl?: BasicTimelineType;
withRenotes?: boolean;
withReplies?: boolean;
onlyFiles?: boolean;
@@ -265,7 +281,7 @@ export function removeColumnWidget(id: Column['id'], widget: ColumnWidget) {
const columns = deepClone(deckStore.state.columns);
const columnIndex = deckStore.state.columns.findIndex(c => c.id === id);
const column = deepClone(deckStore.state.columns[columnIndex]);
- if (column == null) return;
+ if (column == null || column.widgets == null) return;
column.widgets = column.widgets.filter(w => w.id !== widget.id);
columns[columnIndex] = column;
deckStore.set('columns', columns);
@@ -287,7 +303,7 @@ export function updateColumnWidget(id: Column['id'], widgetId: string, widgetDat
const columns = deepClone(deckStore.state.columns);
const columnIndex = deckStore.state.columns.findIndex(c => c.id === id);
const column = deepClone(deckStore.state.columns[columnIndex]);
- if (column == null) return;
+ if (column == null || column.widgets == null) return;
column.widgets = column.widgets.map(w => w.id === widgetId ? {
...w,
data: widgetData,
diff --git a/packages/frontend/src/ui/deck/direct-column.vue b/packages/frontend/src/ui/deck/direct-column.vue
index e011de0e3b..d12a18f760 100644
--- a/packages/frontend/src/ui/deck/direct-column.vue
+++ b/packages/frontend/src/ui/deck/direct-column.vue
@@ -34,7 +34,7 @@ const tlComponent = ref<InstanceType<typeof MkNotes>>();
function reloadTimeline() {
return new Promise<void>((res) => {
- tlComponent.value.pagingComponent?.reload().then(() => {
+ tlComponent.value?.pagingComponent?.reload().then(() => {
res();
});
});
diff --git a/packages/frontend/src/ui/deck/list-column.vue b/packages/frontend/src/ui/deck/list-column.vue
index 5369112494..9aa8f06476 100644
--- a/packages/frontend/src/ui/deck/list-column.vue
+++ b/packages/frontend/src/ui/deck/list-column.vue
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
-<XColumn :menu="menu" :column="column" :isStacked="isStacked" :refresher="() => timeline.reloadTimeline()">
+<XColumn :menu="menu" :column="column" :isStacked="isStacked" :refresher="async () => { await timeline?.reloadTimeline() }">
<template #header>
<i class="ti ti-list"></i><span style="margin-left: 8px;">{{ column.name }}</span>
</template>
@@ -15,6 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { watch, shallowRef, ref } from 'vue';
+import type { entities as MisskeyEntities } from 'misskey-js';
import XColumn from './column.vue';
import { updateColumn, Column } from './deck-store.js';
import MkTimeline from '@/components/MkTimeline.vue';
@@ -23,6 +24,7 @@ import { misskeyApi } from '@/scripts/misskey-api.js';
import { i18n } from '@/i18n.js';
import { MenuItem } from '@/types/menu.js';
import { SoundStore } from '@/store.js';
+import { userListsCache } from '@/cache.js';
import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
import * as sound from '@/scripts/sound.js';
@@ -51,17 +53,38 @@ watch(soundSetting, v => {
async function setList() {
const lists = await misskeyApi('users/lists/list');
- const { canceled, result: list } = await os.select({
+ const { canceled, result: list } = await os.select<MisskeyEntities.UserList | '_CREATE_'>({
title: i18n.ts.selectList,
- items: lists.map(x => ({
- value: x, text: x.name,
- })),
+ items: [
+ { value: '_CREATE_', text: i18n.ts.createNew },
+ (lists.length > 0 ? {
+ sectionTitle: i18n.ts.createdLists,
+ items: lists.map(x => ({
+ value: x, text: x.name,
+ })),
+ } : undefined),
+ ],
default: props.column.listId,
});
- if (canceled) return;
- updateColumn(props.column.id, {
- listId: list.id,
- });
+ if (canceled || list == null) return;
+
+ if (list === '_CREATE_') {
+ const { canceled, result: name } = await os.inputText({
+ title: i18n.ts.enterListName,
+ });
+ if (canceled || name == null || name === '') return;
+
+ const res = await os.apiWithDialog('users/lists/create', { name: name });
+ userListsCache.delete();
+
+ updateColumn(props.column.id, {
+ listId: res.id,
+ });
+ } else {
+ updateColumn(props.column.id, {
+ listId: list.id,
+ });
+ }
}
function editList() {
diff --git a/packages/frontend/src/ui/deck/mentions-column.vue b/packages/frontend/src/ui/deck/mentions-column.vue
index 81926dd7cb..7b25a55ec3 100644
--- a/packages/frontend/src/ui/deck/mentions-column.vue
+++ b/packages/frontend/src/ui/deck/mentions-column.vue
@@ -26,7 +26,7 @@ const tlComponent = ref<InstanceType<typeof MkNotes>>();
function reloadTimeline() {
return new Promise<void>((res) => {
- tlComponent.value.pagingComponent?.reload().then(() => {
+ tlComponent.value?.pagingComponent?.reload().then(() => {
res();
});
});
diff --git a/packages/frontend/src/ui/deck/notifications-column.vue b/packages/frontend/src/ui/deck/notifications-column.vue
index 451cc58791..19ccfc1f7c 100644
--- a/packages/frontend/src/ui/deck/notifications-column.vue
+++ b/packages/frontend/src/ui/deck/notifications-column.vue
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
-<XColumn :column="column" :isStacked="isStacked" :menu="menu" :refresher="() => notificationsComponent.reload()">
+<XColumn :column="column" :isStacked="isStacked" :menu="menu" :refresher="async () => { await notificationsComponent?.reload() }">
<template #header><i class="ti ti-bell" style="margin-right: 8px;"></i>{{ column.name }}</template>
<XNotifications ref="notificationsComponent" :excludeTypes="props.column.excludeTypes"/>
@@ -27,7 +27,7 @@ const props = defineProps<{
const notificationsComponent = shallowRef<InstanceType<typeof XNotifications>>();
function func() {
- os.popup(defineAsyncComponent(() => import('@/components/MkNotificationSelectWindow.vue')), {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkNotificationSelectWindow.vue')), {
excludeTypes: props.column.excludeTypes,
}, {
done: async (res) => {
@@ -36,7 +36,8 @@ function func() {
excludeTypes: excludeTypes,
});
},
- }, 'closed');
+ closed: () => dispose(),
+ });
}
const menu = [{
diff --git a/packages/frontend/src/ui/deck/role-timeline-column.vue b/packages/frontend/src/ui/deck/role-timeline-column.vue
index 32ab7527b4..a375e9c574 100644
--- a/packages/frontend/src/ui/deck/role-timeline-column.vue
+++ b/packages/frontend/src/ui/deck/role-timeline-column.vue
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
-<XColumn :menu="menu" :column="column" :isStacked="isStacked" :refresher="() => timeline.reloadTimeline()">
+<XColumn :menu="menu" :column="column" :isStacked="isStacked" :refresher="async () => { await timeline?.reloadTimeline() }">
<template #header>
<i class="ti ti-badge"></i><span style="margin-left: 8px;">{{ column.name }}</span>
</template>
@@ -53,7 +53,7 @@ async function setRole() {
})),
default: props.column.roleId,
});
- if (canceled) return;
+ if (canceled || role == null) return;
updateColumn(props.column.id, {
roleId: role.id,
});
diff --git a/packages/frontend/src/ui/deck/tl-column.vue b/packages/frontend/src/ui/deck/tl-column.vue
index a967335edf..e210ee7b7a 100644
--- a/packages/frontend/src/ui/deck/tl-column.vue
+++ b/packages/frontend/src/ui/deck/tl-column.vue
@@ -4,16 +4,13 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
-<XColumn :menu="menu" :column="column" :isStacked="isStacked" :refresher="() => timeline.reloadTimeline()">
+<XColumn :menu="menu" :column="column" :isStacked="isStacked" :refresher="async () => { await timeline?.reloadTimeline() }">
<template #header>
- <i v-if="column.tl === 'home'" class="ti ti-home"></i>
- <i v-else-if="column.tl === 'local'" class="ti ti-planet"></i>
- <i v-else-if="column.tl === 'social'" class="ti ti-universe"></i>
- <i v-else-if="column.tl === 'global'" class="ti ti-whirl"></i>
+ <i v-if="column.tl != null" :class="basicTimelineIconClass(column.tl)"/>
<span style="margin-left: 8px;">{{ column.name }}</span>
</template>
- <div v-if="(((column.tl === 'local' || column.tl === 'social') && !isLocalTimelineAvailable) || (column.tl === 'global' && !isGlobalTimelineAvailable))" :class="$style.disabled">
+ <div v-if="!isAvailableBasicTimeline(column.tl)" :class="$style.disabled">
<p :class="$style.disabledTitle">
<i class="ti ti-circle-minus"></i>
{{ i18n.ts._disabledTimeline.title }}
@@ -34,15 +31,15 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
-import { onMounted, watch, ref, shallowRef } from 'vue';
+import { onMounted, watch, ref, shallowRef, computed } from 'vue';
import XColumn from './column.vue';
import { removeColumn, updateColumn, Column } from './deck-store.js';
+import type { MenuItem } from '@/types/menu.js';
import MkTimeline from '@/components/MkTimeline.vue';
import * as os from '@/os.js';
-import { $i } from '@/account.js';
import { i18n } from '@/i18n.js';
+import { hasWithReplies, isAvailableBasicTimeline, basicTimelineIconClass } from '@/timelines.js';
import { instance } from '@/instance.js';
-import { MenuItem } from '@/types/menu.js';
import { SoundStore } from '@/store.js';
import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
import * as sound from '@/scripts/sound.js';
@@ -52,11 +49,8 @@ const props = defineProps<{
isStacked: boolean;
}>();
-const disabled = ref(false);
const timeline = shallowRef<InstanceType<typeof MkTimeline>>();
-const isLocalTimelineAvailable = (($i == null && instance.policies.ltlAvailable) || ($i != null && $i.policies.ltlAvailable));
-const isGlobalTimelineAvailable = (($i == null && instance.policies.gtlAvailable) || ($i != null && $i.policies.gtlAvailable));
const soundSetting = ref<SoundStore>(props.column.soundSetting ?? { type: null, volume: 1 });
const withRenotes = ref(props.column.withRenotes ?? true);
const withReplies = ref(props.column.withReplies ?? false);
@@ -87,10 +81,6 @@ watch(soundSetting, v => {
onMounted(() => {
if (props.column.tl == null) {
setType();
- } else if ($i) {
- disabled.value = (
- (!((instance.policies.ltlAvailable) || ($i.policies.ltlAvailable)) && ['local', 'social'].includes(props.column.tl)) ||
- (!((instance.policies.gtlAvailable) || ($i.policies.gtlAvailable)) && ['global'].includes(props.column.tl)));
}
});
@@ -113,8 +103,9 @@ async function setType() {
}
return;
}
+ if (src == null) return;
updateColumn(props.column.id, {
- tl: src,
+ tl: src ?? undefined,
});
}
@@ -122,7 +113,7 @@ function onNote() {
sound.playMisskeySfxFile(soundSetting.value);
}
-const menu: MenuItem[] = [{
+const menu = computed<MenuItem[]>(() => [{
icon: 'ti ti-pencil',
text: i18n.ts.timeline,
action: setType,
@@ -134,7 +125,7 @@ const menu: MenuItem[] = [{
type: 'switch',
text: i18n.ts.showRenotes,
ref: withRenotes,
-}, props.column.tl === 'local' || props.column.tl === 'social' ? {
+}, hasWithReplies(props.column.tl) ? {
type: 'switch',
text: i18n.ts.showRepliesToOthersInTimeline,
ref: withReplies,
@@ -143,8 +134,8 @@ const menu: MenuItem[] = [{
type: 'switch',
text: i18n.ts.fileAttachedOnly,
ref: onlyFiles,
- disabled: props.column.tl === 'local' || props.column.tl === 'social' ? withReplies : false,
-}];
+ disabled: hasWithReplies(props.column.tl) ? withReplies : false,
+}]);
</script>
<style lang="scss" module>
diff --git a/packages/frontend/src/ui/visitor.vue b/packages/frontend/src/ui/visitor.vue
index 80623083cf..c229946bd4 100644
--- a/packages/frontend/src/ui/visitor.vue
+++ b/packages/frontend/src/ui/visitor.vue
@@ -126,15 +126,19 @@ const keymap = computed(() => {
});
function signin() {
- os.popup(XSigninDialog, {
+ const { dispose } = os.popup(XSigninDialog, {
autoSet: true,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
}
function signup() {
- os.popup(XSignupDialog, {
+ const { dispose } = os.popup(XSignupDialog, {
autoSet: true,
- }, {}, 'closed');
+ }, {
+ closed: () => dispose(),
+ });
}
onMounted(() => {
diff --git a/packages/frontend/src/widgets/WidgetCalendar.vue b/packages/frontend/src/widgets/WidgetCalendar.vue
index c688e8a0b1..6ece33eff3 100644
--- a/packages/frontend/src/widgets/WidgetCalendar.vue
+++ b/packages/frontend/src/widgets/WidgetCalendar.vue
@@ -121,7 +121,7 @@ defineExpose<WidgetComponentExpose>({
.root {
padding: 16px 0;
- &:after {
+ &::after {
content: "";
display: block;
clear: both;
diff --git a/packages/frontend/src/widgets/WidgetInstanceInfo.vue b/packages/frontend/src/widgets/WidgetInstanceInfo.vue
index 25d824c8ae..5d8beaf9a9 100644
--- a/packages/frontend/src/widgets/WidgetInstanceInfo.vue
+++ b/packages/frontend/src/widgets/WidgetInstanceInfo.vue
@@ -81,16 +81,19 @@ defineExpose<WidgetComponentExpose>({
.body {
text-overflow: ellipsis;
overflow: clip;
+ margin-left: -10px;
+ padding: 10px;
}
.name {
color: #fff;
- filter: drop-shadow(0 0 4px #000);
+ filter: drop-shadow(0 0 4px #000) drop-shadow(0 0 0.1px rgba(0, 0, 0, 0.5));
font-weight: bold;
}
.host {
color: #fff;
- filter: drop-shadow(0 0 4px #000);
+ filter: drop-shadow(0 0 4px #000) drop-shadow(0 0 0.1px rgba(0, 0, 0, 0.5));
+
}
</style>
diff --git a/packages/frontend/src/widgets/WidgetNotifications.vue b/packages/frontend/src/widgets/WidgetNotifications.vue
index 4b3265dab7..773c078b49 100644
--- a/packages/frontend/src/widgets/WidgetNotifications.vue
+++ b/packages/frontend/src/widgets/WidgetNotifications.vue
@@ -54,7 +54,7 @@ const { widgetProps, configure, save } = useWidgetPropsManager(name,
);
const configureNotification = () => {
- os.popup(defineAsyncComponent(() => import('@/components/MkNotificationSelectWindow.vue')), {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkNotificationSelectWindow.vue')), {
excludeTypes: widgetProps.excludeTypes,
}, {
done: async (res) => {
@@ -62,7 +62,8 @@ const configureNotification = () => {
widgetProps.excludeTypes = excludeTypes;
save();
},
- }, 'closed');
+ closed: () => dispose(),
+ });
};
defineExpose<WidgetComponentExpose>({
diff --git a/packages/frontend/src/widgets/WidgetProfile.vue b/packages/frontend/src/widgets/WidgetProfile.vue
index a5578d4de6..ae39098305 100644
--- a/packages/frontend/src/widgets/WidgetProfile.vue
+++ b/packages/frontend/src/widgets/WidgetProfile.vue
@@ -82,16 +82,19 @@ defineExpose<WidgetComponentExpose>({
.body {
text-overflow: ellipsis;
overflow: clip;
+ margin-left: -10px;
+ padding: 10px;
}
.name {
color: #fff;
- filter: drop-shadow(0 0 4px #000);
+ filter: drop-shadow(0 0 4px #000) drop-shadow(0 0 0.1px rgba(0, 0, 0, 0.5));
font-weight: bold;
}
.username {
color: #fff;
- filter: drop-shadow(0 0 4px #000);
+ filter: drop-shadow(0 0 4px #000) drop-shadow(0 0 0.1px rgba(0, 0, 0, 0.5));
+ font-weight: normal;
}
</style>
diff --git a/packages/frontend/src/widgets/WidgetTimeline.vue b/packages/frontend/src/widgets/WidgetTimeline.vue
index 150e838582..d02f9b8e22 100644
--- a/packages/frontend/src/widgets/WidgetTimeline.vue
+++ b/packages/frontend/src/widgets/WidgetTimeline.vue
@@ -6,10 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<MkContainer :showHeader="widgetProps.showHeader" :style="`height: ${widgetProps.height}px;`" :scrollable="true" data-cy-mkw-timeline class="mkw-timeline">
<template #icon>
- <i v-if="widgetProps.src === 'home'" class="ti ti-home"></i>
- <i v-else-if="widgetProps.src === 'local'" class="ti ti-planet"></i>
- <i v-else-if="widgetProps.src === 'social'" class="ti ti-universe"></i>
- <i v-else-if="widgetProps.src === 'global'" class="ti ti-whirl"></i>
+ <i v-if="isBasicTimeline(widgetProps.src)" :class="basicTimelineIconClass(widgetProps.src)"></i>
<i v-else-if="widgetProps.src === 'list'" class="ti ti-list"></i>
<i v-else-if="widgetProps.src === 'antenna'" class="ti ti-antenna"></i>
</template>
@@ -20,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</button>
</template>
- <div v-if="(((widgetProps.src === 'local' || widgetProps.src === 'social') && !isLocalTimelineAvailable) || (widgetProps.src === 'global' && !isGlobalTimelineAvailable))" :class="$style.disabled">
+ <div v-if="isBasicTimeline(widgetProps.src) && !isAvailableBasicTimeline(widgetProps.src)" :class="$style.disabled">
<p :class="$style.disabledTitle">
<i class="ti ti-minus"></i>
{{ i18n.ts._disabledTimeline.title }}
@@ -42,12 +39,9 @@ import { misskeyApi } from '@/scripts/misskey-api.js';
import MkContainer from '@/components/MkContainer.vue';
import MkTimeline from '@/components/MkTimeline.vue';
import { i18n } from '@/i18n.js';
-import { $i } from '@/account.js';
-import { instance } from '@/instance.js';
+import { availableBasicTimelines, isAvailableBasicTimeline, isBasicTimeline, basicTimelineIconClass } from '@/timelines.js';
const name = 'timeline';
-const isLocalTimelineAvailable = (($i == null && instance.policies.ltlAvailable) || ($i != null && $i.policies.ltlAvailable));
-const isGlobalTimelineAvailable = (($i == null && instance.policies.gtlAvailable) || ($i != null && $i.policies.gtlAvailable));
const widgetPropsDef = {
showHeader: {
@@ -115,23 +109,11 @@ const choose = async (ev) => {
setSrc('list');
},
}));
- os.popupMenu([{
- text: i18n.ts._timelines.home,
- icon: 'ti ti-home',
- action: () => { setSrc('home'); },
- }, {
- text: i18n.ts._timelines.local,
- icon: 'ti ti-planet',
- action: () => { setSrc('local'); },
- }, {
- text: i18n.ts._timelines.social,
- icon: 'ti ti-universe',
- action: () => { setSrc('social'); },
- }, {
- text: i18n.ts._timelines.global,
- icon: 'ti ti-whirl',
- action: () => { setSrc('global'); },
- }, antennaItems.length > 0 ? { type: 'divider' } : undefined, ...antennaItems, listItems.length > 0 ? { type: 'divider' } : undefined, ...listItems], ev.currentTarget ?? ev.target).then(() => {
+ os.popupMenu([...availableBasicTimelines().map(tl => ({
+ text: i18n.ts._timelines[tl],
+ icon: basicTimelineIconClass(tl),
+ action: () => { setSrc(tl); },
+ })), antennaItems.length > 0 ? { type: 'divider' } : undefined, ...antennaItems, listItems.length > 0 ? { type: 'divider' } : undefined, ...listItems], ev.currentTarget ?? ev.target).then(() => {
menuOpened.value = false;
});
};
diff --git a/packages/frontend/tsconfig.json b/packages/frontend/tsconfig.json
index 819629a9cf..fe4d202894 100644
--- a/packages/frontend/tsconfig.json
+++ b/packages/frontend/tsconfig.json
@@ -37,13 +37,13 @@
],
"lib": [
"esnext",
- "dom"
+ "dom",
+ "dom.iterable"
],
"jsx": "preserve"
},
"compileOnSave": false,
"include": [
- ".eslintrc.js",
"./**/*.ts",
"./**/*.vue"
],
diff --git a/packages/frontend/vite.config.local-dev.ts b/packages/frontend/vite.config.local-dev.ts
index f9dff13b15..887ab7927e 100644
--- a/packages/frontend/vite.config.local-dev.ts
+++ b/packages/frontend/vite.config.local-dev.ts
@@ -1,6 +1,8 @@
import dns from 'dns';
import { readFile } from 'node:fs/promises';
+import type { IncomingMessage } from 'node:http';
import { defineConfig } from 'vite';
+import type { UserConfig } from 'vite';
import * as yaml from 'js-yaml';
import locales from '../../locales/index.js';
import { getConfig } from './vite.config.js';
@@ -14,7 +16,15 @@ const { port } = yaml.load(await readFile('../../.config/default.yml', 'utf-8'))
const httpUrl = `http://localhost:${port}/`;
const websocketUrl = `ws://localhost:${port}/`;
-const devConfig = {
+// activitypubリクエストã¯Proxyを通ã—ã€ãれ以外ã¯Viteã®é–‹ç™ºã‚µãƒ¼ãƒãƒ¼ã‚’è¿”ã™
+function varyHandler(req: IncomingMessage) {
+ if (req.headers.accept?.includes('application/activity+json')) {
+ return null;
+ }
+ return '/index.html';
+}
+
+const devConfig: UserConfig = {
// 基本ã®è¨­å®šã¯ vite.config.js ã‹ã‚‰å¼•ãç¶™ã
...defaultConfig,
root: 'src',
@@ -52,17 +62,14 @@ const devConfig = {
'/bios': httpUrl,
'/cli': httpUrl,
'/inbox': httpUrl,
+ '/emoji/': httpUrl,
'/notes': {
target: httpUrl,
- headers: {
- 'Accept': 'application/activity+json',
- },
+ bypass: varyHandler,
},
'/users': {
target: httpUrl,
- headers: {
- 'Accept': 'application/activity+json',
- },
+ bypass: varyHandler,
},
'/.well-known': {
target: httpUrl,
diff --git a/packages/frontend/vite.config.ts b/packages/frontend/vite.config.ts
index 82eb2af464..6decbc0ef7 100644
--- a/packages/frontend/vite.config.ts
+++ b/packages/frontend/vite.config.ts
@@ -5,7 +5,7 @@ import { type UserConfig, defineConfig } from 'vite';
import locales from '../../locales/index.js';
import meta from '../../package.json';
-import packageInfo from './package.json' assert { type: 'json' };
+import packageInfo from './package.json' with { type: 'json' };
import pluginUnwindCssModuleClassName from './lib/rollup-plugin-unwind-css-module-class-name.js';
import pluginJson5 from './vite.json5.js';
diff --git a/packages/misskey-bubble-game/.eslintignore b/packages/misskey-bubble-game/.eslintignore
deleted file mode 100644
index 52ea8b3362..0000000000
--- a/packages/misskey-bubble-game/.eslintignore
+++ /dev/null
@@ -1,8 +0,0 @@
-node_modules
-/built
-/coverage
-/.eslintrc.js
-/jest.config.ts
-/test
-/test-d
-build.js
diff --git a/packages/misskey-bubble-game/.eslintrc.cjs b/packages/misskey-bubble-game/.eslintrc.cjs
deleted file mode 100644
index e2e31e9e33..0000000000
--- a/packages/misskey-bubble-game/.eslintrc.cjs
+++ /dev/null
@@ -1,9 +0,0 @@
-module.exports = {
- parserOptions: {
- tsconfigRootDir: __dirname,
- project: ['./tsconfig.json'],
- },
- extends: [
- '../shared/.eslintrc.js',
- ],
-};
diff --git a/packages/misskey-bubble-game/build.js b/packages/misskey-bubble-game/build.js
index 0b79f4b915..e626c97a59 100644
--- a/packages/misskey-bubble-game/build.js
+++ b/packages/misskey-bubble-game/build.js
@@ -95,7 +95,6 @@ async function watchSrc() {
process.on('SIGHUP', resolve);
process.on('SIGINT', resolve);
process.on('SIGTERM', resolve);
- process.on('SIGKILL', resolve);
process.on('uncaughtException', reject);
process.on('exit', resolve);
}).finally(async () => {
diff --git a/packages/misskey-bubble-game/eslint.config.js b/packages/misskey-bubble-game/eslint.config.js
new file mode 100644
index 0000000000..86c21a22a3
--- /dev/null
+++ b/packages/misskey-bubble-game/eslint.config.js
@@ -0,0 +1,27 @@
+import tsParser from '@typescript-eslint/parser';
+import sharedConfig from '../shared/eslint.config.js';
+
+export default [
+ ...sharedConfig,
+ {
+ ignores: [
+ '**/node_modules',
+ 'built',
+ 'coverage',
+ 'jest.config.ts',
+ 'test',
+ 'test-d',
+ ],
+ },
+ {
+ files: ['**/*.ts', '**/*.tsx'],
+ languageOptions: {
+ parserOptions: {
+ parser: tsParser,
+ project: ['./tsconfig.json'],
+ sourceType: 'module',
+ tsconfigRootDir: import.meta.dirname,
+ },
+ },
+ },
+];
diff --git a/packages/misskey-bubble-game/package.json b/packages/misskey-bubble-game/package.json
index a3aad147a9..528eb00b74 100644
--- a/packages/misskey-bubble-game/package.json
+++ b/packages/misskey-bubble-game/package.json
@@ -17,18 +17,16 @@
"scripts": {
"build": "node ./build.js",
"watch": "nodemon -w package.json -e json --exec \"node ./build.js --watch\"",
- "eslint": "eslint . --ext .js,.jsx,.ts,.tsx",
+ "eslint": "eslint './**/*.{js,jsx,ts,tsx}'",
"typecheck": "tsc --noEmit",
"lint": "pnpm typecheck && pnpm eslint"
},
"devDependencies": {
- "@misskey-dev/eslint-plugin": "1.0.0",
"@types/matter-js": "0.19.6",
"@types/seedrandom": "3.0.8",
"@types/node": "20.11.5",
"@typescript-eslint/eslint-plugin": "7.1.0",
"@typescript-eslint/parser": "7.1.0",
- "eslint": "8.57.0",
"nodemon": "3.0.2",
"execa": "8.0.1",
"typescript": "5.3.3",
diff --git a/packages/misskey-js/.eslintignore b/packages/misskey-js/.eslintignore
deleted file mode 100644
index 52ea8b3362..0000000000
--- a/packages/misskey-js/.eslintignore
+++ /dev/null
@@ -1,8 +0,0 @@
-node_modules
-/built
-/coverage
-/.eslintrc.js
-/jest.config.ts
-/test
-/test-d
-build.js
diff --git a/packages/misskey-js/.eslintrc.cjs b/packages/misskey-js/.eslintrc.cjs
deleted file mode 100644
index e2e31e9e33..0000000000
--- a/packages/misskey-js/.eslintrc.cjs
+++ /dev/null
@@ -1,9 +0,0 @@
-module.exports = {
- parserOptions: {
- tsconfigRootDir: __dirname,
- project: ['./tsconfig.json'],
- },
- extends: [
- '../shared/.eslintrc.js',
- ],
-};
diff --git a/packages/misskey-js/README.md b/packages/misskey-js/README.md
index 63d4b36c56..4753e2434b 100644
--- a/packages/misskey-js/README.md
+++ b/packages/misskey-js/README.md
@@ -154,5 +154,5 @@ stream.on('_disconnected_', () => {
---
<div align="center">
- <a href="https://github.com/misskey-dev/misskey/blob/develop/CONTRIBUTING.md"><img src="https://raw.githubusercontent.com/misskey-dev/assets/main/i-want-you.png" width="300"></a>
+ <a href="https://github.com/misskey-dev/misskey/blob/develop/CONTRIBUTING.md"><img src="https://assets.misskey-hub.net/public/i-want-you.png" width="300"></a>
</div>
diff --git a/packages/misskey-js/build.js b/packages/misskey-js/build.js
index 0b79f4b915..a80b71646f 100644
--- a/packages/misskey-js/build.js
+++ b/packages/misskey-js/build.js
@@ -1,32 +1,32 @@
-import * as esbuild from "esbuild";
-import { build } from "esbuild";
-import { globSync } from "glob";
-import { execa } from "execa";
-import fs from "node:fs";
-import { fileURLToPath } from "node:url";
-import { dirname } from "node:path";
+import fs from 'node:fs';
+import { fileURLToPath } from 'node:url';
+import { dirname } from 'node:path';
+import * as esbuild from 'esbuild';
+import { build } from 'esbuild';
+import { globSync } from 'glob';
+import { execa } from 'execa';
const _filename = fileURLToPath(import.meta.url);
const _dirname = dirname(_filename);
const _package = JSON.parse(fs.readFileSync(_dirname + '/package.json', 'utf-8'));
-const entryPoints = globSync("./src/**/**.{ts,tsx}");
+const entryPoints = globSync('./src/**/**.{ts,tsx}');
/** @type {import('esbuild').BuildOptions} */
const options = {
entryPoints,
minify: process.env.NODE_ENV === 'production',
- outdir: "./built",
- target: "es2022",
- platform: "browser",
- format: "esm",
+ outdir: './built',
+ target: 'es2022',
+ platform: 'browser',
+ format: 'esm',
sourcemap: 'linked',
};
// builté…下をã™ã¹ã¦å‰Šé™¤ã™ã‚‹
fs.rmSync('./built', { recursive: true, force: true });
-if (process.argv.map(arg => arg.toLowerCase()).includes("--watch")) {
+if (process.argv.map(arg => arg.toLowerCase()).includes('--watch')) {
await watchSrc();
} else {
await buildSrc();
@@ -36,7 +36,7 @@ async function buildSrc() {
console.log(`[${_package.name}] start building...`);
await build(options)
- .then(it => {
+ .then(() => {
console.log(`[${_package.name}] build succeeded.`);
})
.catch((err) => {
@@ -65,7 +65,7 @@ function buildDts() {
{
stdout: process.stdout,
stderr: process.stderr,
- }
+ },
);
}
@@ -86,7 +86,7 @@ async function watchSrc() {
},
}];
- console.log(`[${_package.name}] start watching...`)
+ console.log(`[${_package.name}] start watching...`);
const context = await esbuild.context({ ...options, plugins });
await context.watch();
@@ -95,7 +95,6 @@ async function watchSrc() {
process.on('SIGHUP', resolve);
process.on('SIGINT', resolve);
process.on('SIGTERM', resolve);
- process.on('SIGKILL', resolve);
process.on('uncaughtException', reject);
process.on('exit', resolve);
}).finally(async () => {
diff --git a/packages/misskey-js/eslint.config.js b/packages/misskey-js/eslint.config.js
new file mode 100644
index 0000000000..d8173f30e9
--- /dev/null
+++ b/packages/misskey-js/eslint.config.js
@@ -0,0 +1,29 @@
+import tsParser from '@typescript-eslint/parser';
+import sharedConfig from '../shared/eslint.config.js';
+
+// eslint-disable-next-line import/no-default-export
+export default [
+ ...sharedConfig,
+ {
+ ignores: [
+ '**/node_modules',
+ 'built',
+ 'coverage',
+ 'jest.config.ts',
+ 'test',
+ 'test-d',
+ 'generator',
+ ],
+ },
+ {
+ files: ['**/*.ts', '**/*.tsx'],
+ languageOptions: {
+ parserOptions: {
+ parser: tsParser,
+ project: ['./tsconfig.json'],
+ sourceType: 'module',
+ tsconfigRootDir: import.meta.dirname,
+ },
+ },
+ },
+];
diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md
index 6ff711cabb..16cb560a52 100644
--- a/packages/misskey-js/etc/misskey-js.api.md
+++ b/packages/misskey-js/etc/misskey-js.api.md
@@ -6,6 +6,11 @@
import { EventEmitter } from 'eventemitter3';
+// Warning: (ae-forgotten-export) The symbol "components" needs to be exported by the entry point index.d.ts
+//
+// @public (undocumented)
+type AbuseReportNotificationRecipient = components['schemas']['AbuseReportNotificationRecipient'];
+
// @public (undocumented)
export type Acct = {
username: string;
@@ -21,14 +26,39 @@ declare namespace acct {
}
export { acct }
-// Warning: (ae-forgotten-export) The symbol "components" needs to be exported by the entry point index.d.ts
-//
// @public (undocumented)
type Ad = components['schemas']['Ad'];
// Warning: (ae-forgotten-export) The symbol "operations" needs to be exported by the entry point index.d.ts
//
// @public (undocumented)
+type AdminAbuseReportNotificationRecipientCreateRequest = operations['admin___abuse-report___notification-recipient___create']['requestBody']['content']['application/json'];
+
+// @public (undocumented)
+type AdminAbuseReportNotificationRecipientCreateResponse = operations['admin___abuse-report___notification-recipient___create']['responses']['200']['content']['application/json'];
+
+// @public (undocumented)
+type AdminAbuseReportNotificationRecipientDeleteRequest = operations['admin___abuse-report___notification-recipient___delete']['requestBody']['content']['application/json'];
+
+// @public (undocumented)
+type AdminAbuseReportNotificationRecipientListRequest = operations['admin___abuse-report___notification-recipient___list']['requestBody']['content']['application/json'];
+
+// @public (undocumented)
+type AdminAbuseReportNotificationRecipientListResponse = operations['admin___abuse-report___notification-recipient___list']['responses']['200']['content']['application/json'];
+
+// @public (undocumented)
+type AdminAbuseReportNotificationRecipientShowRequest = operations['admin___abuse-report___notification-recipient___show']['requestBody']['content']['application/json'];
+
+// @public (undocumented)
+type AdminAbuseReportNotificationRecipientShowResponse = operations['admin___abuse-report___notification-recipient___show']['responses']['200']['content']['application/json'];
+
+// @public (undocumented)
+type AdminAbuseReportNotificationRecipientUpdateRequest = operations['admin___abuse-report___notification-recipient___update']['requestBody']['content']['application/json'];
+
+// @public (undocumented)
+type AdminAbuseReportNotificationRecipientUpdateResponse = operations['admin___abuse-report___notification-recipient___update']['responses']['200']['content']['application/json'];
+
+// @public (undocumented)
type AdminAbuseUserReportsRequest = operations['admin___abuse-user-reports']['requestBody']['content']['application/json'];
// @public (undocumented)
@@ -308,6 +338,33 @@ type AdminShowUsersResponse = operations['admin___show-users']['responses']['200
type AdminSuspendUserRequest = operations['admin___suspend-user']['requestBody']['content']['application/json'];
// @public (undocumented)
+type AdminSystemWebhookCreateRequest = operations['admin___system-webhook___create']['requestBody']['content']['application/json'];
+
+// @public (undocumented)
+type AdminSystemWebhookCreateResponse = operations['admin___system-webhook___create']['responses']['200']['content']['application/json'];
+
+// @public (undocumented)
+type AdminSystemWebhookDeleteRequest = operations['admin___system-webhook___delete']['requestBody']['content']['application/json'];
+
+// @public (undocumented)
+type AdminSystemWebhookListRequest = operations['admin___system-webhook___list']['requestBody']['content']['application/json'];
+
+// @public (undocumented)
+type AdminSystemWebhookListResponse = operations['admin___system-webhook___list']['responses']['200']['content']['application/json'];
+
+// @public (undocumented)
+type AdminSystemWebhookShowRequest = operations['admin___system-webhook___show']['requestBody']['content']['application/json'];
+
+// @public (undocumented)
+type AdminSystemWebhookShowResponse = operations['admin___system-webhook___show']['responses']['200']['content']['application/json'];
+
+// @public (undocumented)
+type AdminSystemWebhookUpdateRequest = operations['admin___system-webhook___update']['requestBody']['content']['application/json'];
+
+// @public (undocumented)
+type AdminSystemWebhookUpdateResponse = operations['admin___system-webhook___update']['responses']['200']['content']['application/json'];
+
+// @public (undocumented)
type AdminUnsetUserAvatarRequest = operations['admin___unset-user-avatar']['requestBody']['content']['application/json'];
// @public (undocumented)
@@ -494,7 +551,7 @@ type Channel = components['schemas']['Channel'];
// Warning: (ae-forgotten-export) The symbol "AnyOf" needs to be exported by the entry point index.d.ts
//
// @public (undocumented)
-export abstract class ChannelConnection<Channel extends AnyOf<Channels> = any> extends EventEmitter<Channel['events']> {
+export abstract class ChannelConnection<Channel extends AnyOf<Channels> = AnyOf<Channels>> extends EventEmitter<Channel['events']> {
constructor(stream: Stream, channel: string, name?: string);
// (undocumented)
channel: string;
@@ -714,12 +771,12 @@ export type Channels = {
user1: boolean;
user2: boolean;
}) => void;
- updateSettings: (payload: {
+ updateSettings: <K extends ReversiUpdateKey>(payload: {
userId: User['id'];
- key: string;
- value: any;
+ key: K;
+ value: ReversiGameDetailed[K];
}) => void;
- log: (payload: Record<string, any>) => void;
+ log: (payload: Record<string, unknown>) => void;
};
receives: {
putStone: {
@@ -728,10 +785,7 @@ export type Channels = {
};
ready: boolean;
cancel: null | Record<string, never>;
- updateSettings: {
- key: string;
- value: any;
- };
+ updateSettings: ReversiUpdateSettings<ReversiUpdateKey>;
claimTimeIsUp: null | Record<string, never>;
};
};
@@ -1103,6 +1157,12 @@ export type Endpoints = Overwrite<Endpoints_2, {
req: SigninRequest;
res: SigninResponse;
};
+ 'admin/roles/create': {
+ req: Overwrite<AdminRolesCreateRequest, {
+ policies: PartialRolePolicyOverride;
+ }>;
+ res: AdminRolesCreateResponse;
+ };
}>;
// @public (undocumented)
@@ -1128,11 +1188,21 @@ declare namespace entities {
SignupPendingResponse,
SigninRequest,
SigninResponse,
+ PartialRolePolicyOverride,
EmptyRequest,
EmptyResponse,
AdminMetaResponse,
AdminAbuseUserReportsRequest,
AdminAbuseUserReportsResponse,
+ AdminAbuseReportNotificationRecipientListRequest,
+ AdminAbuseReportNotificationRecipientListResponse,
+ AdminAbuseReportNotificationRecipientShowRequest,
+ AdminAbuseReportNotificationRecipientShowResponse,
+ AdminAbuseReportNotificationRecipientCreateRequest,
+ AdminAbuseReportNotificationRecipientCreateResponse,
+ AdminAbuseReportNotificationRecipientUpdateRequest,
+ AdminAbuseReportNotificationRecipientUpdateResponse,
+ AdminAbuseReportNotificationRecipientDeleteRequest,
AdminAccountsCreateRequest,
AdminAccountsCreateResponse,
AdminAccountsDeleteRequest,
@@ -1228,6 +1298,15 @@ declare namespace entities {
AdminRolesUpdateDefaultPoliciesRequest,
AdminRolesUsersRequest,
AdminRolesUsersResponse,
+ AdminSystemWebhookCreateRequest,
+ AdminSystemWebhookCreateResponse,
+ AdminSystemWebhookDeleteRequest,
+ AdminSystemWebhookListRequest,
+ AdminSystemWebhookListResponse,
+ AdminSystemWebhookShowRequest,
+ AdminSystemWebhookShowResponse,
+ AdminSystemWebhookUpdateRequest,
+ AdminSystemWebhookUpdateResponse,
AnnouncementsRequest,
AnnouncementsResponse,
AnnouncementsShowRequest,
@@ -1733,7 +1812,9 @@ declare namespace entities {
ReversiGameDetailed,
MetaLite,
MetaDetailedOnly,
- MetaDetailed
+ MetaDetailed,
+ SystemWebhook,
+ AbuseReportNotificationRecipient
}
}
export { entities }
@@ -1792,7 +1873,7 @@ type FetchExternalResourcesResponse = operations['fetch-external-resources']['re
// @public (undocumented)
type FetchLike = (input: string, init?: {
method?: string;
- body?: string;
+ body?: Blob | FormData | string;
credentials?: RequestCredentials;
cache?: RequestCache;
headers: {
@@ -2380,12 +2461,27 @@ type ModerationLog = {
type: 'unsetUserAvatar';
info: ModerationLogPayloads['unsetUserAvatar'];
} | {
- type: 'unsetUserBanner';
- info: ModerationLogPayloads['unsetUserBanner'];
+ type: 'createSystemWebhook';
+ info: ModerationLogPayloads['createSystemWebhook'];
+} | {
+ type: 'updateSystemWebhook';
+ info: ModerationLogPayloads['updateSystemWebhook'];
+} | {
+ type: 'deleteSystemWebhook';
+ info: ModerationLogPayloads['deleteSystemWebhook'];
+} | {
+ type: 'createAbuseReportNotificationRecipient';
+ info: ModerationLogPayloads['createAbuseReportNotificationRecipient'];
+} | {
+ type: 'updateAbuseReportNotificationRecipient';
+ info: ModerationLogPayloads['updateAbuseReportNotificationRecipient'];
+} | {
+ type: 'deleteAbuseReportNotificationRecipient';
+ info: ModerationLogPayloads['deleteAbuseReportNotificationRecipient'];
});
// @public (undocumented)
-export const moderationLogTypes: readonly ["updateServerSettings", "suspend", "unsuspend", "updateUserNote", "addCustomEmoji", "updateCustomEmoji", "deleteCustomEmoji", "assignRole", "unassignRole", "createRole", "updateRole", "deleteRole", "clearQueue", "promoteQueue", "deleteDriveFile", "deleteNote", "createGlobalAnnouncement", "createUserAnnouncement", "updateGlobalAnnouncement", "updateUserAnnouncement", "deleteGlobalAnnouncement", "deleteUserAnnouncement", "resetPassword", "suspendRemoteInstance", "unsuspendRemoteInstance", "updateRemoteInstanceNote", "markSensitiveDriveFile", "unmarkSensitiveDriveFile", "resolveAbuseReport", "createInvitation", "createAd", "updateAd", "deleteAd", "createAvatarDecoration", "updateAvatarDecoration", "deleteAvatarDecoration", "unsetUserAvatar", "unsetUserBanner"];
+export const moderationLogTypes: readonly ["updateServerSettings", "suspend", "unsuspend", "updateUserNote", "addCustomEmoji", "updateCustomEmoji", "deleteCustomEmoji", "assignRole", "unassignRole", "createRole", "updateRole", "deleteRole", "clearQueue", "promoteQueue", "deleteDriveFile", "deleteNote", "createGlobalAnnouncement", "createUserAnnouncement", "updateGlobalAnnouncement", "updateUserAnnouncement", "deleteGlobalAnnouncement", "deleteUserAnnouncement", "resetPassword", "suspendRemoteInstance", "unsuspendRemoteInstance", "updateRemoteInstanceNote", "markSensitiveDriveFile", "unmarkSensitiveDriveFile", "resolveAbuseReport", "createInvitation", "createAd", "updateAd", "deleteAd", "createAvatarDecoration", "updateAvatarDecoration", "deleteAvatarDecoration", "unsetUserAvatar", "unsetUserBanner", "createSystemWebhook", "updateSystemWebhook", "deleteSystemWebhook", "createAbuseReportNotificationRecipient", "updateAbuseReportNotificationRecipient", "deleteAbuseReportNotificationRecipient"];
// @public (undocumented)
type MuteCreateRequest = operations['mute___create']['requestBody']['content']['application/json'];
@@ -2631,7 +2727,16 @@ type PagesUnlikeRequest = operations['pages___unlike']['requestBody']['content']
type PagesUpdateRequest = operations['pages___update']['requestBody']['content']['application/json'];
// @public (undocumented)
-function parse(acct: string): Acct;
+function parse(_acct: string): Acct;
+
+// Warning: (ae-forgotten-export) The symbol "Values" needs to be exported by the entry point index.d.ts
+//
+// @public (undocumented)
+type PartialRolePolicyOverride = Partial<{
+ [k in keyof RolePolicies]: Omit<Values<Role['policies']>, 'value'> & {
+ value: RolePolicies[k];
+ };
+}>;
// @public (undocumented)
export const permissions: readonly ["read:account", "write:account", "read:blocks", "write:blocks", "read:drive", "write:drive", "read:favorites", "write:favorites", "read:following", "write:following", "read:messaging", "write:messaging", "read:mutes", "write:mutes", "write:notes", "read:notifications", "write:notifications", "read:reactions", "write:reactions", "write:votes", "read:pages", "write:pages", "write:page-likes", "read:page-likes", "read:user-groups", "write:user-groups", "read:channels", "write:channels", "read:gallery", "write:gallery", "read:gallery-likes", "write:gallery-likes", "read:flash", "write:flash", "read:flash-likes", "write:flash-likes", "read:admin:abuse-user-reports", "write:admin:delete-account", "write:admin:delete-all-files-of-a-user", "read:admin:index-stats", "read:admin:table-stats", "read:admin:user-ips", "read:admin:meta", "write:admin:reset-password", "write:admin:resolve-abuse-user-report", "write:admin:send-email", "read:admin:server-info", "read:admin:show-moderation-log", "read:admin:show-user", "write:admin:suspend-user", "write:admin:unset-user-avatar", "write:admin:unset-user-banner", "write:admin:unsuspend-user", "write:admin:meta", "write:admin:user-note", "write:admin:roles", "read:admin:roles", "write:admin:relays", "read:admin:relays", "write:admin:invite-codes", "read:admin:invite-codes", "write:admin:announcements", "read:admin:announcements", "write:admin:avatar-decorations", "read:admin:avatar-decorations", "write:admin:federation", "write:admin:account", "read:admin:account", "write:admin:emoji", "read:admin:emoji", "write:admin:queue", "read:admin:queue", "write:admin:promo", "write:admin:drive", "read:admin:drive", "write:admin:ad", "read:admin:ad", "write:invite-codes", "read:invite-codes", "write:clip-favorite", "read:clip-favorite", "read:federation", "write:report-abuse"];
@@ -2861,7 +2966,7 @@ export class Stream extends EventEmitter<StreamEvents> {
constructor(origin: string, user: {
token: string;
} | null, options?: {
- WebSocket?: any;
+ WebSocket?: WebSocket;
});
// (undocumented)
close(): void;
@@ -2884,9 +2989,9 @@ export class Stream extends EventEmitter<StreamEvents> {
// (undocumented)
send(typeOrPayload: string): void;
// (undocumented)
- send(typeOrPayload: string, payload: any): void;
+ send(typeOrPayload: string, payload: unknown): void;
// (undocumented)
- send(typeOrPayload: Record<string, any> | any[]): void;
+ send(typeOrPayload: Record<string, unknown> | unknown[]): void;
// (undocumented)
state: 'initializing' | 'reconnecting' | 'connected';
// (undocumented)
@@ -2922,6 +3027,9 @@ type SwUpdateRegistrationRequest = operations['sw___update-registration']['reque
type SwUpdateRegistrationResponse = operations['sw___update-registration']['responses']['200']['content']['application/json'];
// @public (undocumented)
+type SystemWebhook = components['schemas']['SystemWebhook'];
+
+// @public (undocumented)
type TestRequest = operations['test']['requestBody']['content']['application/json'];
// @public (undocumented)
@@ -3118,7 +3226,9 @@ type UsersUpdateMemoRequest = operations['users___update-memo']['requestBody']['
// Warnings were encountered during analysis:
//
-// src/entities.ts:25:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts
+// src/entities.ts:35:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts
+// src/streaming.types.ts:220:4 - (ae-forgotten-export) The symbol "ReversiUpdateKey" needs to be exported by the entry point index.d.ts
+// src/streaming.types.ts:230:4 - (ae-forgotten-export) The symbol "ReversiUpdateSettings" needs to be exported by the entry point index.d.ts
// (No @packageDocumentation comment for this package)
diff --git a/packages/misskey-js/generator/.eslintrc.cjs b/packages/misskey-js/generator/.eslintrc.cjs
deleted file mode 100644
index 6a8b31da9c..0000000000
--- a/packages/misskey-js/generator/.eslintrc.cjs
+++ /dev/null
@@ -1,9 +0,0 @@
-module.exports = {
- parserOptions: {
- tsconfigRootDir: __dirname,
- project: ['./tsconfig.json'],
- },
- extends: [
- '../../shared/.eslintrc.js',
- ],
-};
diff --git a/packages/misskey-js/generator/eslint.config.js b/packages/misskey-js/generator/eslint.config.js
new file mode 100644
index 0000000000..4bf78c3b91
--- /dev/null
+++ b/packages/misskey-js/generator/eslint.config.js
@@ -0,0 +1,17 @@
+import tsParser from '@typescript-eslint/parser';
+import sharedConfig from '../../shared/eslint.config.js';
+
+export default [
+ ...sharedConfig,
+ {
+ files: ['**/*.ts', '**/*.tsx'],
+ languageOptions: {
+ parserOptions: {
+ parser: tsParser,
+ project: ['./tsconfig.json'],
+ sourceType: 'module',
+ tsconfigRootDir: import.meta.dirname,
+ },
+ },
+ },
+];
diff --git a/packages/misskey-js/generator/package.json b/packages/misskey-js/generator/package.json
index a1c0f41cb2..4a02bcd8ff 100644
--- a/packages/misskey-js/generator/package.json
+++ b/packages/misskey-js/generator/package.json
@@ -4,15 +4,13 @@
"description": "Misskey TypeGenerator",
"type": "module",
"scripts": {
- "generate": "tsx src/generator.ts && eslint ./built/**/* --ext .ts --fix"
+ "generate": "tsx src/generator.ts && eslint ./built/**/*.ts --fix"
},
"devDependencies": {
- "@misskey-dev/eslint-plugin": "^1.0.0",
"@readme/openapi-parser": "2.5.0",
"@types/node": "20.9.1",
"@typescript-eslint/eslint-plugin": "6.11.0",
"@typescript-eslint/parser": "6.11.0",
- "eslint": "8.53.0",
"openapi-types": "12.1.3",
"openapi-typescript": "6.7.3",
"ts-case-convert": "2.0.2",
diff --git a/packages/misskey-js/generator/src/generator.ts b/packages/misskey-js/generator/src/generator.ts
index 78178d7c7e..4ae00a4522 100644
--- a/packages/misskey-js/generator/src/generator.ts
+++ b/packages/misskey-js/generator/src/generator.ts
@@ -20,7 +20,14 @@ async function generateBaseTypes(
}
lines.push('');
- const generatedTypes = await openapiTS(openApiJsonPath, { exportType: true });
+ const generatedTypes = await openapiTS(openApiJsonPath, {
+ exportType: true,
+ transform(schemaObject) {
+ if ('format' in schemaObject && schemaObject.format === 'binary') {
+ return schemaObject.nullable ? 'Blob | null' : 'Blob';
+ }
+ },
+ });
lines.push(generatedTypes);
lines.push('');
@@ -56,6 +63,8 @@ async function generateEndpoints(
endpointOutputPath: string,
) {
const endpoints: Endpoint[] = [];
+ const endpointReqMediaTypes: EndpointReqMediaType[] = [];
+ const endpointReqMediaTypesSet = new Set<string>();
// misskey-jsã¯POST固定ã§é€ã£ã¦ã„ã‚‹ã®ã§ã€ã“ã¡ã‚‰ã‚‚æ±ºã‚æ‰“ã¡ã™ã‚‹ã€‚別メソッドã«å¯¾å¿œã™ã‚‹ã“ã¨ãŒã‚れã°ã“ã¡ã‚‰ã‚‚ç›´ã™å¿…è¦ã‚り
const paths = openApiDocs.paths ?? {};
@@ -78,13 +87,24 @@ async function generateEndpoints(
const supportMediaTypes = Object.keys(reqContent);
if (supportMediaTypes.length > 0) {
// ã„ã¾ã®ã¨ã“ã‚複数ã®ãƒ¡ãƒ‡ã‚£ã‚¢ã‚¿ã‚¤ãƒ—ã‚’ã¨ã‚‹ã‚¨ãƒ³ãƒ‰ãƒã‚¤ãƒ³ãƒˆã¯ç„¡ã„ã®ã§æ±ºã‚打ã¡ã™ã‚‹
- endpoint.request = new OperationTypeAlias(
+ const req = new OperationTypeAlias(
operationId,
path,
supportMediaTypes[0],
OperationsAliasType.REQUEST,
);
+ endpoint.request = req;
+
+ const reqType = new EndpointReqMediaType(path, req);
+ endpointReqMediaTypesSet.add(reqType.getMediaType());
+ endpointReqMediaTypes.push(reqType);
+ } else {
+ endpointReqMediaTypesSet.add('application/json');
+ endpointReqMediaTypes.push(new EndpointReqMediaType(path, undefined, 'application/json'));
}
+ } else {
+ endpointReqMediaTypesSet.add('application/json');
+ endpointReqMediaTypes.push(new EndpointReqMediaType(path, undefined, 'application/json'));
}
if (operation.responses && isResponseObject(operation.responses['200']) && operation.responses['200'].content) {
@@ -137,6 +157,19 @@ async function generateEndpoints(
endpointOutputLine.push('}');
endpointOutputLine.push('');
+ function generateEndpointReqMediaTypesType() {
+ return `Record<keyof Endpoints, ${[...endpointReqMediaTypesSet].map((t) => `'${t}'`).join(' | ')}>`;
+ }
+
+ endpointOutputLine.push(`export const endpointReqTypes: ${generateEndpointReqMediaTypesType()} = {`);
+
+ endpointOutputLine.push(
+ ...endpointReqMediaTypes.map(it => '\t' + it.toLine()),
+ );
+
+ endpointOutputLine.push('};');
+ endpointOutputLine.push('');
+
await writeFile(endpointOutputPath, endpointOutputLine.join('\n'));
}
@@ -314,6 +347,26 @@ class Endpoint {
}
}
+class EndpointReqMediaType {
+ public readonly path: string;
+ public readonly mediaType: string;
+
+ constructor(path: string, request: OperationTypeAlias, mediaType?: undefined);
+ constructor(path: string, request: undefined, mediaType: string);
+ constructor(path: string, request: OperationTypeAlias | undefined, mediaType?: string) {
+ this.path = path;
+ this.mediaType = mediaType ?? request?.mediaType ?? 'application/json';
+ }
+
+ getMediaType(): string {
+ return this.mediaType;
+ }
+
+ toLine(): string {
+ return `'${this.path}': '${this.mediaType}',`;
+ }
+}
+
async function main() {
const generatePath = './built/autogen';
await mkdir(generatePath, { recursive: true });
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index 4ff1a57309..f0e8733e67 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,7 +1,7 @@
{
"type": "module",
"name": "misskey-js",
- "version": "2024.5.0",
+ "version": "2024.7.0",
"description": "Misskey SDK for JavaScript",
"license": "MIT",
"main": "./built/index.js",
@@ -22,7 +22,7 @@
"tsd": "tsd",
"api": "pnpm api-extractor run --local --verbose",
"api-prod": "pnpm api-extractor run --verbose",
- "eslint": "eslint . --ext .js,.jsx,.ts,.tsx",
+ "eslint": "eslint './**/*.{js,jsx,ts,tsx}'",
"typecheck": "tsc --noEmit",
"lint": "pnpm typecheck && pnpm eslint",
"jest": "jest --coverage --detectOpenHandles",
@@ -35,25 +35,23 @@
"directory": "packages/misskey-js"
},
"devDependencies": {
- "@microsoft/api-extractor": "7.43.1",
- "@misskey-dev/eslint-plugin": "1.0.0",
+ "@microsoft/api-extractor": "7.47.4",
"@swc/jest": "0.2.36",
"@types/jest": "29.5.12",
- "@types/node": "20.12.7",
- "@typescript-eslint/eslint-plugin": "7.7.1",
- "@typescript-eslint/parser": "7.7.1",
- "eslint": "8.57.0",
+ "@types/node": "20.14.12",
+ "@typescript-eslint/eslint-plugin": "7.17.0",
+ "@typescript-eslint/parser": "7.17.0",
"jest": "29.7.0",
"jest-fetch-mock": "3.0.3",
"jest-websocket-mock": "2.5.0",
"mock-socket": "9.3.1",
"ncp": "2.0.0",
- "nodemon": "3.1.0",
- "execa": "8.0.1",
- "tsd": "0.30.7",
- "typescript": "5.4.5",
- "esbuild": "0.19.11",
- "glob": "10.3.12"
+ "nodemon": "3.1.4",
+ "execa": "9.3.0",
+ "tsd": "0.31.1",
+ "typescript": "5.5.4",
+ "esbuild": "0.23.0",
+ "glob": "11.0.0"
},
"files": [
"built"
diff --git a/packages/misskey-js/src/acct.ts b/packages/misskey-js/src/acct.ts
index b25bc564ea..aa8658cdbd 100644
--- a/packages/misskey-js/src/acct.ts
+++ b/packages/misskey-js/src/acct.ts
@@ -3,7 +3,8 @@ export type Acct = {
host: string | null;
};
-export function parse(acct: string): Acct {
+export function parse(_acct: string): Acct {
+ let acct = _acct;
if (acct.startsWith('@')) acct = acct.substring(1);
const split = acct.split('@', 2);
return { username: split[0], host: split[1] || null };
diff --git a/packages/misskey-js/src/api.ts b/packages/misskey-js/src/api.ts
index 959a634a74..ea1df57f3d 100644
--- a/packages/misskey-js/src/api.ts
+++ b/packages/misskey-js/src/api.ts
@@ -1,7 +1,7 @@
import './autogen/apiClientJSDoc.js';
-import { SwitchCaseResponseType } from './api.types.js';
-import type { Endpoints } from './api.types.js';
+import { endpointReqTypes } from './autogen/endpoint.js';
+import type { SwitchCaseResponseType, Endpoints } from './api.types.js';
export type {
SwitchCaseResponseType,
@@ -14,6 +14,7 @@ export type APIError = {
code: string;
message: string;
kind: 'client' | 'server';
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
info: Record<string, any>;
};
@@ -23,12 +24,13 @@ export function isAPIError(reason: Record<PropertyKey, unknown>): reason is APIE
export type FetchLike = (input: string, init?: {
method?: string;
- body?: string;
+ body?: Blob | FormData | string;
credentials?: RequestCredentials;
cache?: RequestCache;
headers: { [key in string]: string }
}) => Promise<{
status: number;
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
json(): Promise<any>;
}>;
@@ -49,20 +51,56 @@ export class APIClient {
this.fetch = opts.fetch ?? ((...args) => fetch(...args));
}
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ private assertIsRecord<T>(obj: T): obj is T & Record<string, any> {
+ return obj !== null && typeof obj === 'object' && !Array.isArray(obj);
+ }
+
public request<E extends keyof Endpoints, P extends Endpoints[E]['req']>(
endpoint: E,
params: P = {} as P,
credential?: string | null,
): Promise<SwitchCaseResponseType<E, P>> {
return new Promise((resolve, reject) => {
- this.fetch(`${this.origin}/api/${endpoint}`, {
- method: 'POST',
- body: JSON.stringify({
+ let mediaType = 'application/json';
+ if (endpoint in endpointReqTypes) {
+ mediaType = endpointReqTypes[endpoint];
+ }
+ let payload: FormData | string = '{}';
+
+ if (mediaType === 'application/json') {
+ payload = JSON.stringify({
...params,
i: credential !== undefined ? credential : this.credential,
- }),
+ });
+ } else if (mediaType === 'multipart/form-data') {
+ payload = new FormData();
+ const i = credential !== undefined ? credential : this.credential;
+ if (i != null) {
+ payload.append('i', i);
+ }
+ if (this.assertIsRecord(params)) {
+ for (const key in params) {
+ const value = params[key];
+
+ if (value == null) continue;
+
+ if (value instanceof File || value instanceof Blob) {
+ payload.append(key, value);
+ } else if (typeof value === 'object') {
+ payload.append(key, JSON.stringify(value));
+ } else {
+ payload.append(key, value);
+ }
+ }
+ }
+ }
+
+ this.fetch(`${this.origin}/api/${endpoint}`, {
+ method: 'POST',
+ body: payload,
headers: {
- 'Content-Type': 'application/json',
+ 'Content-Type': endpointReqTypes[endpoint],
},
credentials: 'omit',
cache: 'no-cache',
diff --git a/packages/misskey-js/src/api.types.ts b/packages/misskey-js/src/api.types.ts
index af0bade5b3..5ee4194db2 100644
--- a/packages/misskey-js/src/api.types.ts
+++ b/packages/misskey-js/src/api.types.ts
@@ -1,7 +1,8 @@
import { Endpoints as Gen } from './autogen/endpoint.js';
import { UserDetailed } from './autogen/models.js';
-import { UsersShowRequest } from './autogen/entities.js';
+import { AdminRolesCreateRequest, AdminRolesCreateResponse, UsersShowRequest } from './autogen/entities.js';
import {
+ PartialRolePolicyOverride,
SigninRequest,
SigninResponse,
SignupPendingRequest,
@@ -27,11 +28,13 @@ type StrictExtract<Union, Cond> = Cond extends Union ? Union : never;
type IsCaseMatched<E extends keyof Endpoints, P extends Endpoints[E]['req'], C extends number> =
Endpoints[E]['res'] extends SwitchCase
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
? IsNeverType<StrictExtract<Endpoints[E]['res']['$switch']['$cases'][C], [P, any]>> extends false ? true : false
: false
type GetCaseResult<E extends keyof Endpoints, P extends Endpoints[E]['req'], C extends number> =
Endpoints[E]['res'] extends SwitchCase
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
? StrictExtract<Endpoints[E]['res']['$switch']['$cases'][C], [P, any]>[1]
: never
@@ -79,5 +82,9 @@ export type Endpoints = Overwrite<
req: SigninRequest;
res: SigninResponse;
},
+ 'admin/roles/create': {
+ req: Overwrite<AdminRolesCreateRequest, { policies: PartialRolePolicyOverride }>;
+ res: AdminRolesCreateResponse;
+ }
}
>
diff --git a/packages/misskey-js/src/autogen/apiClientJSDoc.ts b/packages/misskey-js/src/autogen/apiClientJSDoc.ts
index 181f7274b7..e799d4a0c5 100644
--- a/packages/misskey-js/src/autogen/apiClientJSDoc.ts
+++ b/packages/misskey-js/src/autogen/apiClientJSDoc.ts
@@ -28,6 +28,66 @@ declare module '../api.js' {
/**
* No description provided.
*
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *read:admin:abuse-report:notification-recipient*
+ */
+ request<E extends 'admin/abuse-report/notification-recipient/list', P extends Endpoints[E]['req']>(
+ endpoint: E,
+ params: P,
+ credential?: string | null,
+ ): Promise<SwitchCaseResponseType<E, P>>;
+
+ /**
+ * No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *read:admin:abuse-report:notification-recipient*
+ */
+ request<E extends 'admin/abuse-report/notification-recipient/show', P extends Endpoints[E]['req']>(
+ endpoint: E,
+ params: P,
+ credential?: string | null,
+ ): Promise<SwitchCaseResponseType<E, P>>;
+
+ /**
+ * No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *write:admin:abuse-report:notification-recipient*
+ */
+ request<E extends 'admin/abuse-report/notification-recipient/create', P extends Endpoints[E]['req']>(
+ endpoint: E,
+ params: P,
+ credential?: string | null,
+ ): Promise<SwitchCaseResponseType<E, P>>;
+
+ /**
+ * No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *write:admin:abuse-report:notification-recipient*
+ */
+ request<E extends 'admin/abuse-report/notification-recipient/update', P extends Endpoints[E]['req']>(
+ endpoint: E,
+ params: P,
+ credential?: string | null,
+ ): Promise<SwitchCaseResponseType<E, P>>;
+
+ /**
+ * No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *write:admin:abuse-report:notification-recipient*
+ */
+ request<E extends 'admin/abuse-report/notification-recipient/delete', P extends Endpoints[E]['req']>(
+ endpoint: E,
+ params: P,
+ credential?: string | null,
+ ): Promise<SwitchCaseResponseType<E, P>>;
+
+ /**
+ * No description provided.
+ *
* **Credential required**: *No*
*/
request<E extends 'admin/accounts/create', P extends Endpoints[E]['req']>(
@@ -843,6 +903,66 @@ declare module '../api.js' {
/**
* No description provided.
*
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook*
+ */
+ request<E extends 'admin/system-webhook/create', P extends Endpoints[E]['req']>(
+ endpoint: E,
+ params: P,
+ credential?: string | null,
+ ): Promise<SwitchCaseResponseType<E, P>>;
+
+ /**
+ * No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook*
+ */
+ request<E extends 'admin/system-webhook/delete', P extends Endpoints[E]['req']>(
+ endpoint: E,
+ params: P,
+ credential?: string | null,
+ ): Promise<SwitchCaseResponseType<E, P>>;
+
+ /**
+ * No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook*
+ */
+ request<E extends 'admin/system-webhook/list', P extends Endpoints[E]['req']>(
+ endpoint: E,
+ params: P,
+ credential?: string | null,
+ ): Promise<SwitchCaseResponseType<E, P>>;
+
+ /**
+ * No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook*
+ */
+ request<E extends 'admin/system-webhook/show', P extends Endpoints[E]['req']>(
+ endpoint: E,
+ params: P,
+ credential?: string | null,
+ ): Promise<SwitchCaseResponseType<E, P>>;
+
+ /**
+ * No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook*
+ */
+ request<E extends 'admin/system-webhook/update', P extends Endpoints[E]['req']>(
+ endpoint: E,
+ params: P,
+ credential?: string | null,
+ ): Promise<SwitchCaseResponseType<E, P>>;
+
+ /**
+ * No description provided.
+ *
* **Credential required**: *No*
*/
request<E extends 'announcements', P extends Endpoints[E]['req']>(
diff --git a/packages/misskey-js/src/autogen/endpoint.ts b/packages/misskey-js/src/autogen/endpoint.ts
index ab3baf1670..be41951e4d 100644
--- a/packages/misskey-js/src/autogen/endpoint.ts
+++ b/packages/misskey-js/src/autogen/endpoint.ts
@@ -4,6 +4,15 @@ import type {
AdminMetaResponse,
AdminAbuseUserReportsRequest,
AdminAbuseUserReportsResponse,
+ AdminAbuseReportNotificationRecipientListRequest,
+ AdminAbuseReportNotificationRecipientListResponse,
+ AdminAbuseReportNotificationRecipientShowRequest,
+ AdminAbuseReportNotificationRecipientShowResponse,
+ AdminAbuseReportNotificationRecipientCreateRequest,
+ AdminAbuseReportNotificationRecipientCreateResponse,
+ AdminAbuseReportNotificationRecipientUpdateRequest,
+ AdminAbuseReportNotificationRecipientUpdateResponse,
+ AdminAbuseReportNotificationRecipientDeleteRequest,
AdminAccountsCreateRequest,
AdminAccountsCreateResponse,
AdminAccountsDeleteRequest,
@@ -99,6 +108,15 @@ import type {
AdminRolesUpdateDefaultPoliciesRequest,
AdminRolesUsersRequest,
AdminRolesUsersResponse,
+ AdminSystemWebhookCreateRequest,
+ AdminSystemWebhookCreateResponse,
+ AdminSystemWebhookDeleteRequest,
+ AdminSystemWebhookListRequest,
+ AdminSystemWebhookListResponse,
+ AdminSystemWebhookShowRequest,
+ AdminSystemWebhookShowResponse,
+ AdminSystemWebhookUpdateRequest,
+ AdminSystemWebhookUpdateResponse,
AnnouncementsRequest,
AnnouncementsResponse,
AnnouncementsShowRequest,
@@ -558,6 +576,11 @@ import type {
export type Endpoints = {
'admin/meta': { req: EmptyRequest; res: AdminMetaResponse };
'admin/abuse-user-reports': { req: AdminAbuseUserReportsRequest; res: AdminAbuseUserReportsResponse };
+ 'admin/abuse-report/notification-recipient/list': { req: AdminAbuseReportNotificationRecipientListRequest; res: AdminAbuseReportNotificationRecipientListResponse };
+ 'admin/abuse-report/notification-recipient/show': { req: AdminAbuseReportNotificationRecipientShowRequest; res: AdminAbuseReportNotificationRecipientShowResponse };
+ 'admin/abuse-report/notification-recipient/create': { req: AdminAbuseReportNotificationRecipientCreateRequest; res: AdminAbuseReportNotificationRecipientCreateResponse };
+ 'admin/abuse-report/notification-recipient/update': { req: AdminAbuseReportNotificationRecipientUpdateRequest; res: AdminAbuseReportNotificationRecipientUpdateResponse };
+ 'admin/abuse-report/notification-recipient/delete': { req: AdminAbuseReportNotificationRecipientDeleteRequest; res: EmptyResponse };
'admin/accounts/create': { req: AdminAccountsCreateRequest; res: AdminAccountsCreateResponse };
'admin/accounts/delete': { req: AdminAccountsDeleteRequest; res: EmptyResponse };
'admin/accounts/find-by-email': { req: AdminAccountsFindByEmailRequest; res: AdminAccountsFindByEmailResponse };
@@ -632,6 +655,11 @@ export type Endpoints = {
'admin/roles/unassign': { req: AdminRolesUnassignRequest; res: EmptyResponse };
'admin/roles/update-default-policies': { req: AdminRolesUpdateDefaultPoliciesRequest; res: EmptyResponse };
'admin/roles/users': { req: AdminRolesUsersRequest; res: AdminRolesUsersResponse };
+ 'admin/system-webhook/create': { req: AdminSystemWebhookCreateRequest; res: AdminSystemWebhookCreateResponse };
+ 'admin/system-webhook/delete': { req: AdminSystemWebhookDeleteRequest; res: EmptyResponse };
+ 'admin/system-webhook/list': { req: AdminSystemWebhookListRequest; res: AdminSystemWebhookListResponse };
+ 'admin/system-webhook/show': { req: AdminSystemWebhookShowRequest; res: AdminSystemWebhookShowResponse };
+ 'admin/system-webhook/update': { req: AdminSystemWebhookUpdateRequest; res: AdminSystemWebhookUpdateResponse };
'announcements': { req: AnnouncementsRequest; res: AnnouncementsResponse };
'announcements/show': { req: AnnouncementsShowRequest; res: AnnouncementsShowResponse };
'antennas/create': { req: AntennasCreateRequest; res: AntennasCreateResponse };
@@ -926,3 +954,385 @@ export type Endpoints = {
'reversi/surrender': { req: ReversiSurrenderRequest; res: EmptyResponse };
'reversi/verify': { req: ReversiVerifyRequest; res: ReversiVerifyResponse };
}
+
+export const endpointReqTypes: Record<keyof Endpoints, 'application/json' | 'multipart/form-data'> = {
+ 'admin/meta': 'application/json',
+ 'admin/abuse-user-reports': 'application/json',
+ 'admin/abuse-report/notification-recipient/list': 'application/json',
+ 'admin/abuse-report/notification-recipient/show': 'application/json',
+ 'admin/abuse-report/notification-recipient/create': 'application/json',
+ 'admin/abuse-report/notification-recipient/update': 'application/json',
+ 'admin/abuse-report/notification-recipient/delete': 'application/json',
+ 'admin/accounts/create': 'application/json',
+ 'admin/accounts/delete': 'application/json',
+ 'admin/accounts/find-by-email': 'application/json',
+ 'admin/ad/create': 'application/json',
+ 'admin/ad/delete': 'application/json',
+ 'admin/ad/list': 'application/json',
+ 'admin/ad/update': 'application/json',
+ 'admin/announcements/create': 'application/json',
+ 'admin/announcements/delete': 'application/json',
+ 'admin/announcements/list': 'application/json',
+ 'admin/announcements/update': 'application/json',
+ 'admin/avatar-decorations/create': 'application/json',
+ 'admin/avatar-decorations/delete': 'application/json',
+ 'admin/avatar-decorations/list': 'application/json',
+ 'admin/avatar-decorations/update': 'application/json',
+ 'admin/delete-all-files-of-a-user': 'application/json',
+ 'admin/unset-user-avatar': 'application/json',
+ 'admin/unset-user-banner': 'application/json',
+ 'admin/drive/clean-remote-files': 'application/json',
+ 'admin/drive/cleanup': 'application/json',
+ 'admin/drive/files': 'application/json',
+ 'admin/drive/show-file': 'application/json',
+ 'admin/emoji/add-aliases-bulk': 'application/json',
+ 'admin/emoji/add': 'application/json',
+ 'admin/emoji/copy': 'application/json',
+ 'admin/emoji/delete-bulk': 'application/json',
+ 'admin/emoji/delete': 'application/json',
+ 'admin/emoji/import-zip': 'application/json',
+ 'admin/emoji/list-remote': 'application/json',
+ 'admin/emoji/list': 'application/json',
+ 'admin/emoji/remove-aliases-bulk': 'application/json',
+ 'admin/emoji/set-aliases-bulk': 'application/json',
+ 'admin/emoji/set-category-bulk': 'application/json',
+ 'admin/emoji/set-license-bulk': 'application/json',
+ 'admin/emoji/update': 'application/json',
+ 'admin/federation/delete-all-files': 'application/json',
+ 'admin/federation/refresh-remote-instance-metadata': 'application/json',
+ 'admin/federation/remove-all-following': 'application/json',
+ 'admin/federation/update-instance': 'application/json',
+ 'admin/get-index-stats': 'application/json',
+ 'admin/get-table-stats': 'application/json',
+ 'admin/get-user-ips': 'application/json',
+ 'admin/invite/create': 'application/json',
+ 'admin/invite/list': 'application/json',
+ 'admin/promo/create': 'application/json',
+ 'admin/queue/clear': 'application/json',
+ 'admin/queue/deliver-delayed': 'application/json',
+ 'admin/queue/inbox-delayed': 'application/json',
+ 'admin/queue/promote': 'application/json',
+ 'admin/queue/stats': 'application/json',
+ 'admin/relays/add': 'application/json',
+ 'admin/relays/list': 'application/json',
+ 'admin/relays/remove': 'application/json',
+ 'admin/reset-password': 'application/json',
+ 'admin/resolve-abuse-user-report': 'application/json',
+ 'admin/send-email': 'application/json',
+ 'admin/server-info': 'application/json',
+ 'admin/show-moderation-logs': 'application/json',
+ 'admin/show-user': 'application/json',
+ 'admin/show-users': 'application/json',
+ 'admin/suspend-user': 'application/json',
+ 'admin/unsuspend-user': 'application/json',
+ 'admin/update-meta': 'application/json',
+ 'admin/delete-account': 'application/json',
+ 'admin/update-user-note': 'application/json',
+ 'admin/roles/create': 'application/json',
+ 'admin/roles/delete': 'application/json',
+ 'admin/roles/list': 'application/json',
+ 'admin/roles/show': 'application/json',
+ 'admin/roles/update': 'application/json',
+ 'admin/roles/assign': 'application/json',
+ 'admin/roles/unassign': 'application/json',
+ 'admin/roles/update-default-policies': 'application/json',
+ 'admin/roles/users': 'application/json',
+ 'admin/system-webhook/create': 'application/json',
+ 'admin/system-webhook/delete': 'application/json',
+ 'admin/system-webhook/list': 'application/json',
+ 'admin/system-webhook/show': 'application/json',
+ 'admin/system-webhook/update': 'application/json',
+ 'announcements': 'application/json',
+ 'announcements/show': 'application/json',
+ 'antennas/create': 'application/json',
+ 'antennas/delete': 'application/json',
+ 'antennas/list': 'application/json',
+ 'antennas/notes': 'application/json',
+ 'antennas/show': 'application/json',
+ 'antennas/update': 'application/json',
+ 'ap/get': 'application/json',
+ 'ap/show': 'application/json',
+ 'app/create': 'application/json',
+ 'app/show': 'application/json',
+ 'auth/accept': 'application/json',
+ 'auth/session/generate': 'application/json',
+ 'auth/session/show': 'application/json',
+ 'auth/session/userkey': 'application/json',
+ 'blocking/create': 'application/json',
+ 'blocking/delete': 'application/json',
+ 'blocking/list': 'application/json',
+ 'channels/create': 'application/json',
+ 'channels/featured': 'application/json',
+ 'channels/follow': 'application/json',
+ 'channels/followed': 'application/json',
+ 'channels/owned': 'application/json',
+ 'channels/show': 'application/json',
+ 'channels/timeline': 'application/json',
+ 'channels/unfollow': 'application/json',
+ 'channels/update': 'application/json',
+ 'channels/favorite': 'application/json',
+ 'channels/unfavorite': 'application/json',
+ 'channels/my-favorites': 'application/json',
+ 'channels/search': 'application/json',
+ 'charts/active-users': 'application/json',
+ 'charts/ap-request': 'application/json',
+ 'charts/drive': 'application/json',
+ 'charts/federation': 'application/json',
+ 'charts/instance': 'application/json',
+ 'charts/notes': 'application/json',
+ 'charts/user/drive': 'application/json',
+ 'charts/user/following': 'application/json',
+ 'charts/user/notes': 'application/json',
+ 'charts/user/pv': 'application/json',
+ 'charts/user/reactions': 'application/json',
+ 'charts/users': 'application/json',
+ 'clips/add-note': 'application/json',
+ 'clips/remove-note': 'application/json',
+ 'clips/create': 'application/json',
+ 'clips/delete': 'application/json',
+ 'clips/list': 'application/json',
+ 'clips/notes': 'application/json',
+ 'clips/show': 'application/json',
+ 'clips/update': 'application/json',
+ 'clips/favorite': 'application/json',
+ 'clips/unfavorite': 'application/json',
+ 'clips/my-favorites': 'application/json',
+ 'drive': 'application/json',
+ 'drive/files': 'application/json',
+ 'drive/files/attached-notes': 'application/json',
+ 'drive/files/check-existence': 'application/json',
+ 'drive/files/create': 'multipart/form-data',
+ 'drive/files/delete': 'application/json',
+ 'drive/files/find-by-hash': 'application/json',
+ 'drive/files/find': 'application/json',
+ 'drive/files/show': 'application/json',
+ 'drive/files/update': 'application/json',
+ 'drive/files/upload-from-url': 'application/json',
+ 'drive/folders': 'application/json',
+ 'drive/folders/create': 'application/json',
+ 'drive/folders/delete': 'application/json',
+ 'drive/folders/find': 'application/json',
+ 'drive/folders/show': 'application/json',
+ 'drive/folders/update': 'application/json',
+ 'drive/stream': 'application/json',
+ 'email-address/available': 'application/json',
+ 'endpoint': 'application/json',
+ 'endpoints': 'application/json',
+ 'export-custom-emojis': 'application/json',
+ 'federation/followers': 'application/json',
+ 'federation/following': 'application/json',
+ 'federation/instances': 'application/json',
+ 'federation/show-instance': 'application/json',
+ 'federation/update-remote-user': 'application/json',
+ 'federation/users': 'application/json',
+ 'federation/stats': 'application/json',
+ 'following/create': 'application/json',
+ 'following/delete': 'application/json',
+ 'following/update': 'application/json',
+ 'following/update-all': 'application/json',
+ 'following/invalidate': 'application/json',
+ 'following/requests/accept': 'application/json',
+ 'following/requests/cancel': 'application/json',
+ 'following/requests/list': 'application/json',
+ 'following/requests/reject': 'application/json',
+ 'gallery/featured': 'application/json',
+ 'gallery/popular': 'application/json',
+ 'gallery/posts': 'application/json',
+ 'gallery/posts/create': 'application/json',
+ 'gallery/posts/delete': 'application/json',
+ 'gallery/posts/like': 'application/json',
+ 'gallery/posts/show': 'application/json',
+ 'gallery/posts/unlike': 'application/json',
+ 'gallery/posts/update': 'application/json',
+ 'get-online-users-count': 'application/json',
+ 'get-avatar-decorations': 'application/json',
+ 'hashtags/list': 'application/json',
+ 'hashtags/search': 'application/json',
+ 'hashtags/show': 'application/json',
+ 'hashtags/trend': 'application/json',
+ 'hashtags/users': 'application/json',
+ 'i': 'application/json',
+ 'i/2fa/done': 'application/json',
+ 'i/2fa/key-done': 'application/json',
+ 'i/2fa/password-less': 'application/json',
+ 'i/2fa/register-key': 'application/json',
+ 'i/2fa/register': 'application/json',
+ 'i/2fa/update-key': 'application/json',
+ 'i/2fa/remove-key': 'application/json',
+ 'i/2fa/unregister': 'application/json',
+ 'i/apps': 'application/json',
+ 'i/authorized-apps': 'application/json',
+ 'i/claim-achievement': 'application/json',
+ 'i/change-password': 'application/json',
+ 'i/delete-account': 'application/json',
+ 'i/export-blocking': 'application/json',
+ 'i/export-following': 'application/json',
+ 'i/export-mute': 'application/json',
+ 'i/export-notes': 'application/json',
+ 'i/export-clips': 'application/json',
+ 'i/export-favorites': 'application/json',
+ 'i/export-user-lists': 'application/json',
+ 'i/export-antennas': 'application/json',
+ 'i/favorites': 'application/json',
+ 'i/gallery/likes': 'application/json',
+ 'i/gallery/posts': 'application/json',
+ 'i/import-blocking': 'application/json',
+ 'i/import-following': 'application/json',
+ 'i/import-muting': 'application/json',
+ 'i/import-user-lists': 'application/json',
+ 'i/import-antennas': 'application/json',
+ 'i/notifications': 'application/json',
+ 'i/notifications-grouped': 'application/json',
+ 'i/page-likes': 'application/json',
+ 'i/pages': 'application/json',
+ 'i/pin': 'application/json',
+ 'i/read-all-unread-notes': 'application/json',
+ 'i/read-announcement': 'application/json',
+ 'i/regenerate-token': 'application/json',
+ 'i/registry/get-all': 'application/json',
+ 'i/registry/get-detail': 'application/json',
+ 'i/registry/get': 'application/json',
+ 'i/registry/keys-with-type': 'application/json',
+ 'i/registry/keys': 'application/json',
+ 'i/registry/remove': 'application/json',
+ 'i/registry/scopes-with-domain': 'application/json',
+ 'i/registry/set': 'application/json',
+ 'i/revoke-token': 'application/json',
+ 'i/signin-history': 'application/json',
+ 'i/unpin': 'application/json',
+ 'i/update-email': 'application/json',
+ 'i/update': 'application/json',
+ 'i/move': 'application/json',
+ 'i/webhooks/create': 'application/json',
+ 'i/webhooks/list': 'application/json',
+ 'i/webhooks/show': 'application/json',
+ 'i/webhooks/update': 'application/json',
+ 'i/webhooks/delete': 'application/json',
+ 'invite/create': 'application/json',
+ 'invite/delete': 'application/json',
+ 'invite/list': 'application/json',
+ 'invite/limit': 'application/json',
+ 'meta': 'application/json',
+ 'emojis': 'application/json',
+ 'emoji': 'application/json',
+ 'miauth/gen-token': 'application/json',
+ 'mute/create': 'application/json',
+ 'mute/delete': 'application/json',
+ 'mute/list': 'application/json',
+ 'renote-mute/create': 'application/json',
+ 'renote-mute/delete': 'application/json',
+ 'renote-mute/list': 'application/json',
+ 'my/apps': 'application/json',
+ 'notes': 'application/json',
+ 'notes/children': 'application/json',
+ 'notes/clips': 'application/json',
+ 'notes/conversation': 'application/json',
+ 'notes/create': 'application/json',
+ 'notes/delete': 'application/json',
+ 'notes/favorites/create': 'application/json',
+ 'notes/favorites/delete': 'application/json',
+ 'notes/featured': 'application/json',
+ 'notes/global-timeline': 'application/json',
+ 'notes/hybrid-timeline': 'application/json',
+ 'notes/local-timeline': 'application/json',
+ 'notes/mentions': 'application/json',
+ 'notes/polls/recommendation': 'application/json',
+ 'notes/polls/vote': 'application/json',
+ 'notes/reactions': 'application/json',
+ 'notes/reactions/create': 'application/json',
+ 'notes/reactions/delete': 'application/json',
+ 'notes/renotes': 'application/json',
+ 'notes/replies': 'application/json',
+ 'notes/search-by-tag': 'application/json',
+ 'notes/search': 'application/json',
+ 'notes/show': 'application/json',
+ 'notes/state': 'application/json',
+ 'notes/thread-muting/create': 'application/json',
+ 'notes/thread-muting/delete': 'application/json',
+ 'notes/timeline': 'application/json',
+ 'notes/translate': 'application/json',
+ 'notes/unrenote': 'application/json',
+ 'notes/user-list-timeline': 'application/json',
+ 'notifications/create': 'application/json',
+ 'notifications/flush': 'application/json',
+ 'notifications/mark-all-as-read': 'application/json',
+ 'notifications/test-notification': 'application/json',
+ 'page-push': 'application/json',
+ 'pages/create': 'application/json',
+ 'pages/delete': 'application/json',
+ 'pages/featured': 'application/json',
+ 'pages/like': 'application/json',
+ 'pages/show': 'application/json',
+ 'pages/unlike': 'application/json',
+ 'pages/update': 'application/json',
+ 'flash/create': 'application/json',
+ 'flash/delete': 'application/json',
+ 'flash/featured': 'application/json',
+ 'flash/like': 'application/json',
+ 'flash/show': 'application/json',
+ 'flash/unlike': 'application/json',
+ 'flash/update': 'application/json',
+ 'flash/my': 'application/json',
+ 'flash/my-likes': 'application/json',
+ 'ping': 'application/json',
+ 'pinned-users': 'application/json',
+ 'promo/read': 'application/json',
+ 'roles/list': 'application/json',
+ 'roles/show': 'application/json',
+ 'roles/users': 'application/json',
+ 'roles/notes': 'application/json',
+ 'request-reset-password': 'application/json',
+ 'reset-db': 'application/json',
+ 'reset-password': 'application/json',
+ 'server-info': 'application/json',
+ 'stats': 'application/json',
+ 'sw/show-registration': 'application/json',
+ 'sw/update-registration': 'application/json',
+ 'sw/register': 'application/json',
+ 'sw/unregister': 'application/json',
+ 'test': 'application/json',
+ 'username/available': 'application/json',
+ 'users': 'application/json',
+ 'users/clips': 'application/json',
+ 'users/followers': 'application/json',
+ 'users/following': 'application/json',
+ 'users/gallery/posts': 'application/json',
+ 'users/get-frequently-replied-users': 'application/json',
+ 'users/featured-notes': 'application/json',
+ 'users/lists/create': 'application/json',
+ 'users/lists/delete': 'application/json',
+ 'users/lists/list': 'application/json',
+ 'users/lists/pull': 'application/json',
+ 'users/lists/push': 'application/json',
+ 'users/lists/show': 'application/json',
+ 'users/lists/favorite': 'application/json',
+ 'users/lists/unfavorite': 'application/json',
+ 'users/lists/update': 'application/json',
+ 'users/lists/create-from-public': 'application/json',
+ 'users/lists/update-membership': 'application/json',
+ 'users/lists/get-memberships': 'application/json',
+ 'users/notes': 'application/json',
+ 'users/pages': 'application/json',
+ 'users/flashs': 'application/json',
+ 'users/reactions': 'application/json',
+ 'users/recommendation': 'application/json',
+ 'users/relation': 'application/json',
+ 'users/report-abuse': 'application/json',
+ 'users/search-by-username-and-host': 'application/json',
+ 'users/search': 'application/json',
+ 'users/show': 'application/json',
+ 'users/achievements': 'application/json',
+ 'users/update-memo': 'application/json',
+ 'fetch-rss': 'application/json',
+ 'fetch-external-resources': 'application/json',
+ 'retention': 'application/json',
+ 'bubble-game/register': 'application/json',
+ 'bubble-game/ranking': 'application/json',
+ 'reversi/cancel-match': 'application/json',
+ 'reversi/games': 'application/json',
+ 'reversi/match': 'application/json',
+ 'reversi/invitations': 'application/json',
+ 'reversi/show-game': 'application/json',
+ 'reversi/surrender': 'application/json',
+ 'reversi/verify': 'application/json',
+};
diff --git a/packages/misskey-js/src/autogen/entities.ts b/packages/misskey-js/src/autogen/entities.ts
index 02ca932d8a..357b5e9eaf 100644
--- a/packages/misskey-js/src/autogen/entities.ts
+++ b/packages/misskey-js/src/autogen/entities.ts
@@ -7,6 +7,15 @@ export type EmptyResponse = Record<string, unknown> | undefined;
export type AdminMetaResponse = operations['admin___meta']['responses']['200']['content']['application/json'];
export type AdminAbuseUserReportsRequest = operations['admin___abuse-user-reports']['requestBody']['content']['application/json'];
export type AdminAbuseUserReportsResponse = operations['admin___abuse-user-reports']['responses']['200']['content']['application/json'];
+export type AdminAbuseReportNotificationRecipientListRequest = operations['admin___abuse-report___notification-recipient___list']['requestBody']['content']['application/json'];
+export type AdminAbuseReportNotificationRecipientListResponse = operations['admin___abuse-report___notification-recipient___list']['responses']['200']['content']['application/json'];
+export type AdminAbuseReportNotificationRecipientShowRequest = operations['admin___abuse-report___notification-recipient___show']['requestBody']['content']['application/json'];
+export type AdminAbuseReportNotificationRecipientShowResponse = operations['admin___abuse-report___notification-recipient___show']['responses']['200']['content']['application/json'];
+export type AdminAbuseReportNotificationRecipientCreateRequest = operations['admin___abuse-report___notification-recipient___create']['requestBody']['content']['application/json'];
+export type AdminAbuseReportNotificationRecipientCreateResponse = operations['admin___abuse-report___notification-recipient___create']['responses']['200']['content']['application/json'];
+export type AdminAbuseReportNotificationRecipientUpdateRequest = operations['admin___abuse-report___notification-recipient___update']['requestBody']['content']['application/json'];
+export type AdminAbuseReportNotificationRecipientUpdateResponse = operations['admin___abuse-report___notification-recipient___update']['responses']['200']['content']['application/json'];
+export type AdminAbuseReportNotificationRecipientDeleteRequest = operations['admin___abuse-report___notification-recipient___delete']['requestBody']['content']['application/json'];
export type AdminAccountsCreateRequest = operations['admin___accounts___create']['requestBody']['content']['application/json'];
export type AdminAccountsCreateResponse = operations['admin___accounts___create']['responses']['200']['content']['application/json'];
export type AdminAccountsDeleteRequest = operations['admin___accounts___delete']['requestBody']['content']['application/json'];
@@ -102,6 +111,15 @@ export type AdminRolesUnassignRequest = operations['admin___roles___unassign']['
export type AdminRolesUpdateDefaultPoliciesRequest = operations['admin___roles___update-default-policies']['requestBody']['content']['application/json'];
export type AdminRolesUsersRequest = operations['admin___roles___users']['requestBody']['content']['application/json'];
export type AdminRolesUsersResponse = operations['admin___roles___users']['responses']['200']['content']['application/json'];
+export type AdminSystemWebhookCreateRequest = operations['admin___system-webhook___create']['requestBody']['content']['application/json'];
+export type AdminSystemWebhookCreateResponse = operations['admin___system-webhook___create']['responses']['200']['content']['application/json'];
+export type AdminSystemWebhookDeleteRequest = operations['admin___system-webhook___delete']['requestBody']['content']['application/json'];
+export type AdminSystemWebhookListRequest = operations['admin___system-webhook___list']['requestBody']['content']['application/json'];
+export type AdminSystemWebhookListResponse = operations['admin___system-webhook___list']['responses']['200']['content']['application/json'];
+export type AdminSystemWebhookShowRequest = operations['admin___system-webhook___show']['requestBody']['content']['application/json'];
+export type AdminSystemWebhookShowResponse = operations['admin___system-webhook___show']['responses']['200']['content']['application/json'];
+export type AdminSystemWebhookUpdateRequest = operations['admin___system-webhook___update']['requestBody']['content']['application/json'];
+export type AdminSystemWebhookUpdateResponse = operations['admin___system-webhook___update']['responses']['200']['content']['application/json'];
export type AnnouncementsRequest = operations['announcements']['requestBody']['content']['application/json'];
export type AnnouncementsResponse = operations['announcements']['responses']['200']['content']['application/json'];
export type AnnouncementsShowRequest = operations['announcements___show']['requestBody']['content']['application/json'];
diff --git a/packages/misskey-js/src/autogen/models.ts b/packages/misskey-js/src/autogen/models.ts
index a6e5fbe689..04574849d4 100644
--- a/packages/misskey-js/src/autogen/models.ts
+++ b/packages/misskey-js/src/autogen/models.ts
@@ -51,3 +51,5 @@ export type ReversiGameDetailed = components['schemas']['ReversiGameDetailed'];
export type MetaLite = components['schemas']['MetaLite'];
export type MetaDetailedOnly = components['schemas']['MetaDetailedOnly'];
export type MetaDetailed = components['schemas']['MetaDetailed'];
+export type SystemWebhook = components['schemas']['SystemWebhook'];
+export type AbuseReportNotificationRecipient = components['schemas']['AbuseReportNotificationRecipient'];
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index 2c80676f3e..db5efd4a00 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -30,6 +30,56 @@ export type paths = {
*/
post: operations['admin___abuse-user-reports'];
};
+ '/admin/abuse-report/notification-recipient/list': {
+ /**
+ * admin/abuse-report/notification-recipient/list
+ * @description No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *read:admin:abuse-report:notification-recipient*
+ */
+ post: operations['admin___abuse-report___notification-recipient___list'];
+ };
+ '/admin/abuse-report/notification-recipient/show': {
+ /**
+ * admin/abuse-report/notification-recipient/show
+ * @description No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *read:admin:abuse-report:notification-recipient*
+ */
+ post: operations['admin___abuse-report___notification-recipient___show'];
+ };
+ '/admin/abuse-report/notification-recipient/create': {
+ /**
+ * admin/abuse-report/notification-recipient/create
+ * @description No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *write:admin:abuse-report:notification-recipient*
+ */
+ post: operations['admin___abuse-report___notification-recipient___create'];
+ };
+ '/admin/abuse-report/notification-recipient/update': {
+ /**
+ * admin/abuse-report/notification-recipient/update
+ * @description No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *write:admin:abuse-report:notification-recipient*
+ */
+ post: operations['admin___abuse-report___notification-recipient___update'];
+ };
+ '/admin/abuse-report/notification-recipient/delete': {
+ /**
+ * admin/abuse-report/notification-recipient/delete
+ * @description No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *write:admin:abuse-report:notification-recipient*
+ */
+ post: operations['admin___abuse-report___notification-recipient___delete'];
+ };
'/admin/accounts/create': {
/**
* admin/accounts/create
@@ -697,6 +747,56 @@ export type paths = {
*/
post: operations['admin___roles___users'];
};
+ '/admin/system-webhook/create': {
+ /**
+ * admin/system-webhook/create
+ * @description No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook*
+ */
+ post: operations['admin___system-webhook___create'];
+ };
+ '/admin/system-webhook/delete': {
+ /**
+ * admin/system-webhook/delete
+ * @description No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook*
+ */
+ post: operations['admin___system-webhook___delete'];
+ };
+ '/admin/system-webhook/list': {
+ /**
+ * admin/system-webhook/list
+ * @description No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook*
+ */
+ post: operations['admin___system-webhook___list'];
+ };
+ '/admin/system-webhook/show': {
+ /**
+ * admin/system-webhook/show
+ * @description No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook*
+ */
+ post: operations['admin___system-webhook___show'];
+ };
+ '/admin/system-webhook/update': {
+ /**
+ * admin/system-webhook/update
+ * @description No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook*
+ */
+ post: operations['admin___system-webhook___update'];
+ };
'/announcements': {
/**
* announcements
@@ -3989,7 +4089,8 @@ export type components = {
userId: string | null;
}) | null;
localOnly?: boolean;
- reactionAcceptance: string | null;
+ /** @enum {string|null} */
+ reactionAcceptance: 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote' | null;
reactionEmojis: {
[key: string]: string;
};
@@ -4199,7 +4300,7 @@ export type components = {
id: string;
/** Format: date-time */
createdAt: string;
- /** @example lenna.jpg */
+ /** @example 192.jpg */
name: string;
/** @example image/jpeg */
type: string;
@@ -4498,6 +4599,7 @@ export type components = {
maintainerName: string | null;
maintainerEmail: string | null;
isSilenced: boolean;
+ isMediaSilenced: boolean;
/** Format: url */
iconUrl: string | null;
/** Format: url */
@@ -4686,6 +4788,7 @@ export type components = {
canHideAds: boolean;
driveCapacityMb: number;
alwaysMarkNsfw: boolean;
+ canUpdateBioMedia: boolean;
pinLimit: number;
antennaLimit: number;
wordMuteLimit: number;
@@ -4837,6 +4940,11 @@ export type components = {
serverRules: string[];
themeColor: string | null;
policies: components['schemas']['RolePolicies'];
+ /**
+ * @default local
+ * @enum {string}
+ */
+ noteSearchableScope: 'local' | 'global';
};
MetaDetailedOnly: {
features?: {
@@ -4859,6 +4967,32 @@ export type components = {
cacheRemoteSensitiveFiles: boolean;
};
MetaDetailed: components['schemas']['MetaLite'] & components['schemas']['MetaDetailedOnly'];
+ SystemWebhook: {
+ id: string;
+ isActive: boolean;
+ /** Format: date-time */
+ updatedAt: string;
+ /** Format: date-time */
+ latestSentAt: string | null;
+ latestStatus: number | null;
+ name: string;
+ on: ('abuseReport' | 'abuseReportResolved' | 'userCreated')[];
+ url: string;
+ secret: string;
+ };
+ AbuseReportNotificationRecipient: {
+ id: string;
+ isActive: boolean;
+ /** Format: date-time */
+ updatedAt: string;
+ name: string;
+ /** @enum {string} */
+ method: 'email' | 'webhook';
+ userId?: string;
+ user?: components['schemas']['UserLite'];
+ systemWebhookId?: string;
+ systemWebhook?: components['schemas']['SystemWebhook'];
+ };
};
responses: never;
parameters: never;
@@ -4911,6 +5045,7 @@ export type operations = {
enableServiceWorker: boolean;
translatorAvailable: boolean;
silencedHosts?: string[];
+ mediaSilencedHosts: string[];
pinnedUsers: string[];
hiddenTags: string[];
blockedHosts: string[];
@@ -5126,6 +5261,292 @@ export type operations = {
};
};
/**
+ * admin/abuse-report/notification-recipient/list
+ * @description No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *read:admin:abuse-report:notification-recipient*
+ */
+ 'admin___abuse-report___notification-recipient___list': {
+ requestBody: {
+ content: {
+ 'application/json': {
+ method?: ('email' | 'webhook')[];
+ };
+ };
+ };
+ responses: {
+ /** @description OK (with results) */
+ 200: {
+ content: {
+ 'application/json': components['schemas']['AbuseReportNotificationRecipient'][];
+ };
+ };
+ /** @description Client error */
+ 400: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Authentication error */
+ 401: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Forbidden error */
+ 403: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description I'm Ai */
+ 418: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Internal server error */
+ 500: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ };
+ };
+ /**
+ * admin/abuse-report/notification-recipient/show
+ * @description No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *read:admin:abuse-report:notification-recipient*
+ */
+ 'admin___abuse-report___notification-recipient___show': {
+ requestBody: {
+ content: {
+ 'application/json': {
+ /** Format: misskey:id */
+ id: string;
+ };
+ };
+ };
+ responses: {
+ /** @description OK (with results) */
+ 200: {
+ content: {
+ 'application/json': components['schemas']['AbuseReportNotificationRecipient'];
+ };
+ };
+ /** @description Client error */
+ 400: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Authentication error */
+ 401: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Forbidden error */
+ 403: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description I'm Ai */
+ 418: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Internal server error */
+ 500: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ };
+ };
+ /**
+ * admin/abuse-report/notification-recipient/create
+ * @description No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *write:admin:abuse-report:notification-recipient*
+ */
+ 'admin___abuse-report___notification-recipient___create': {
+ requestBody: {
+ content: {
+ 'application/json': {
+ isActive: boolean;
+ name: string;
+ /** @enum {string} */
+ method: 'email' | 'webhook';
+ /** Format: misskey:id */
+ userId?: string;
+ /** Format: misskey:id */
+ systemWebhookId?: string;
+ };
+ };
+ };
+ responses: {
+ /** @description OK (with results) */
+ 200: {
+ content: {
+ 'application/json': components['schemas']['AbuseReportNotificationRecipient'];
+ };
+ };
+ /** @description Client error */
+ 400: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Authentication error */
+ 401: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Forbidden error */
+ 403: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description I'm Ai */
+ 418: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Internal server error */
+ 500: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ };
+ };
+ /**
+ * admin/abuse-report/notification-recipient/update
+ * @description No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *write:admin:abuse-report:notification-recipient*
+ */
+ 'admin___abuse-report___notification-recipient___update': {
+ requestBody: {
+ content: {
+ 'application/json': {
+ /** Format: misskey:id */
+ id: string;
+ isActive: boolean;
+ name: string;
+ /** @enum {string} */
+ method: 'email' | 'webhook';
+ /** Format: misskey:id */
+ userId?: string;
+ /** Format: misskey:id */
+ systemWebhookId?: string;
+ };
+ };
+ };
+ responses: {
+ /** @description OK (with results) */
+ 200: {
+ content: {
+ 'application/json': components['schemas']['AbuseReportNotificationRecipient'];
+ };
+ };
+ /** @description Client error */
+ 400: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Authentication error */
+ 401: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Forbidden error */
+ 403: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description I'm Ai */
+ 418: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Internal server error */
+ 500: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ };
+ };
+ /**
+ * admin/abuse-report/notification-recipient/delete
+ * @description No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *write:admin:abuse-report:notification-recipient*
+ */
+ 'admin___abuse-report___notification-recipient___delete': {
+ requestBody: {
+ content: {
+ 'application/json': {
+ /** Format: misskey:id */
+ id: string;
+ };
+ };
+ };
+ responses: {
+ /** @description OK (without any results) */
+ 204: {
+ content: never;
+ };
+ /** @description Client error */
+ 400: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Authentication error */
+ 401: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Forbidden error */
+ 403: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description I'm Ai */
+ 418: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Internal server error */
+ 500: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ };
+ };
+ /**
* admin/accounts/create
* @description No description provided.
*
@@ -5469,15 +5890,15 @@ export type operations = {
'application/json': {
/** Format: misskey:id */
id: string;
- memo: string;
- url: string;
- imageUrl: string;
- place: string;
- priority: string;
- ratio: number;
- expiresAt: number;
- startsAt: number;
- dayOfWeek: number;
+ memo?: string;
+ url?: string;
+ imageUrl?: string;
+ place?: string;
+ priority?: string;
+ ratio?: number;
+ expiresAt?: number;
+ startsAt?: number;
+ dayOfWeek?: number;
};
};
};
@@ -5677,6 +6098,11 @@ export type operations = {
untilId?: string;
/** Format: misskey:id */
userId?: string | null;
+ /**
+ * @default active
+ * @enum {string}
+ */
+ status?: 'all' | 'active' | 'archived';
};
};
};
@@ -6387,7 +6813,7 @@ export type operations = {
* @example 15eca7fba0480996e2245f5185bf39f2
*/
md5: string;
- /** @example lenna.jpg */
+ /** @example 192.jpg */
name: string;
/** @example image/jpeg */
type: string;
@@ -8947,6 +9373,7 @@ export type operations = {
perUserListTimelineCacheMax?: number;
notesPerOneAd?: number;
silencedHosts?: string[] | null;
+ mediaSilencedHosts?: string[] | null;
/** @description [Deprecated] Use "urlPreviewSummaryProxyUrl" instead. */
summalyProxy?: string | null;
urlPreviewEnabled?: boolean;
@@ -9332,21 +9759,21 @@ export type operations = {
'application/json': {
/** Format: misskey:id */
roleId: string;
- name: string;
- description: string;
- color: string | null;
- iconUrl: string | null;
+ name?: string;
+ description?: string;
+ color?: string | null;
+ iconUrl?: string | null;
/** @enum {string} */
- target: 'manual' | 'conditional';
- condFormula: Record<string, never>;
- isPublic: boolean;
- isModerator: boolean;
- isAdministrator: boolean;
+ target?: 'manual' | 'conditional';
+ condFormula?: Record<string, never>;
+ isPublic?: boolean;
+ isModerator?: boolean;
+ isAdministrator?: boolean;
isExplorable?: boolean;
- asBadge: boolean;
- canEditMembersByModerator: boolean;
- displayOrder: number;
- policies: Record<string, never>;
+ asBadge?: boolean;
+ canEditMembersByModerator?: boolean;
+ displayOrder?: number;
+ policies?: Record<string, never>;
};
};
};
@@ -9616,6 +10043,287 @@ export type operations = {
};
};
/**
+ * admin/system-webhook/create
+ * @description No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook*
+ */
+ 'admin___system-webhook___create': {
+ requestBody: {
+ content: {
+ 'application/json': {
+ isActive: boolean;
+ name: string;
+ on: ('abuseReport' | 'abuseReportResolved' | 'userCreated')[];
+ url: string;
+ secret: string;
+ };
+ };
+ };
+ responses: {
+ /** @description OK (with results) */
+ 200: {
+ content: {
+ 'application/json': components['schemas']['SystemWebhook'];
+ };
+ };
+ /** @description Client error */
+ 400: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Authentication error */
+ 401: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Forbidden error */
+ 403: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description I'm Ai */
+ 418: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Internal server error */
+ 500: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ };
+ };
+ /**
+ * admin/system-webhook/delete
+ * @description No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook*
+ */
+ 'admin___system-webhook___delete': {
+ requestBody: {
+ content: {
+ 'application/json': {
+ /** Format: misskey:id */
+ id: string;
+ };
+ };
+ };
+ responses: {
+ /** @description OK (without any results) */
+ 204: {
+ content: never;
+ };
+ /** @description Client error */
+ 400: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Authentication error */
+ 401: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Forbidden error */
+ 403: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description I'm Ai */
+ 418: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Internal server error */
+ 500: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ };
+ };
+ /**
+ * admin/system-webhook/list
+ * @description No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook*
+ */
+ 'admin___system-webhook___list': {
+ requestBody: {
+ content: {
+ 'application/json': {
+ isActive?: boolean;
+ on?: ('abuseReport' | 'abuseReportResolved' | 'userCreated')[];
+ };
+ };
+ };
+ responses: {
+ /** @description OK (with results) */
+ 200: {
+ content: {
+ 'application/json': components['schemas']['SystemWebhook'][];
+ };
+ };
+ /** @description Client error */
+ 400: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Authentication error */
+ 401: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Forbidden error */
+ 403: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description I'm Ai */
+ 418: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Internal server error */
+ 500: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ };
+ };
+ /**
+ * admin/system-webhook/show
+ * @description No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook*
+ */
+ 'admin___system-webhook___show': {
+ requestBody: {
+ content: {
+ 'application/json': {
+ /** Format: misskey:id */
+ id: string;
+ };
+ };
+ };
+ responses: {
+ /** @description OK (with results) */
+ 200: {
+ content: {
+ 'application/json': components['schemas']['SystemWebhook'];
+ };
+ };
+ /** @description Client error */
+ 400: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Authentication error */
+ 401: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Forbidden error */
+ 403: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description I'm Ai */
+ 418: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Internal server error */
+ 500: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ };
+ };
+ /**
+ * admin/system-webhook/update
+ * @description No description provided.
+ *
+ * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties.
+ * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook*
+ */
+ 'admin___system-webhook___update': {
+ requestBody: {
+ content: {
+ 'application/json': {
+ /** Format: misskey:id */
+ id: string;
+ isActive: boolean;
+ name: string;
+ on: ('abuseReport' | 'abuseReportResolved' | 'userCreated')[];
+ url: string;
+ secret: string;
+ };
+ };
+ };
+ responses: {
+ /** @description OK (with results) */
+ 200: {
+ content: {
+ 'application/json': components['schemas']['SystemWebhook'];
+ };
+ };
+ /** @description Client error */
+ 400: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Authentication error */
+ 401: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Forbidden error */
+ 403: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description I'm Ai */
+ 418: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ /** @description Internal server error */
+ 500: {
+ content: {
+ 'application/json': components['schemas']['Error'];
+ };
+ };
+ };
+ };
+ /**
* announcements
* @description No description provided.
*
@@ -12707,7 +13415,7 @@ export type operations = {
'application/json': {
/** Format: misskey:id */
clipId: string;
- name: string;
+ name?: string;
isPublic?: boolean;
description?: string | null;
};
@@ -13157,7 +13865,7 @@ export type operations = {
* Format: binary
* @description The file contents.
*/
- file: string;
+ file: Blob;
};
};
};
@@ -15554,9 +16262,9 @@ export type operations = {
'application/json': {
/** Format: misskey:id */
postId: string;
- title: string;
+ title?: string;
description?: string | null;
- fileIds: string[];
+ fileIds?: string[];
/** @default false */
isSensitive?: boolean;
};
@@ -19337,12 +20045,11 @@ export type operations = {
'application/json': {
/** Format: misskey:id */
webhookId: string;
- name: string;
- url: string;
- /** @default */
- secret?: string;
- on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction')[];
- active: boolean;
+ name?: string;
+ url?: string;
+ secret?: string | null;
+ on?: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction')[];
+ active?: boolean;
};
};
};
@@ -22711,16 +23418,16 @@ export type operations = {
'application/json': {
/** Format: misskey:id */
pageId: string;
- title: string;
- name: string;
+ title?: string;
+ name?: string;
summary?: string | null;
- content: {
+ content?: {
[key: string]: unknown;
}[];
- variables: {
+ variables?: {
[key: string]: unknown;
}[];
- script: string;
+ script?: string;
/** Format: misskey:id */
eyeCatchingImageId?: string | null;
/** @enum {string} */
diff --git a/packages/misskey-js/src/consts.ts b/packages/misskey-js/src/consts.ts
index fd6ef4d68d..aa8eeb48cb 100644
--- a/packages/misskey-js/src/consts.ts
+++ b/packages/misskey-js/src/consts.ts
@@ -1,3 +1,13 @@
+import type { operations } from './autogen/types.js';
+import type {
+ AbuseReportNotificationRecipient, Ad,
+ Announcement,
+ EmojiDetailed, InviteCode,
+ MetaDetailed,
+ Note,
+ Role, SystemWebhook, UserLite,
+} from './autogen/models.js';
+
export const notificationTypes = ['note', 'follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'app', 'roleAssigned', 'achievementEarned'] as const;
export const noteVisibilities = ['public', 'home', 'followers', 'specified'] as const;
@@ -133,12 +143,38 @@ export const moderationLogTypes = [
'deleteAvatarDecoration',
'unsetUserAvatar',
'unsetUserBanner',
+ 'createSystemWebhook',
+ 'updateSystemWebhook',
+ 'deleteSystemWebhook',
+ 'createAbuseReportNotificationRecipient',
+ 'updateAbuseReportNotificationRecipient',
+ 'deleteAbuseReportNotificationRecipient',
+] as const;
+
+// See: packages/backend/src/core/ReversiService.ts@L410
+export const reversiUpdateKeys = [
+ 'map',
+ 'bw',
+ 'isLlotheo',
+ 'canPutEverywhere',
+ 'loopedBoard',
+ 'timeLimitForEachTurn',
] as const;
+export type ReversiUpdateKey = typeof reversiUpdateKeys[number];
+
+type AvatarDecoration = UserLite['avatarDecorations'][number];
+
+type ReceivedAbuseReport = {
+ reportId: AbuseReportNotificationRecipient['id'];
+ report: operations['admin___abuse-user-reports']['responses'][200]['content']['application/json'];
+ forwarded: boolean;
+};
+
export type ModerationLogPayloads = {
updateServerSettings: {
- before: any | null;
- after: any | null;
+ before: MetaDetailed | null;
+ after: MetaDetailed | null;
};
suspend: {
userId: string;
@@ -159,16 +195,16 @@ export type ModerationLogPayloads = {
};
addCustomEmoji: {
emojiId: string;
- emoji: any;
+ emoji: EmojiDetailed;
};
updateCustomEmoji: {
emojiId: string;
- before: any;
- after: any;
+ before: EmojiDetailed;
+ after: EmojiDetailed;
};
deleteCustomEmoji: {
emojiId: string;
- emoji: any;
+ emoji: EmojiDetailed;
};
assignRole: {
userId: string;
@@ -187,16 +223,16 @@ export type ModerationLogPayloads = {
};
createRole: {
roleId: string;
- role: any;
+ role: Role;
};
updateRole: {
roleId: string;
- before: any;
- after: any;
+ before: Role;
+ after: Role;
};
deleteRole: {
roleId: string;
- role: any;
+ role: Role;
};
clearQueue: Record<string, never>;
promoteQueue: Record<string, never>;
@@ -211,39 +247,39 @@ export type ModerationLogPayloads = {
noteUserId: string;
noteUserUsername: string;
noteUserHost: string | null;
- note: any;
+ note: Note;
};
createGlobalAnnouncement: {
announcementId: string;
- announcement: any;
+ announcement: Announcement;
};
createUserAnnouncement: {
announcementId: string;
- announcement: any;
+ announcement: Announcement;
userId: string;
userUsername: string;
userHost: string | null;
};
updateGlobalAnnouncement: {
announcementId: string;
- before: any;
- after: any;
+ before: Announcement;
+ after: Announcement;
};
updateUserAnnouncement: {
announcementId: string;
- before: any;
- after: any;
+ before: Announcement;
+ after: Announcement;
userId: string;
userUsername: string;
userHost: string | null;
};
deleteGlobalAnnouncement: {
announcementId: string;
- announcement: any;
+ announcement: Announcement;
};
deleteUserAnnouncement: {
announcementId: string;
- announcement: any;
+ announcement: Announcement;
userId: string;
userUsername: string;
userHost: string | null;
@@ -281,37 +317,37 @@ export type ModerationLogPayloads = {
};
resolveAbuseReport: {
reportId: string;
- report: any;
+ report: ReceivedAbuseReport;
forwarded: boolean;
};
createInvitation: {
- invitations: any[];
+ invitations: InviteCode[];
};
createAd: {
adId: string;
- ad: any;
+ ad: Ad;
};
updateAd: {
adId: string;
- before: any;
- after: any;
+ before: Ad;
+ after: Ad;
};
deleteAd: {
adId: string;
- ad: any;
+ ad: Ad;
};
createAvatarDecoration: {
avatarDecorationId: string;
- avatarDecoration: any;
+ avatarDecoration: AvatarDecoration;
};
updateAvatarDecoration: {
avatarDecorationId: string;
- before: any;
- after: any;
+ before: AvatarDecoration;
+ after: AvatarDecoration;
};
deleteAvatarDecoration: {
avatarDecorationId: string;
- avatarDecoration: any;
+ avatarDecoration: AvatarDecoration;
};
unsetUserAvatar: {
userId: string;
@@ -325,4 +361,30 @@ export type ModerationLogPayloads = {
userHost: string | null;
fileId: string;
};
+ createSystemWebhook: {
+ systemWebhookId: string;
+ webhook: SystemWebhook;
+ };
+ updateSystemWebhook: {
+ systemWebhookId: string;
+ before: SystemWebhook;
+ after: SystemWebhook;
+ };
+ deleteSystemWebhook: {
+ systemWebhookId: string;
+ webhook: SystemWebhook;
+ };
+ createAbuseReportNotificationRecipient: {
+ recipientId: string;
+ recipient: AbuseReportNotificationRecipient;
+ };
+ updateAbuseReportNotificationRecipient: {
+ recipientId: string;
+ before: AbuseReportNotificationRecipient;
+ after: AbuseReportNotificationRecipient;
+ };
+ deleteAbuseReportNotificationRecipient: {
+ recipientId: string;
+ recipient: AbuseReportNotificationRecipient;
+ };
};
diff --git a/packages/misskey-js/src/entities.ts b/packages/misskey-js/src/entities.ts
index 35503d6d6f..ce58fb2970 100644
--- a/packages/misskey-js/src/entities.ts
+++ b/packages/misskey-js/src/entities.ts
@@ -1,5 +1,14 @@
import { ModerationLogPayloads } from './consts.js';
-import { Announcement, EmojiDetailed, MeDetailed, Page, User, UserDetailedNotMe } from './autogen/models.js';
+import {
+ Announcement,
+ EmojiDetailed,
+ MeDetailed,
+ Page,
+ Role,
+ RolePolicies,
+ User,
+ UserDetailedNotMe,
+} from './autogen/models.js';
export * from './autogen/entities.js';
export * from './autogen/models.js';
@@ -10,6 +19,7 @@ export type DateString = string;
export type PageEvent = {
pageId: Page['id'];
event: string;
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
var: any;
userId: User['id'];
user: User;
@@ -132,8 +142,23 @@ export type ModerationLog = {
type: 'unsetUserAvatar';
info: ModerationLogPayloads['unsetUserAvatar'];
} | {
- type: 'unsetUserBanner';
- info: ModerationLogPayloads['unsetUserBanner'];
+ type: 'createSystemWebhook';
+ info: ModerationLogPayloads['createSystemWebhook'];
+} | {
+ type: 'updateSystemWebhook';
+ info: ModerationLogPayloads['updateSystemWebhook'];
+} | {
+ type: 'deleteSystemWebhook';
+ info: ModerationLogPayloads['deleteSystemWebhook'];
+} | {
+ type: 'createAbuseReportNotificationRecipient';
+ info: ModerationLogPayloads['createAbuseReportNotificationRecipient'];
+} | {
+ type: 'updateAbuseReportNotificationRecipient';
+ info: ModerationLogPayloads['updateAbuseReportNotificationRecipient'];
+} | {
+ type: 'deleteAbuseReportNotificationRecipient';
+ info: ModerationLogPayloads['deleteAbuseReportNotificationRecipient'];
});
export type ServerStats = {
@@ -221,3 +246,7 @@ export type SigninResponse = {
id: User['id'],
i: string,
};
+
+type Values<T extends Record<PropertyKey, unknown>> = T[keyof T];
+
+export type PartialRolePolicyOverride = Partial<{[k in keyof RolePolicies]: Omit<Values<Role['policies']>, 'value'> & { value: RolePolicies[k] }}>;
diff --git a/packages/misskey-js/src/streaming.ts b/packages/misskey-js/src/streaming.ts
index 0f26857782..d1d131cfc1 100644
--- a/packages/misskey-js/src/streaming.ts
+++ b/packages/misskey-js/src/streaming.ts
@@ -15,7 +15,7 @@ export function urlQuery(obj: Record<string, string | number | boolean | undefin
.join('&');
}
-type AnyOf<T extends Record<any, any>> = T[keyof T];
+type AnyOf<T extends Record<PropertyKey, unknown>> = T[keyof T];
type StreamEvents = {
_connected_: void;
@@ -25,6 +25,7 @@ type StreamEvents = {
/**
* Misskey stream connection
*/
+// eslint-disable-next-line import/no-default-export
export default class Stream extends EventEmitter<StreamEvents> {
private stream: _ReconnectingWebsocket.default;
public state: 'initializing' | 'reconnecting' | 'connected' = 'initializing';
@@ -34,7 +35,7 @@ export default class Stream extends EventEmitter<StreamEvents> {
private idCounter = 0;
constructor(origin: string, user: { token: string; } | null, options?: {
- WebSocket?: any;
+ WebSocket?: WebSocket;
}) {
super();
@@ -51,6 +52,7 @@ export default class Stream extends EventEmitter<StreamEvents> {
this.send = this.send.bind(this);
this.close = this.close.bind(this);
+ // eslint-disable-next-line no-param-reassign
options = options ?? { };
const query = urlQuery({
@@ -91,8 +93,8 @@ export default class Stream extends EventEmitter<StreamEvents> {
this.sharedConnectionPools.push(pool);
}
- const connection = new SharedConnection(this, channel, pool, name);
- this.sharedConnections.push(connection);
+ const connection = new SharedConnection<Channels[C]>(this, channel, pool, name);
+ this.sharedConnections.push(connection as unknown as SharedConnection);
return connection;
}
@@ -106,7 +108,7 @@ export default class Stream extends EventEmitter<StreamEvents> {
private connectToChannel<C extends keyof Channels>(channel: C, params: Channels[C]['params']): NonSharedConnection<Channels[C]> {
const connection = new NonSharedConnection(this, channel, this.genId(), params);
- this.nonSharedConnections.push(connection);
+ this.nonSharedConnections.push(connection as unknown as NonSharedConnection);
return connection;
}
@@ -174,9 +176,9 @@ export default class Stream extends EventEmitter<StreamEvents> {
* ! ストリーム上ã®ã‚„りå–りã¯ã™ã¹ã¦JSONã§è¡Œã‚れã¾ã™ !
*/
public send(typeOrPayload: string): void
- public send(typeOrPayload: string, payload: any): void
- public send(typeOrPayload: Record<string, any> | any[]): void
- public send(typeOrPayload: string | Record<string, any> | any[], payload?: any): void {
+ public send(typeOrPayload: string, payload: unknown): void
+ public send(typeOrPayload: Record<string, unknown> | unknown[]): void
+ public send(typeOrPayload: string | Record<string, unknown> | unknown[], payload?: unknown): void {
if (typeof typeOrPayload === 'string') {
this.stream.send(JSON.stringify({
type: typeOrPayload,
@@ -211,7 +213,7 @@ class Pool {
public id: string;
protected stream: Stream;
public users = 0;
- private disposeTimerId: any;
+ private disposeTimerId: ReturnType<typeof setTimeout> | null = null;
private isConnected = false;
constructor(stream: Stream, channel: string, id: string) {
@@ -275,7 +277,7 @@ class Pool {
}
}
-export abstract class Connection<Channel extends AnyOf<Channels> = any> extends EventEmitter<Channel['events']> {
+export abstract class Connection<Channel extends AnyOf<Channels> = AnyOf<Channels>> extends EventEmitter<Channel['events']> {
public channel: string;
protected stream: Stream;
public abstract id: string;
@@ -291,7 +293,9 @@ export abstract class Connection<Channel extends AnyOf<Channels> = any> extends
this.stream = stream;
this.channel = channel;
- this.name = name;
+ if (name !== undefined) {
+ this.name = name;
+ }
}
public send<T extends keyof Channel['receives']>(type: T, body: Channel['receives'][T]): void {
@@ -307,7 +311,7 @@ export abstract class Connection<Channel extends AnyOf<Channels> = any> extends
public abstract dispose(): void;
}
-class SharedConnection<Channel extends AnyOf<Channels> = any> extends Connection<Channel> {
+class SharedConnection<Channel extends AnyOf<Channels> = AnyOf<Channels>> extends Connection<Channel> {
private pool: Pool;
public get id(): string {
@@ -326,11 +330,11 @@ class SharedConnection<Channel extends AnyOf<Channels> = any> extends Connection
public dispose(): void {
this.pool.dec();
this.removeAllListeners();
- this.stream.removeSharedConnection(this);
+ this.stream.removeSharedConnection(this as unknown as SharedConnection);
}
}
-class NonSharedConnection<Channel extends AnyOf<Channels> = any> extends Connection<Channel> {
+class NonSharedConnection<Channel extends AnyOf<Channels> = AnyOf<Channels>> extends Connection<Channel> {
public id: string;
protected params: Channel['params'];
@@ -357,6 +361,6 @@ class NonSharedConnection<Channel extends AnyOf<Channels> = any> extends Connect
public dispose(): void {
this.removeAllListeners();
this.stream.send('disconnect', { id: this.id });
- this.stream.disconnectToChannel(this);
+ this.stream.disconnectToChannel(this as unknown as NonSharedConnection);
}
}
diff --git a/packages/misskey-js/src/streaming.types.ts b/packages/misskey-js/src/streaming.types.ts
index 9a86e03d69..4447a2e8fc 100644
--- a/packages/misskey-js/src/streaming.types.ts
+++ b/packages/misskey-js/src/streaming.types.ts
@@ -21,6 +21,14 @@ import {
ServerStatsLog,
ReversiGameDetailed,
} from './entities.js';
+import {
+ ReversiUpdateKey,
+} from './consts.js';
+
+type ReversiUpdateSettings<K extends ReversiUpdateKey> = {
+ key: K;
+ value: ReversiGameDetailed[K];
+};
export type Channels = {
main: {
@@ -51,6 +59,7 @@ export type Channels = {
registryUpdated: (payload: {
scope?: string[];
key: string;
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
value: any | null;
}) => void;
driveFileCreated: (payload: DriveFile) => void;
@@ -208,8 +217,8 @@ export type Channels = {
ended: (payload: { winnerId: User['id'] | null; game: ReversiGameDetailed; }) => void;
canceled: (payload: { userId: User['id']; }) => void;
changeReadyStates: (payload: { user1: boolean; user2: boolean; }) => void;
- updateSettings: (payload: { userId: User['id']; key: string; value: any; }) => void;
- log: (payload: Record<string, any>) => void;
+ updateSettings: <K extends ReversiUpdateKey>(payload: { userId: User['id']; key: K; value: ReversiGameDetailed[K]; }) => void;
+ log: (payload: Record<string, unknown>) => void;
};
receives: {
putStone: {
@@ -218,10 +227,7 @@ export type Channels = {
};
ready: boolean;
cancel: null | Record<string, never>;
- updateSettings: {
- key: string;
- value: any;
- };
+ updateSettings: ReversiUpdateSettings<ReversiUpdateKey>;
claimTimeIsUp: null | Record<string, never>;
}
}
diff --git a/packages/misskey-js/test/api.ts b/packages/misskey-js/test/api.ts
index fa31d23faa..1a7574de25 100644
--- a/packages/misskey-js/test/api.ts
+++ b/packages/misskey-js/test/api.ts
@@ -5,13 +5,19 @@ enableFetchMocks();
function getFetchCall(call: any[]) {
const { body, method } = call[1];
- if (body != null && typeof body != 'string') {
+ const contentType = call[1].headers['Content-Type'];
+ if (
+ body == null ||
+ (contentType === 'application/json' && typeof body !== 'string') ||
+ (contentType === 'multipart/form-data' && !(body instanceof FormData))
+ ) {
throw new Error('invalid body');
}
return {
url: call[0],
method: method,
- body: JSON.parse(body as any)
+ contentType: contentType,
+ body: body instanceof FormData ? Object.fromEntries(body.entries()) : JSON.parse(body),
};
}
@@ -45,6 +51,7 @@ describe('API', () => {
expect(getFetchCall(fetchMock.mock.calls[0])).toEqual({
url: 'https://misskey.test/api/i',
method: 'POST',
+ contentType: 'application/json',
body: { i: 'TOKEN' }
});
});
@@ -78,10 +85,52 @@ describe('API', () => {
expect(getFetchCall(fetchMock.mock.calls[0])).toEqual({
url: 'https://misskey.test/api/notes/show',
method: 'POST',
+ contentType: 'application/json',
body: { i: 'TOKEN', noteId: 'aaaaa' }
});
});
+ test('multipart/form-data', async () => {
+ fetchMock.resetMocks();
+ fetchMock.mockResponse(async (req) => {
+ if (req.method == 'POST' && req.url == 'https://misskey.test/api/drive/files/create') {
+ if (req.headers.get('Content-Type')?.includes('multipart/form-data')) {
+ return JSON.stringify({ id: 'foo' });
+ } else {
+ return { status: 400 };
+ }
+ } else {
+ return { status: 404 };
+ }
+ });
+
+ const cli = new APIClient({
+ origin: 'https://misskey.test',
+ credential: 'TOKEN',
+ });
+
+ const testFile = new File([], 'foo.txt');
+
+ const res = await cli.request('drive/files/create', {
+ file: testFile,
+ name: null, // nullã®ãƒ‘ãƒ©ãƒ¡ãƒ¼ã‚¿ã¯æ¶ˆãˆã‚‹
+ });
+
+ expect(res).toEqual({
+ id: 'foo'
+ });
+
+ expect(getFetchCall(fetchMock.mock.calls[0])).toEqual({
+ url: 'https://misskey.test/api/drive/files/create',
+ method: 'POST',
+ contentType: 'multipart/form-data',
+ body: {
+ i: 'TOKEN',
+ file: testFile,
+ }
+ });
+ });
+
test('204 No Content ã§ null ãŒè¿”ã‚‹', async () => {
fetchMock.resetMocks();
fetchMock.mockResponse(async (req) => {
@@ -104,6 +153,7 @@ describe('API', () => {
expect(getFetchCall(fetchMock.mock.calls[0])).toEqual({
url: 'https://misskey.test/api/reset-password',
method: 'POST',
+ contentType: 'application/json',
body: { i: 'TOKEN', token: 'aaa', password: 'aaa' }
});
});
@@ -209,4 +259,42 @@ describe('API', () => {
expect(isAPIError(e)).toEqual(false);
}
});
+
+ test('admin/roles/create ã®åž‹ãŒåˆã†', async() => {
+ fetchMock.resetMocks();
+ fetchMock.mockResponse(async () => {
+ return {
+ // 本æ¥è¿”ã™ã¹ã値ã¯`Role`åž‹ã ãŒã€ãƒ†ã‚¹ãƒˆãªã®ã§ãŠèŒ¶ã‚’æ¿ã™
+ status: 200,
+ body: '{}'
+ };
+ });
+
+ const cli = new APIClient({
+ origin: 'https://misskey.test',
+ credential: 'TOKEN',
+ });
+ await cli.request('admin/roles/create', {
+ name: 'aaa',
+ asBadge: false,
+ canEditMembersByModerator: false,
+ color: '#123456',
+ condFormula: {},
+ description: '',
+ displayOrder: 0,
+ iconUrl: '',
+ isAdministrator: false,
+ isExplorable: false,
+ isModerator: false,
+ isPublic: false,
+ policies: {
+ ltlAvailable: {
+ value: true,
+ priority: 0,
+ useDefault: false,
+ },
+ },
+ target: 'manual',
+ });
+ })
});
diff --git a/packages/misskey-js/tsconfig.json b/packages/misskey-js/tsconfig.json
index 6e34e332e0..f7bbc47304 100644
--- a/packages/misskey-js/tsconfig.json
+++ b/packages/misskey-js/tsconfig.json
@@ -15,6 +15,7 @@
"experimentalDecorators": true,
"noImplicitReturns": true,
"esModuleInterop": true,
+ "exactOptionalPropertyTypes": true,
"typeRoots": [
"./node_modules/@types"
],
diff --git a/packages/misskey-reversi/.eslintignore b/packages/misskey-reversi/.eslintignore
deleted file mode 100644
index 52ea8b3362..0000000000
--- a/packages/misskey-reversi/.eslintignore
+++ /dev/null
@@ -1,8 +0,0 @@
-node_modules
-/built
-/coverage
-/.eslintrc.js
-/jest.config.ts
-/test
-/test-d
-build.js
diff --git a/packages/misskey-reversi/.eslintrc.cjs b/packages/misskey-reversi/.eslintrc.cjs
deleted file mode 100644
index db37a01098..0000000000
--- a/packages/misskey-reversi/.eslintrc.cjs
+++ /dev/null
@@ -1,10 +0,0 @@
-module.exports = {
- root: true,
- parserOptions: {
- tsconfigRootDir: __dirname,
- project: ['./tsconfig.json'],
- },
- extends: [
- '../shared/.eslintrc.js',
- ],
-};
diff --git a/packages/misskey-reversi/build.js b/packages/misskey-reversi/build.js
index 0b79f4b915..e626c97a59 100644
--- a/packages/misskey-reversi/build.js
+++ b/packages/misskey-reversi/build.js
@@ -95,7 +95,6 @@ async function watchSrc() {
process.on('SIGHUP', resolve);
process.on('SIGINT', resolve);
process.on('SIGTERM', resolve);
- process.on('SIGKILL', resolve);
process.on('uncaughtException', reject);
process.on('exit', resolve);
}).finally(async () => {
diff --git a/packages/misskey-reversi/eslint.config.js b/packages/misskey-reversi/eslint.config.js
new file mode 100644
index 0000000000..3f81df7145
--- /dev/null
+++ b/packages/misskey-reversi/eslint.config.js
@@ -0,0 +1,23 @@
+import tsParser from '@typescript-eslint/parser';
+import sharedConfig from '../shared/eslint.config.js';
+
+export default [
+ ...sharedConfig,
+ {
+ ignores: [
+ '**/node_modules',
+ 'built',
+ ],
+ },
+ {
+ files: ['**/*.ts', '**/*.tsx'],
+ languageOptions: {
+ parserOptions: {
+ parser: tsParser,
+ project: ['./tsconfig.json'],
+ sourceType: 'module',
+ tsconfigRootDir: import.meta.dirname,
+ },
+ },
+ },
+];
diff --git a/packages/misskey-reversi/package.json b/packages/misskey-reversi/package.json
index 45a6120861..c6db6e6221 100644
--- a/packages/misskey-reversi/package.json
+++ b/packages/misskey-reversi/package.json
@@ -17,16 +17,14 @@
"scripts": {
"build": "node ./build.js",
"watch": "nodemon -w package.json -e json --exec \"node ./build.js --watch\"",
- "eslint": "eslint . --ext .js,.jsx,.ts,.tsx",
+ "eslint": "eslint './**/*.{js,jsx,ts,tsx}'",
"typecheck": "tsc --noEmit",
"lint": "pnpm typecheck && pnpm eslint"
},
"devDependencies": {
- "@misskey-dev/eslint-plugin": "1.0.0",
"@types/node": "20.11.5",
"@typescript-eslint/eslint-plugin": "7.1.0",
"@typescript-eslint/parser": "7.1.0",
- "eslint": "8.57.0",
"execa": "8.0.1",
"nodemon": "3.0.2",
"typescript": "5.3.3",
diff --git a/packages/shared/.eslintrc.js b/packages/shared/.eslintrc.js
deleted file mode 100644
index 58247877ae..0000000000
--- a/packages/shared/.eslintrc.js
+++ /dev/null
@@ -1,7 +0,0 @@
-module.exports = {
- root: true,
- ignorePatterns: ['**/.eslintrc.cjs'],
- extends: [
- 'plugin:@misskey-dev/recommended',
- ],
-};
diff --git a/packages/shared/eslint.config.js b/packages/shared/eslint.config.js
new file mode 100644
index 0000000000..e9d27c4a72
--- /dev/null
+++ b/packages/shared/eslint.config.js
@@ -0,0 +1,28 @@
+import globals from 'globals';
+import pluginMisskey from '@misskey-dev/eslint-plugin';
+
+export default [
+ ...pluginMisskey.configs['recommended'],
+ {
+ files: ['**/*.cjs'],
+ languageOptions: {
+ parserOptions: {
+ sourceType: 'commonjs',
+ },
+ },
+ },
+ {
+ files: ['**/*.js', '**/*.jsx'],
+ languageOptions: {
+ parserOptions: {
+ sourceType: 'module',
+ },
+ },
+ },
+ {
+ files: ['build.js'],
+ languageOptions: {
+ globals: globals.node,
+ },
+ },
+];
diff --git a/packages/shared/package.json b/packages/shared/package.json
new file mode 100644
index 0000000000..bedb411a91
--- /dev/null
+++ b/packages/shared/package.json
@@ -0,0 +1,3 @@
+{
+ "type": "module"
+}
diff --git a/packages/sw/.eslintrc.cjs b/packages/sw/.eslintrc.cjs
deleted file mode 100644
index b1fd6b5edc..0000000000
--- a/packages/sw/.eslintrc.cjs
+++ /dev/null
@@ -1,20 +0,0 @@
-module.exports = {
- root: true,
- env: {
- node: false,
- },
- parserOptions: {
- parser: '@typescript-eslint/parser',
- tsconfigRootDir: __dirname,
- project: ['./tsconfig.json'],
- },
- extends: ['../shared/.eslintrc.js'],
- globals: {
- require: false,
- _DEV_: false,
- _LANGS_: false,
- _VERSION_: false,
- _ENV_: false,
- _PERF_PREFIX_: false,
- },
-};
diff --git a/packages/sw/build.js b/packages/sw/build.js
index eb9a944f47..9522d061e0 100644
--- a/packages/sw/build.js
+++ b/packages/sw/build.js
@@ -8,7 +8,7 @@
import { fileURLToPath } from 'node:url';
import * as esbuild from 'esbuild';
import locales from '../../locales/index.js';
-import meta from '../../package.json' assert { type: "json" };
+import meta from '../../package.json' with { type: "json" };
const watch = process.argv[2]?.includes('watch');
const __dirname = fileURLToPath(new URL('.', import.meta.url))
diff --git a/packages/sw/eslint.config.js b/packages/sw/eslint.config.js
new file mode 100644
index 0000000000..c62a2eadc6
--- /dev/null
+++ b/packages/sw/eslint.config.js
@@ -0,0 +1,32 @@
+import globals from 'globals';
+import tsParser from '@typescript-eslint/parser';
+import sharedConfig from '../shared/eslint.config.js';
+
+export default [
+ ...sharedConfig,
+ {
+ ignores: ['build.js'],
+ languageOptions: {
+ globals: {
+ ...Object.fromEntries(Object.entries(globals.node).map(([key]) => [key, 'off'])),
+ require: false,
+ _DEV_: false,
+ _LANGS_: false,
+ _VERSION_: false,
+ _ENV_: false,
+ _PERF_PREFIX_: false,
+ },
+ },
+ },
+ {
+ files: ['**/*.ts', '**/*.tsx'],
+ languageOptions: {
+ parserOptions: {
+ parser: tsParser,
+ project: ['./tsconfig.json'],
+ sourceType: 'module',
+ tsconfigRootDir: import.meta.dirname,
+ },
+ },
+ },
+];
diff --git a/packages/sw/package.json b/packages/sw/package.json
index cb59a70238..9174f50ae3 100644
--- a/packages/sw/package.json
+++ b/packages/sw/package.json
@@ -9,18 +9,16 @@
"lint": "pnpm typecheck && pnpm eslint"
},
"dependencies": {
- "esbuild": "0.20.2",
+ "esbuild": "0.23.0",
"idb-keyval": "6.2.1",
"misskey-js": "workspace:*"
},
"devDependencies": {
- "@misskey-dev/eslint-plugin": "1.0.0",
- "@typescript-eslint/parser": "7.7.1",
+ "@typescript-eslint/parser": "7.17.0",
"@typescript/lib-webworker": "npm:@types/serviceworker@0.0.67",
- "eslint": "8.57.0",
"eslint-plugin-import": "2.29.1",
- "nodemon": "3.1.0",
- "typescript": "5.4.5"
+ "nodemon": "3.1.4",
+ "typescript": "5.5.4"
},
"type": "module"
}
diff --git a/packages/sw/tsconfig.json b/packages/sw/tsconfig.json
index f3f3543013..50d4aae19d 100644
--- a/packages/sw/tsconfig.json
+++ b/packages/sw/tsconfig.json
@@ -2,7 +2,6 @@
"compilerOptions": {
"allowJs": true,
"noEmitOnError": false,
- "noImplicitAny": false,
"noImplicitReturns": true,
"noUnusedParameters": false,
"noUnusedLocals": true,
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 6bf1cf158c..eb8047cde5 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -14,10 +14,10 @@ importers:
dependencies:
cssnano:
specifier: 6.1.2
- version: 6.1.2(postcss@8.4.38)
+ version: 6.1.2(postcss@8.4.40)
esbuild:
- specifier: 0.20.2
- version: 0.20.2
+ specifier: 0.23.0
+ version: 0.23.0
execa:
specifier: 8.0.1
version: 8.0.1
@@ -25,73 +25,79 @@ importers:
specifier: 3.3.2
version: 3.3.2
glob:
- specifier: 10.3.12
- version: 10.3.12
+ specifier: 11.0.0
+ version: 11.0.0
ignore-walk:
- specifier: 6.0.4
- version: 6.0.4
+ specifier: 6.0.5
+ version: 6.0.5
js-yaml:
specifier: 4.1.0
version: 4.1.0
postcss:
- specifier: 8.4.38
- version: 8.4.38
+ specifier: 8.4.40
+ version: 8.4.40
tar:
specifier: 6.2.1
version: 6.2.1
terser:
- specifier: 5.30.3
- version: 5.30.3
+ specifier: 5.31.3
+ version: 5.31.3
typescript:
- specifier: 5.4.5
- version: 5.4.5
+ specifier: 5.5.4
+ version: 5.5.4
optionalDependencies:
'@tensorflow/tfjs-core':
specifier: 4.4.0
version: 4.4.0(encoding@0.1.13)
devDependencies:
+ '@misskey-dev/eslint-plugin':
+ specifier: 2.0.2
+ version: 2.0.2(@eslint/compat@1.1.1)(@typescript-eslint/eslint-plugin@7.17.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.5.4))(eslint@9.8.0)(typescript@5.5.4))(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.5.4))(eslint@9.8.0))(eslint@9.8.0)(globals@15.8.0)
'@types/node':
- specifier: 20.12.7
- version: 20.12.7
+ specifier: 20.14.12
+ version: 20.14.12
'@typescript-eslint/eslint-plugin':
- specifier: 7.7.1
- version: 7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
+ specifier: 7.17.0
+ version: 7.17.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.5.4))(eslint@9.8.0)(typescript@5.5.4)
'@typescript-eslint/parser':
- specifier: 7.7.1
- version: 7.7.1(eslint@8.57.0)(typescript@5.4.5)
+ specifier: 7.17.0
+ version: 7.17.0(eslint@9.8.0)(typescript@5.5.4)
cross-env:
specifier: 7.0.3
version: 7.0.3
cypress:
- specifier: 13.7.3
- version: 13.7.3
+ specifier: 13.13.1
+ version: 13.13.1
eslint:
- specifier: 8.57.0
- version: 8.57.0
+ specifier: 9.8.0
+ version: 9.8.0
+ globals:
+ specifier: 15.8.0
+ version: 15.8.0
ncp:
specifier: 2.0.0
version: 2.0.0
start-server-and-test:
- specifier: 2.0.3
- version: 2.0.3
+ specifier: 2.0.4
+ version: 2.0.4
packages/backend:
dependencies:
'@aws-sdk/client-s3':
- specifier: 3.412.0
- version: 3.412.0
+ specifier: 3.620.0
+ version: 3.620.0
'@aws-sdk/lib-storage':
- specifier: 3.412.0
- version: 3.412.0(@aws-sdk/client-s3@3.412.0)
+ specifier: 3.620.0
+ version: 3.620.0(@aws-sdk/client-s3@3.620.0)
'@bull-board/api':
- specifier: 5.17.0
- version: 5.17.0(@bull-board/ui@5.17.0)
+ specifier: 5.21.1
+ version: 5.21.1(@bull-board/ui@5.21.1)
'@bull-board/fastify':
- specifier: 5.17.0
- version: 5.17.0
+ specifier: 5.21.1
+ version: 5.21.1
'@bull-board/ui':
- specifier: 5.17.0
- version: 5.17.0
+ specifier: 5.21.1
+ version: 5.21.1
'@discordapp/twemoji':
specifier: 15.0.3
version: 15.0.3
@@ -111,11 +117,11 @@ importers:
specifier: 9.5.0
version: 9.5.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
'@fastify/multipart':
- specifier: 8.2.0
- version: 8.2.0
+ specifier: 8.3.0
+ version: 8.3.0
'@fastify/static':
- specifier: 7.0.3
- version: 7.0.3
+ specifier: 7.0.4
+ version: 7.0.4
'@fastify/view':
specifier: 9.1.0
version: 9.1.0
@@ -126,29 +132,29 @@ importers:
specifier: 5.1.0
version: 5.1.0
'@napi-rs/canvas':
- specifier: ^0.1.52
- version: 0.1.52
+ specifier: ^0.1.53
+ version: 0.1.53
'@nestjs/common':
- specifier: 10.3.8
- version: 10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ specifier: 10.3.10
+ version: 10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1)
'@nestjs/core':
- specifier: 10.3.8
- version: 10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ specifier: 10.3.10
+ version: 10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.10)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1)
'@nestjs/testing':
- specifier: 10.3.8
- version: 10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8))
+ specifier: 10.3.10
+ version: 10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.10)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.10))
'@peertube/http-signature':
specifier: 1.7.0
version: 1.7.0
'@sentry/node':
- specifier: ^8.5.0
- version: 8.5.0
+ specifier: 8.20.0
+ version: 8.20.0
'@sentry/profiling-node':
- specifier: ^8.5.0
- version: 8.5.0
+ specifier: 8.20.0
+ version: 8.20.0
'@simplewebauthn/server':
- specifier: 10.0.0
- version: 10.0.0(encoding@0.1.13)
+ specifier: 10.0.1
+ version: 10.0.1(encoding@0.1.13)
'@sinonjs/fake-timers':
specifier: 11.2.2
version: 11.2.2
@@ -157,10 +163,10 @@ importers:
version: 2.5.0
'@swc/cli':
specifier: 0.3.12
- version: 0.3.12(@swc/core@1.4.17)(chokidar@3.5.3)
+ version: 0.3.12(@swc/core@1.6.6)(chokidar@3.5.3)
'@swc/core':
- specifier: 1.4.17
- version: 1.4.17
+ specifier: 1.6.6
+ version: 1.6.6
'@twemoji/parser':
specifier: 15.1.1
version: 15.1.1
@@ -168,8 +174,8 @@ importers:
specifier: 1.3.8
version: 1.3.8
ajv:
- specifier: 8.13.0
- version: 8.13.0
+ specifier: 8.17.1
+ version: 8.17.1
archiver:
specifier: 7.0.1
version: 7.0.1
@@ -186,8 +192,8 @@ importers:
specifier: 1.20.2
version: 1.20.2
bullmq:
- specifier: 5.7.8
- version: 5.7.8
+ specifier: 5.10.4
+ version: 5.10.4
cacheable-lookup:
specifier: 7.0.0
version: 7.0.0
@@ -219,8 +225,8 @@ importers:
specifier: 0.1.21
version: 0.1.21
fastify:
- specifier: 4.26.2
- version: 4.26.2
+ specifier: 4.28.1
+ version: 4.28.1
fastify-raw-body:
specifier: 4.3.0
version: 4.3.0
@@ -228,17 +234,17 @@ importers:
specifier: 4.2.2
version: 4.2.2
file-type:
- specifier: 19.0.0
- version: 19.0.0
+ specifier: 19.3.0
+ version: 19.3.0
fluent-ffmpeg:
- specifier: 2.1.2
- version: 2.1.2
+ specifier: 2.1.3
+ version: 2.1.3
form-data:
specifier: 4.0.0
version: 4.0.0
got:
- specifier: 14.2.1
- version: 14.2.1
+ specifier: 14.4.2
+ version: 14.4.2
happy-dom:
specifier: 10.0.3
version: 10.0.3
@@ -255,32 +261,32 @@ importers:
specifier: 5.4.1
version: 5.4.1
ip-cidr:
- specifier: 3.1.0
- version: 3.1.0
+ specifier: 4.0.1
+ version: 4.0.1
ipaddr.js:
specifier: 2.2.0
version: 2.2.0
is-svg:
- specifier: 5.0.0
- version: 5.0.0
+ specifier: 5.0.1
+ version: 5.0.1
js-yaml:
specifier: 4.1.0
version: 4.1.0
jsdom:
- specifier: 24.0.0
- version: 24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
+ specifier: 24.1.1
+ version: 24.1.1(bufferutil@4.0.7)(utf-8-validate@6.0.3)
json5:
specifier: 2.2.3
version: 2.2.3
jsonld:
specifier: 8.3.2
- version: 8.3.2(web-streams-polyfill@3.2.1)
+ version: 8.3.2(web-streams-polyfill@4.0.0)
jsrsasign:
specifier: 11.1.0
version: 11.1.0
meilisearch:
- specifier: 0.38.0
- version: 0.38.0(encoding@0.1.13)
+ specifier: 0.41.0
+ version: 0.41.0(encoding@0.1.13)
mfm-js:
specifier: 0.24.0
version: 0.24.0
@@ -309,8 +315,8 @@ importers:
specifier: 3.3.2
version: 3.3.2
nodemailer:
- specifier: 6.9.13
- version: 6.9.13
+ specifier: 6.9.14
+ version: 6.9.14
nsfwjs:
specifier: 2.4.2
version: 2.4.2(@tensorflow/tfjs@4.4.0(encoding@0.1.13)(seedrandom@3.0.5))
@@ -327,14 +333,14 @@ importers:
specifier: 0.0.14
version: 0.0.14
otpauth:
- specifier: 9.2.3
- version: 9.2.3
+ specifier: 9.3.1
+ version: 9.3.1
parse5:
specifier: 7.1.2
version: 7.1.2
pg:
- specifier: 8.11.5
- version: 8.11.5
+ specifier: 8.12.0
+ version: 8.12.0
pkce-challenge:
specifier: 4.1.0
version: 4.1.0
@@ -345,8 +351,8 @@ importers:
specifier: 2.7.0
version: 2.7.0
pug:
- specifier: 3.0.2
- version: 3.0.2
+ specifier: 3.0.3
+ version: 3.0.3
punycode:
specifier: 2.3.1
version: 2.3.1
@@ -360,8 +366,8 @@ importers:
specifier: 3.4.1
version: 3.4.1
re2:
- specifier: 1.20.10
- version: 1.20.10
+ specifier: 1.21.3
+ version: 1.21.3
redis-lock:
specifier: 0.1.4
version: 0.1.4
@@ -384,8 +390,8 @@ importers:
specifier: 2.7.0
version: 2.7.0
sharp:
- specifier: 0.33.3
- version: 0.33.3
+ specifier: 0.33.4
+ version: 0.33.4
slacc:
specifier: 0.0.10
version: 0.0.10
@@ -396,8 +402,8 @@ importers:
specifier: 2.1.0
version: 2.1.0
systeminformation:
- specifier: 5.22.7
- version: 5.22.7
+ specifier: 5.22.11
+ version: 5.22.11
tinycolor2:
specifier: 1.6.0
version: 1.6.0
@@ -405,17 +411,17 @@ importers:
specifier: 0.2.3
version: 0.2.3
tsc-alias:
- specifier: 1.8.8
- version: 1.8.8
+ specifier: 1.8.10
+ version: 1.8.10
tsconfig-paths:
specifier: 4.2.0
version: 4.2.0
typeorm:
specifier: 0.3.20
- version: 0.3.20(ioredis@5.4.1)(pg@8.11.5)
+ version: 0.3.20(ioredis@5.4.1)(pg@8.12.0)
typescript:
- specifier: 5.4.5
- version: 5.4.5
+ specifier: 5.5.4
+ version: 5.5.4
ulid:
specifier: 2.3.0
version: 2.3.0
@@ -426,8 +432,8 @@ importers:
specifier: 3.6.7
version: 3.6.7
ws:
- specifier: 8.17.0
- version: 8.17.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
+ specifier: 8.18.0
+ version: 8.18.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
xev:
specifier: 3.0.2
version: 3.0.2
@@ -523,18 +529,15 @@ importers:
'@jest/globals':
specifier: 29.7.0
version: 29.7.0
- '@misskey-dev/eslint-plugin':
- specifier: 1.0.0
- version: 1.0.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0)
'@nestjs/platform-express':
- specifier: 10.3.8
- version: 10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8)
+ specifier: 10.3.10
+ version: 10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.10)
'@simplewebauthn/types':
specifier: 10.0.0
version: 10.0.0
'@swc/jest':
specifier: 0.2.36
- version: 0.2.36(@swc/core@1.4.17)
+ version: 0.2.36(@swc/core@1.6.6)
'@types/accepts':
specifier: 1.3.7
version: 1.3.7
@@ -557,11 +560,11 @@ importers:
specifier: 2.1.24
version: 2.1.24
'@types/htmlescape':
- specifier: ^1.1.3
+ specifier: 1.1.3
version: 1.1.3
'@types/http-link-header':
- specifier: 1.0.5
- version: 1.0.5
+ specifier: 1.0.7
+ version: 1.0.7
'@types/jest':
specifier: 29.5.12
version: 29.5.12
@@ -569,11 +572,11 @@ importers:
specifier: 4.0.9
version: 4.0.9
'@types/jsdom':
- specifier: 21.1.6
- version: 21.1.6
+ specifier: 21.1.7
+ version: 21.1.7
'@types/jsonld':
- specifier: 1.5.13
- version: 1.5.13
+ specifier: 1.5.15
+ version: 1.5.15
'@types/jsrsasign':
specifier: 10.5.14
version: 10.5.14
@@ -584,17 +587,14 @@ importers:
specifier: 0.7.34
version: 0.7.34
'@types/node':
- specifier: 20.12.7
- version: 20.12.7
- '@types/node-fetch':
- specifier: 3.0.3
- version: 3.0.3
+ specifier: 20.14.12
+ version: 20.14.12
'@types/nodemailer':
specifier: 6.4.15
version: 6.4.15
'@types/oauth':
- specifier: 0.9.4
- version: 0.9.4
+ specifier: 0.9.5
+ version: 0.9.5
'@types/oauth2orize':
specifier: 1.11.5
version: 1.11.5
@@ -602,8 +602,8 @@ importers:
specifier: 0.1.2
version: 0.1.2
'@types/pg':
- specifier: 8.11.5
- version: 8.11.5
+ specifier: 8.11.6
+ version: 8.11.6
'@types/pug':
specifier: 2.0.10
version: 2.0.10
@@ -647,47 +647,44 @@ importers:
specifier: 3.6.3
version: 3.6.3
'@types/ws':
- specifier: 8.5.10
- version: 8.5.10
+ specifier: 8.5.11
+ version: 8.5.11
'@typescript-eslint/eslint-plugin':
- specifier: 7.7.1
- version: 7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
+ specifier: 7.17.0
+ version: 7.17.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.5.4))(eslint@9.8.0)(typescript@5.5.4)
'@typescript-eslint/parser':
- specifier: 7.7.1
- version: 7.7.1(eslint@8.57.0)(typescript@5.4.5)
+ specifier: 7.17.0
+ version: 7.17.0(eslint@9.8.0)(typescript@5.5.4)
aws-sdk-client-mock:
- specifier: 3.0.1
- version: 3.0.1
+ specifier: 4.0.1
+ version: 4.0.1
cross-env:
specifier: 7.0.3
version: 7.0.3
- eslint:
- specifier: 8.57.0
- version: 8.57.0
eslint-plugin-import:
specifier: 2.29.1
- version: 2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)
+ version: 2.29.1(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.5.4))(eslint@9.8.0)
execa:
- specifier: 8.0.1
- version: 8.0.1
+ specifier: 9.3.0
+ version: 9.3.0
fkill:
- specifier: ^9.0.0
+ specifier: 9.0.0
version: 9.0.0
jest:
specifier: 29.7.0
- version: 29.7.0(@types/node@20.12.7)
+ version: 29.7.0(@types/node@20.14.12)
jest-mock:
specifier: 29.7.0
version: 29.7.0
nodemon:
- specifier: 3.1.0
- version: 3.1.0
+ specifier: 3.1.4
+ version: 3.1.4
pid-port:
specifier: 1.0.0
version: 1.0.0
simple-oauth2:
- specifier: 5.0.0
- version: 5.0.0
+ specifier: 5.1.0
+ version: 5.1.0
packages/frontend:
dependencies:
@@ -705,16 +702,16 @@ importers:
version: 2024.1.0
'@rollup/plugin-json':
specifier: 6.1.0
- version: 6.1.0(rollup@4.17.2)
+ version: 6.1.0(rollup@4.19.1)
'@rollup/plugin-replace':
- specifier: 5.0.5
- version: 5.0.5(rollup@4.17.2)
+ specifier: 5.0.7
+ version: 5.0.7(rollup@4.19.1)
'@rollup/pluginutils':
specifier: 5.1.0
- version: 5.1.0(rollup@4.17.2)
+ version: 5.1.0(rollup@4.19.1)
'@syuilo/aiscript':
- specifier: 0.18.0
- version: 0.18.0
+ specifier: 0.19.0
+ version: 0.19.0
'@tabler/icons-webfont':
specifier: 3.3.0
version: 3.3.0
@@ -722,14 +719,14 @@ importers:
specifier: 15.1.1
version: 15.1.1
'@vitejs/plugin-vue':
- specifier: 5.0.4
- version: 5.0.4(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))(vue@3.4.26(typescript@5.4.5))
+ specifier: 5.1.0
+ version: 5.1.0(vite@5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3))(vue@3.4.34(typescript@5.5.4))
'@vue/compiler-sfc':
- specifier: 3.4.26
- version: 3.4.26
+ specifier: 3.4.34
+ version: 3.4.34
aiscript-vscode:
- specifier: github:aiscript-dev/aiscript-vscode#v0.1.9
- version: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/34bf4e1530efcf1efa855bd04e2dab39735e1b02
+ specifier: github:aiscript-dev/aiscript-vscode#v0.1.11
+ version: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/e1e1b27f2f72cd28a473e004b6da0d8fc0bd40d9
astring:
specifier: 1.8.6
version: 1.8.6
@@ -743,29 +740,29 @@ importers:
specifier: 1.9.3
version: 1.9.3
chart.js:
- specifier: 4.4.2
- version: 4.4.2
+ specifier: 4.4.3
+ version: 4.4.3
chartjs-adapter-date-fns:
specifier: 3.0.0
- version: 3.0.0(chart.js@4.4.2)(date-fns@2.30.0)
+ version: 3.0.0(chart.js@4.4.3)(date-fns@2.30.0)
chartjs-chart-matrix:
specifier: 2.0.1
- version: 2.0.1(chart.js@4.4.2)
+ version: 2.0.1(chart.js@4.4.3)
chartjs-plugin-gradient:
specifier: 0.6.1
- version: 0.6.1(chart.js@4.4.2)
+ version: 0.6.1(chart.js@4.4.3)
chartjs-plugin-zoom:
specifier: 2.0.1
- version: 2.0.1(chart.js@4.4.2)
+ version: 2.0.1(chart.js@4.4.3)
chromatic:
- specifier: 11.3.0
- version: 11.3.0
+ specifier: 11.5.6
+ version: 11.5.6
compare-versions:
- specifier: 6.1.0
- version: 6.1.0
+ specifier: 6.1.1
+ version: 6.1.1
cropperjs:
- specifier: 2.0.0-beta.5
- version: 2.0.0-beta.5
+ specifier: 2.0.0-rc.1
+ version: 2.0.0-rc.1
date-fns:
specifier: 2.30.0
version: 2.30.0
@@ -806,23 +803,23 @@ importers:
specifier: workspace:*
version: link:../misskey-reversi
photoswipe:
- specifier: 5.4.3
- version: 5.4.3
+ specifier: 5.4.4
+ version: 5.4.4
punycode:
specifier: 2.3.1
version: 2.3.1
rollup:
- specifier: 4.17.2
- version: 4.17.2
+ specifier: 4.19.1
+ version: 4.19.1
sanitize-html:
specifier: 2.13.0
version: 2.13.0
sass:
- specifier: 1.76.0
- version: 1.76.0
+ specifier: 1.77.8
+ version: 1.77.8
shiki:
- specifier: 1.4.0
- version: 1.4.0
+ specifier: 1.12.0
+ version: 1.12.0
strict-event-emitter-types:
specifier: 2.0.0
version: 2.0.0
@@ -830,102 +827,99 @@ importers:
specifier: 3.1.0
version: 3.1.0
three:
- specifier: 0.164.1
- version: 0.164.1
+ specifier: 0.167.0
+ version: 0.167.0
throttle-debounce:
- specifier: 5.0.0
- version: 5.0.0
+ specifier: 5.0.2
+ version: 5.0.2
tinycolor2:
specifier: 1.6.0
version: 1.6.0
tsc-alias:
- specifier: 1.8.8
- version: 1.8.8
+ specifier: 1.8.10
+ version: 1.8.10
tsconfig-paths:
specifier: 4.2.0
version: 4.2.0
typescript:
- specifier: 5.4.5
- version: 5.4.5
+ specifier: 5.5.4
+ version: 5.5.4
uuid:
- specifier: 9.0.1
- version: 9.0.1
+ specifier: 10.0.0
+ version: 10.0.0
v-code-diff:
- specifier: 1.11.0
- version: 1.11.0(vue@3.4.26(typescript@5.4.5))
+ specifier: 1.12.0
+ version: 1.12.0(vue@3.4.34(typescript@5.5.4))
vite:
- specifier: 5.2.11
- version: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3)
+ specifier: 5.3.5
+ version: 5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3)
vue:
- specifier: 3.4.26
- version: 3.4.26(typescript@5.4.5)
+ specifier: 3.4.34
+ version: 3.4.34(typescript@5.5.4)
vuedraggable:
specifier: next
- version: 4.1.0(vue@3.4.26(typescript@5.4.5))
+ version: 4.1.0(vue@3.4.34(typescript@5.5.4))
devDependencies:
- '@misskey-dev/eslint-plugin':
- specifier: 1.0.0
- version: 1.0.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0)
'@misskey-dev/summaly':
specifier: 5.1.0
version: 5.1.0
'@storybook/addon-actions':
- specifier: 8.0.9
- version: 8.0.9
+ specifier: 8.2.6
+ version: 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
'@storybook/addon-essentials':
- specifier: 8.0.9
- version: 8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ specifier: 8.2.6
+ version: 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
'@storybook/addon-interactions':
- specifier: 8.0.9
- version: 8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))
+ specifier: 8.2.6
+ version: 8.2.6(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.14.12))(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.8)(terser@5.31.3))
'@storybook/addon-links':
- specifier: 8.0.9
- version: 8.0.9(react@18.3.1)
+ specifier: 8.2.6
+ version: 8.2.6(react@18.3.1)(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
'@storybook/addon-mdx-gfm':
- specifier: 8.0.9
- version: 8.0.9
+ specifier: 8.2.6
+ version: 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
'@storybook/addon-storysource':
- specifier: 8.0.9
- version: 8.0.9
+ specifier: 8.2.6
+ version: 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
'@storybook/blocks':
- specifier: 8.0.9
- version: 8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ specifier: 8.2.6
+ version: 8.2.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
'@storybook/components':
- specifier: 8.0.9
- version: 8.0.9(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ specifier: 8.2.6
+ version: 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
'@storybook/core-events':
- specifier: 8.0.9
- version: 8.0.9
+ specifier: 8.2.6
+ version: 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
'@storybook/manager-api':
- specifier: 8.0.9
- version: 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ specifier: 8.2.6
+ version: 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
'@storybook/preview-api':
- specifier: 8.0.9
- version: 8.0.9
+ specifier: 8.2.6
+ version: 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
'@storybook/react':
- specifier: 8.0.9
- version: 8.0.9(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
+ specifier: 8.2.6
+ version: 8.2.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))(typescript@5.5.4)
'@storybook/react-vite':
- specifier: 8.0.9
- version: 8.0.9(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.17.2)(typescript@5.4.5)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))
+ specifier: 8.2.6
+ version: 8.2.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.19.1)(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))(typescript@5.5.4)(vite@5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3))
'@storybook/test':
- specifier: 8.0.9
- version: 8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))
+ specifier: 8.2.6
+ version: 8.2.6(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.14.12))(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.8)(terser@5.31.3))
'@storybook/theming':
- specifier: 8.0.9
- version: 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ specifier: 8.2.6
+ version: 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
'@storybook/types':
- specifier: 8.0.9
- version: 8.0.9
+ specifier: 8.2.6
+ version: 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
'@storybook/vue3':
- specifier: 8.0.9
- version: 8.0.9(encoding@0.1.13)(vue@3.4.26(typescript@5.4.5))
+ specifier: 8.2.6
+ version: 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))(vue@3.4.34(typescript@5.5.4))
'@storybook/vue3-vite':
- specifier: 8.0.9
- version: 8.0.9(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))(vue@3.4.26(typescript@5.4.5))
+ specifier: 8.1.11
+ version: 8.1.11(bufferutil@4.0.8)(encoding@0.1.13)(prettier@3.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.4)(vite@5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3))(vue@3.4.34(typescript@5.5.4))
'@testing-library/vue':
- specifier: 8.0.3
- version: 8.0.3(@vue/compiler-sfc@3.4.26)(@vue/server-renderer@3.4.26(vue@3.4.26(typescript@5.4.5)))(vue@3.4.26(typescript@5.4.5))
+ specifier: 8.1.0
+ version: 8.1.0(@vue/compiler-sfc@3.4.34)(@vue/server-renderer@3.4.34(vue@3.4.34(typescript@5.5.4)))(vue@3.4.34(typescript@5.5.4))
'@types/escape-regexp':
specifier: 0.0.3
version: 0.0.3
@@ -933,20 +927,23 @@ importers:
specifier: 1.0.5
version: 1.0.5
'@types/matter-js':
- specifier: 0.19.6
- version: 0.19.6
+ specifier: 0.19.7
+ version: 0.19.7
'@types/micromatch':
- specifier: 4.0.7
- version: 4.0.7
+ specifier: 4.0.9
+ version: 4.0.9
'@types/node':
- specifier: 20.12.7
- version: 20.12.7
+ specifier: 20.14.12
+ version: 20.14.12
'@types/punycode':
specifier: 2.1.4
version: 2.1.4
'@types/sanitize-html':
specifier: 2.11.0
version: 2.11.0
+ '@types/seedrandom':
+ specifier: 3.0.8
+ version: 3.0.8
'@types/throttle-debounce':
specifier: 5.0.2
version: 5.0.2
@@ -954,41 +951,38 @@ importers:
specifier: 1.4.6
version: 1.4.6
'@types/uuid':
- specifier: 9.0.8
- version: 9.0.8
+ specifier: 10.0.0
+ version: 10.0.0
'@types/ws':
- specifier: 8.5.10
- version: 8.5.10
+ specifier: 8.5.11
+ version: 8.5.11
'@typescript-eslint/eslint-plugin':
- specifier: 7.7.1
- version: 7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
+ specifier: 7.17.0
+ version: 7.17.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.5.4))(eslint@9.8.0)(typescript@5.5.4)
'@typescript-eslint/parser':
- specifier: 7.7.1
- version: 7.7.1(eslint@8.57.0)(typescript@5.4.5)
+ specifier: 7.17.0
+ version: 7.17.0(eslint@9.8.0)(typescript@5.5.4)
'@vitest/coverage-v8':
- specifier: 0.34.6
- version: 0.34.6(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))
+ specifier: 1.6.0
+ version: 1.6.0(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.8)(terser@5.31.3))
'@vue/runtime-core':
- specifier: 3.4.26
- version: 3.4.26
+ specifier: 3.4.34
+ version: 3.4.34
acorn:
- specifier: 8.11.3
- version: 8.11.3
+ specifier: 8.12.1
+ version: 8.12.1
cross-env:
specifier: 7.0.3
version: 7.0.3
cypress:
- specifier: 13.8.1
- version: 13.8.1
- eslint:
- specifier: 8.57.0
- version: 8.57.0
+ specifier: 13.13.1
+ version: 13.13.1
eslint-plugin-import:
specifier: 2.29.1
- version: 2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)
+ version: 2.29.1(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.5.4))(eslint@9.8.0)
eslint-plugin-vue:
- specifier: 9.25.0
- version: 9.25.0(eslint@8.57.0)
+ specifier: 9.27.0
+ version: 9.27.0(eslint@9.8.0)
fast-glob:
specifier: 3.3.2
version: 3.3.2
@@ -999,53 +993,56 @@ importers:
specifier: 0.12.2
version: 0.12.2
micromatch:
- specifier: 4.0.5
- version: 4.0.5
+ specifier: 4.0.7
+ version: 4.0.7
msw:
- specifier: 2.2.14
- version: 2.2.14(typescript@5.4.5)
+ specifier: 2.3.4
+ version: 2.3.4(typescript@5.5.4)
msw-storybook-addon:
- specifier: 2.0.1
- version: 2.0.1(msw@2.2.14(typescript@5.4.5))
+ specifier: 2.0.3
+ version: 2.0.3(msw@2.3.4(typescript@5.5.4))
nodemon:
- specifier: 3.1.0
- version: 3.1.0
+ specifier: 3.1.4
+ version: 3.1.4
prettier:
- specifier: 3.2.5
- version: 3.2.5
+ specifier: 3.3.3
+ version: 3.3.3
react:
specifier: 18.3.1
version: 18.3.1
react-dom:
specifier: 18.3.1
version: 18.3.1(react@18.3.1)
+ seedrandom:
+ specifier: 3.0.5
+ version: 3.0.5
start-server-and-test:
- specifier: 2.0.3
- version: 2.0.3
+ specifier: 2.0.4
+ version: 2.0.4
storybook:
- specifier: 8.0.9
- version: 8.0.9(@babel/preset-env@7.23.5(@babel/core@7.24.0))(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3)
+ specifier: 8.2.6
+ version: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
storybook-addon-misskey-theme:
specifier: github:misskey-dev/storybook-addon-misskey-theme
- version: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/components@8.0.9(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/core-events@8.0.9)(@storybook/manager-api@8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/preview-api@8.0.9)(@storybook/theming@8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/types@8.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ version: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(3rvqj7p7l43ansgshs3zbslm7u)
vite-plugin-turbosnap:
specifier: 1.0.3
version: 1.0.3
vitest:
- specifier: 0.34.6
- version: 0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)
+ specifier: 1.6.0
+ version: 1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.8)(terser@5.31.3)
vitest-fetch-mock:
specifier: 0.2.2
- version: 0.2.2(encoding@0.1.13)(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))
+ version: 0.2.2(encoding@0.1.13)(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.8)(terser@5.31.3))
vue-component-type-helpers:
- specifier: 2.0.16
- version: 2.0.16
+ specifier: 2.0.29
+ version: 2.0.29
vue-eslint-parser:
- specifier: 9.4.2
- version: 9.4.2(eslint@8.57.0)
+ specifier: 9.4.3
+ version: 9.4.3(eslint@9.8.0)
vue-tsc:
- specifier: 2.0.16
- version: 2.0.16(typescript@5.4.5)
+ specifier: 2.0.29
+ version: 2.0.29(typescript@5.5.4)
packages/misskey-bubble-game:
dependencies:
@@ -1059,9 +1056,6 @@ importers:
specifier: 3.0.5
version: 3.0.5
devDependencies:
- '@misskey-dev/eslint-plugin':
- specifier: 1.0.0
- version: 1.0.0(@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3))(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0))(eslint@8.57.0)
'@types/matter-js':
specifier: 0.19.6
version: 0.19.6
@@ -1073,16 +1067,13 @@ importers:
version: 3.0.8
'@typescript-eslint/eslint-plugin':
specifier: 7.1.0
- version: 7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3)
+ version: 7.1.0(@typescript-eslint/parser@7.1.0(eslint@9.8.0)(typescript@5.3.3))(eslint@9.8.0)(typescript@5.3.3)
'@typescript-eslint/parser':
specifier: 7.1.0
- version: 7.1.0(eslint@8.57.0)(typescript@5.3.3)
+ version: 7.1.0(eslint@9.8.0)(typescript@5.3.3)
esbuild:
specifier: 0.19.11
version: 0.19.11
- eslint:
- specifier: 8.57.0
- version: 8.57.0
execa:
specifier: 8.0.1
version: 8.0.1
@@ -1106,41 +1097,35 @@ importers:
version: 4.4.0
devDependencies:
'@microsoft/api-extractor':
- specifier: 7.43.1
- version: 7.43.1(@types/node@20.12.7)
- '@misskey-dev/eslint-plugin':
- specifier: 1.0.0
- version: 1.0.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0)
+ specifier: 7.47.4
+ version: 7.47.4(@types/node@20.14.12)
'@swc/jest':
specifier: 0.2.36
- version: 0.2.36(@swc/core@1.4.17)
+ version: 0.2.36(@swc/core@1.6.13)
'@types/jest':
specifier: 29.5.12
version: 29.5.12
'@types/node':
- specifier: 20.12.7
- version: 20.12.7
+ specifier: 20.14.12
+ version: 20.14.12
'@typescript-eslint/eslint-plugin':
- specifier: 7.7.1
- version: 7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
+ specifier: 7.17.0
+ version: 7.17.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.5.4))(eslint@9.8.0)(typescript@5.5.4)
'@typescript-eslint/parser':
- specifier: 7.7.1
- version: 7.7.1(eslint@8.57.0)(typescript@5.4.5)
+ specifier: 7.17.0
+ version: 7.17.0(eslint@9.8.0)(typescript@5.5.4)
esbuild:
- specifier: 0.19.11
- version: 0.19.11
- eslint:
- specifier: 8.57.0
- version: 8.57.0
+ specifier: 0.23.0
+ version: 0.23.0
execa:
- specifier: 8.0.1
- version: 8.0.1
+ specifier: 9.3.0
+ version: 9.3.0
glob:
- specifier: 10.3.12
- version: 10.3.12
+ specifier: 11.0.0
+ version: 11.0.0
jest:
specifier: 29.7.0
- version: 29.7.0(@types/node@20.12.7)
+ version: 29.7.0(@types/node@20.14.12)
jest-fetch-mock:
specifier: 3.0.3
version: 3.0.3(encoding@0.1.13)
@@ -1154,20 +1139,17 @@ importers:
specifier: 2.0.0
version: 2.0.0
nodemon:
- specifier: 3.1.0
- version: 3.1.0
+ specifier: 3.1.4
+ version: 3.1.4
tsd:
- specifier: 0.30.7
- version: 0.30.7
+ specifier: 0.31.1
+ version: 0.31.1
typescript:
- specifier: 5.4.5
- version: 5.4.5
+ specifier: 5.5.4
+ version: 5.5.4
packages/misskey-js/generator:
devDependencies:
- '@misskey-dev/eslint-plugin':
- specifier: ^1.0.0
- version: 1.0.0(@typescript-eslint/eslint-plugin@6.11.0(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0)(typescript@5.3.3))(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0))(eslint@8.53.0)
'@readme/openapi-parser':
specifier: 2.5.0
version: 2.5.0(openapi-types@12.1.3)
@@ -1176,13 +1158,10 @@ importers:
version: 20.9.1
'@typescript-eslint/eslint-plugin':
specifier: 6.11.0
- version: 6.11.0(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0)(typescript@5.3.3)
+ version: 6.11.0(@typescript-eslint/parser@6.11.0(eslint@9.8.0)(typescript@5.3.3))(eslint@9.8.0)(typescript@5.3.3)
'@typescript-eslint/parser':
specifier: 6.11.0
- version: 6.11.0(eslint@8.53.0)(typescript@5.3.3)
- eslint:
- specifier: 8.53.0
- version: 8.53.0
+ version: 6.11.0(eslint@9.8.0)(typescript@5.3.3)
openapi-types:
specifier: 12.1.3
version: 12.1.3
@@ -1205,24 +1184,18 @@ importers:
specifier: 1.2.2
version: 1.2.2
devDependencies:
- '@misskey-dev/eslint-plugin':
- specifier: 1.0.0
- version: 1.0.0(@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3))(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0))(eslint@8.57.0)
'@types/node':
specifier: 20.11.5
version: 20.11.5
'@typescript-eslint/eslint-plugin':
specifier: 7.1.0
- version: 7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3)
+ version: 7.1.0(@typescript-eslint/parser@7.1.0(eslint@9.8.0)(typescript@5.3.3))(eslint@9.8.0)(typescript@5.3.3)
'@typescript-eslint/parser':
specifier: 7.1.0
- version: 7.1.0(eslint@8.57.0)(typescript@5.3.3)
+ version: 7.1.0(eslint@9.8.0)(typescript@5.3.3)
esbuild:
specifier: 0.19.11
version: 0.19.11
- eslint:
- specifier: 8.57.0
- version: 8.57.0
execa:
specifier: 8.0.1
version: 8.0.1
@@ -1239,8 +1212,8 @@ importers:
packages/sw:
dependencies:
esbuild:
- specifier: 0.20.2
- version: 0.20.2
+ specifier: 0.23.0
+ version: 0.23.0
idb-keyval:
specifier: 6.2.1
version: 6.2.1
@@ -1248,34 +1221,24 @@ importers:
specifier: workspace:*
version: link:../misskey-js
devDependencies:
- '@misskey-dev/eslint-plugin':
- specifier: 1.0.0
- version: 1.0.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0)
'@typescript-eslint/parser':
- specifier: 7.7.1
- version: 7.7.1(eslint@8.57.0)(typescript@5.4.5)
+ specifier: 7.17.0
+ version: 7.17.0(eslint@9.8.0)(typescript@5.5.4)
'@typescript/lib-webworker':
specifier: npm:@types/serviceworker@0.0.67
version: '@types/serviceworker@0.0.67'
- eslint:
- specifier: 8.57.0
- version: 8.57.0
eslint-plugin-import:
specifier: 2.29.1
- version: 2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)
+ version: 2.29.1(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.5.4))(eslint@9.8.0)
nodemon:
- specifier: 3.1.0
- version: 3.1.0
+ specifier: 3.1.4
+ version: 3.1.4
typescript:
- specifier: 5.4.5
- version: 5.4.5
+ specifier: 5.5.4
+ version: 5.5.4
packages:
- '@aashutoshrathi/word-wrap@1.2.6':
- resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==}
- engines: {node: '>=0.10.0'}
-
'@adobe/css-tools@4.3.3':
resolution: {integrity: sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ==}
@@ -1299,221 +1262,241 @@ packages:
resolution: {integrity: sha512-Xk1sIhyNC/esHGGVjL/niHLowM0csl/kFO5uawBy4IrWwy0o1G8LGt3jP6nmWGz+USxeeqbihAmp/oVZju6wug==}
hasBin: true
- '@aws-crypto/crc32@3.0.0':
- resolution: {integrity: sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==}
+ '@aws-crypto/crc32@5.2.0':
+ resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==}
+ engines: {node: '>=16.0.0'}
- '@aws-crypto/crc32c@3.0.0':
- resolution: {integrity: sha512-ENNPPManmnVJ4BTXlOjAgD7URidbAznURqD0KvfREyc4o20DPYdEldU1f5cQ7Jbj0CJJSPaMIk/9ZshdB3210w==}
+ '@aws-crypto/crc32c@5.2.0':
+ resolution: {integrity: sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==}
- '@aws-crypto/ie11-detection@3.0.0':
- resolution: {integrity: sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==}
+ '@aws-crypto/sha1-browser@5.2.0':
+ resolution: {integrity: sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==}
- '@aws-crypto/sha1-browser@3.0.0':
- resolution: {integrity: sha512-NJth5c997GLHs6nOYTzFKTbYdMNA6/1XlKVgnZoaZcQ7z7UJlOgj2JdbHE8tiYLS3fzXNCguct77SPGat2raSw==}
+ '@aws-crypto/sha256-browser@5.2.0':
+ resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==}
- '@aws-crypto/sha256-browser@3.0.0':
- resolution: {integrity: sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==}
+ '@aws-crypto/sha256-js@5.2.0':
+ resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==}
+ engines: {node: '>=16.0.0'}
- '@aws-crypto/sha256-js@3.0.0':
- resolution: {integrity: sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==}
+ '@aws-crypto/supports-web-crypto@5.2.0':
+ resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==}
- '@aws-crypto/supports-web-crypto@3.0.0':
- resolution: {integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==}
+ '@aws-crypto/util@5.2.0':
+ resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==}
- '@aws-crypto/util@3.0.0':
- resolution: {integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==}
+ '@aws-sdk/client-s3@3.620.0':
+ resolution: {integrity: sha512-kf3Lqvuq/ciUn4myQjd1a9nhVg95+FEWkIq7pdkgxFoKow8HKj3nuiwI7zYBRTfk0RKXRkJca3GE+3RXpeZSiA==}
+ engines: {node: '>=16.0.0'}
- '@aws-sdk/client-s3@3.412.0':
- resolution: {integrity: sha512-sNrlx9sSBmFUCqMgTznwk9Fee3PJat0nZ3RIDR5Crhsld/eexxrqb6TYKsxzFfBfXTL/oPh+/S5driRV2xsB8A==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/client-sso-oidc@3.620.0':
+ resolution: {integrity: sha512-CWL8aJa6rrNaQXNsLhblGZzbFBrRz4BXAsFBbyqAZEmryr9q/IC7z/ww3nq8CD2UsW+bn89U/XcoP5r1KWUHuQ==}
+ engines: {node: '>=16.0.0'}
+ peerDependencies:
+ '@aws-sdk/client-sts': ^3.620.0
- '@aws-sdk/client-sso@3.410.0':
- resolution: {integrity: sha512-MC9GrgwtlOuSL2WS3DRM3dQ/5y+49KSMMJRH6JiEcU5vE0dX/OtEcX+VfEwpi73x5pSfIjm7xnzjzOFx+sQBIg==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/client-sso@3.620.0':
+ resolution: {integrity: sha512-J1CvF7u39XwtCK9rPlkW2AA631EPqkb4PjOOj9aZ9LjQmkJ0DkL+9tEqU2XIWcjDd2Z3hS3LBuS8uN7upIkEnQ==}
+ engines: {node: '>=16.0.0'}
- '@aws-sdk/client-sts@3.410.0':
- resolution: {integrity: sha512-e6VMrBJtnTxxUXwDmkADGIvyppmDMFf4+cGGA68tVCUm1cFNlCI6M/67bVSIPN/WVKAAfhEL5O2vVXCM7aatYg==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/client-sts@3.620.0':
+ resolution: {integrity: sha512-pG4SqDHZV/ZbpoVoVtpxo6ZZoqVDbVItC3QUO73UJ3Gemxznd/Ck7kAsyb6/dJkV/Aqm3gt2O5UL7vzQLNHSjw==}
+ engines: {node: '>=16.0.0'}
- '@aws-sdk/credential-provider-env@3.410.0':
- resolution: {integrity: sha512-c7TB9LbN0PkFOsXI0lcRJnqPNOmc4VBvrHf8jP/BkTDg4YUoKQKOFd4d0SqzODmlZiAyoMQVZTR4ISZo95Zj4Q==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/core@3.620.0':
+ resolution: {integrity: sha512-5D9tMahxIDDFLULS9/ULa0HuIu7CZSshfj6wmDSmigXzkWyUvHoVIrme2z6eM3Icat/MO3d4WEy3445Vk385gQ==}
+ engines: {node: '>=16.0.0'}
- '@aws-sdk/credential-provider-ini@3.410.0':
- resolution: {integrity: sha512-D8rcr5bRCFD0f42MPQ7K6TWZq5d3pfqrKINL1/bpfkK5BJbvq1BGYmR88UC6CLpTRtZ1LHY2HgYG0fp/2zjjww==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/credential-provider-env@3.609.0':
+ resolution: {integrity: sha512-v69ZCWcec2iuV9vLVJMa6fAb5xwkzN4jYIT8yjo2c4Ia/j976Q+TPf35Pnz5My48Xr94EFcaBazrWedF+kwfuQ==}
+ engines: {node: '>=16.0.0'}
- '@aws-sdk/credential-provider-node@3.410.0':
- resolution: {integrity: sha512-0wmVm33T/j1FS7MZ/j+WsPlgSc0YnCXnpbWSov1Mn6R86SHI2b2JhdIPRRE4XbGfyW2QGNUl2CwoZVaqhXeF5g==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/credential-provider-http@3.620.0':
+ resolution: {integrity: sha512-BI2BdrSKDmB/2ouB/NJR0PT0x/+5fmoF6XOE78hFBb4F5w/yynGgcJY936dF+oREfpME6ehjB2b0okGg78Scpw==}
+ engines: {node: '>=16.0.0'}
- '@aws-sdk/credential-provider-process@3.410.0':
- resolution: {integrity: sha512-BMju1hlDCDNkkSZpKF5SQ8G0WCLRj6/Jvw9QmudLHJuVwYJXEW1r2AsVMg98OZ3hB9G+MAvHruHZIbMiNmUMXQ==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/credential-provider-ini@3.620.0':
+ resolution: {integrity: sha512-P9fYi6dzZIl8ITC7qAPf5DX9omI3LfA91g3KH+0OUmS3ctP7tN+gNo3HmqlzoqnwPe0pXn1FumYAe1qFl6Yjjg==}
+ engines: {node: '>=16.0.0'}
+ peerDependencies:
+ '@aws-sdk/client-sts': ^3.620.0
- '@aws-sdk/credential-provider-sso@3.410.0':
- resolution: {integrity: sha512-zEaoY/sY+KYTlQUkp9dvveAHf175b8RIt0DsQkDrRPtrg/RBHR00r5rFvz9+nrwsR8546RaBU7h/zzTaQGhmcA==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/credential-provider-node@3.620.0':
+ resolution: {integrity: sha512-or8ahy4ysURcWgKX00367DMDTTyMynDEl+FQh4wce66fMyePhFVuoPcRgXzWsi8KYmL95sPCfJFNqBMyFNcgvQ==}
+ engines: {node: '>=16.0.0'}
- '@aws-sdk/credential-provider-web-identity@3.410.0':
- resolution: {integrity: sha512-cE0l8LmEHdWbDkdPNgrfdYSgp4/cIVXrjUKI1QCATA729CrHZ/OQjB/maOBOrMHO9YTiggko887NkslVvwVB7w==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/credential-provider-process@3.614.0':
+ resolution: {integrity: sha512-Q0SI0sTRwi8iNODLs5+bbv8vgz8Qy2QdxbCHnPk/6Cx6LMf7i3dqmWquFbspqFRd8QiqxStrblwxrUYZi09tkA==}
+ engines: {node: '>=16.0.0'}
- '@aws-sdk/lib-storage@3.412.0':
- resolution: {integrity: sha512-uAdVtNuip06rJOs28zVrYXLNeHfKraxvJRTzTA+DW1dXkzh70GTKqDKHWH9IJkW/xMTE6wGSM+fDs8jsMOn/yA==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/credential-provider-sso@3.620.0':
+ resolution: {integrity: sha512-xtIj2hmq3jcKwvGmqhoYapbWeQfFyoQgKBtwD6nx0M6oS5lbFH4rzHhj0gBwatZDjMa35cWtcYVUJCv2/9mWvA==}
+ engines: {node: '>=16.0.0'}
+
+ '@aws-sdk/credential-provider-web-identity@3.609.0':
+ resolution: {integrity: sha512-U+PG8NhlYYF45zbr1km3ROtBMYqyyj/oK8NRp++UHHeuavgrP+4wJ4wQnlEaKvJBjevfo3+dlIBcaeQ7NYejWg==}
+ engines: {node: '>=16.0.0'}
peerDependencies:
- '@aws-sdk/client-s3': ^3.0.0
+ '@aws-sdk/client-sts': ^3.609.0
- '@aws-sdk/middleware-bucket-endpoint@3.410.0':
- resolution: {integrity: sha512-pUGrpFgCKf9fDHu01JJhhw+MUImheS0HFlZwNG37OMubkxUAbCdmYGewGxfTCUvWyZJtx9bVjrSu6gG7w+RARg==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/lib-storage@3.620.0':
+ resolution: {integrity: sha512-xUeKH8RrPQqE6J49Yun0qCdu5SGaN5LgyyjWutLeElqR0G3jhmPVrRzFXsHDXbr9S0QVE4V8DjeC17bkEdG4dw==}
+ engines: {node: '>=16.0.0'}
+ peerDependencies:
+ '@aws-sdk/client-s3': ^3.620.0
- '@aws-sdk/middleware-expect-continue@3.410.0':
- resolution: {integrity: sha512-e5YqGCNmW99GZjEPPujJ02RlEZql19U40oORysBhVF7mKz8BBvF3s8l37tvu37oxebDEkh1u/2cm2+ggOXxLjQ==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/middleware-bucket-endpoint@3.620.0':
+ resolution: {integrity: sha512-eGLL0W6L3HDb3OACyetZYOWpHJ+gLo0TehQKeQyy2G8vTYXqNTeqYhuI6up9HVjBzU9eQiULVQETmgQs7TFaRg==}
+ engines: {node: '>=16.0.0'}
- '@aws-sdk/middleware-flexible-checksums@3.410.0':
- resolution: {integrity: sha512-IK7KlvEKtrQVBfmAp/MmGd0wbWLuN2GZwwfAmsU0qFb0f5vOVUbKDsu6tudtDKCBG9uXyTEsx3/QGvoK2zDy+g==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/middleware-expect-continue@3.620.0':
+ resolution: {integrity: sha512-QXeRFMLfyQ31nAHLbiTLtk0oHzG9QLMaof5jIfqcUwnOkO8YnQdeqzakrg1Alpy/VQ7aqzIi8qypkBe2KXZz0A==}
+ engines: {node: '>=16.0.0'}
- '@aws-sdk/middleware-host-header@3.410.0':
- resolution: {integrity: sha512-ED/OVcyITln5rrxnajZP+V0PN1nug+gSDHJDqdDo/oLy7eiDr/ZWn3nlWW7WcMplQ1/Jnb+hK0UetBp/25XooA==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/middleware-flexible-checksums@3.620.0':
+ resolution: {integrity: sha512-ftz+NW7qka2sVuwnnO1IzBku5ccP+s5qZGeRTPgrKB7OzRW85gthvIo1vQR2w+OwHFk7WJbbhhWwbCbktnP4UA==}
+ engines: {node: '>=16.0.0'}
- '@aws-sdk/middleware-location-constraint@3.410.0':
- resolution: {integrity: sha512-jAftSpOpw/5AdpOJ/cGiXCb+Vv22KXR5QZmxmllUDsnlm18672tpRaI2plmu/1d98CVvqhY61eSklFMrIf2c4w==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/middleware-host-header@3.620.0':
+ resolution: {integrity: sha512-VMtPEZwqYrII/oUkffYsNWY9PZ9xpNJpMgmyU0rlDQ25O1c0Hk3fJmZRe6pEkAJ0omD7kLrqGl1DUjQVxpd/Rg==}
+ engines: {node: '>=16.0.0'}
- '@aws-sdk/middleware-logger@3.410.0':
- resolution: {integrity: sha512-YtmKYCVtBfScq3/UFJk+aSZOktKJBNZL9DaSc2aPcy/goCVsYDOkGwtHk0jIkC1JRSNCkVTqL7ya60sSr8zaQQ==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/middleware-location-constraint@3.609.0':
+ resolution: {integrity: sha512-xzsdoTkszGVqGVPjUmgoP7TORiByLueMHieI1fhQL888WPdqctwAx3ES6d/bA9Q/i8jnc6hs+Fjhy8UvBTkE9A==}
+ engines: {node: '>=16.0.0'}
- '@aws-sdk/middleware-recursion-detection@3.410.0':
- resolution: {integrity: sha512-KWaes5FLzRqj28vaIEE4Bimpga2E596WdPF2HaH6zsVMJddoRDsc3ZX9ZhLOGrXzIO1RqBd0QxbLrM0S/B2aOQ==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/middleware-logger@3.609.0':
+ resolution: {integrity: sha512-S62U2dy4jMDhDFDK5gZ4VxFdWzCtLzwbYyFZx2uvPYTECkepLUfzLic2BHg2Qvtu4QjX+oGE3P/7fwaGIsGNuQ==}
+ engines: {node: '>=16.0.0'}
- '@aws-sdk/middleware-sdk-s3@3.410.0':
- resolution: {integrity: sha512-K2sG2V1ZkezYMCIy3uMt0MwtflcfIwLptwm0iFLaYitiINZQ1tcslk9ggAjyTHg0rslDSI4/zjkhy8VHFOV7HA==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/middleware-recursion-detection@3.620.0':
+ resolution: {integrity: sha512-nh91S7aGK3e/o1ck64sA/CyoFw+gAYj2BDOnoNa6ouyCrVJED96ZXWbhye/fz9SgmNUZR2g7GdVpiLpMKZoI5w==}
+ engines: {node: '>=16.0.0'}
- '@aws-sdk/middleware-sdk-sts@3.410.0':
- resolution: {integrity: sha512-YfBpctDocRR4CcROoDueJA7D+aMLBV8nTFfmVNdLLLgyuLZ/AUR11VQSu1lf9gQZKl8IpKE/BLf2fRE/qV1ZuA==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/middleware-sdk-s3@3.620.0':
+ resolution: {integrity: sha512-AAZ6NLVOx/bP97PYj/afCMeySzxOHocgJG3ZXh6f8MnJcGpZgx8NyRm0vtiYUTFrS2JtU4xV05Dl3j4afV3s4A==}
+ engines: {node: '>=16.0.0'}
- '@aws-sdk/middleware-signing@3.410.0':
- resolution: {integrity: sha512-KBAZ/eoAJUSJv5us2HsKwK2OszG2s9FEyKpEhgnHLcbbKzW873zHBH5GcOGEQu4AWArTy2ndzJu3FF+9/J9hJQ==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/middleware-signing@3.620.0':
+ resolution: {integrity: sha512-gxI7rubiaanUXaLfJ4NybERa9MGPNg2Ycl/OqANsozrBnR3Pw8vqy3EuVImQOyn2pJ2IFvl8ZPoSMHf4pX56FQ==}
+ engines: {node: '>=16.0.0'}
- '@aws-sdk/middleware-ssec@3.410.0':
- resolution: {integrity: sha512-DNsjVTXoxIh+PuW9o45CFaMiconbuZRm19MC3NA1yNCaCj3ZxD5OdXAutq6UjQdrx8UG4EjUlCJEEvBKmboITw==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/middleware-ssec@3.609.0':
+ resolution: {integrity: sha512-GZSD1s7+JswWOTamVap79QiDaIV7byJFssBW68GYjyRS5EBjNfwA/8s+6uE6g39R3ojyTbYOmvcANoZEhSULXg==}
+ engines: {node: '>=16.0.0'}
- '@aws-sdk/middleware-user-agent@3.410.0':
- resolution: {integrity: sha512-ZayDtLfvCZUohSxQc/49BfoU/y6bDHLfLdyyUJbJ54Sv8zQcrmdyKvCBFUZwE6tHQgAmv9/ZT18xECMl+xiONA==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/middleware-user-agent@3.620.0':
+ resolution: {integrity: sha512-bvS6etn+KsuL32ubY5D3xNof1qkenpbJXf/ugGXbg0n98DvDFQ/F+SMLxHgbnER5dsKYchNnhmtI6/FC3HFu/A==}
+ engines: {node: '>=16.0.0'}
- '@aws-sdk/signature-v4-multi-region@3.412.0':
- resolution: {integrity: sha512-ijxOeYpNDuk2T940S9HYcZ1C+wTP9vqp1Cw37zw9whVY2mKV3Vr7i+44D4FQ5HhWULgdwhjD7IctbNxPIPzUZQ==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/region-config-resolver@3.614.0':
+ resolution: {integrity: sha512-vDCeMXvic/LU0KFIUjpC3RiSTIkkvESsEfbVHiHH0YINfl8HnEqR5rj+L8+phsCeVg2+LmYwYxd5NRz4PHxt5g==}
+ engines: {node: '>=16.0.0'}
- '@aws-sdk/token-providers@3.410.0':
- resolution: {integrity: sha512-d5Nc0xydkH/X0LA1HDyhGY5sEv4LuADFk+QpDtT8ogLilcre+b1jpdY8Sih/gd1KoGS1H+d1tz2hSGwUHAbUbw==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/signature-v4-multi-region@3.620.0':
+ resolution: {integrity: sha512-yu1pTCqIbkSdaOvmyfW9vV9jWe3pDApkQPZLg4VEN5dXDWRtgQ/amv88myyCEoG14irUN1tsbvytcKzGyEXnhA==}
+ engines: {node: '>=16.0.0'}
- '@aws-sdk/types@3.410.0':
- resolution: {integrity: sha512-D7iaUCszv/v04NDaZUmCmekamy6VD/lKozm/3gS9+dkfU6cC2CsNoUfPV8BlV6dPdw0oWgF91am3I1stdvfVrQ==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/token-providers@3.614.0':
+ resolution: {integrity: sha512-okItqyY6L9IHdxqs+Z116y5/nda7rHxLvROxtAJdLavWTYDydxrZstImNgGWTeVdmc0xX2gJCI77UYUTQWnhRw==}
+ engines: {node: '>=16.0.0'}
+ peerDependencies:
+ '@aws-sdk/client-sso-oidc': ^3.614.0
- '@aws-sdk/types@3.413.0':
- resolution: {integrity: sha512-j1xib0f/TazIFc5ySIKOlT1ujntRbaoG4LJFeEezz4ji03/wSJMI8Vi4KjzpBp8J1tTu0oRDnsxRIGixsUBeYQ==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/types@3.609.0':
+ resolution: {integrity: sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==}
+ engines: {node: '>=16.0.0'}
- '@aws-sdk/util-arn-parser@3.310.0':
- resolution: {integrity: sha512-jL8509owp/xB9+Or0pvn3Fe+b94qfklc2yPowZZIFAkFcCSIdkIglz18cPDWnYAcy9JGewpMS1COXKIUhZkJsA==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/util-arn-parser@3.568.0':
+ resolution: {integrity: sha512-XUKJWWo+KOB7fbnPP0+g/o5Ulku/X53t7i/h+sPHr5xxYTJJ9CYnbToo95mzxe7xWvkLrsNtJ8L+MnNn9INs2w==}
+ engines: {node: '>=16.0.0'}
- '@aws-sdk/util-endpoints@3.410.0':
- resolution: {integrity: sha512-iNiqJyC7N3+8zFwnXUqcWSxrZecVZLToo1iTQQdeYL2af1IcOtRgb7n8jpAI/hmXhBSx2+3RI+Y7pxyFo1vu+w==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/util-endpoints@3.614.0':
+ resolution: {integrity: sha512-wK2cdrXHH4oz4IomV/yrGkftU9A+ITB6nFL+rxxyO78is2ifHJpFdV4aqk4LSkXYPi6CXWNru/Dqc7yiKXgJPw==}
+ engines: {node: '>=16.0.0'}
'@aws-sdk/util-locate-window@3.208.0':
resolution: {integrity: sha512-iua1A2+P7JJEDHVgvXrRJSvsnzG7stYSGQnBVphIUlemwl6nN5D+QrgbjECtrbxRz8asYFHSzhdhECqN+tFiBg==}
engines: {node: '>=14.0.0'}
- '@aws-sdk/util-user-agent-browser@3.410.0':
- resolution: {integrity: sha512-i1G/XGpXGMRT2zEiAhi1xucJsfCWk8nNYjk/LbC0sA+7B9Huri96YAzVib12wkHPsJQvZxZC6CpQDIHWm4lXMA==}
+ '@aws-sdk/util-user-agent-browser@3.609.0':
+ resolution: {integrity: sha512-fojPU+mNahzQ0YHYBsx0ZIhmMA96H+ZIZ665ObU9tl+SGdbLneVZVikGve+NmHTQwHzwkFsZYYnVKAkreJLAtA==}
- '@aws-sdk/util-user-agent-node@3.410.0':
- resolution: {integrity: sha512-bK70t1jHRl8HrJXd4hEIwc5PBZ7U0w+81AKFnanIVKZwZedd6nLibUXDTK14z/Jp2GFcBqd4zkt2YLGkRt/U4A==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/util-user-agent-node@3.614.0':
+ resolution: {integrity: sha512-15ElZT88peoHnq5TEoEtZwoXTXRxNrk60TZNdpl/TUBJ5oNJ9Dqb5Z4ryb8ofN6nm9aFf59GVAerFDz8iUoHBA==}
+ engines: {node: '>=16.0.0'}
peerDependencies:
aws-crt: '>=1.0.0'
peerDependenciesMeta:
aws-crt:
optional: true
- '@aws-sdk/util-utf8-browser@3.259.0':
- resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==}
-
- '@aws-sdk/xml-builder@3.310.0':
- resolution: {integrity: sha512-TqELu4mOuSIKQCqj63fGVs86Yh+vBx5nHRpWKNUNhB2nPTpfbziTs5c1X358be3peVWA4wPxW7Nt53KIg1tnNw==}
- engines: {node: '>=14.0.0'}
+ '@aws-sdk/xml-builder@3.609.0':
+ resolution: {integrity: sha512-l9XxNcA4HX98rwCC2/KoiWcmEiRfZe4G+mYwDbCFT87JIMj6GBhLDkAzr/W8KAaA2IDr8Vc6J8fZPgVulxxfMA==}
+ engines: {node: '>=16.0.0'}
'@babel/code-frame@7.23.5':
resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==}
engines: {node: '>=6.9.0'}
+ '@babel/code-frame@7.24.7':
+ resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==}
+ engines: {node: '>=6.9.0'}
+
'@babel/compat-data@7.23.5':
resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==}
engines: {node: '>=6.9.0'}
+ '@babel/compat-data@7.24.7':
+ resolution: {integrity: sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==}
+ engines: {node: '>=6.9.0'}
+
'@babel/core@7.23.5':
resolution: {integrity: sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==}
engines: {node: '>=6.9.0'}
- '@babel/core@7.24.0':
- resolution: {integrity: sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw==}
+ '@babel/core@7.24.7':
+ resolution: {integrity: sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==}
engines: {node: '>=6.9.0'}
'@babel/generator@7.23.5':
resolution: {integrity: sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==}
engines: {node: '>=6.9.0'}
- '@babel/generator@7.23.6':
- resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==}
+ '@babel/generator@7.24.7':
+ resolution: {integrity: sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==}
engines: {node: '>=6.9.0'}
- '@babel/helper-annotate-as-pure@7.22.5':
- resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==}
+ '@babel/helper-annotate-as-pure@7.24.7':
+ resolution: {integrity: sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==}
engines: {node: '>=6.9.0'}
- '@babel/helper-builder-binary-assignment-operator-visitor@7.22.15':
- resolution: {integrity: sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==}
+ '@babel/helper-builder-binary-assignment-operator-visitor@7.24.7':
+ resolution: {integrity: sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==}
engines: {node: '>=6.9.0'}
'@babel/helper-compilation-targets@7.22.15':
resolution: {integrity: sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==}
engines: {node: '>=6.9.0'}
- '@babel/helper-compilation-targets@7.23.6':
- resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==}
+ '@babel/helper-compilation-targets@7.24.7':
+ resolution: {integrity: sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==}
engines: {node: '>=6.9.0'}
- '@babel/helper-create-class-features-plugin@7.23.5':
- resolution: {integrity: sha512-QELlRWxSpgdwdJzSJn4WAhKC+hvw/AtHbbrIoncKHkhKKR/luAlKkgBDcri1EzWAo8f8VvYVryEHN4tax/V67A==}
+ '@babel/helper-create-class-features-plugin@7.24.7':
+ resolution: {integrity: sha512-kTkaDl7c9vO80zeX1rJxnuRpEsD5tA81yh11X1gQo+PhSti3JS+7qeZo9U4RHobKRiFPKaGK3svUAeb8D0Q7eg==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
- '@babel/helper-create-regexp-features-plugin@7.22.15':
- resolution: {integrity: sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==}
+ '@babel/helper-create-regexp-features-plugin@7.24.7':
+ resolution: {integrity: sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
- '@babel/helper-define-polyfill-provider@0.4.3':
- resolution: {integrity: sha512-WBrLmuPP47n7PNwsZ57pqam6G/RGo1vw/87b0Blc53tZNGZ4x7YvZ6HgQe2vo1W/FR20OgjeZuGXzudPiXHFug==}
+ '@babel/helper-define-polyfill-provider@0.6.2':
+ resolution: {integrity: sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==}
peerDependencies:
'@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
@@ -1521,44 +1504,70 @@ packages:
resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==}
engines: {node: '>=6.9.0'}
+ '@babel/helper-environment-visitor@7.24.7':
+ resolution: {integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==}
+ engines: {node: '>=6.9.0'}
+
'@babel/helper-function-name@7.23.0':
resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==}
engines: {node: '>=6.9.0'}
+ '@babel/helper-function-name@7.24.7':
+ resolution: {integrity: sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==}
+ engines: {node: '>=6.9.0'}
+
'@babel/helper-hoist-variables@7.22.5':
resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==}
engines: {node: '>=6.9.0'}
- '@babel/helper-member-expression-to-functions@7.23.0':
- resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==}
+ '@babel/helper-hoist-variables@7.24.7':
+ resolution: {integrity: sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-member-expression-to-functions@7.24.7':
+ resolution: {integrity: sha512-LGeMaf5JN4hAT471eJdBs/GK1DoYIJ5GCtZN/EsL6KUiiDZOvO/eKE11AMZJa2zP4zk4qe9V2O/hxAmkRc8p6w==}
engines: {node: '>=6.9.0'}
'@babel/helper-module-imports@7.22.15':
resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==}
engines: {node: '>=6.9.0'}
+ '@babel/helper-module-imports@7.24.7':
+ resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==}
+ engines: {node: '>=6.9.0'}
+
'@babel/helper-module-transforms@7.23.3':
resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
- '@babel/helper-optimise-call-expression@7.22.5':
- resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==}
+ '@babel/helper-module-transforms@7.24.7':
+ resolution: {integrity: sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+
+ '@babel/helper-optimise-call-expression@7.24.7':
+ resolution: {integrity: sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==}
engines: {node: '>=6.9.0'}
'@babel/helper-plugin-utils@7.22.5':
resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==}
engines: {node: '>=6.9.0'}
- '@babel/helper-remap-async-to-generator@7.22.20':
- resolution: {integrity: sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==}
+ '@babel/helper-plugin-utils@7.24.7':
+ resolution: {integrity: sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-remap-async-to-generator@7.24.7':
+ resolution: {integrity: sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
- '@babel/helper-replace-supers@7.22.20':
- resolution: {integrity: sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==}
+ '@babel/helper-replace-supers@7.24.7':
+ resolution: {integrity: sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
@@ -1567,71 +1576,101 @@ packages:
resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==}
engines: {node: '>=6.9.0'}
- '@babel/helper-skip-transparent-expression-wrappers@7.22.5':
- resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==}
+ '@babel/helper-simple-access@7.24.7':
+ resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-skip-transparent-expression-wrappers@7.24.7':
+ resolution: {integrity: sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==}
engines: {node: '>=6.9.0'}
'@babel/helper-split-export-declaration@7.22.6':
resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==}
engines: {node: '>=6.9.0'}
+ '@babel/helper-split-export-declaration@7.24.7':
+ resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==}
+ engines: {node: '>=6.9.0'}
+
'@babel/helper-string-parser@7.23.4':
resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==}
engines: {node: '>=6.9.0'}
+ '@babel/helper-string-parser@7.24.7':
+ resolution: {integrity: sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==}
+ engines: {node: '>=6.9.0'}
+
'@babel/helper-validator-identifier@7.22.20':
resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==}
engines: {node: '>=6.9.0'}
+ '@babel/helper-validator-identifier@7.24.7':
+ resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==}
+ engines: {node: '>=6.9.0'}
+
'@babel/helper-validator-option@7.23.5':
resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==}
engines: {node: '>=6.9.0'}
- '@babel/helper-wrap-function@7.22.20':
- resolution: {integrity: sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==}
+ '@babel/helper-validator-option@7.24.7':
+ resolution: {integrity: sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-wrap-function@7.24.7':
+ resolution: {integrity: sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==}
engines: {node: '>=6.9.0'}
'@babel/helpers@7.23.5':
resolution: {integrity: sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==}
engines: {node: '>=6.9.0'}
- '@babel/helpers@7.24.0':
- resolution: {integrity: sha512-ulDZdc0Aj5uLc5nETsa7EPx2L7rM0YJM8r7ck7U73AXi7qOV44IHHRAYZHY6iU1rr3C5N4NtTmMRUJP6kwCWeA==}
+ '@babel/helpers@7.24.7':
+ resolution: {integrity: sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==}
engines: {node: '>=6.9.0'}
'@babel/highlight@7.23.4':
resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==}
engines: {node: '>=6.9.0'}
+ '@babel/highlight@7.24.7':
+ resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==}
+ engines: {node: '>=6.9.0'}
+
'@babel/parser@7.23.9':
resolution: {integrity: sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==}
engines: {node: '>=6.0.0'}
hasBin: true
- '@babel/parser@7.24.0':
- resolution: {integrity: sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==}
+ '@babel/parser@7.24.5':
+ resolution: {integrity: sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==}
engines: {node: '>=6.0.0'}
hasBin: true
- '@babel/parser@7.24.5':
- resolution: {integrity: sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==}
+ '@babel/parser@7.24.7':
+ resolution: {integrity: sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==}
engines: {node: '>=6.0.0'}
hasBin: true
- '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3':
- resolution: {integrity: sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==}
+ '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.7':
+ resolution: {integrity: sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
- '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3':
- resolution: {integrity: sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==}
+ '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.7':
+ resolution: {integrity: sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+
+ '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.7':
+ resolution: {integrity: sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.13.0
- '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.3':
- resolution: {integrity: sha512-XaJak1qcityzrX0/IU5nKHb34VaibwP3saKqG6a/tppelgllOH13LUann4ZCIBcVOeE6H18K4Vx9QKkVww3z/w==}
+ '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.24.7':
+ resolution: {integrity: sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
@@ -1679,14 +1718,14 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-syntax-import-assertions@7.23.3':
- resolution: {integrity: sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==}
+ '@babel/plugin-syntax-import-assertions@7.24.7':
+ resolution: {integrity: sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-syntax-import-attributes@7.23.3':
- resolution: {integrity: sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==}
+ '@babel/plugin-syntax-import-attributes@7.24.7':
+ resolution: {integrity: sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
@@ -1761,92 +1800,92 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0
- '@babel/plugin-transform-arrow-functions@7.23.3':
- resolution: {integrity: sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==}
+ '@babel/plugin-transform-arrow-functions@7.24.7':
+ resolution: {integrity: sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-async-generator-functions@7.23.4':
- resolution: {integrity: sha512-efdkfPhHYTtn0G6n2ddrESE91fgXxjlqLsnUtPWnJs4a4mZIbUaK7ffqKIIUKXSHwcDvaCVX6GXkaJJFqtX7jw==}
+ '@babel/plugin-transform-async-generator-functions@7.24.7':
+ resolution: {integrity: sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-async-to-generator@7.23.3':
- resolution: {integrity: sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==}
+ '@babel/plugin-transform-async-to-generator@7.24.7':
+ resolution: {integrity: sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-block-scoped-functions@7.23.3':
- resolution: {integrity: sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==}
+ '@babel/plugin-transform-block-scoped-functions@7.24.7':
+ resolution: {integrity: sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-block-scoping@7.23.4':
- resolution: {integrity: sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==}
+ '@babel/plugin-transform-block-scoping@7.24.7':
+ resolution: {integrity: sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-class-properties@7.23.3':
- resolution: {integrity: sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==}
+ '@babel/plugin-transform-class-properties@7.24.7':
+ resolution: {integrity: sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-class-static-block@7.23.4':
- resolution: {integrity: sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==}
+ '@babel/plugin-transform-class-static-block@7.24.7':
+ resolution: {integrity: sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.12.0
- '@babel/plugin-transform-classes@7.23.5':
- resolution: {integrity: sha512-jvOTR4nicqYC9yzOHIhXG5emiFEOpappSJAl73SDSEDcybD+Puuze8Tnpb9p9qEyYup24tq891gkaygIFvWDqg==}
+ '@babel/plugin-transform-classes@7.24.7':
+ resolution: {integrity: sha512-CFbbBigp8ln4FU6Bpy6g7sE8B/WmCmzvivzUC6xDAdWVsjYTXijpuuGJmYkAaoWAzcItGKT3IOAbxRItZ5HTjw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-computed-properties@7.23.3':
- resolution: {integrity: sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==}
+ '@babel/plugin-transform-computed-properties@7.24.7':
+ resolution: {integrity: sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-destructuring@7.23.3':
- resolution: {integrity: sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==}
+ '@babel/plugin-transform-destructuring@7.24.7':
+ resolution: {integrity: sha512-19eJO/8kdCQ9zISOf+SEUJM/bAUIsvY3YDnXZTupUCQ8LgrWnsG/gFB9dvXqdXnRXMAM8fvt7b0CBKQHNGy1mw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-dotall-regex@7.23.3':
- resolution: {integrity: sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==}
+ '@babel/plugin-transform-dotall-regex@7.24.7':
+ resolution: {integrity: sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-duplicate-keys@7.23.3':
- resolution: {integrity: sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==}
+ '@babel/plugin-transform-duplicate-keys@7.24.7':
+ resolution: {integrity: sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-dynamic-import@7.23.4':
- resolution: {integrity: sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==}
+ '@babel/plugin-transform-dynamic-import@7.24.7':
+ resolution: {integrity: sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-exponentiation-operator@7.23.3':
- resolution: {integrity: sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==}
+ '@babel/plugin-transform-exponentiation-operator@7.24.7':
+ resolution: {integrity: sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-export-namespace-from@7.23.4':
- resolution: {integrity: sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==}
+ '@babel/plugin-transform-export-namespace-from@7.24.7':
+ resolution: {integrity: sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
@@ -1857,176 +1896,176 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-for-of@7.23.3':
- resolution: {integrity: sha512-X8jSm8X1CMwxmK878qsUGJRmbysKNbdpTv/O1/v0LuY/ZkZrng5WYiekYSdg9m09OTmDDUWeEDsTE+17WYbAZw==}
+ '@babel/plugin-transform-for-of@7.24.7':
+ resolution: {integrity: sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-function-name@7.23.3':
- resolution: {integrity: sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==}
+ '@babel/plugin-transform-function-name@7.24.7':
+ resolution: {integrity: sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-json-strings@7.23.4':
- resolution: {integrity: sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==}
+ '@babel/plugin-transform-json-strings@7.24.7':
+ resolution: {integrity: sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-literals@7.23.3':
- resolution: {integrity: sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==}
+ '@babel/plugin-transform-literals@7.24.7':
+ resolution: {integrity: sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-logical-assignment-operators@7.23.4':
- resolution: {integrity: sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==}
+ '@babel/plugin-transform-logical-assignment-operators@7.24.7':
+ resolution: {integrity: sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-member-expression-literals@7.23.3':
- resolution: {integrity: sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==}
+ '@babel/plugin-transform-member-expression-literals@7.24.7':
+ resolution: {integrity: sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-modules-amd@7.23.3':
- resolution: {integrity: sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==}
+ '@babel/plugin-transform-modules-amd@7.24.7':
+ resolution: {integrity: sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-modules-commonjs@7.23.3':
- resolution: {integrity: sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==}
+ '@babel/plugin-transform-modules-commonjs@7.24.7':
+ resolution: {integrity: sha512-iFI8GDxtevHJ/Z22J5xQpVqFLlMNstcLXh994xifFwxxGslr2ZXXLWgtBeLctOD63UFDArdvN6Tg8RFw+aEmjQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-modules-systemjs@7.23.3':
- resolution: {integrity: sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==}
+ '@babel/plugin-transform-modules-systemjs@7.24.7':
+ resolution: {integrity: sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-modules-umd@7.23.3':
- resolution: {integrity: sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==}
+ '@babel/plugin-transform-modules-umd@7.24.7':
+ resolution: {integrity: sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-named-capturing-groups-regex@7.22.5':
- resolution: {integrity: sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==}
+ '@babel/plugin-transform-named-capturing-groups-regex@7.24.7':
+ resolution: {integrity: sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
- '@babel/plugin-transform-new-target@7.23.3':
- resolution: {integrity: sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==}
+ '@babel/plugin-transform-new-target@7.24.7':
+ resolution: {integrity: sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-nullish-coalescing-operator@7.23.4':
- resolution: {integrity: sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==}
+ '@babel/plugin-transform-nullish-coalescing-operator@7.24.7':
+ resolution: {integrity: sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-numeric-separator@7.23.4':
- resolution: {integrity: sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==}
+ '@babel/plugin-transform-numeric-separator@7.24.7':
+ resolution: {integrity: sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-object-rest-spread@7.23.4':
- resolution: {integrity: sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==}
+ '@babel/plugin-transform-object-rest-spread@7.24.7':
+ resolution: {integrity: sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-object-super@7.23.3':
- resolution: {integrity: sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==}
+ '@babel/plugin-transform-object-super@7.24.7':
+ resolution: {integrity: sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-optional-catch-binding@7.23.4':
- resolution: {integrity: sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==}
+ '@babel/plugin-transform-optional-catch-binding@7.24.7':
+ resolution: {integrity: sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-optional-chaining@7.23.4':
- resolution: {integrity: sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==}
+ '@babel/plugin-transform-optional-chaining@7.24.7':
+ resolution: {integrity: sha512-tK+0N9yd4j+x/4hxF3F0e0fu/VdcxU18y5SevtyM/PCFlQvXbR0Zmlo2eBrKtVipGNFzpq56o8WsIIKcJFUCRQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-parameters@7.23.3':
- resolution: {integrity: sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==}
+ '@babel/plugin-transform-parameters@7.24.7':
+ resolution: {integrity: sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-private-methods@7.23.3':
- resolution: {integrity: sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==}
+ '@babel/plugin-transform-private-methods@7.24.7':
+ resolution: {integrity: sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-private-property-in-object@7.23.4':
- resolution: {integrity: sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==}
+ '@babel/plugin-transform-private-property-in-object@7.24.7':
+ resolution: {integrity: sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-property-literals@7.23.3':
- resolution: {integrity: sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==}
+ '@babel/plugin-transform-property-literals@7.24.7':
+ resolution: {integrity: sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-regenerator@7.23.3':
- resolution: {integrity: sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==}
+ '@babel/plugin-transform-regenerator@7.24.7':
+ resolution: {integrity: sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-reserved-words@7.23.3':
- resolution: {integrity: sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==}
+ '@babel/plugin-transform-reserved-words@7.24.7':
+ resolution: {integrity: sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-shorthand-properties@7.23.3':
- resolution: {integrity: sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==}
+ '@babel/plugin-transform-shorthand-properties@7.24.7':
+ resolution: {integrity: sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-spread@7.23.3':
- resolution: {integrity: sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==}
+ '@babel/plugin-transform-spread@7.24.7':
+ resolution: {integrity: sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-sticky-regex@7.23.3':
- resolution: {integrity: sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==}
+ '@babel/plugin-transform-sticky-regex@7.24.7':
+ resolution: {integrity: sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-template-literals@7.23.3':
- resolution: {integrity: sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==}
+ '@babel/plugin-transform-template-literals@7.24.7':
+ resolution: {integrity: sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-typeof-symbol@7.23.3':
- resolution: {integrity: sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==}
+ '@babel/plugin-transform-typeof-symbol@7.24.7':
+ resolution: {integrity: sha512-VtR8hDy7YLB7+Pet9IarXjg/zgCMSF+1mNS/EQEiEaUPoFXCVsHG64SIxcaaI2zJgRiv+YmgaQESUfWAdbjzgg==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
@@ -2037,32 +2076,32 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-unicode-escapes@7.23.3':
- resolution: {integrity: sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==}
+ '@babel/plugin-transform-unicode-escapes@7.24.7':
+ resolution: {integrity: sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-unicode-property-regex@7.23.3':
- resolution: {integrity: sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==}
+ '@babel/plugin-transform-unicode-property-regex@7.24.7':
+ resolution: {integrity: sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-unicode-regex@7.23.3':
- resolution: {integrity: sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==}
+ '@babel/plugin-transform-unicode-regex@7.24.7':
+ resolution: {integrity: sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-unicode-sets-regex@7.23.3':
- resolution: {integrity: sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==}
+ '@babel/plugin-transform-unicode-sets-regex@7.24.7':
+ resolution: {integrity: sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
- '@babel/preset-env@7.23.5':
- resolution: {integrity: sha512-0d/uxVD6tFGWXGDSfyMD1p2otoaKmu6+GD+NfAx0tMaH+dxORnp7T9TaVQ6mKyya7iBtCIVxHjWT7MuzzM9z+A==}
+ '@babel/preset-env@7.24.7':
+ resolution: {integrity: sha512-1YZNsc+y6cTvWlDHidMBsQZrZfEFjRIo/BZCT906PMdzOyXtSLTgqGdrpcuTDCXyd11Am5uQULtDIcCfnTc8fQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
@@ -2105,12 +2144,16 @@ packages:
resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==}
engines: {node: '>=6.9.0'}
+ '@babel/template@7.24.7':
+ resolution: {integrity: sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==}
+ engines: {node: '>=6.9.0'}
+
'@babel/traverse@7.23.5':
resolution: {integrity: sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==}
engines: {node: '>=6.9.0'}
- '@babel/traverse@7.24.0':
- resolution: {integrity: sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw==}
+ '@babel/traverse@7.24.7':
+ resolution: {integrity: sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==}
engines: {node: '>=6.9.0'}
'@babel/types@7.23.5':
@@ -2121,22 +2164,26 @@ packages:
resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==}
engines: {node: '>=6.9.0'}
+ '@babel/types@7.24.7':
+ resolution: {integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==}
+ engines: {node: '>=6.9.0'}
+
'@base2/pretty-print-object@1.0.1':
resolution: {integrity: sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==}
'@bcoe/v8-coverage@0.2.3':
resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
- '@bull-board/api@5.17.0':
- resolution: {integrity: sha512-qU+AiZIaYa//rkt1x7jDowtYa8u7/dLsDfEWgenZMkgvUszZ1kxJszdCtGapsDTVyPmnXgTRxpOWcR6sAYwSNQ==}
+ '@bull-board/api@5.21.1':
+ resolution: {integrity: sha512-anzTfhOJ93eraT/GYeyxWpxRMarHwuevn6pPBfdOj0LC2eg98OPnkfdMSjcrpL3qrqsxON0RslS7kuPfCEnX6A==}
peerDependencies:
- '@bull-board/ui': 5.17.0
+ '@bull-board/ui': 5.21.1
- '@bull-board/fastify@5.17.0':
- resolution: {integrity: sha512-73YrPc7ERTWSOQRgBP6a7BPscWfcHd8U+Zq0auMdL/KkjPhG9GxapbfnovGZDDahJL/p/4YQb6ULu03zdtOrEA==}
+ '@bull-board/fastify@5.21.1':
+ resolution: {integrity: sha512-We33yolc70SALjDdF3cjEaLn1L/vrw85eFCsrviESaW3dFVIdB+xn0fdqMFK6NnaC0JjBa3Ypfev4Co+eaZ+1A==}
- '@bull-board/ui@5.17.0':
- resolution: {integrity: sha512-Vj+yWPjrjx3Iqh2N/ZBDhK2d2yJD44dfvIxm+SnXQb4ne312j117TpViInceysxGtbbAOlAW6hq6JvsDoRl7KQ==}
+ '@bull-board/ui@5.21.1':
+ resolution: {integrity: sha512-JBDeCqG7j/c3WE0uGMN9snPkRJz9/D6MpTZzyVj7KOxIJwNKPOICNFZbCrCNi7bcJYHDJ2xGTN9OO1mw7i43BQ==}
'@bundled-es-modules/cookie@2.0.0':
resolution: {integrity: sha512-Or6YHg/kamKHpxULAdSqhGqnWFneIXu1NKvvfBBzKGwpVsYuFIQ5aBPHDnnoR3ghW1nvSkALd+EF9iMtY7Vjxw==}
@@ -2144,6 +2191,9 @@ packages:
'@bundled-es-modules/statuses@1.0.1':
resolution: {integrity: sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==}
+ '@bundled-es-modules/tough-cookie@0.1.6':
+ resolution: {integrity: sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==}
+
'@canvas/image-data@1.0.0':
resolution: {integrity: sha512-BxOqI5LgsIQP1odU5KMwV9yoijleOPzHL18/YvNqF9KFSGF2K/DLlYAbDQsWqd/1nbaFuSkYD/191dpMtNh4vw==}
@@ -2151,38 +2201,38 @@ packages:
resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==}
engines: {node: '>=0.1.90'}
- '@cropper/element-canvas@2.0.0-beta.5':
- resolution: {integrity: sha512-TS+NTVQAyLKBFLIjzFcaFK6V5GaNCNSp8FBjApTD/AosV/dPRlNCsgmdJ/BugwJTJUSowVnLrPmulI35z4npAg==}
+ '@cropper/element-canvas@2.0.0-rc.1':
+ resolution: {integrity: sha512-jRt9OM7cls+zch8U2m7pA9wp8dNOz0EtedGKkqH+DInUYw1+UtonEJirrxyl1YHRgOme5M5DTsDmkUSrUiZN6g==}
- '@cropper/element-crosshair@2.0.0-beta.5':
- resolution: {integrity: sha512-en3EjiqS/O/uVPVLUanx2ZxvE2n3J5VxGABvBTwQimX4c3kNixq8TUVlsaLdcG7jbehxFpT3S19+tiuZudHqxg==}
+ '@cropper/element-crosshair@2.0.0-rc.1':
+ resolution: {integrity: sha512-xfLelqM8EnRZUf7xEE88RWQQx5erUv7jrzni52bAw3/Ua8HXIz3uAMnkrGKOTBj8K4Rv/mNJY8k1DVAEfHY6Lg==}
- '@cropper/element-grid@2.0.0-beta.5':
- resolution: {integrity: sha512-uKQExNTOMOGo5d6Tv1NJDbjJHRR/0NgqeROUSt2J8g9ymPP+/MoFdCCf+Nj/KM5pk7/fBEV3HhzUnO8jh1hZfQ==}
+ '@cropper/element-grid@2.0.0-rc.1':
+ resolution: {integrity: sha512-U/BYPl76upd9sXT+pZTFoQzUqWyNxdGs4YR2UtaVCfTMHLDTrssPAedmqEEnHgbqVcr325sIEfVmwWVA+v+8Dg==}
- '@cropper/element-handle@2.0.0-beta.5':
- resolution: {integrity: sha512-SlaV5/qbEBQLHnuaGD8J0EqSp797m/MMB8V10EUZpv6cznSRxg/SXOj6ROE0ePzo5+0i96Dw+8ZukLilDgc1Xw==}
+ '@cropper/element-handle@2.0.0-rc.1':
+ resolution: {integrity: sha512-GuOHbjkg5CP1+oFzWQeD7VZffUE86dp4gKv5egLxkBEwnQp1VQxjO7L1Wkgj+KsQymoDczsl+x4bF12KDyDg2g==}
- '@cropper/element-image@2.0.0-beta.5':
- resolution: {integrity: sha512-369ztVaoRS2DN8SaiHZ/bRCz0Snw9ss7PZrX1OQK86fwVhCoeRqCHj48ayfLMdchx+J3RbM5f2g8ePf7ejwOKw==}
+ '@cropper/element-image@2.0.0-rc.1':
+ resolution: {integrity: sha512-ttzawKbUkR2A9U3bc2AN/jbNdszBP/yb83PIc5jekjOs+Z7kUBVdOo1SLIewpQ0DjUzhfCRXWUowP1McVQUXZw==}
- '@cropper/element-selection@2.0.0-beta.5':
- resolution: {integrity: sha512-l8DvOBAZYytTarpkfhCglhxD+zDQ2acVwIzGwp5r9xR+ERleJHxr2rHYVhowRHT/JZRd94DJBlye91c1uO/XGg==}
+ '@cropper/element-selection@2.0.0-rc.1':
+ resolution: {integrity: sha512-AcRHRbsyt9xRfBD1QRyNDTS+vaYg6uAeuqhk/Ra58pqxlhtoimAV3oQ7uc/edwOlK60f/DxtKCc8rSOYFQ85bQ==}
- '@cropper/element-shade@2.0.0-beta.5':
- resolution: {integrity: sha512-LGSVLAD1lasFrS+Pd7JnQSJRCMSNnc40UCcjLhscDuRcRHK/ViMglnwCfFxeGnS26kugbDLF5IbYDCLCbykUog==}
+ '@cropper/element-shade@2.0.0-rc.1':
+ resolution: {integrity: sha512-nHv2WujETENoIfxWQn7TYiOnXm5YUnZsoG4r6njK5cxj0gIUfPudUSbjWCQSuB2oxxpeEK8oyTdfOZtP9cxK4g==}
- '@cropper/element-viewer@2.0.0-beta.5':
- resolution: {integrity: sha512-i4cc+L+j8Gq1L8g1BQWfQ842QxH5T9v2EkIeGuW66SVSBglafxu8gxmSOyRD3hDAMHM3wbJ+XVmFwBHZzlYCvQ==}
+ '@cropper/element-viewer@2.0.0-rc.1':
+ resolution: {integrity: sha512-xTj0BObCygbVWXc7t7FYZ9k2eFyWN360it5uGeAkImXcwINRQGTFcLLOjs6i3SwedI7F1a1yNcTBfoT1B/sNAg==}
- '@cropper/element@2.0.0-beta.5':
- resolution: {integrity: sha512-+pHX/iYw+Y/HxgpcjvSPBc3+hvJaycznbZdWifnChmDkpLStd6Xu9gO2ful9sSL0uGSjQxUYV4xPyikYJOnfug==}
+ '@cropper/element@2.0.0-rc.1':
+ resolution: {integrity: sha512-OPKgjUgYC2Xmv77vEqtAR6bdfKOW+v9FrSjr4re3u95rcVj6NJ0JidIta41Ipp8KydHTXSmLetq4XDrA+vuIJQ==}
- '@cropper/elements@2.0.0-beta.5':
- resolution: {integrity: sha512-KWa5/dmJpLcKDJpNlbEQzO9Shz+f4aB0I3y97CqqTf8JSGS6CEKOd9uLywd1eow1r4O0Hwo65ktXPwAEhMWDZg==}
+ '@cropper/elements@2.0.0-rc.1':
+ resolution: {integrity: sha512-6qbtCq3iL3dETVav2XA03a8iLkHXWMIqHFxViMjlLr9CSuDjjaS5wp0JDuGtPv5FHxjsjyQ8Yayt8Ak5p09Zxg==}
- '@cropper/utils@2.0.0-beta.5':
- resolution: {integrity: sha512-xE7Klel/4WSjhLUeldfROwbWqV/1A3YKrQLqTrs5/X0ath7B05Fmvhr3TNFvN51v2KSx46Ug6xDJzmbg772m1g==}
+ '@cropper/utils@2.0.0-rc.1':
+ resolution: {integrity: sha512-kreB3wdrAhmTEscfB8/j7ksGBgYSKN+28t37CAI0Vb5DvX/aUDPDH+3e2kyD7YE+DIZgdnuY2FsMYJAQ9sTThg==}
'@cypress/request@3.0.0':
resolution: {integrity: sha512-GKFCqwZwMYmL3IBoNeR2MM1SnxRIGERsQOTWeQKoYBt2JLqcqiy7JXqO894FLrpjZYqGxW92MNwRH2BN56obdQ==}
@@ -2216,12 +2266,18 @@ packages:
cpu: [ppc64]
os: [aix]
- '@esbuild/aix-ppc64@0.20.2':
- resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==}
+ '@esbuild/aix-ppc64@0.21.5':
+ resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [aix]
+ '@esbuild/aix-ppc64@0.23.0':
+ resolution: {integrity: sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [aix]
+
'@esbuild/android-arm64@0.18.20':
resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==}
engines: {node: '>=12'}
@@ -2234,12 +2290,18 @@ packages:
cpu: [arm64]
os: [android]
- '@esbuild/android-arm64@0.20.2':
- resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==}
+ '@esbuild/android-arm64@0.21.5':
+ resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==}
engines: {node: '>=12'}
cpu: [arm64]
os: [android]
+ '@esbuild/android-arm64@0.23.0':
+ resolution: {integrity: sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [android]
+
'@esbuild/android-arm@0.18.20':
resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==}
engines: {node: '>=12'}
@@ -2252,12 +2314,18 @@ packages:
cpu: [arm]
os: [android]
- '@esbuild/android-arm@0.20.2':
- resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==}
+ '@esbuild/android-arm@0.21.5':
+ resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==}
engines: {node: '>=12'}
cpu: [arm]
os: [android]
+ '@esbuild/android-arm@0.23.0':
+ resolution: {integrity: sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [android]
+
'@esbuild/android-x64@0.18.20':
resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==}
engines: {node: '>=12'}
@@ -2270,12 +2338,18 @@ packages:
cpu: [x64]
os: [android]
- '@esbuild/android-x64@0.20.2':
- resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==}
+ '@esbuild/android-x64@0.21.5':
+ resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==}
engines: {node: '>=12'}
cpu: [x64]
os: [android]
+ '@esbuild/android-x64@0.23.0':
+ resolution: {integrity: sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [android]
+
'@esbuild/darwin-arm64@0.18.20':
resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==}
engines: {node: '>=12'}
@@ -2288,12 +2362,18 @@ packages:
cpu: [arm64]
os: [darwin]
- '@esbuild/darwin-arm64@0.20.2':
- resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==}
+ '@esbuild/darwin-arm64@0.21.5':
+ resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
+ '@esbuild/darwin-arm64@0.23.0':
+ resolution: {integrity: sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [darwin]
+
'@esbuild/darwin-x64@0.18.20':
resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==}
engines: {node: '>=12'}
@@ -2306,12 +2386,18 @@ packages:
cpu: [x64]
os: [darwin]
- '@esbuild/darwin-x64@0.20.2':
- resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==}
+ '@esbuild/darwin-x64@0.21.5':
+ resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
+ '@esbuild/darwin-x64@0.23.0':
+ resolution: {integrity: sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [darwin]
+
'@esbuild/freebsd-arm64@0.18.20':
resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==}
engines: {node: '>=12'}
@@ -2324,12 +2410,18 @@ packages:
cpu: [arm64]
os: [freebsd]
- '@esbuild/freebsd-arm64@0.20.2':
- resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==}
+ '@esbuild/freebsd-arm64@0.21.5':
+ resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==}
engines: {node: '>=12'}
cpu: [arm64]
os: [freebsd]
+ '@esbuild/freebsd-arm64@0.23.0':
+ resolution: {integrity: sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [freebsd]
+
'@esbuild/freebsd-x64@0.18.20':
resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==}
engines: {node: '>=12'}
@@ -2342,12 +2434,18 @@ packages:
cpu: [x64]
os: [freebsd]
- '@esbuild/freebsd-x64@0.20.2':
- resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==}
+ '@esbuild/freebsd-x64@0.21.5':
+ resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [freebsd]
+ '@esbuild/freebsd-x64@0.23.0':
+ resolution: {integrity: sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [freebsd]
+
'@esbuild/linux-arm64@0.18.20':
resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==}
engines: {node: '>=12'}
@@ -2360,12 +2458,18 @@ packages:
cpu: [arm64]
os: [linux]
- '@esbuild/linux-arm64@0.20.2':
- resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==}
+ '@esbuild/linux-arm64@0.21.5':
+ resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==}
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
+ '@esbuild/linux-arm64@0.23.0':
+ resolution: {integrity: sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [linux]
+
'@esbuild/linux-arm@0.18.20':
resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==}
engines: {node: '>=12'}
@@ -2378,12 +2482,18 @@ packages:
cpu: [arm]
os: [linux]
- '@esbuild/linux-arm@0.20.2':
- resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==}
+ '@esbuild/linux-arm@0.21.5':
+ resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==}
engines: {node: '>=12'}
cpu: [arm]
os: [linux]
+ '@esbuild/linux-arm@0.23.0':
+ resolution: {integrity: sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [linux]
+
'@esbuild/linux-ia32@0.18.20':
resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==}
engines: {node: '>=12'}
@@ -2396,12 +2506,18 @@ packages:
cpu: [ia32]
os: [linux]
- '@esbuild/linux-ia32@0.20.2':
- resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==}
+ '@esbuild/linux-ia32@0.21.5':
+ resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==}
engines: {node: '>=12'}
cpu: [ia32]
os: [linux]
+ '@esbuild/linux-ia32@0.23.0':
+ resolution: {integrity: sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [linux]
+
'@esbuild/linux-loong64@0.18.20':
resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==}
engines: {node: '>=12'}
@@ -2414,12 +2530,18 @@ packages:
cpu: [loong64]
os: [linux]
- '@esbuild/linux-loong64@0.20.2':
- resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==}
+ '@esbuild/linux-loong64@0.21.5':
+ resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==}
engines: {node: '>=12'}
cpu: [loong64]
os: [linux]
+ '@esbuild/linux-loong64@0.23.0':
+ resolution: {integrity: sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==}
+ engines: {node: '>=18'}
+ cpu: [loong64]
+ os: [linux]
+
'@esbuild/linux-mips64el@0.18.20':
resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==}
engines: {node: '>=12'}
@@ -2432,12 +2554,18 @@ packages:
cpu: [mips64el]
os: [linux]
- '@esbuild/linux-mips64el@0.20.2':
- resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==}
+ '@esbuild/linux-mips64el@0.21.5':
+ resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==}
engines: {node: '>=12'}
cpu: [mips64el]
os: [linux]
+ '@esbuild/linux-mips64el@0.23.0':
+ resolution: {integrity: sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==}
+ engines: {node: '>=18'}
+ cpu: [mips64el]
+ os: [linux]
+
'@esbuild/linux-ppc64@0.18.20':
resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==}
engines: {node: '>=12'}
@@ -2450,12 +2578,18 @@ packages:
cpu: [ppc64]
os: [linux]
- '@esbuild/linux-ppc64@0.20.2':
- resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==}
+ '@esbuild/linux-ppc64@0.21.5':
+ resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [linux]
+ '@esbuild/linux-ppc64@0.23.0':
+ resolution: {integrity: sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [linux]
+
'@esbuild/linux-riscv64@0.18.20':
resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==}
engines: {node: '>=12'}
@@ -2468,12 +2602,18 @@ packages:
cpu: [riscv64]
os: [linux]
- '@esbuild/linux-riscv64@0.20.2':
- resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==}
+ '@esbuild/linux-riscv64@0.21.5':
+ resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==}
engines: {node: '>=12'}
cpu: [riscv64]
os: [linux]
+ '@esbuild/linux-riscv64@0.23.0':
+ resolution: {integrity: sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==}
+ engines: {node: '>=18'}
+ cpu: [riscv64]
+ os: [linux]
+
'@esbuild/linux-s390x@0.18.20':
resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==}
engines: {node: '>=12'}
@@ -2486,12 +2626,18 @@ packages:
cpu: [s390x]
os: [linux]
- '@esbuild/linux-s390x@0.20.2':
- resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==}
+ '@esbuild/linux-s390x@0.21.5':
+ resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==}
engines: {node: '>=12'}
cpu: [s390x]
os: [linux]
+ '@esbuild/linux-s390x@0.23.0':
+ resolution: {integrity: sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==}
+ engines: {node: '>=18'}
+ cpu: [s390x]
+ os: [linux]
+
'@esbuild/linux-x64@0.18.20':
resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==}
engines: {node: '>=12'}
@@ -2504,12 +2650,18 @@ packages:
cpu: [x64]
os: [linux]
- '@esbuild/linux-x64@0.20.2':
- resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==}
+ '@esbuild/linux-x64@0.21.5':
+ resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
+ '@esbuild/linux-x64@0.23.0':
+ resolution: {integrity: sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [linux]
+
'@esbuild/netbsd-x64@0.18.20':
resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==}
engines: {node: '>=12'}
@@ -2522,12 +2674,24 @@ packages:
cpu: [x64]
os: [netbsd]
- '@esbuild/netbsd-x64@0.20.2':
- resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==}
+ '@esbuild/netbsd-x64@0.21.5':
+ resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==}
engines: {node: '>=12'}
cpu: [x64]
os: [netbsd]
+ '@esbuild/netbsd-x64@0.23.0':
+ resolution: {integrity: sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [netbsd]
+
+ '@esbuild/openbsd-arm64@0.23.0':
+ resolution: {integrity: sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openbsd]
+
'@esbuild/openbsd-x64@0.18.20':
resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==}
engines: {node: '>=12'}
@@ -2540,12 +2704,18 @@ packages:
cpu: [x64]
os: [openbsd]
- '@esbuild/openbsd-x64@0.20.2':
- resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==}
+ '@esbuild/openbsd-x64@0.21.5':
+ resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==}
engines: {node: '>=12'}
cpu: [x64]
os: [openbsd]
+ '@esbuild/openbsd-x64@0.23.0':
+ resolution: {integrity: sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [openbsd]
+
'@esbuild/sunos-x64@0.18.20':
resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==}
engines: {node: '>=12'}
@@ -2558,12 +2728,18 @@ packages:
cpu: [x64]
os: [sunos]
- '@esbuild/sunos-x64@0.20.2':
- resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==}
+ '@esbuild/sunos-x64@0.21.5':
+ resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==}
engines: {node: '>=12'}
cpu: [x64]
os: [sunos]
+ '@esbuild/sunos-x64@0.23.0':
+ resolution: {integrity: sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [sunos]
+
'@esbuild/win32-arm64@0.18.20':
resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==}
engines: {node: '>=12'}
@@ -2576,12 +2752,18 @@ packages:
cpu: [arm64]
os: [win32]
- '@esbuild/win32-arm64@0.20.2':
- resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==}
+ '@esbuild/win32-arm64@0.21.5':
+ resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==}
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
+ '@esbuild/win32-arm64@0.23.0':
+ resolution: {integrity: sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [win32]
+
'@esbuild/win32-ia32@0.18.20':
resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==}
engines: {node: '>=12'}
@@ -2594,12 +2776,18 @@ packages:
cpu: [ia32]
os: [win32]
- '@esbuild/win32-ia32@0.20.2':
- resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==}
+ '@esbuild/win32-ia32@0.21.5':
+ resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==}
engines: {node: '>=12'}
cpu: [ia32]
os: [win32]
+ '@esbuild/win32-ia32@0.23.0':
+ resolution: {integrity: sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [win32]
+
'@esbuild/win32-x64@0.18.20':
resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==}
engines: {node: '>=12'}
@@ -2612,37 +2800,51 @@ packages:
cpu: [x64]
os: [win32]
- '@esbuild/win32-x64@0.20.2':
- resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==}
+ '@esbuild/win32-x64@0.21.5':
+ resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==}
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
+ '@esbuild/win32-x64@0.23.0':
+ resolution: {integrity: sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [win32]
+
'@eslint-community/eslint-utils@4.4.0':
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
- '@eslint-community/regexpp@4.10.0':
- resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==}
+ '@eslint-community/regexpp@4.11.0':
+ resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
'@eslint-community/regexpp@4.6.2':
resolution: {integrity: sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
- '@eslint/eslintrc@2.1.4':
- resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ '@eslint/compat@1.1.1':
+ resolution: {integrity: sha512-lpHyRyplhGPL5mGEh6M9O5nnKk0Gz4bFI+Zu6tKlPpDUN7XshWvH9C/px4UVm87IAANE0W81CEsNGbS1KlzXpA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@eslint/js@8.53.0':
- resolution: {integrity: sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ '@eslint/config-array@0.17.1':
+ resolution: {integrity: sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@eslint/js@8.57.0':
- resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ '@eslint/eslintrc@3.1.0':
+ resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/js@9.8.0':
+ resolution: {integrity: sha512-MfluB7EUfxXtv3i/++oh89uzAr4PDI4nn201hsp+qaXqsjAWzinlZEHEfPgAX4doIlKvPG/i0A9dpKxOLII8yA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/object-schema@2.1.4':
+ resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@fal-works/esbuild-plugin-global-externals@2.1.2':
resolution: {integrity: sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ==}
@@ -2682,8 +2884,8 @@ packages:
'@fastify/http-proxy@9.5.0':
resolution: {integrity: sha512-1iqIdV10d5k9YtfHq9ylX5zt1NiM50fG+rIX40qt00R694sqWso3ukyTFZVk33SDoSiBW8roB7n11RUVUoN+Ag==}
- '@fastify/multipart@8.2.0':
- resolution: {integrity: sha512-OZ8nsyyoS2TV7Yeu3ZdrdDGsKUTAbfjrKC9jSxGgT2qdgek+BxpWX31ZubTrWMNZyU5xwk4ox6AvTjAbYWjrWg==}
+ '@fastify/multipart@8.3.0':
+ resolution: {integrity: sha512-A8h80TTyqUzaMVH0Cr9Qcm6RxSkVqmhK/MVBYHYeRRSUbUYv08WecjWKSlG2aSnD4aGI841pVxAjC+G1GafUeQ==}
'@fastify/reply-from@9.0.1':
resolution: {integrity: sha512-q9vFNUiXZTY1x8omDPe59os2MYq+3y7KgO/kZoXpZlnud+45Nd8Ot/svEvrUATzjkizIggfS4K8LR9zXDyZZKg==}
@@ -2694,8 +2896,8 @@ packages:
'@fastify/static@6.12.0':
resolution: {integrity: sha512-KK1B84E6QD/FcQWxDI2aiUCwHxMJBI1KeCUzm1BwYpPY1b742+jeKruGHP2uOluuM6OkBPI8CIANrXcCRtC2oQ==}
- '@fastify/static@7.0.3':
- resolution: {integrity: sha512-2tmTdF+uFCykasutaO6k4/wOt7eXyi7m3dGuCPo5micXzv0qt6ttb/nWnDYL/BlXjYGfp1JI4a1gyluTIylvQA==}
+ '@fastify/static@7.0.4':
+ resolution: {integrity: sha512-p2uKtaf8BMOZWLs6wu+Ihg7bWNBdjNgCwDza4MJtTqg+5ovKmcbgbR9Xs5/smZ1YISfzKOCNYmZV8LaCj+eJ1Q==}
'@fastify/view@8.2.0':
resolution: {integrity: sha512-hBSiBofCnJNlPHEMZWpO1SL84eqOaqujJ1hR3jntFyZZCkweH5jMs12DKYyGesjVll7SJFRRxPUBB8kmUmneRQ==}
@@ -2713,11 +2915,8 @@ packages:
'@hapi/bourne@3.0.0':
resolution: {integrity: sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==}
- '@hapi/hoek@10.0.1':
- resolution: {integrity: sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==}
-
- '@hapi/hoek@11.0.2':
- resolution: {integrity: sha512-aKmlCO57XFZ26wso4rJsW4oTUnrgTFw2jh3io7CAtO9w4UltBNwRXvXIVzzyfkaaLRo3nluP/19msA8vDUUuKw==}
+ '@hapi/hoek@11.0.4':
+ resolution: {integrity: sha512-PnsP5d4q7289pS2T2EgGz147BFJ2Jpb4yrEdkpz2IhgEUzos1S7HTl7ezWh1yfYzYlj89KzLdCRkqsP6SIryeQ==}
'@hapi/hoek@9.3.0':
resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==}
@@ -2731,14 +2930,6 @@ packages:
'@hexagon/base64@1.1.27':
resolution: {integrity: sha512-PdUmzpvcUM3Rh39kvz9RdbPVYhMjBjdV7Suw7ZduP7urRLsZR8l5tzgSWKm7TExwBYDFwTnYrZbnE0rQ3N5NLQ==}
- '@humanwhocodes/config-array@0.11.13':
- resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==}
- engines: {node: '>=10.10.0'}
-
- '@humanwhocodes/config-array@0.11.14':
- resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==}
- engines: {node: '>=10.10.0'}
-
'@humanwhocodes/module-importer@1.0.1':
resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
engines: {node: '>=12.22'}
@@ -2747,20 +2938,18 @@ packages:
resolution: {integrity: sha512-RE815I4arJFtt+FVeU1Tgp9/Xvecacji8w/V6XtXsWWH/wz/eNkNbhb+ny/+PlVZjV0rxQpRSQKNKE3lcktHEA==}
engines: {node: '>=10.10.0'}
- '@humanwhocodes/object-schema@2.0.1':
- resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==}
-
- '@humanwhocodes/object-schema@2.0.2':
- resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==}
+ '@humanwhocodes/retry@0.3.0':
+ resolution: {integrity: sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==}
+ engines: {node: '>=18.18'}
- '@img/sharp-darwin-arm64@0.33.3':
- resolution: {integrity: sha512-FaNiGX1MrOuJ3hxuNzWgsT/mg5OHG/Izh59WW2mk1UwYHUwtfbhk5QNKYZgxf0pLOhx9ctGiGa2OykD71vOnSw==}
+ '@img/sharp-darwin-arm64@0.33.4':
+ resolution: {integrity: sha512-p0suNqXufJs9t3RqLBO6vvrgr5OhgbWp76s5gTRvdmxmuv9E1rcaqGUsl3l4mKVmXPkTkTErXediAui4x+8PSA==}
engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [arm64]
os: [darwin]
- '@img/sharp-darwin-x64@0.33.3':
- resolution: {integrity: sha512-2QeSl7QDK9ru//YBT4sQkoq7L0EAJZA3rtV+v9p8xTKl4U1bUqTIaCnoC7Ctx2kCjQgwFXDasOtPTCT8eCTXvw==}
+ '@img/sharp-darwin-x64@0.33.4':
+ resolution: {integrity: sha512-0l7yRObwtTi82Z6ebVI2PnHT8EB2NxBgpK2MiKJZJ7cz32R4lxd001ecMhzzsZig3Yv9oclvqqdV93jo9hy+Dw==}
engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [x64]
os: [darwin]
@@ -2813,55 +3002,55 @@ packages:
cpu: [x64]
os: [linux]
- '@img/sharp-linux-arm64@0.33.3':
- resolution: {integrity: sha512-Zf+sF1jHZJKA6Gor9hoYG2ljr4wo9cY4twaxgFDvlG0Xz9V7sinsPp8pFd1XtlhTzYo0IhDbl3rK7P6MzHpnYA==}
+ '@img/sharp-linux-arm64@0.33.4':
+ resolution: {integrity: sha512-2800clwVg1ZQtxwSoTlHvtm9ObgAax7V6MTAB/hDT945Tfyy3hVkmiHpeLPCKYqYR1Gcmv1uDZ3a4OFwkdBL7Q==}
engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [arm64]
os: [linux]
- '@img/sharp-linux-arm@0.33.3':
- resolution: {integrity: sha512-Q7Ee3fFSC9P7vUSqVEF0zccJsZ8GiiCJYGWDdhEjdlOeS9/jdkyJ6sUSPj+bL8VuOYFSbofrW0t/86ceVhx32w==}
+ '@img/sharp-linux-arm@0.33.4':
+ resolution: {integrity: sha512-RUgBD1c0+gCYZGCCe6mMdTiOFS0Zc/XrN0fYd6hISIKcDUbAW5NtSQW9g/powkrXYm6Vzwd6y+fqmExDuCdHNQ==}
engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [arm]
os: [linux]
- '@img/sharp-linux-s390x@0.33.3':
- resolution: {integrity: sha512-vFk441DKRFepjhTEH20oBlFrHcLjPfI8B0pMIxGm3+yilKyYeHEVvrZhYFdqIseSclIqbQ3SnZMwEMWonY5XFA==}
- engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+ '@img/sharp-linux-s390x@0.33.4':
+ resolution: {integrity: sha512-h3RAL3siQoyzSoH36tUeS0PDmb5wINKGYzcLB5C6DIiAn2F3udeFAum+gj8IbA/82+8RGCTn7XW8WTFnqag4tQ==}
+ engines: {glibc: '>=2.31', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [s390x]
os: [linux]
- '@img/sharp-linux-x64@0.33.3':
- resolution: {integrity: sha512-Q4I++herIJxJi+qmbySd072oDPRkCg/SClLEIDh5IL9h1zjhqjv82H0Seupd+q2m0yOfD+/fJnjSoDFtKiHu2g==}
+ '@img/sharp-linux-x64@0.33.4':
+ resolution: {integrity: sha512-GoR++s0XW9DGVi8SUGQ/U4AeIzLdNjHka6jidVwapQ/JebGVQIpi52OdyxCNVRE++n1FCLzjDovJNozif7w/Aw==}
engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [x64]
os: [linux]
- '@img/sharp-linuxmusl-arm64@0.33.3':
- resolution: {integrity: sha512-qnDccehRDXadhM9PM5hLvcPRYqyFCBN31kq+ErBSZtZlsAc1U4Z85xf/RXv1qolkdu+ibw64fUDaRdktxTNP9A==}
+ '@img/sharp-linuxmusl-arm64@0.33.4':
+ resolution: {integrity: sha512-nhr1yC3BlVrKDTl6cO12gTpXMl4ITBUZieehFvMntlCXFzH2bvKG76tBL2Y/OqhupZt81pR7R+Q5YhJxW0rGgQ==}
engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [arm64]
os: [linux]
- '@img/sharp-linuxmusl-x64@0.33.3':
- resolution: {integrity: sha512-Jhchim8kHWIU/GZ+9poHMWRcefeaxFIs9EBqf9KtcC14Ojk6qua7ghKiPs0sbeLbLj/2IGBtDcxHyjCdYWkk2w==}
+ '@img/sharp-linuxmusl-x64@0.33.4':
+ resolution: {integrity: sha512-uCPTku0zwqDmZEOi4ILyGdmW76tH7dm8kKlOIV1XC5cLyJ71ENAAqarOHQh0RLfpIpbV5KOpXzdU6XkJtS0daw==}
engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [x64]
os: [linux]
- '@img/sharp-wasm32@0.33.3':
- resolution: {integrity: sha512-68zivsdJ0koE96stdUfM+gmyaK/NcoSZK5dV5CAjES0FUXS9lchYt8LAB5rTbM7nlWtxaU/2GON0HVN6/ZYJAQ==}
+ '@img/sharp-wasm32@0.33.4':
+ resolution: {integrity: sha512-Bmmauh4sXUsUqkleQahpdNXKvo+wa1V9KhT2pDA4VJGKwnKMJXiSTGphn0gnJrlooda0QxCtXc6RX1XAU6hMnQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [wasm32]
- '@img/sharp-win32-ia32@0.33.3':
- resolution: {integrity: sha512-CyimAduT2whQD8ER4Ux7exKrtfoaUiVr7HG0zZvO0XTFn2idUWljjxv58GxNTkFb8/J9Ub9AqITGkJD6ZginxQ==}
+ '@img/sharp-win32-ia32@0.33.4':
+ resolution: {integrity: sha512-99SJ91XzUhYHbx7uhK3+9Lf7+LjwMGQZMDlO/E/YVJ7Nc3lyDFZPGhjwiYdctoH2BOzW9+TnfqcaMKt0jHLdqw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [ia32]
os: [win32]
- '@img/sharp-win32-x64@0.33.3':
- resolution: {integrity: sha512-viT4fUIDKnli3IfOephGnolMzhz5VaTvDRkYqtZxOMIoMQ4MrAziO7pT1nVnOt2FAm7qW5aa+CCc13aEY6Le0g==}
+ '@img/sharp-win32-x64@0.33.4':
+ resolution: {integrity: sha512-3QLocdTRVIrFNye5YocZl+KKpYKP+fksi1QhmOArgx7GyhIbQp/WrJRu176jm8IxromS7RIkzMiMINVdBtC8Aw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [x64]
os: [win32]
@@ -2979,8 +3168,8 @@ packages:
resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- '@joshwooding/vite-plugin-react-docgen-typescript@0.3.0':
- resolution: {integrity: sha512-2D6y7fNvFmsLmRt6UCOFJPvFoPMJGT0Uh1Wg0RaigUp7kdQPs6yYn8Dmx6GZkOH/NW0yMTwRz/p0SRMMRo50vA==}
+ '@joshwooding/vite-plugin-react-docgen-typescript@0.3.1':
+ resolution: {integrity: sha512-pdoMZ9QaPnVlSM+SdU/wgg0nyD/8wQ7y90ttO2CMCyrrm7RxveYIJ5eNfjPaoMFqW41LZra7QO9j+xV4Y18Glw==}
peerDependencies:
typescript: '>= 4.3.x'
vite: ^3.0.0 || ^4.0.0 || ^5.0.0
@@ -2992,6 +3181,10 @@ packages:
resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==}
engines: {node: '>=6.0.0'}
+ '@jridgewell/gen-mapping@0.3.5':
+ resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
+ engines: {node: '>=6.0.0'}
+
'@jridgewell/resolve-uri@3.1.0':
resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==}
engines: {node: '>=6.0.0'}
@@ -3000,8 +3193,12 @@ packages:
resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==}
engines: {node: '>=6.0.0'}
- '@jridgewell/source-map@0.3.5':
- resolution: {integrity: sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==}
+ '@jridgewell/set-array@1.2.1':
+ resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/source-map@0.3.6':
+ resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==}
'@jridgewell/sourcemap-codec@1.4.14':
resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==}
@@ -3012,6 +3209,9 @@ packages:
'@jridgewell/trace-mapping@0.3.18':
resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==}
+ '@jridgewell/trace-mapping@0.3.25':
+ resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
+
'@jsdevtools/ono@7.1.3':
resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==}
@@ -3045,29 +3245,31 @@ packages:
'@types/react': '>=16'
react: '>=16'
- '@microsoft/api-extractor-model@7.28.14':
- resolution: {integrity: sha512-Bery/c8A8SsKPSvA82cTTuy/+OcxZbLRmKhPkk91/AJOQzxZsShcrmHFAGeiEqSIrv1nPZ3tKq9kfMLdCHmsqg==}
+ '@microsoft/api-extractor-model@7.29.4':
+ resolution: {integrity: sha512-LHOMxmT8/tU1IiiiHOdHFF83Qsi+V8d0kLfscG4EvQE9cafiR8blOYr8SfkQKWB1wgEilQgXJX3MIA4vetDLZw==}
- '@microsoft/api-extractor@7.43.1':
- resolution: {integrity: sha512-ohg40SsvFFgzHFAtYq5wKJc8ZDyY46bphjtnSvhSSlXpPTG7GHwyyXkn48UZiUCBwr2WC7TRC1Jfwz7nreuiyQ==}
+ '@microsoft/api-extractor@7.47.4':
+ resolution: {integrity: sha512-HKm+P4VNzWwvq1Ey+Jfhhj/3MjsD+ka2hbt8L5AcRM95lu1MFOYnz3XlU7Gr79Q/ZhOb7W/imAKeYrOI0bFydg==}
hasBin: true
- '@microsoft/tsdoc-config@0.16.2':
- resolution: {integrity: sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==}
+ '@microsoft/tsdoc-config@0.17.0':
+ resolution: {integrity: sha512-v/EYRXnCAIHxOHW+Plb6OWuUoMotxTN0GLatnpOb1xq0KuTNw/WI3pamJx/UbsoJP5k9MCw1QxvvhPcF9pH3Zg==}
- '@microsoft/tsdoc@0.14.2':
- resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==}
+ '@microsoft/tsdoc@0.15.0':
+ resolution: {integrity: sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA==}
'@misskey-dev/browser-image-resizer@2024.1.0':
resolution: {integrity: sha512-4EnO0zLW5NDtng3Gaz5MuT761uiuoOuplwX18wBqgj8w56LTU5BjLn/vbHwDIIe0j2gwqDYhMb7bDjmr1/Fomg==}
- '@misskey-dev/eslint-plugin@1.0.0':
- resolution: {integrity: sha512-dh6UbcrNDVg5DD8k8Qh4ab30OPpuEYIlJCqaBV/lkIV8wNN/AfCJ2V7iTP8V8KjryM4t+sf5IqzQLQnT0mWI4A==}
+ '@misskey-dev/eslint-plugin@2.0.2':
+ resolution: {integrity: sha512-bnTqxCSP0CIN0xSpIGib13bz+K8/3e4h8OlQjuCPlhZF7oFwtn339EZM8yJkHg6gdfciV8KOr3gzlLyG3jiVEQ==}
peerDependencies:
- '@typescript-eslint/eslint-plugin': '>= 6'
- '@typescript-eslint/parser': '>= 6'
- eslint: '>= 3'
+ '@eslint/compat': '>= 1'
+ '@typescript-eslint/eslint-plugin': '>= 7'
+ '@typescript-eslint/parser': '>= 7'
+ eslint: '>= 8'
eslint-plugin-import: '>= 2'
+ globals: '>= 15'
'@misskey-dev/sharp-read-bmp@1.2.0':
resolution: {integrity: sha512-er4pRakXzHYfEgOFAFfQagqDouG+wLm+kwNq1I30oSdIHDa0wM3KjFpfIGQ25Fks4GcmOl1s7Zh6xoQu5dNjTw==}
@@ -3109,77 +3311,70 @@ packages:
cpu: [x64]
os: [win32]
- '@mswjs/cookies@1.1.0':
- resolution: {integrity: sha512-0ZcCVQxifZmhwNBoQIrystCb+2sWBY2Zw8lpfJBPCHGCA/HWqehITeCRVIv4VMy8MPlaHo2w2pTHFV2pFfqKPw==}
+ '@mswjs/interceptors@0.29.1':
+ resolution: {integrity: sha512-3rDakgJZ77+RiQUuSK69t1F0m8BQKA8Vh5DCS5V0DWvNY67zob2JhhQrhCO0AKLGINTRSFd1tBaHcJTkhefoSw==}
engines: {node: '>=18'}
- '@mswjs/interceptors@0.26.15':
- resolution: {integrity: sha512-HM47Lu1YFmnYHKMBynFfjCp0U/yRskHj/8QEJW0CBEPOlw8Gkmjfll+S9b8M7V5CNDw2/ciRxjjnWeaCiblSIQ==}
- engines: {node: '>=18'}
-
- '@napi-rs/canvas-android-arm64@0.1.52':
- resolution: {integrity: sha512-x/K471KbASPVh5mfBUxokza66J0FNIlOgMNANWAf5C8HiATb487KecEhSkUQvvTS3WLYC9uSqIPHFgwF+tir3w==}
+ '@napi-rs/canvas-android-arm64@0.1.53':
+ resolution: {integrity: sha512-2YhxfVsZguATlRWE0fZdTx35SE9+r5D7HV5GPNDataZOKmHf+zZ5//dspuuBSbOriQdoicaFrgXKCUqI0pK3WQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [android]
- '@napi-rs/canvas-darwin-arm64@0.1.52':
- resolution: {integrity: sha512-4OgVRD7TW02q5Q7lWLLjT+pYJ9ZHkQUTBOuXbPQ5wB0Wnh3RIq/aMY6thoXDZDzdR5vV3a5TUtbZUJ0aqLq3NA==}
+ '@napi-rs/canvas-darwin-arm64@0.1.53':
+ resolution: {integrity: sha512-ls+CWLMusf4RAGo5BvIIzA6dNcc0elwVp6LKjHfQECHA8KKmvdB58YuE5BQcTlb2rzk0SEKtBC/Th3NI2oNdfg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
- '@napi-rs/canvas-darwin-x64@0.1.52':
- resolution: {integrity: sha512-3fgeGJ3j2X6Mtmn0QYf3iA+A6y1ePnsayakc2emEokzf03ErrPczONw3vjnTQo53JLPMzEnfPGAffdktU/ssPA==}
+ '@napi-rs/canvas-darwin-x64@0.1.53':
+ resolution: {integrity: sha512-ZAgcoCH5+5OKS2P8Lxx+jbkAPKkyLD2x6OvSrHg1U6ppdxmLA+CkJlRl8w45HCXwuyIiP7OeymECRtiNYTwznQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
- '@napi-rs/canvas-linux-arm-gnueabihf@0.1.52':
- resolution: {integrity: sha512-aaDEEK5XwHUrPt0q4SR8l7Va0vtn50KmSs+itxP+o7RNk3Nuch8fINHOXyhMyhwNYgv1tfiJVyHsJhD0E6lXGA==}
+ '@napi-rs/canvas-linux-arm-gnueabihf@0.1.53':
+ resolution: {integrity: sha512-p9km/3C/loDxu3AvA8/vtpIS1BGMd/Ehkl2Iu/v/Gw8N/KUIt3HUvTS7AKApyVE28bxTfq96wJQjtcT8jzDncw==}
engines: {node: '>= 10'}
cpu: [arm]
os: [linux]
- '@napi-rs/canvas-linux-arm64-gnu@0.1.52':
- resolution: {integrity: sha512-tzuwM7Amt5mkrp4csQjYWkFzwFdiCm7RNdJ5usX8syzKSXmozqWzLHjzo/2ozdSQNUy6wyzRrxkG4Rh6g0OpOA==}
+ '@napi-rs/canvas-linux-arm64-gnu@0.1.53':
+ resolution: {integrity: sha512-QKK+sykEiYwjwd+ogyLcpcnH38DNZ8KViBlnfEpoGA2Wa+21/cWQKfMxnbgb/rbvm5tazJinZcihFvH577WQ5g==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
- '@napi-rs/canvas-linux-arm64-musl@0.1.52':
- resolution: {integrity: sha512-HQCtJlDT0dFp3uUZVzZOZ1VLMO7lbLRc548MjMxPpojit2ZdGopFzJ8jDSr4iszHrTO1SM1AxPaCM3pRvCAtjw==}
+ '@napi-rs/canvas-linux-arm64-musl@0.1.53':
+ resolution: {integrity: sha512-2N41U0X8RnrTKzpTtPv1ozlYkJtPsUdbfF3uP/KEd/BsULGd8Y8ghkGMS6CM+821au4ex0dPrWOOdT9wC1rSqQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
- '@napi-rs/canvas-linux-x64-gnu@0.1.52':
- resolution: {integrity: sha512-z5sBEw0PVWPH/MIQL8hOR8C3YYVlu8lqtRUcYajigMfXAhbMiNqDWTjuIWGMz3nIydDjZmn8KTxw/D4a0HFPqQ==}
+ '@napi-rs/canvas-linux-x64-gnu@0.1.53':
+ resolution: {integrity: sha512-7XjuTvDKCODtf/vMwF43VGDrjfgwYKgS91ggdcX3UrJaBYWyWu/+eqNvNj+zdXSe/0x+YOjf5jG4m8xIXdBMQA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
- '@napi-rs/canvas-linux-x64-musl@0.1.52':
- resolution: {integrity: sha512-G1+JdWFhHLyHhULJS51xTEhB7EL0ZiAUQwQaRi4/w75OOYDQ91O+o4miaxDHiV0hZuxBhHtZU6ftV2Zl3RMguw==}
+ '@napi-rs/canvas-linux-x64-musl@0.1.53':
+ resolution: {integrity: sha512-970WEvB8vmj+uxvgdBZ+AGFV7uq9GJhXrqG5PGQ5lWciHX0P0d/OhS2F7TITgFR0LsKDQZ7XQgzMxsYOfwZ0FQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
- '@napi-rs/canvas-win32-x64-msvc@0.1.52':
- resolution: {integrity: sha512-hMI626VsCC/wv29qHF78N7TSG+auatOp08DHln0Zdif5y1NJ14NU/rNUhzlTW8Zc6ssw+AMDJ3KKYYWYYg1aoA==}
+ '@napi-rs/canvas-win32-x64-msvc@0.1.53':
+ resolution: {integrity: sha512-rLFQCSJaWg/sv54Aap9nAhaodi4Vyb4un50EgW+PNkk8icMziU6KLRKirGBdQr9ZdxnshAPeQXD1g2ArStujKA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
- '@napi-rs/canvas@0.1.52':
- resolution: {integrity: sha512-xeW9EghZLDPZuqWJ4l1+eG3ld0i9J7SpV2zlgi34MPt/FE9K2XWGCfnLr0gHGOBkcI3YOVhI13I0HqRAkMPdVw==}
+ '@napi-rs/canvas@0.1.53':
+ resolution: {integrity: sha512-XsEZi97+kKykmAiPpY+IpZoHxJY1srqFZp8jDt1/RySzC0kB0iZYt/VMIFqQKpLCARZjD7SOAz2AULtwYlesCA==}
engines: {node: '>= 10'}
- '@ndelangen/get-tarball@3.0.7':
- resolution: {integrity: sha512-NqGfTZIZpRFef1GoVaShSSRwDC3vde3ThtTeqFdcYd6ipKqnfEVhjK2hUeHjCQUcptyZr2TONqcloFXM+5QBrQ==}
-
- '@nestjs/common@10.3.8':
- resolution: {integrity: sha512-P+vPEIvqx2e+fonsYVlFXKvoChyJ8Tq+lfpqdVFqblovHbFr3kZ/nYX0cPs+XuW6bnRT8tz0SSR9XBGU43kJhw==}
+ '@nestjs/common@10.3.10':
+ resolution: {integrity: sha512-H8k0jZtxk1IdtErGDmxFRy0PfcOAUg41Prrqpx76DQusGGJjsaovs1zjXVD1rZWaVYchfT1uczJ6L4Kio10VNg==}
peerDependencies:
class-transformer: '*'
class-validator: '*'
@@ -3191,8 +3386,8 @@ packages:
class-validator:
optional: true
- '@nestjs/core@10.3.8':
- resolution: {integrity: sha512-AxF4tpYLDNn5Wfb3C4bNaaHJ4pREH5FJrSisR2A5zkYpQFORFs0Tc36lOFPMwBTy8Iv2wUwWLUVc5ftBnxEv4w==}
+ '@nestjs/core@10.3.10':
+ resolution: {integrity: sha512-ZbQ4jovQyzHtCGCrzK5NdtW1SYO2fHSsgSY1+/9WdruYCUra+JDkWEXgZ4M3Hv480Dl3OXehAmY1wCOojeMyMQ==}
peerDependencies:
'@nestjs/common': ^10.0.0
'@nestjs/microservices': ^10.0.0
@@ -3208,14 +3403,14 @@ packages:
'@nestjs/websockets':
optional: true
- '@nestjs/platform-express@10.3.8':
- resolution: {integrity: sha512-sifLoxgEJvAgbim1UuW6wyScMfkS9SVQRH+lN33N/9ZvZSjO6NSDLOe+wxqsnZkia+QrjFC0qy0ITRAsggfqbg==}
+ '@nestjs/platform-express@10.3.10':
+ resolution: {integrity: sha512-wK2ow3CZI2KFqWeEpPmoR300OB6BcBLxARV1EiClJLCj4S1mZsoCmS0YWgpk3j1j6mo0SI8vNLi/cC2iZPEPQA==}
peerDependencies:
'@nestjs/common': ^10.0.0
'@nestjs/core': ^10.0.0
- '@nestjs/testing@10.3.8':
- resolution: {integrity: sha512-hpX9das2TdFTKQ4/2ojhjI6YgXtCfXRKui3A4Qaj54VVzc5+mtK502Jj18Vzji98o9MVS6skmYu+S/UvW3U6Fw==}
+ '@nestjs/testing@10.3.10':
+ resolution: {integrity: sha512-i3HAtVQJijxNxJq1k39aelyJlyEIBRONys7IipH/4r8W0J+M1V+y5EKDOyi4j1SdNSb/vmNyWpZ2/ewZjl3kRA==}
peerDependencies:
'@nestjs/common': ^10.0.0
'@nestjs/core': ^10.0.0
@@ -3227,6 +3422,10 @@ packages:
'@nestjs/platform-express':
optional: true
+ '@noble/hashes@1.4.0':
+ resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==}
+ engines: {node: '>= 16'}
+
'@nodelib/fs.scandir@2.1.5':
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@@ -3270,19 +3469,19 @@ packages:
'@open-draft/until@2.1.0':
resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==}
- '@opentelemetry/api-logs@0.51.1':
- resolution: {integrity: sha512-E3skn949Pk1z2XtXu/lxf6QAZpawuTM/IUEXcAzpiUkTd73Hmvw26FiN3cJuTmkpM5hZzHwkomVdtrh/n/zzwA==}
+ '@opentelemetry/api-logs@0.52.1':
+ resolution: {integrity: sha512-qnSqB2DQ9TPP96dl8cDubDvrUyWc0/sK81xHTK8eSUspzDM3bsewX903qclQFvVhgStjRWdC5bLb3kQqMkfV5A==}
engines: {node: '>=14'}
- '@opentelemetry/api@1.8.0':
- resolution: {integrity: sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w==}
+ '@opentelemetry/api@1.9.0':
+ resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
engines: {node: '>=8.0.0'}
- '@opentelemetry/context-async-hooks@1.24.1':
- resolution: {integrity: sha512-R5r6DO4kgEOVBxFXhXjwospLQkv+sYxwCfjvoZBe7Zm6KKXAV9kDSJhi/D1BweowdZmO+sdbENLs374gER8hpQ==}
+ '@opentelemetry/context-async-hooks@1.25.1':
+ resolution: {integrity: sha512-UW/ge9zjvAEmRWVapOP0qyCvPulWU6cQxGxDbWEFfGOj1VBBZAuOqTo3X6yWmDTD3Xe15ysCZChHncr2xFMIfQ==}
engines: {node: '>=14'}
peerDependencies:
- '@opentelemetry/api': '>=1.0.0 <1.9.0'
+ '@opentelemetry/api': '>=1.0.0 <1.10.0'
'@opentelemetry/core@1.24.1':
resolution: {integrity: sha512-wMSGfsdmibI88K9wB498zXY04yThPexo8jvwNNlm542HZB7XrrMRBbAyKJqG8qDRJwIBdBrPMi4V9ZPW/sqrcg==}
@@ -3290,98 +3489,110 @@ packages:
peerDependencies:
'@opentelemetry/api': '>=1.0.0 <1.9.0'
- '@opentelemetry/instrumentation-connect@0.36.0':
- resolution: {integrity: sha512-k9++bmJZ9zDEs3u3DnKTn2l7QTiNFg3gPx7G9rW0TPnP+xZoBSBTrEcGYBaqflQlrFG23Q58+X1sM2ayWPv5Fg==}
+ '@opentelemetry/core@1.25.1':
+ resolution: {integrity: sha512-GeT/l6rBYWVQ4XArluLVB6WWQ8flHbdb6r2FCHC3smtdOAbrJBIv35tpV/yp9bmYUJf+xmZpu9DRTIeJVhFbEQ==}
+ engines: {node: '>=14'}
+ peerDependencies:
+ '@opentelemetry/api': '>=1.0.0 <1.10.0'
+
+ '@opentelemetry/instrumentation-connect@0.38.0':
+ resolution: {integrity: sha512-2/nRnx3pjYEmdPIaBwtgtSviTKHWnDZN3R+TkRUnhIVrvBKVcq+I5B2rtd6mr6Fe9cHlZ9Ojcuh7pkNh/xdWWg==}
+ engines: {node: '>=14'}
+ peerDependencies:
+ '@opentelemetry/api': ^1.3.0
+
+ '@opentelemetry/instrumentation-express@0.41.0':
+ resolution: {integrity: sha512-/B7fbMdaf3SYe5f1P973tkqd6s7XZirjpfkoJ63E7nltU30qmlgm9tY5XwZOzAFI0rHS9tbrFI2HFPAvQUFe/A==}
engines: {node: '>=14'}
peerDependencies:
'@opentelemetry/api': ^1.3.0
- '@opentelemetry/instrumentation-express@0.39.0':
- resolution: {integrity: sha512-AG8U7z7D0JcBu/7dDcwb47UMEzj9/FMiJV2iQZqrsZnxR3FjB9J9oIH2iszJYci2eUdp2WbdvtpD9RV/zmME5A==}
+ '@opentelemetry/instrumentation-fastify@0.38.0':
+ resolution: {integrity: sha512-HBVLpTSYpkQZ87/Df3N0gAw7VzYZV3n28THIBrJWfuqw3Or7UqdhnjeuMIPQ04BKk3aZc0cWn2naSQObbh5vXw==}
engines: {node: '>=14'}
peerDependencies:
'@opentelemetry/api': ^1.3.0
- '@opentelemetry/instrumentation-fastify@0.36.1':
- resolution: {integrity: sha512-3Nfm43PI0I+3EX+1YbSy6xbDu276R1Dh1tqAk68yd4yirnIh52Kd5B+nJ8CgHA7o3UKakpBjj6vSzi5vNCzJIA==}
+ '@opentelemetry/instrumentation-graphql@0.42.0':
+ resolution: {integrity: sha512-N8SOwoKL9KQSX7z3gOaw5UaTeVQcfDO1c21csVHnmnmGUoqsXbArK2B8VuwPWcv6/BC/i3io+xTo7QGRZ/z28Q==}
engines: {node: '>=14'}
peerDependencies:
'@opentelemetry/api': ^1.3.0
- '@opentelemetry/instrumentation-graphql@0.40.0':
- resolution: {integrity: sha512-LVRdEHWACWOczv2imD+mhUrLMxsEjPPi32vIZJT57zygR5aUiA4em8X3aiGOCycgbMWkIu8xOSGSxdx3JmzN+w==}
+ '@opentelemetry/instrumentation-hapi@0.40.0':
+ resolution: {integrity: sha512-8U/w7Ifumtd2bSN1OLaSwAAFhb9FyqWUki3lMMB0ds+1+HdSxYBe9aspEJEgvxAqOkrQnVniAPTEGf1pGM7SOw==}
engines: {node: '>=14'}
peerDependencies:
'@opentelemetry/api': ^1.3.0
- '@opentelemetry/instrumentation-hapi@0.38.0':
- resolution: {integrity: sha512-ZcOqEuwuutTDYIjhDIStix22ECblG/i9pHje23QGs4Q4YS4RMaZ5hKCoQJxW88Z4K7T53rQkdISmoXFKDV8xMg==}
+ '@opentelemetry/instrumentation-http@0.52.1':
+ resolution: {integrity: sha512-dG/aevWhaP+7OLv4BQQSEKMJv8GyeOp3Wxl31NHqE8xo9/fYMfEljiZphUHIfyg4gnZ9swMyWjfOQs5GUQe54Q==}
engines: {node: '>=14'}
peerDependencies:
'@opentelemetry/api': ^1.3.0
- '@opentelemetry/instrumentation-http@0.51.1':
- resolution: {integrity: sha512-6b3nZnFFEz/3xZ6w8bVxctPUWIPWiXuPQ725530JgxnN1cvYFd8CJ75PrHZNjynmzSSnqBkN3ef4R9N+RpMh8Q==}
+ '@opentelemetry/instrumentation-ioredis@0.42.0':
+ resolution: {integrity: sha512-P11H168EKvBB9TUSasNDOGJCSkpT44XgoM6d3gRIWAa9ghLpYhl0uRkS8//MqPzcJVHr3h3RmfXIpiYLjyIZTw==}
engines: {node: '>=14'}
peerDependencies:
'@opentelemetry/api': ^1.3.0
- '@opentelemetry/instrumentation-ioredis@0.40.0':
- resolution: {integrity: sha512-Jv/fH7KhpWe4KBirsiqeUJIYrsdR2iu2l4nWhfOlRvaZ+zYIiLEzTQR6QhBbyRoAbU4OuYJzjWusOmmpGBnwng==}
+ '@opentelemetry/instrumentation-koa@0.42.0':
+ resolution: {integrity: sha512-H1BEmnMhho8o8HuNRq5zEI4+SIHDIglNB7BPKohZyWG4fWNuR7yM4GTlR01Syq21vODAS7z5omblScJD/eZdKw==}
engines: {node: '>=14'}
peerDependencies:
'@opentelemetry/api': ^1.3.0
- '@opentelemetry/instrumentation-koa@0.40.0':
- resolution: {integrity: sha512-dJc3H/bKMcgUYcQpLF+1IbmUKus0e5Fnn/+ru/3voIRHwMADT3rFSUcGLWSczkg68BCgz0vFWGDTvPtcWIFr7A==}
+ '@opentelemetry/instrumentation-mongodb@0.46.0':
+ resolution: {integrity: sha512-VF/MicZ5UOBiXrqBslzwxhN7TVqzu1/LN/QDpkskqM0Zm0aZ4CVRbUygL8d7lrjLn15x5kGIe8VsSphMfPJzlA==}
engines: {node: '>=14'}
peerDependencies:
'@opentelemetry/api': ^1.3.0
- '@opentelemetry/instrumentation-mongodb@0.43.0':
- resolution: {integrity: sha512-bMKej7Y76QVUD3l55Q9YqizXybHUzF3pujsBFjqbZrRn2WYqtsDtTUlbCK7fvXNPwFInqZ2KhnTqd0gwo8MzaQ==}
+ '@opentelemetry/instrumentation-mongoose@0.40.0':
+ resolution: {integrity: sha512-niRi5ZUnkgzRhIGMOozTyoZIvJKNJyhijQI4nF4iFSb+FUx2v5fngfR+8XLmdQAO7xmsD8E5vEGdDVYVtKbZew==}
engines: {node: '>=14'}
peerDependencies:
'@opentelemetry/api': ^1.3.0
- '@opentelemetry/instrumentation-mongoose@0.38.1':
- resolution: {integrity: sha512-zaeiasdnRjXe6VhYCBMdkmAVh1S5MmXC/0spet+yqoaViGnYst/DOxPvhwg3yT4Yag5crZNWsVXnA538UjP6Ow==}
+ '@opentelemetry/instrumentation-mysql2@0.40.0':
+ resolution: {integrity: sha512-0xfS1xcqUmY7WE1uWjlmI67Xg3QsSUlNT+AcXHeA4BDUPwZtWqF4ezIwLgpVZfHOnkAEheqGfNSWd1PIu3Wnfg==}
engines: {node: '>=14'}
peerDependencies:
'@opentelemetry/api': ^1.3.0
- '@opentelemetry/instrumentation-mysql2@0.38.1':
- resolution: {integrity: sha512-qkpHMgWSDTYVB1vlZ9sspf7l2wdS5DDq/rbIepDwX5BA0N0068JTQqh0CgAh34tdFqSCnWXIhcyOXC2TtRb0sg==}
+ '@opentelemetry/instrumentation-mysql@0.40.0':
+ resolution: {integrity: sha512-d7ja8yizsOCNMYIJt5PH/fKZXjb/mS48zLROO4BzZTtDfhNCl2UM/9VIomP2qkGIFVouSJrGr/T00EzY7bPtKA==}
engines: {node: '>=14'}
peerDependencies:
'@opentelemetry/api': ^1.3.0
- '@opentelemetry/instrumentation-mysql@0.38.1':
- resolution: {integrity: sha512-+iBAawUaTfX/HAlvySwozx0C2B6LBfNPXX1W8Z2On1Uva33AGkw2UjL9XgIg1Pj4eLZ9R4EoJ/aFz+Xj4E/7Fw==}
+ '@opentelemetry/instrumentation-nestjs-core@0.39.0':
+ resolution: {integrity: sha512-mewVhEXdikyvIZoMIUry8eb8l3HUjuQjSjVbmLVTt4NQi35tkpnHQrG9bTRBrl3403LoWZ2njMPJyg4l6HfKvA==}
engines: {node: '>=14'}
peerDependencies:
'@opentelemetry/api': ^1.3.0
- '@opentelemetry/instrumentation-nestjs-core@0.37.1':
- resolution: {integrity: sha512-ebYQjHZEmGHWEALwwDGhSQVLBaurFnuLIkZD5igPXrt7ohfF4lc5/4al1LO+vKc0NHk8SJWStuRueT86ISA8Vg==}
+ '@opentelemetry/instrumentation-pg@0.43.0':
+ resolution: {integrity: sha512-og23KLyoxdnAeFs1UWqzSonuCkePUzCX30keSYigIzJe/6WSYA8rnEI5lobcxPEzg+GcU06J7jzokuEHbjVJNw==}
engines: {node: '>=14'}
peerDependencies:
'@opentelemetry/api': ^1.3.0
- '@opentelemetry/instrumentation-pg@0.41.0':
- resolution: {integrity: sha512-BSlhpivzBD77meQNZY9fS4aKgydA8AJBzv2dqvxXFy/Hq64b7HURgw/ztbmwFeYwdF5raZZUifiiNSMLpOJoSA==}
+ '@opentelemetry/instrumentation-redis-4@0.41.0':
+ resolution: {integrity: sha512-H7IfGTqW2reLXqput4yzAe8YpDC0fmVNal95GHMLOrS89W+qWUKIqxolSh63hJyfmwPSFwXASzj7wpSk8Az+Dg==}
engines: {node: '>=14'}
peerDependencies:
'@opentelemetry/api': ^1.3.0
- '@opentelemetry/instrumentation@0.43.0':
- resolution: {integrity: sha512-S1uHE+sxaepgp+t8lvIDuRgyjJWisAb733198kwQTUc9ZtYQ2V2gmyCtR1x21ePGVLoMiX/NWY7WA290hwkjJQ==}
+ '@opentelemetry/instrumentation@0.46.0':
+ resolution: {integrity: sha512-a9TijXZZbk0vI5TGLZl+0kxyFfrXHhX6Svtz7Pp2/VBlCSKrazuULEyoJQrOknJyFWNMEmbbJgOciHCCpQcisw==}
engines: {node: '>=14'}
peerDependencies:
'@opentelemetry/api': ^1.3.0
- '@opentelemetry/instrumentation@0.51.1':
- resolution: {integrity: sha512-JIrvhpgqY6437QIqToyozrUG1h5UhwHkaGK/WAX+fkrpyPtc+RO5FkRtUd9BH0MibabHHvqsnBGKfKVijbmp8w==}
+ '@opentelemetry/instrumentation@0.52.1':
+ resolution: {integrity: sha512-uXJbYU/5/MBHjMp1FqrILLRuiJCs3Ofk0MeRDk8g1S1gD47U8X3JnSwcMO1rtRo1x1a7zKaQHaoYu49p/4eSKw==}
engines: {node: '>=14'}
peerDependencies:
'@opentelemetry/api': ^1.3.0
@@ -3396,22 +3607,32 @@ packages:
peerDependencies:
'@opentelemetry/api': '>=1.0.0 <1.9.0'
+ '@opentelemetry/resources@1.25.1':
+ resolution: {integrity: sha512-pkZT+iFYIZsVn6+GzM0kSX+u3MSLCY9md+lIJOoKl/P+gJFfxJte/60Usdp8Ce4rOs8GduUpSPNe1ddGyDT1sQ==}
+ engines: {node: '>=14'}
+ peerDependencies:
+ '@opentelemetry/api': '>=1.0.0 <1.10.0'
+
'@opentelemetry/sdk-metrics@1.24.1':
resolution: {integrity: sha512-FrAqCbbGao9iKI+Mgh+OsC9+U2YMoXnlDHe06yH7dvavCKzE3S892dGtX54+WhSFVxHR/TMRVJiK/CV93GR0TQ==}
engines: {node: '>=14'}
peerDependencies:
'@opentelemetry/api': '>=1.3.0 <1.9.0'
- '@opentelemetry/sdk-trace-base@1.24.1':
- resolution: {integrity: sha512-zz+N423IcySgjihl2NfjBf0qw1RWe11XIAWVrTNOSSI6dtSPJiVom2zipFB2AEEtJWpv0Iz6DY6+TjnyTV5pWg==}
+ '@opentelemetry/sdk-trace-base@1.25.1':
+ resolution: {integrity: sha512-C8k4hnEbc5FamuZQ92nTOp8X/diCY56XUTnMiv9UTuJitCzaNNHAVsdm5+HLCdI8SLQsLWIrG38tddMxLVoftw==}
engines: {node: '>=14'}
peerDependencies:
- '@opentelemetry/api': '>=1.0.0 <1.9.0'
+ '@opentelemetry/api': '>=1.0.0 <1.10.0'
'@opentelemetry/semantic-conventions@1.24.1':
resolution: {integrity: sha512-VkliWlS4/+GHLLW7J/rVBA00uXus1SWvwFvcUDxDwmFxYfg/2VI6ekwdXS28cjI8Qz2ky2BzG8OUHo+WeYIWqw==}
engines: {node: '>=14'}
+ '@opentelemetry/semantic-conventions@1.25.1':
+ resolution: {integrity: sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==}
+ engines: {node: '>=14'}
+
'@opentelemetry/sql-common@0.40.1':
resolution: {integrity: sha512-nSDlnHSqzC3pXn/wZEZVLuAuJ1MYMXPBwtv2qAbCa3847SaHItdE7SzUq/Jtb0KZmh1zfAbNi3AAMjztTT4Ugg==}
engines: {node: '>=14'}
@@ -3441,26 +3662,8 @@ packages:
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
- '@prisma/instrumentation@5.14.0':
- resolution: {integrity: sha512-DeybWvIZzu/mUsOYP9MVd6AyBj+MP7xIMrcuIn25MX8FiQX39QBnET5KhszTAip/ToctUuDwSJ46QkIoyo3RFA==}
-
- '@radix-ui/react-compose-refs@1.0.1':
- resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==}
- peerDependencies:
- '@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
- '@radix-ui/react-slot@1.0.2':
- resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==}
- peerDependencies:
- '@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0
- peerDependenciesMeta:
- '@types/react':
- optional: true
+ '@prisma/instrumentation@5.17.0':
+ resolution: {integrity: sha512-c1Sle4ji8aasMcYfBBHFM56We4ljfenVtRmS8aY06BllS7SoU6SmJBwG7vil+GHiR0Yrh+t9iBwt4AY0Jr4KNQ==}
'@readme/better-ajv-errors@1.6.0':
resolution: {integrity: sha512-9gO9rld84Jgu13kcbKRU+WHseNhaVt76wYMeRDGsUGYxwJtI3RmEJ9LY9dZCYQGI8eUZLuxb5qDja0nqklpFjQ==}
@@ -3486,8 +3689,8 @@ packages:
rollup:
optional: true
- '@rollup/plugin-replace@5.0.5':
- resolution: {integrity: sha512-rYO4fOi8lMaTg/z5Jb+hKnrHHVn8j2lwkqwyS4kTRhKyWOLf2wST2sWXr4WzWiTcoHTp2sTjqUbqIj2E39slKQ==}
+ '@rollup/plugin-replace@5.0.7':
+ resolution: {integrity: sha512-PqxSfuorkHz/SPpyngLyg5GCEkOcee9M1bkxiVDr41Pd61mqP1PLOoDPbpl44SB2mQGKwV/In74gqQmGITOhEQ==}
engines: {node: '>=14.0.0'}
peerDependencies:
rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
@@ -3504,141 +3707,144 @@ packages:
rollup:
optional: true
- '@rollup/rollup-android-arm-eabi@4.17.2':
- resolution: {integrity: sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==}
+ '@rollup/rollup-android-arm-eabi@4.19.1':
+ resolution: {integrity: sha512-XzqSg714++M+FXhHfXpS1tDnNZNpgxxuGZWlRG/jSj+VEPmZ0yg6jV4E0AL3uyBKxO8mO3xtOsP5mQ+XLfrlww==}
cpu: [arm]
os: [android]
- '@rollup/rollup-android-arm64@4.17.2':
- resolution: {integrity: sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==}
+ '@rollup/rollup-android-arm64@4.19.1':
+ resolution: {integrity: sha512-thFUbkHteM20BGShD6P08aungq4irbIZKUNbG70LN8RkO7YztcGPiKTTGZS7Kw+x5h8hOXs0i4OaHwFxlpQN6A==}
cpu: [arm64]
os: [android]
- '@rollup/rollup-darwin-arm64@4.17.2':
- resolution: {integrity: sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==}
+ '@rollup/rollup-darwin-arm64@4.19.1':
+ resolution: {integrity: sha512-8o6eqeFZzVLia2hKPUZk4jdE3zW7LCcZr+MD18tXkgBBid3lssGVAYuox8x6YHoEPDdDa9ixTaStcmx88lio5Q==}
cpu: [arm64]
os: [darwin]
- '@rollup/rollup-darwin-x64@4.17.2':
- resolution: {integrity: sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==}
+ '@rollup/rollup-darwin-x64@4.19.1':
+ resolution: {integrity: sha512-4T42heKsnbjkn7ovYiAdDVRRWZLU9Kmhdt6HafZxFcUdpjlBlxj4wDrt1yFWLk7G4+E+8p2C9tcmSu0KA6auGA==}
cpu: [x64]
os: [darwin]
- '@rollup/rollup-linux-arm-gnueabihf@4.17.2':
- resolution: {integrity: sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==}
+ '@rollup/rollup-linux-arm-gnueabihf@4.19.1':
+ resolution: {integrity: sha512-MXg1xp+e5GhZ3Vit1gGEyoC+dyQUBy2JgVQ+3hUrD9wZMkUw/ywgkpK7oZgnB6kPpGrxJ41clkPPnsknuD6M2Q==}
cpu: [arm]
os: [linux]
- '@rollup/rollup-linux-arm-musleabihf@4.17.2':
- resolution: {integrity: sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==}
+ '@rollup/rollup-linux-arm-musleabihf@4.19.1':
+ resolution: {integrity: sha512-DZNLwIY4ftPSRVkJEaxYkq7u2zel7aah57HESuNkUnz+3bZHxwkCUkrfS2IWC1sxK6F2QNIR0Qr/YXw7nkF3Pw==}
cpu: [arm]
os: [linux]
- '@rollup/rollup-linux-arm64-gnu@4.17.2':
- resolution: {integrity: sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==}
+ '@rollup/rollup-linux-arm64-gnu@4.19.1':
+ resolution: {integrity: sha512-C7evongnjyxdngSDRRSQv5GvyfISizgtk9RM+z2biV5kY6S/NF/wta7K+DanmktC5DkuaJQgoKGf7KUDmA7RUw==}
cpu: [arm64]
os: [linux]
- '@rollup/rollup-linux-arm64-musl@4.17.2':
- resolution: {integrity: sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==}
+ '@rollup/rollup-linux-arm64-musl@4.19.1':
+ resolution: {integrity: sha512-89tFWqxfxLLHkAthAcrTs9etAoBFRduNfWdl2xUs/yLV+7XDrJ5yuXMHptNqf1Zw0UCA3cAutkAiAokYCkaPtw==}
cpu: [arm64]
os: [linux]
- '@rollup/rollup-linux-powerpc64le-gnu@4.17.2':
- resolution: {integrity: sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==}
+ '@rollup/rollup-linux-powerpc64le-gnu@4.19.1':
+ resolution: {integrity: sha512-PromGeV50sq+YfaisG8W3fd+Cl6mnOOiNv2qKKqKCpiiEke2KiKVyDqG/Mb9GWKbYMHj5a01fq/qlUR28PFhCQ==}
cpu: [ppc64]
os: [linux]
- '@rollup/rollup-linux-riscv64-gnu@4.17.2':
- resolution: {integrity: sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==}
+ '@rollup/rollup-linux-riscv64-gnu@4.19.1':
+ resolution: {integrity: sha512-/1BmHYh+iz0cNCP0oHCuF8CSiNj0JOGf0jRlSo3L/FAyZyG2rGBuKpkZVH9YF+x58r1jgWxvm1aRg3DHrLDt6A==}
cpu: [riscv64]
os: [linux]
- '@rollup/rollup-linux-s390x-gnu@4.17.2':
- resolution: {integrity: sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==}
+ '@rollup/rollup-linux-s390x-gnu@4.19.1':
+ resolution: {integrity: sha512-0cYP5rGkQWRZKy9/HtsWVStLXzCF3cCBTRI+qRL8Z+wkYlqN7zrSYm6FuY5Kd5ysS5aH0q5lVgb/WbG4jqXN1Q==}
cpu: [s390x]
os: [linux]
- '@rollup/rollup-linux-x64-gnu@4.17.2':
- resolution: {integrity: sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==}
+ '@rollup/rollup-linux-x64-gnu@4.19.1':
+ resolution: {integrity: sha512-XUXeI9eM8rMP8aGvii/aOOiMvTs7xlCosq9xCjcqI9+5hBxtjDpD+7Abm1ZhVIFE1J2h2VIg0t2DX/gjespC2Q==}
cpu: [x64]
os: [linux]
- '@rollup/rollup-linux-x64-musl@4.17.2':
- resolution: {integrity: sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==}
+ '@rollup/rollup-linux-x64-musl@4.19.1':
+ resolution: {integrity: sha512-V7cBw/cKXMfEVhpSvVZhC+iGifD6U1zJ4tbibjjN+Xi3blSXaj/rJynAkCFFQfoG6VZrAiP7uGVzL440Q6Me2Q==}
cpu: [x64]
os: [linux]
- '@rollup/rollup-win32-arm64-msvc@4.17.2':
- resolution: {integrity: sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==}
+ '@rollup/rollup-win32-arm64-msvc@4.19.1':
+ resolution: {integrity: sha512-88brja2vldW/76jWATlBqHEoGjJLRnP0WOEKAUbMcXaAZnemNhlAHSyj4jIwMoP2T750LE9lblvD4e2jXleZsA==}
cpu: [arm64]
os: [win32]
- '@rollup/rollup-win32-ia32-msvc@4.17.2':
- resolution: {integrity: sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==}
+ '@rollup/rollup-win32-ia32-msvc@4.19.1':
+ resolution: {integrity: sha512-LdxxcqRVSXi6k6JUrTah1rHuaupoeuiv38du8Mt4r4IPer3kwlTo+RuvfE8KzZ/tL6BhaPlzJ3835i6CxrFIRQ==}
cpu: [ia32]
os: [win32]
- '@rollup/rollup-win32-x64-msvc@4.17.2':
- resolution: {integrity: sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w==}
+ '@rollup/rollup-win32-x64-msvc@4.19.1':
+ resolution: {integrity: sha512-2bIrL28PcK3YCqD9anGxDxamxdiJAxA+l7fWIwM5o8UqNy1t3d1NdAweO2XhA0KTDJ5aH1FsuiT5+7VhtHliXg==}
cpu: [x64]
os: [win32]
- '@rushstack/node-core-library@4.1.0':
- resolution: {integrity: sha512-qz4JFBZJCf1YN5cAXa1dP6Mki/HrsQxc/oYGAGx29dF2cwF2YMxHoly0FBhMw3IEnxo5fMj0boVfoHVBkpkx/w==}
+ '@rushstack/node-core-library@5.5.1':
+ resolution: {integrity: sha512-ZutW56qIzH8xIOlfyaLQJFx+8IBqdbVCZdnj+XT1MorQ1JqqxHse8vbCpEM+2MjsrqcbxcgDIbfggB1ZSQ2A3g==}
peerDependencies:
'@types/node': '*'
peerDependenciesMeta:
'@types/node':
optional: true
- '@rushstack/rig-package@0.5.2':
- resolution: {integrity: sha512-mUDecIJeH3yYGZs2a48k+pbhM6JYwWlgjs2Ca5f2n1G2/kgdgP9D/07oglEGf6mRyXEnazhEENeYTSNDRCwdqA==}
+ '@rushstack/rig-package@0.5.3':
+ resolution: {integrity: sha512-olzSSjYrvCNxUFZowevC3uz8gvKr3WTpHQ7BkpjtRpA3wK+T0ybep/SRUMfr195gBzJm5gaXw0ZMgjIyHqJUow==}
- '@rushstack/terminal@0.10.1':
- resolution: {integrity: sha512-C6Vi/m/84IYJTkfzmXr1+W8Wi3MmBjVF/q3za91Gb3VYjKbpALHVxY6FgH625AnDe5Z0Kh4MHKWA3Z7bqgAezA==}
+ '@rushstack/terminal@0.13.3':
+ resolution: {integrity: sha512-fc3zjXOw8E0pXS5t9vTiIPx9gHA0fIdTXsu9mT4WbH+P3mYvnrX0iAQ5a6NvyK1+CqYWBTw/wVNx7SDJkI+WYQ==}
peerDependencies:
'@types/node': '*'
peerDependenciesMeta:
'@types/node':
optional: true
- '@rushstack/ts-command-line@4.19.2':
- resolution: {integrity: sha512-cqmXXmBEBlzo9WtyUrHtF9e6kl0LvBY7aTSVX4jfnBfXWZQWnPq9JTFPlQZ+L/ZwjZ4HrNwQsOVvhe9oOucZkw==}
+ '@rushstack/ts-command-line@4.22.3':
+ resolution: {integrity: sha512-edMpWB3QhFFZ4KtSzS8WNjBgR4PXPPOVrOHMbb7kNpmQ1UFS9HdVtjCXg1H5fG+xYAbeE+TMPcVPUyX2p84STA==}
+
+ '@sec-ant/readable-stream@0.4.1':
+ resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==}
- '@sentry/core@8.5.0':
- resolution: {integrity: sha512-SO3ddBzGdha+Oflp+IKwBxj+7ds1q69OAT3VsypTd+WUFQdI9DIhR92Bjf+QQZCIzUNOi79VWOh3aOi3f6hMnw==}
+ '@sentry/core@8.20.0':
+ resolution: {integrity: sha512-R81snuw+67VT4aCxr6ShST/s0Y6FlwN2YczhDwaGyzumn5rlvA6A4JtQDeExduNoDDyv4T3LrmW8wlYZn3CJJw==}
engines: {node: '>=14.18'}
- '@sentry/node@8.5.0':
- resolution: {integrity: sha512-t9cHAx/wLJYtdVf2XlzKlRJGvwdAp1wjzG0tC4E1Znx74OuUS1cFNo5WrGuOi0/YcWSxiJaxBvtUcsWK86fIgw==}
+ '@sentry/node@8.20.0':
+ resolution: {integrity: sha512-i4ywT2m0Gw65U3uwI4NwiNcyqp9YF6/RsusfH1pg4YkiL/RYp7FS0MPVgMggfvoue9S3KjCgRVlzTLwFATyPXQ==}
engines: {node: '>=14.18'}
- '@sentry/opentelemetry@8.5.0':
- resolution: {integrity: sha512-AbxFUNjuTKQ9ugZrssmGtPxWkBr4USNoP7GjaaGCNwNzvIVYCa+i8dv7BROJiW2lsxNAremULEbh+nbVmhGxDA==}
+ '@sentry/opentelemetry@8.20.0':
+ resolution: {integrity: sha512-NFcLK6+t9wUc4HlGKeuDn6W4KjZxZfZmWlrK2/tgC5KzG1cnVeOnWUrJzGHTa+YDDdIijpjiFUcpXGPkX3rmIg==}
engines: {node: '>=14.18'}
peerDependencies:
- '@opentelemetry/api': ^1.8.0
- '@opentelemetry/core': ^1.24.1
- '@opentelemetry/instrumentation': ^0.51.1
- '@opentelemetry/sdk-trace-base': ^1.23.0
- '@opentelemetry/semantic-conventions': ^1.23.0
+ '@opentelemetry/api': ^1.9.0
+ '@opentelemetry/core': ^1.25.1
+ '@opentelemetry/instrumentation': ^0.52.1
+ '@opentelemetry/sdk-trace-base': ^1.25.1
+ '@opentelemetry/semantic-conventions': ^1.25.1
- '@sentry/profiling-node@8.5.0':
- resolution: {integrity: sha512-nEXJqVNfZWYi4PakQXBZCJeH59UlnBv+zaYftDNUUXttCmzRXpL1ujNm5mJrJHlWjV7tgIFw02HW3nh2yyKOkw==}
+ '@sentry/profiling-node@8.20.0':
+ resolution: {integrity: sha512-vQaMYjPM7o0qvmj4atxXZywIDhnxMwTlc6x24eKqT8zN0OFBuIc1nYIacT7pEmd7R6e/mXdiG04GH1Vg0bHfOQ==}
engines: {node: '>=14.18'}
hasBin: true
- '@sentry/types@8.5.0':
- resolution: {integrity: sha512-eDgkSmKI4+XL0QZm4H3j/n1RgnrbnjXZmjj+LsfccRZQwbPu9bWlc8q7Y7Ty1gOsoUpX+TecNLp2a8CRID4KHA==}
+ '@sentry/types@8.20.0':
+ resolution: {integrity: sha512-6IP278KojOpiAA7vrd1hjhUyn26cl0n0nGsShzic5ztCVs92sTeVRnh7MTB9irDVtAbOEyt/YH6go3h+Jia1pA==}
engines: {node: '>=14.18'}
- '@sentry/utils@8.5.0':
- resolution: {integrity: sha512-fdrCzo8SAYiw9JBhkJPqYqJkDXZ/wICzN7+zcXIuzKNhE1hdoFjeKcPnpUI3bKZCG6e3hT1PTYQXhVw7GIZV9w==}
+ '@sentry/utils@8.20.0':
+ resolution: {integrity: sha512-+1I5H8dojURiEUGPliDwheQk8dhjp8uV1sMccR/W/zjFrt4wZyPs+Ttp/V7gzm9LDJoNek9tmELert/jQqWTgg==}
engines: {node: '>=14.18'}
- '@shikijs/core@1.4.0':
- resolution: {integrity: sha512-CxpKLntAi64h3j+TwWqVIQObPTED0FyXLHTTh3MKXtqiQNn2JGcMQQ362LftDbc9kYbDtrksNMNoVmVXzKFYUQ==}
+ '@shikijs/core@1.12.0':
+ resolution: {integrity: sha512-mc1cLbm6UQ8RxLc0dZES7v5rkH+99LxQp/ZvTqV3NLyYsO/fD6JhEflP1H5b2SDq9gI0+0G36AVZWxvounfR9w==}
'@sideway/address@4.1.4':
resolution: {integrity: sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==}
@@ -3649,8 +3855,8 @@ packages:
'@sideway/pinpoint@2.0.0':
resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==}
- '@simplewebauthn/server@10.0.0':
- resolution: {integrity: sha512-w5eIoiF7ltg1sgggjY5Tx654j+DBuyEx2B3869jjmPp0xl2Z4BUP4kJ3yJ6DnZIv+ZYYntT3E6nZXNjPOQbrtw==}
+ '@simplewebauthn/server@10.0.1':
+ resolution: {integrity: sha512-djNWcRn+H+6zvihBFJSpG3fzb0NQS9c/Mw5dYOtZ9H+oDw8qn9Htqxt4cpqRvSOAfwqP7rOvE9rwqVaoGGc3hg==}
engines: {node: '>=20.0.0'}
'@simplewebauthn/types@10.0.0':
@@ -3667,9 +3873,17 @@ packages:
resolution: {integrity: sha512-CX6t4SYQ37lzxicAqsBtxA3OseeoVrh9cSJ5PFYam0GksYlupRfy1A+Q4aYD3zvcfECLc0zO2u+ZnR2UYKvCrw==}
engines: {node: '>=14.16'}
- '@sindresorhus/is@6.1.0':
- resolution: {integrity: sha512-BuvU07zq3tQ/2SIgBsEuxKYDyDjC0n7Zir52bpHy2xnBbW81+po43aLFPLbeV3HRAheFbGud1qgcqSYfhtHMAg==}
- engines: {node: '>=16'}
+ '@sindresorhus/is@7.0.0':
+ resolution: {integrity: sha512-WDTlVTyvFivSOuyvMeedzg2hdoBLZ3f1uNVuEida2Rl9BrfjrIRjWA/VZIrMRLvSwJYCAlCRA3usDt1THytxWQ==}
+ engines: {node: '>=18'}
+
+ '@sindresorhus/merge-streams@2.3.0':
+ resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==}
+ engines: {node: '>=18'}
+
+ '@sindresorhus/merge-streams@4.0.0':
+ resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==}
+ engines: {node: '>=18'}
'@sinonjs/commons@2.0.0':
resolution: {integrity: sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==}
@@ -3689,277 +3903,345 @@ packages:
'@sinonjs/text-encoding@0.7.2':
resolution: {integrity: sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==}
- '@smithy/abort-controller@2.0.14':
- resolution: {integrity: sha512-zXtteuYLWbSXnzI3O6xq3FYvigYZFW8mdytGibfarLL2lxHto9L3ILtGVnVGmFZa7SDh62l39EnU5hesLN87Fw==}
- engines: {node: '>=14.0.0'}
-
'@smithy/abort-controller@2.2.0':
resolution: {integrity: sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw==}
engines: {node: '>=14.0.0'}
- '@smithy/chunked-blob-reader-native@2.0.0':
- resolution: {integrity: sha512-HM8V2Rp1y8+1343tkZUKZllFhEQPNmpNdgFAncbTsxkZ18/gqjk23XXv3qGyXWp412f3o43ZZ1UZHVcHrpRnCQ==}
+ '@smithy/abort-controller@3.1.1':
+ resolution: {integrity: sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==}
+ engines: {node: '>=16.0.0'}
- '@smithy/chunked-blob-reader@2.0.0':
- resolution: {integrity: sha512-k+J4GHJsMSAIQPChGBrjEmGS+WbPonCXesoqP9fynIqjn7rdOThdH8FAeCmokP9mxTYKQAKoHCLPzNlm6gh7Wg==}
+ '@smithy/chunked-blob-reader-native@3.0.0':
+ resolution: {integrity: sha512-VDkpCYW+peSuM4zJip5WDfqvg2Mo/e8yxOv3VF1m11y7B8KKMKVFtmZWDe36Fvk8rGuWrPZHHXZ7rR7uM5yWyg==}
- '@smithy/config-resolver@2.0.9':
- resolution: {integrity: sha512-QBkGPLUqyPmis9Erz8v4q5lo/ErnF7+GD5WZHa6JZiXopUPfaaM+B21n8gzS5xCkIXZmnwzNQhObP9xQPu8oqQ==}
- engines: {node: '>=14.0.0'}
+ '@smithy/chunked-blob-reader@3.0.0':
+ resolution: {integrity: sha512-sbnURCwjF0gSToGlsBiAmd1lRCmSn72nu9axfJu5lIx6RUEgHu6GwTMbqCdhQSi0Pumcm5vFxsi9XWXb2mTaoA==}
- '@smithy/credential-provider-imds@2.0.11':
- resolution: {integrity: sha512-uJJs8dnM5iXkn8a2GaKvlKMhcOJ+oJPYqY9gY3CM/EieCVObIDjxUtR/g8lU/k/A+OauA78GzScAfulmFjPOYA==}
- engines: {node: '>=14.0.0'}
+ '@smithy/config-resolver@3.0.5':
+ resolution: {integrity: sha512-SkW5LxfkSI1bUC74OtfBbdz+grQXYiPYolyu8VfpLIjEoN/sHVBlLeGXMQ1vX4ejkgfv6sxVbQJ32yF2cl1veA==}
+ engines: {node: '>=16.0.0'}
- '@smithy/eventstream-codec@2.0.8':
- resolution: {integrity: sha512-onO4to8ujCKn4m5XagReT9Nc6FlNG5vveuvjp1H7AtaG7njdet1LOl6/jmUOkskF2C/w+9jNw3r9Ak+ghOvN0A==}
+ '@smithy/core@2.3.1':
+ resolution: {integrity: sha512-BC7VMXx/1BCmRPCVzzn4HGWAtsrb7/0758EtwOGFJQrlSwJBEjCcDLNZLFoL/68JexYa2s+KmgL/UfmXdG6v1w==}
+ engines: {node: '>=16.0.0'}
- '@smithy/eventstream-serde-browser@2.0.8':
- resolution: {integrity: sha512-/RGlkKUnC0sd+xKBKH/2APSBRmVMZTeLOKZMhrZmrO+ONoU+DwyMr/RLJ6WnmBKN+2ebjffM4pcIJTKLNNDD8g==}
- engines: {node: '>=14.0.0'}
+ '@smithy/credential-provider-imds@3.2.0':
+ resolution: {integrity: sha512-0SCIzgd8LYZ9EJxUjLXBmEKSZR/P/w6l7Rz/pab9culE/RWuqelAKGJvn5qUOl8BgX8Yj5HWM50A5hiB/RzsgA==}
+ engines: {node: '>=16.0.0'}
- '@smithy/eventstream-serde-config-resolver@2.0.8':
- resolution: {integrity: sha512-EyAEj258eMUv9zcMvBbqrInh2eHRYuiwQAjXDMxZFCyP+JePzQB6O++3wFwjQeRKMFFgZipNgnEXfReII4+NAw==}
- engines: {node: '>=14.0.0'}
+ '@smithy/eventstream-codec@3.1.2':
+ resolution: {integrity: sha512-0mBcu49JWt4MXhrhRAlxASNy0IjDRFU+aWNDRal9OtUJvJNiwDuyKMUONSOjLjSCeGwZaE0wOErdqULer8r7yw==}
- '@smithy/eventstream-serde-node@2.0.8':
- resolution: {integrity: sha512-FMBatSUSKwh6aguKVJokXfJaV8nqsuCkCZHb9MP9zah0ZF+ohbTLeeed7DQGeTVBueVIVWEzIsShPxtxBv7MMQ==}
- engines: {node: '>=14.0.0'}
+ '@smithy/eventstream-serde-browser@3.0.5':
+ resolution: {integrity: sha512-dEyiUYL/ekDfk+2Ra4GxV+xNnFoCmk1nuIXg+fMChFTrM2uI/1r9AdiTYzPqgb72yIv/NtAj6C3dG//1wwgakQ==}
+ engines: {node: '>=16.0.0'}
- '@smithy/eventstream-serde-universal@2.0.8':
- resolution: {integrity: sha512-6InMXH8BUKoEDa6CAuxR4Gn8Gf2vBfVtjA9A6zDKZClYHT+ANUJS+2EtOBc5wECJJGk4KLn5ajQyrt9MBv5lcw==}
- engines: {node: '>=14.0.0'}
+ '@smithy/eventstream-serde-config-resolver@3.0.3':
+ resolution: {integrity: sha512-NVTYjOuYpGfrN/VbRQgn31x73KDLfCXCsFdad8DiIc3IcdxL+dYA9zEQPyOP7Fy2QL8CPy2WE4WCUD+ZsLNfaQ==}
+ engines: {node: '>=16.0.0'}
- '@smithy/fetch-http-handler@2.1.4':
- resolution: {integrity: sha512-SL24M9W5ERByoXaVicRx+bj9GJVujDnPn+QO7GY7adhY0mPGa6DSF58pVKsgIh4r5Tx/k3SWCPlH4BxxSxA/fQ==}
+ '@smithy/eventstream-serde-node@3.0.4':
+ resolution: {integrity: sha512-mjlG0OzGAYuUpdUpflfb9zyLrBGgmQmrobNT8b42ZTsGv/J03+t24uhhtVEKG/b2jFtPIHF74Bq+VUtbzEKOKg==}
+ engines: {node: '>=16.0.0'}
- '@smithy/hash-blob-browser@2.0.8':
- resolution: {integrity: sha512-IgvRlBMfg/qLg321a59T1yTdEEbaizLrEVsU3DHj65DAO4lFRMF5f+l7vuV+je6m1G9wSD5GQXLturX8qlGb4g==}
+ '@smithy/eventstream-serde-universal@3.0.4':
+ resolution: {integrity: sha512-Od9dv8zh3PgOD7Vj4T3HSuox16n0VG8jJIM2gvKASL6aCtcS8CfHZDWe1Ik3ZXW6xBouU+45Q5wgoliWDZiJ0A==}
+ engines: {node: '>=16.0.0'}
- '@smithy/hash-node@2.0.8':
- resolution: {integrity: sha512-yZL/nmxZzjZV5/QX5JWSgXlt0HxuMTwFO89CS++jOMMPiCMZngf6VYmtNdccs8IIIAMmfQeTzwu07XgUE/Zd3Q==}
- engines: {node: '>=14.0.0'}
+ '@smithy/fetch-http-handler@3.2.4':
+ resolution: {integrity: sha512-kBprh5Gs5h7ug4nBWZi1FZthdqSM+T7zMmsZxx0IBvWUn7dK3diz2SHn7Bs4dQGFDk8plDv375gzenDoNwrXjg==}
- '@smithy/hash-stream-node@2.0.8':
- resolution: {integrity: sha512-82zC6I9ZJycbEZH8TVyXyBx9c2ZIPQDgBvM0x5AFPUl/i1AxwKKX+lwYRnzgkF//cYhIIoJaCfJ9mjSMPRGvCQ==}
- engines: {node: '>=14.0.0'}
+ '@smithy/hash-blob-browser@3.1.2':
+ resolution: {integrity: sha512-hAbfqN2UbISltakCC2TP0kx4LqXBttEv2MqSPE98gVuDFMf05lU+TpC41QtqGP3Ff5A3GwZMPfKnEy0VmEUpmg==}
+
+ '@smithy/hash-node@3.0.3':
+ resolution: {integrity: sha512-2ctBXpPMG+B3BtWSGNnKELJ7SH9e4TNefJS0cd2eSkOOROeBnnVBnAy9LtJ8tY4vUEoe55N4CNPxzbWvR39iBw==}
+ engines: {node: '>=16.0.0'}
- '@smithy/invalid-dependency@2.0.8':
- resolution: {integrity: sha512-88VOS7W3KzUz/bNRc+Sl/F/CDIasFspEE4G39YZRHIh9YmsXF7GUyVaAKURfMNulTie62ayk6BHC9O0nOBAVgQ==}
+ '@smithy/hash-stream-node@3.1.2':
+ resolution: {integrity: sha512-PBgDMeEdDzi6JxKwbfBtwQG9eT9cVwsf0dZzLXoJF4sHKHs5HEo/3lJWpn6jibfJwT34I1EBXpBnZE8AxAft6g==}
+ engines: {node: '>=16.0.0'}
+
+ '@smithy/invalid-dependency@3.0.3':
+ resolution: {integrity: sha512-ID1eL/zpDULmHJbflb864k72/SNOZCADRc9i7Exq3RUNJw6raWUSlFEQ+3PX3EYs++bTxZB2dE9mEHTQLv61tw==}
'@smithy/is-array-buffer@2.0.0':
resolution: {integrity: sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug==}
engines: {node: '>=14.0.0'}
- '@smithy/md5-js@2.0.8':
- resolution: {integrity: sha512-1VVECXEiuJvjXv+mudiaUFKYwgDLOWz5MTTy8RzbrPiU3GiOb3/o5/urdkYpqmgoMfxdvxxOw/Adjv2dV2q2Yg==}
+ '@smithy/is-array-buffer@3.0.0':
+ resolution: {integrity: sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==}
+ engines: {node: '>=16.0.0'}
- '@smithy/middleware-content-length@2.0.10':
- resolution: {integrity: sha512-EGSbysyA4jH0p3xI6G0jdXoj9Iz9GUnAta6aEaHtXm3wVWtenRf80y2TeVvNkVSr5jwKOdSCjKIRI2l1A/oZLA==}
- engines: {node: '>=14.0.0'}
+ '@smithy/md5-js@3.0.3':
+ resolution: {integrity: sha512-O/SAkGVwpWmelpj/8yDtsaVe6sINHLB1q8YE/+ZQbDxIw3SRLbTZuRaI10K12sVoENdnHqzPp5i3/H+BcZ3m3Q==}
- '@smithy/middleware-endpoint@2.0.8':
- resolution: {integrity: sha512-yOpogfG2d2V0cbJdAJ6GLAWkNOc9pVsL5hZUfXcxJu408N3CUCsXzIAFF6+70ZKSE+lCfG3GFErcSXv/UfUbjw==}
- engines: {node: '>=14.0.0'}
+ '@smithy/middleware-content-length@3.0.5':
+ resolution: {integrity: sha512-ILEzC2eyxx6ncej3zZSwMpB5RJ0zuqH7eMptxC4KN3f+v9bqT8ohssKbhNR78k/2tWW+KS5Spw+tbPF4Ejyqvw==}
+ engines: {node: '>=16.0.0'}
- '@smithy/middleware-retry@2.0.11':
- resolution: {integrity: sha512-pknfokumZ+wvBERSuKAI2vVr+aK3ZgPiWRg6+0ZG4kKJogBRpPmDGWw+Jht0izS9ZaEbIobNzueIb4wD33JJVg==}
- engines: {node: '>=14.0.0'}
+ '@smithy/middleware-endpoint@3.1.0':
+ resolution: {integrity: sha512-5y5aiKCEwg9TDPB4yFE7H6tYvGFf1OJHNczeY10/EFF8Ir8jZbNntQJxMWNfeQjC1mxPsaQ6mR9cvQbf+0YeMw==}
+ engines: {node: '>=16.0.0'}
- '@smithy/middleware-serde@2.0.8':
- resolution: {integrity: sha512-Is0sm+LiNlgsc0QpstDzifugzL9ehno1wXp109GgBgpnKTK3j+KphiparBDI4hWTtH9/7OUsxuspNqai2yyhcg==}
- engines: {node: '>=14.0.0'}
+ '@smithy/middleware-retry@3.0.13':
+ resolution: {integrity: sha512-zvCLfaRYCaUmjbF2yxShGZdolSHft7NNCTA28HVN9hKcEbOH+g5irr1X9s+in8EpambclGnevZY4A3lYpvDCFw==}
+ engines: {node: '>=16.0.0'}
- '@smithy/middleware-stack@2.0.1':
- resolution: {integrity: sha512-UexsfY6/oQZRjTQL56s9AKtMcR60tBNibSgNYX1I2WXaUaXg97W9JCkFyth85TzBWKDBTyhLfenrukS/kyu54A==}
- engines: {node: '>=14.0.0'}
+ '@smithy/middleware-serde@3.0.3':
+ resolution: {integrity: sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA==}
+ engines: {node: '>=16.0.0'}
- '@smithy/node-config-provider@2.0.11':
- resolution: {integrity: sha512-CaR1dciSSGKttjhcefpytYjsfI/Yd5mqL8am4wfmyFCDxSiPsvnEWHl8UjM/RbcAjX0klt+CeIKPSHEc0wGvJA==}
- engines: {node: '>=14.0.0'}
+ '@smithy/middleware-stack@3.0.3':
+ resolution: {integrity: sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA==}
+ engines: {node: '>=16.0.0'}
+
+ '@smithy/node-config-provider@3.1.4':
+ resolution: {integrity: sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==}
+ engines: {node: '>=16.0.0'}
'@smithy/node-http-handler@2.5.0':
resolution: {integrity: sha512-mVGyPBzkkGQsPoxQUbxlEfRjrj6FPyA3u3u2VXGr9hT8wilsoQdZdvKpMBFMB8Crfhv5dNkKHIW0Yyuc7eABqA==}
engines: {node: '>=14.0.0'}
- '@smithy/property-provider@2.0.9':
- resolution: {integrity: sha512-25pPZ8f8DeRwYI5wbPRZaoMoR+3vrw8DwbA0TjP+GsdiB2KxScndr4HQehiJ5+WJ0giOTWhLz0bd+7Djv1qpUQ==}
- engines: {node: '>=14.0.0'}
+ '@smithy/node-http-handler@3.1.4':
+ resolution: {integrity: sha512-+UmxgixgOr/yLsUxcEKGH0fMNVteJFGkmRltYFHnBMlogyFdpzn2CwqWmxOrfJELhV34v0WSlaqG1UtE1uXlJg==}
+ engines: {node: '>=16.0.0'}
- '@smithy/protocol-http@3.0.10':
- resolution: {integrity: sha512-6+tjNk7rXW7YTeGo9qwxXj/2BFpJTe37kTj3EnZCoX/nH+NP/WLA7O83fz8XhkGqsaAhLUPo/bB12vvd47nsmg==}
- engines: {node: '>=14.0.0'}
+ '@smithy/property-provider@3.1.3':
+ resolution: {integrity: sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==}
+ engines: {node: '>=16.0.0'}
'@smithy/protocol-http@3.3.0':
resolution: {integrity: sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==}
engines: {node: '>=14.0.0'}
- '@smithy/querystring-builder@2.0.14':
- resolution: {integrity: sha512-lQ4pm9vTv9nIhl5jt6uVMPludr6syE2FyJmHsIJJuOD7QPIJnrf9HhUGf1iHh9KJ4CUv21tpOU3X6s0rB6uJ0g==}
- engines: {node: '>=14.0.0'}
+ '@smithy/protocol-http@4.1.0':
+ resolution: {integrity: sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==}
+ engines: {node: '>=16.0.0'}
'@smithy/querystring-builder@2.2.0':
resolution: {integrity: sha512-L1kSeviUWL+emq3CUVSgdogoM/D9QMFaqxL/dd0X7PCNWmPXqt+ExtrBjqT0V7HLN03Vs9SuiLrG3zy3JGnE5A==}
engines: {node: '>=14.0.0'}
- '@smithy/querystring-parser@2.0.8':
- resolution: {integrity: sha512-ArbanNuR7O/MmTd90ZqhDqGOPPDYmxx3huHxD+R3cuCnazcK/1tGQA+SnnR5307T7ZRb5WTpB6qBggERuibVSA==}
- engines: {node: '>=14.0.0'}
+ '@smithy/querystring-builder@3.0.3':
+ resolution: {integrity: sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==}
+ engines: {node: '>=16.0.0'}
- '@smithy/service-error-classification@2.0.1':
- resolution: {integrity: sha512-QHa9+t+v4s0cMuDCcbjIJN67mNZ42/+fc3jKe8P6ZMPXZl5ksKk6a8vhZ/m494GZng5eFTc3OePv+NF9cG83yg==}
- engines: {node: '>=14.0.0'}
+ '@smithy/querystring-parser@3.0.3':
+ resolution: {integrity: sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==}
+ engines: {node: '>=16.0.0'}
- '@smithy/shared-ini-file-loader@2.0.10':
- resolution: {integrity: sha512-jWASteSezRKohJ7GdA7pHDvmr7Q7tw3b5mu3xLHIkZy/ICftJ+O7aqNaF8wklhI7UNFoQ7flFRM3Rd0KA+1BbQ==}
- engines: {node: '>=14.0.0'}
+ '@smithy/service-error-classification@3.0.3':
+ resolution: {integrity: sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ==}
+ engines: {node: '>=16.0.0'}
- '@smithy/signature-v4@2.0.5':
- resolution: {integrity: sha512-ABIzXmUDXK4n2c9cXjQLELgH2RdtABpYKT+U131e2I6RbCypFZmxIHmIBufJzU2kdMCQ3+thBGDWorAITFW04A==}
- engines: {node: '>=14.0.0'}
+ '@smithy/shared-ini-file-loader@3.1.4':
+ resolution: {integrity: sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==}
+ engines: {node: '>=16.0.0'}
- '@smithy/smithy-client@2.1.5':
- resolution: {integrity: sha512-7S865uKzsxApM8W8Q6zkij7tcUFgaG8PuADMFdMt1yL/ku3d0+s6Zwrg3N7iXCPM08Gu/mf0BIfTXIu/9i450Q==}
- engines: {node: '>=14.0.0'}
+ '@smithy/signature-v4@4.1.0':
+ resolution: {integrity: sha512-aRryp2XNZeRcOtuJoxjydO6QTaVhxx/vjaR+gx7ZjaFgrgPRyZ3HCTbfwqYj6ZWEBHkCSUfcaymKPURaByukag==}
+ engines: {node: '>=16.0.0'}
+
+ '@smithy/smithy-client@3.1.11':
+ resolution: {integrity: sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==}
+ engines: {node: '>=16.0.0'}
'@smithy/types@2.12.0':
resolution: {integrity: sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==}
engines: {node: '>=14.0.0'}
- '@smithy/types@2.6.0':
- resolution: {integrity: sha512-PgqxJq2IcdMF9iAasxcqZqqoOXBHufEfmbEUdN1pmJrJltT42b0Sc8UiYSWWzKkciIp9/mZDpzYi4qYG1qqg6g==}
- engines: {node: '>=14.0.0'}
+ '@smithy/types@3.3.0':
+ resolution: {integrity: sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==}
+ engines: {node: '>=16.0.0'}
- '@smithy/url-parser@2.0.8':
- resolution: {integrity: sha512-wQw7j004ScCrBRJ+oNPXlLE9mtofxyadSZ9D8ov/rHkyurS7z1HTNuyaGRj6OvKsEk0SVQsuY0C9+EfM75XTkw==}
+ '@smithy/url-parser@3.0.3':
+ resolution: {integrity: sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A==}
- '@smithy/util-base64@2.0.0':
- resolution: {integrity: sha512-Zb1E4xx+m5Lud8bbeYi5FkcMJMnn+1WUnJF3qD7rAdXpaL7UjkFQLdmW5fHadoKbdHpwH9vSR8EyTJFHJs++tA==}
- engines: {node: '>=14.0.0'}
+ '@smithy/util-base64@3.0.0':
+ resolution: {integrity: sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==}
+ engines: {node: '>=16.0.0'}
- '@smithy/util-body-length-browser@2.0.0':
- resolution: {integrity: sha512-JdDuS4ircJt+FDnaQj88TzZY3+njZ6O+D3uakS32f2VNnDo3vyEuNdBOh/oFd8Df1zSZOuH1HEChk2AOYDezZg==}
+ '@smithy/util-body-length-browser@3.0.0':
+ resolution: {integrity: sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==}
- '@smithy/util-body-length-node@2.1.0':
- resolution: {integrity: sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw==}
- engines: {node: '>=14.0.0'}
+ '@smithy/util-body-length-node@3.0.0':
+ resolution: {integrity: sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==}
+ engines: {node: '>=16.0.0'}
'@smithy/util-buffer-from@2.0.0':
resolution: {integrity: sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw==}
engines: {node: '>=14.0.0'}
- '@smithy/util-config-provider@2.0.0':
- resolution: {integrity: sha512-xCQ6UapcIWKxXHEU4Mcs2s7LcFQRiU3XEluM2WcCjjBtQkUN71Tb+ydGmJFPxMUrW/GWMgQEEGipLym4XG0jZg==}
- engines: {node: '>=14.0.0'}
+ '@smithy/util-buffer-from@3.0.0':
+ resolution: {integrity: sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==}
+ engines: {node: '>=16.0.0'}
+
+ '@smithy/util-config-provider@3.0.0':
+ resolution: {integrity: sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==}
+ engines: {node: '>=16.0.0'}
- '@smithy/util-defaults-mode-browser@2.0.9':
- resolution: {integrity: sha512-JONLJVQWT8165XoSV36ERn3SVlZLJJ4D6IeGsCSePv65Uxa93pzSLE0UMSR9Jwm4zix7rst9AS8W5QIypZWP8Q==}
+ '@smithy/util-defaults-mode-browser@3.0.13':
+ resolution: {integrity: sha512-ZIRSUsnnMRStOP6OKtW+gCSiVFkwnfQF2xtf32QKAbHR6ACjhbAybDvry+3L5qQYdh3H6+7yD/AiUE45n8mTTw==}
engines: {node: '>= 10.0.0'}
- '@smithy/util-defaults-mode-node@2.0.11':
- resolution: {integrity: sha512-tmqjNsfj+bgZN6jXBe6efZnukzILA7BUytHkzqikuRLNtR+0VVchQHvawD0w6vManh76rO81ydhioe7i4oBzuA==}
+ '@smithy/util-defaults-mode-node@3.0.13':
+ resolution: {integrity: sha512-voUa8TFJGfD+U12tlNNLCDlXibt9vRdNzRX45Onk/WxZe7TS+hTOZouEZRa7oARGicdgeXvt1A0W45qLGYdy+g==}
engines: {node: '>= 10.0.0'}
- '@smithy/util-hex-encoding@2.0.0':
- resolution: {integrity: sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA==}
- engines: {node: '>=14.0.0'}
+ '@smithy/util-endpoints@2.0.5':
+ resolution: {integrity: sha512-ReQP0BWihIE68OAblC/WQmDD40Gx+QY1Ez8mTdFMXpmjfxSyz2fVQu3A4zXRfQU9sZXtewk3GmhfOHswvX+eNg==}
+ engines: {node: '>=16.0.0'}
- '@smithy/util-middleware@2.0.1':
- resolution: {integrity: sha512-LnsBMi0Mg3gfz/TpNGLv2Jjcz2ra1OX5HR/4IaCepIYmtPQzqMWDdhX/XTW1LS8OZ0xbQuyQPcHkQ+2XkhWOVQ==}
- engines: {node: '>=14.0.0'}
+ '@smithy/util-hex-encoding@3.0.0':
+ resolution: {integrity: sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==}
+ engines: {node: '>=16.0.0'}
- '@smithy/util-retry@2.0.1':
- resolution: {integrity: sha512-naj4X0IafJ9yJnVJ58QgSMkCNLjyQOnyrnKh/T0f+0UOUxJiT8vuFn/hS7B/pNqbo2STY7PyJ4J4f+5YqxwNtA==}
- engines: {node: '>= 14.0.0'}
+ '@smithy/util-middleware@3.0.3':
+ resolution: {integrity: sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==}
+ engines: {node: '>=16.0.0'}
- '@smithy/util-stream@2.0.11':
- resolution: {integrity: sha512-2MeWfqSpZKdmEJ+tH8CJQSgzLWhH5cmdE24X7JB0hiamXrOmswWGGuPvyj/9sQCTclo57pNxLR2p7KrP8Ahiyg==}
- engines: {node: '>=14.0.0'}
+ '@smithy/util-retry@3.0.3':
+ resolution: {integrity: sha512-AFw+hjpbtVApzpNDhbjNG5NA3kyoMs7vx0gsgmlJF4s+yz1Zlepde7J58zpIRIsdjc+emhpAITxA88qLkPF26w==}
+ engines: {node: '>=16.0.0'}
- '@smithy/util-uri-escape@2.0.0':
- resolution: {integrity: sha512-ebkxsqinSdEooQduuk9CbKcI+wheijxEb3utGXkCoYQkJnwTnLbH1JXGimJtUkQwNQbsbuYwG2+aFVyZf5TLaw==}
- engines: {node: '>=14.0.0'}
+ '@smithy/util-stream@3.1.3':
+ resolution: {integrity: sha512-FIv/bRhIlAxC0U7xM1BCnF2aDRPq0UaelqBHkM2lsCp26mcBbgI0tCVTv+jGdsQLUmAMybua/bjDsSu8RQHbmw==}
+ engines: {node: '>=16.0.0'}
'@smithy/util-uri-escape@2.2.0':
resolution: {integrity: sha512-jtmJMyt1xMD/d8OtbVJ2gFZOSKc+ueYJZPW20ULW1GOp/q/YIM0wNh+u8ZFao9UaIGz4WoPW8hC64qlWLIfoDA==}
engines: {node: '>=14.0.0'}
+ '@smithy/util-uri-escape@3.0.0':
+ resolution: {integrity: sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==}
+ engines: {node: '>=16.0.0'}
+
'@smithy/util-utf8@2.0.0':
resolution: {integrity: sha512-rctU1VkziY84n5OXe3bPNpKR001ZCME2JCaBBFgtiM2hfKbHFudc/BkMuPab8hRbLd0j3vbnBTTZ1igBf0wgiQ==}
engines: {node: '>=14.0.0'}
- '@smithy/util-waiter@2.0.8':
- resolution: {integrity: sha512-t9yaoofNhdEhNlyDeV5al/JJEFJ62HIQBGktgCUE63MvKn6imnbkh1qISsYMyMYVLwhWCpZ3Xa3R1LA+SnWcng==}
- engines: {node: '>=14.0.0'}
+ '@smithy/util-utf8@3.0.0':
+ resolution: {integrity: sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==}
+ engines: {node: '>=16.0.0'}
+
+ '@smithy/util-waiter@3.1.2':
+ resolution: {integrity: sha512-4pP0EV3iTsexDx+8PPGAKCQpd/6hsQBaQhqWzU4hqKPHN5epPsxKbvUTIiYIHTxaKt6/kEaqPBpu/ufvfbrRzw==}
+ engines: {node: '>=16.0.0'}
'@sqltools/formatter@1.2.5':
resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==}
- '@storybook/addon-actions@8.0.9':
- resolution: {integrity: sha512-+I3VTvlKdj8puHeS2tyaOVv9syDiNLneVZbTfqN+UDOK2i42NwvZr8PVwjTzMlEj9eePJdCZgiipz55xwts5bw==}
+ '@storybook/addon-actions@8.2.6':
+ resolution: {integrity: sha512-iCsf3V28/jJ95w2zd8aSvR4denoA2UYV3fpNCTGOURqICyKOG3cyVxvqKp8Hhcwn7trNOsK+HlL6q5gpv56ViA==}
+ peerDependencies:
+ storybook: ^8.2.6
- '@storybook/addon-backgrounds@8.0.9':
- resolution: {integrity: sha512-pCDecACrVyxPaJKEWS0sHsRb8xw+IPCSxDM1TkjaAQ6zZ468A/dcUnqW+LVK8bSXgQwWzn23wqnqPFSy5yptuQ==}
+ '@storybook/addon-backgrounds@8.2.6':
+ resolution: {integrity: sha512-61NFowA6EmCw+Eyzp0U4fat9MlPDdnT7aoDyzqSImLwWLITY9IvmWuTeo7XKJZN3fe22z1r7cZseKdYrtaHcKw==}
+ peerDependencies:
+ storybook: ^8.2.6
- '@storybook/addon-controls@8.0.9':
- resolution: {integrity: sha512-wWdmd62UP/sfPm8M7aJjEA+kEXTUIR/QsYi9PoYBhBZcXiikZ4kNan7oD7GfsnzGGKHrBVfwQhO+TqaENGYytA==}
+ '@storybook/addon-controls@8.2.6':
+ resolution: {integrity: sha512-EHUwHy+oZZv3pXzN7fuXWrS/meHFjqcELY3RBvOyEkGf21agl6co6R1tnf6d5N5QoYAGfIbDO7dkauSL2RfNAw==}
+ peerDependencies:
+ storybook: ^8.2.6
- '@storybook/addon-docs@8.0.9':
- resolution: {integrity: sha512-x7hX7UuzJtClu6XwU3SfpyFhuckVcgqgD6BU6Ihxl0zs+i4xp6iKVXYSnHFMRM1sgoeT8TjPxab35Ke8w8BVRw==}
+ '@storybook/addon-docs@8.2.6':
+ resolution: {integrity: sha512-qe7hxntaezqjKdU9QS+Q9NFL6i/uNdBxdvOnCKgPhBAY/zY6yhk5t3sOvonynPK5nkaNAowfSNPIzNxAXlJ1sA==}
+ peerDependencies:
+ storybook: ^8.2.6
- '@storybook/addon-essentials@8.0.9':
- resolution: {integrity: sha512-mwAgdfrOsTuTDcagvM7veBh+iayZIWmKOazzkhrIWbhYcrXOsweigD2UOVeHgAiAzJK49znr4FXTCKcE1hOWcw==}
+ '@storybook/addon-essentials@8.2.6':
+ resolution: {integrity: sha512-diGjGZcZNov+RCAVQBTm8JKP2kUtMRuJIQFBeXdPWpu6hYBk6lw1FlAf2GywWGCvdny1pJT90hfoD33qUMNuDg==}
+ peerDependencies:
+ storybook: ^8.2.6
- '@storybook/addon-highlight@8.0.9':
- resolution: {integrity: sha512-vaRHGDbx7dpNpQECAHk5wczlZO3ntstprGlqnZt0o7ylz6xB5+pTQwTuIFty0hwKv+3TPcskzzifATUyEOEmyg==}
+ '@storybook/addon-highlight@8.2.6':
+ resolution: {integrity: sha512-03cV9USsfP3bS4wYV06DYcIaGPfoheQe53Q0Jr1B2yJUVyIPKvmO2nGjLBsqzeL3Wl7vSfLQn0/dUdxCcbqLsw==}
+ peerDependencies:
+ storybook: ^8.2.6
- '@storybook/addon-interactions@8.0.9':
- resolution: {integrity: sha512-AMIdNcyM6DDAWvMitBJMqp1iPZND8AXB4QT4VZHGMKG2ngHNKktriEKpTfcRkfKPGTJs9T+71dWfm6/R4tticw==}
+ '@storybook/addon-interactions@8.2.6':
+ resolution: {integrity: sha512-YXpHf8jWPz9HJV+Fw4GaunaCWeE6uqF24aLXdAd8xuhN1UfWJeNV6AwAvFQ0hTLqvmz0yMhX/5JXDKeKESoYDA==}
+ peerDependencies:
+ storybook: ^8.2.6
- '@storybook/addon-links@8.0.9':
- resolution: {integrity: sha512-FVt+AdW3JFSqbJzkKiqKsMRWqHXqEvCBqFs7lNfk3OW0w0jfv1iREtrxE0dVdJoUFQC9V/2Im/EpJ7UB3C2bNQ==}
+ '@storybook/addon-links@8.2.6':
+ resolution: {integrity: sha512-CUuU3nk8wyZ3bljCmOG/OCKazan+bPuNbCph8N763zyzdEx5M/CbBxV9d3pi3zjYpix7txlqrl2/YdMCejfyFw==}
peerDependencies:
- react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
+ storybook: ^8.2.6
peerDependenciesMeta:
react:
optional: true
- '@storybook/addon-mdx-gfm@8.0.9':
- resolution: {integrity: sha512-AoEx+OGKANtVZgKyWKrQhGpMpDuc2S7PnOlNLUiDYzmj8ABAGPmEJmqeb/VHVgqLQSjhOW1fMsQ4fYsecvMxTQ==}
+ '@storybook/addon-mdx-gfm@8.2.6':
+ resolution: {integrity: sha512-PFVfJeuydxlV1VmxEuKNQ7z2vCDvQtHa2GB0ANM11ahxDSUz8QxsO0Y/L3LOn2JjJGYiVFrsHAaC+8NW43iArQ==}
+ peerDependencies:
+ storybook: ^8.2.6
- '@storybook/addon-measure@8.0.9':
- resolution: {integrity: sha512-91svOOGEXmGG4USglwXLE3wtlUVgtbKJVxTKX7xRI+AC5JEEaKByVzP17/X8Qn/8HilUL7AfSQ0kCoqtPSJ5cA==}
+ '@storybook/addon-measure@8.2.6':
+ resolution: {integrity: sha512-neI8YeSOAtOmzasLxo6O8ZLr2ebMaD7XVF+kYatl5+SpyuwwvUGcP9NkKe5S+mB8V2zxFUIsXS74XrhmQhRoaQ==}
+ peerDependencies:
+ storybook: ^8.2.6
- '@storybook/addon-outline@8.0.9':
- resolution: {integrity: sha512-fQ+jm356TgUnz81IxsC99/aOesbLw3N5OQRJpo/A6kqbLMzlq3ybVzuXYCKC3f0ArgQRNh4NoMeJBMRFMtaWRw==}
+ '@storybook/addon-outline@8.2.6':
+ resolution: {integrity: sha512-uAlPtqDWlq7MQQ4zJT80qdjbSdLF/zsvtPhidX6h9cjLKNPWAv79xJQ14AJHaMv+Hzy5xKnM4wdEhgPbzKabQg==}
+ peerDependencies:
+ storybook: ^8.2.6
- '@storybook/addon-storysource@8.0.9':
- resolution: {integrity: sha512-5m3K2Rs4fQtKtqwrq4CDS1jK2wzWOlnxhE2ArX5XTWytb1am65CEPxfYTEQkvZH9oPGwX3cXytPCziynqysFMQ==}
+ '@storybook/addon-storysource@8.2.6':
+ resolution: {integrity: sha512-8H2kvRIM12oXN4kO/oowABu88IOY9Je7PphCUUs/nIfTIB+Ck1GrLxx5fCNNCSwUrTBEZY8bDOfxmkf9d4qngw==}
+ peerDependencies:
+ storybook: ^8.2.6
- '@storybook/addon-toolbars@8.0.9':
- resolution: {integrity: sha512-nNSBnnBOhQ+EJwkrIkK4ZBYPcozNmEH770CZ/6NK85SUJ6WEBZapE6ru33jIUokFGEvlOlNCeai0GUc++cQP8w==}
+ '@storybook/addon-toolbars@8.2.6':
+ resolution: {integrity: sha512-0JmRirMpxHS6VZzBk0kY871xWTpkk3TN4S1sxoFf5fcnCfVTHDjEJ5Ws/QWru1RJlIZHuJKRdQIA6Vuq5X+KfQ==}
+ peerDependencies:
+ storybook: ^8.2.6
- '@storybook/addon-viewport@8.0.9':
- resolution: {integrity: sha512-Ao4+D56cO7biaw+iTlMU1FBec1idX0cmdosDeCFZin06MSawcPkeBlRBeruaSQYdLes8TBMdZPFgfuqI5yIk6g==}
+ '@storybook/addon-viewport@8.2.6':
+ resolution: {integrity: sha512-IAxH9H8tVFzSmZhKf5E+EALiAdkp19RzGqP/rWluD8LH7oW5HumQE/4oN0ZhVMy1RxYsCKFYjWyAp7AuxeMRSw==}
+ peerDependencies:
+ storybook: ^8.2.6
- '@storybook/blocks@8.0.9':
- resolution: {integrity: sha512-F2zSrfSwzTFN7qW3zB80tG+EXtmfmCDC6Ird0F7tolszb6tOqJcAcBOwQbE2O0wI63sLu21qxzXgaKBMkiWvJg==}
+ '@storybook/blocks@8.2.6':
+ resolution: {integrity: sha512-nMlZJjVTyfOJ6xwORptsNuS1AZZlDbJUVXc2R8uukGd5GIXxxCdrPk4NvUsjfQslMT9LhYuFld3z62FATsM2rw==}
peerDependencies:
- react: ^16.8.0 || ^17.0.0 || ^18.0.0
- react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
+ react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
+ storybook: ^8.2.6
peerDependenciesMeta:
react:
optional: true
react-dom:
optional: true
- '@storybook/builder-manager@8.0.9':
- resolution: {integrity: sha512-/PxDwZIfMc/PSRZcasb6SIdGr3azIlenzx7dBF7Imt8i4jLHiAf1t00GvghlfJsvsrn4DNp95rbRbXTDyTj7tQ==}
+ '@storybook/builder-manager@8.1.11':
+ resolution: {integrity: sha512-U7bmed4Ayg+OlJ8HPmLeGxLTHzDY7rxmxM4aAs4YL01fufYfBcjkIP9kFhJm+GJOvGm+YJEUAPe5mbM1P/bn0Q==}
+
+ '@storybook/builder-vite@8.1.11':
+ resolution: {integrity: sha512-hG4eoNMCPgjZ2Ai+zSmk69zjsyEihe75XbJXtYfGRqjMWtz2+SAUFO54fLc2BD5svcUiTeN+ukWcTrwApyPsKg==}
+ peerDependencies:
+ '@preact/preset-vite': '*'
+ typescript: '>= 4.3.x'
+ vite: ^4.0.0 || ^5.0.0
+ vite-plugin-glimmerx: '*'
+ peerDependenciesMeta:
+ '@preact/preset-vite':
+ optional: true
+ typescript:
+ optional: true
+ vite-plugin-glimmerx:
+ optional: true
- '@storybook/builder-vite@8.0.9':
- resolution: {integrity: sha512-7hEQFZIIz7VvxdySDpPE96iMvZxQvRZcRdhaNGeE+8Y2pyc3DgYE4WY3sjr+LUoB0a6TYLpAIKqbXwtLz0R+PQ==}
+ '@storybook/builder-vite@8.2.6':
+ resolution: {integrity: sha512-3PrsPZAedpQUbzRBEl23Fi1zG5bkQD76JsygVwmfiSm4Est4K8kW2AIB2ht9cIfKXh3mfQkyQlxXKHeQEHeQwQ==}
peerDependencies:
'@preact/preset-vite': '*'
+ storybook: ^8.2.6
typescript: '>= 4.3.x'
vite: ^4.0.0 || ^5.0.0
vite-plugin-glimmerx: '*'
@@ -3971,48 +4253,64 @@ packages:
vite-plugin-glimmerx:
optional: true
- '@storybook/channels@8.0.9':
- resolution: {integrity: sha512-7Lcfyy5CsLWWGhMPO9WG4jZ/Alzp0AjepFhEreYHRPtQrfttp6qMAjE/g1aHgun0qHCYWxwqIG4NLR/hqDNrXQ==}
+ '@storybook/channels@8.1.11':
+ resolution: {integrity: sha512-fu5FTqo6duOqtJFa6gFzKbiSLJoia+8Tibn3xFfB6BeifWrH81hc+AZq0lTmHo5qax2G5t8ZN8JooHjMw6k2RA==}
- '@storybook/cli@8.0.9':
- resolution: {integrity: sha512-lilYTKn8F5YOePijqfRYFa5v2mHVIJxPCIgTn+OXAmAFbcizZ6P8P6niU4J/NXulgx68Ln1M7hYhFtTP25hVTw==}
- hasBin: true
+ '@storybook/client-logger@8.1.11':
+ resolution: {integrity: sha512-DVMh2usz3yYmlqCLCiCKy5fT8/UR9aTh+gSqwyNFkGZrIM4otC5A8eMXajXifzotQLT5SaOEnM3WzHwmpvMIEA==}
- '@storybook/client-logger@8.0.9':
- resolution: {integrity: sha512-LzV/RHkbf07sRc1Jc0ff36RlapKf9Ul7/+9VMvVbI3hshH1CpmrZK4t/tsIdpX/EVOdJ1Gg5cES06PnleOAIPA==}
+ '@storybook/codemod@8.2.6':
+ resolution: {integrity: sha512-+mFJ6R+JhJLpU7VPDlXU5Yn6nqIBq745GaEosnIiFOdNo3jaxJ58wq/sGhbQvoCHPUxMA+sDQvR7pS62YFoLRQ==}
- '@storybook/codemod@8.0.9':
- resolution: {integrity: sha512-VBeGpSZSQpL6iyLLqceJSNGhdCqcNwv+xC/aWdDFOkmuE1YfbmNNwpa9QYv4ZFJ2QjUsm4iTWG60qK+9NXeSKA==}
+ '@storybook/components@8.2.6':
+ resolution: {integrity: sha512-H8ckH1AnLkHtMtvJ3J8LxnmDtHxkJ7NJacGctHMRrsBIvdKTVwlT4su5nAVVJlan/PrEou+jESfw+OjjBYE5PA==}
+ peerDependencies:
+ storybook: ^8.2.6
- '@storybook/components@8.0.9':
- resolution: {integrity: sha512-JcwBGADzIJs0PSzqykrrD2KHzNG9wtexUOKuidt+FSv9szpUhe3qBAXIHpdfBRl7mOJ9TRZ5rt+mukEnfncdzA==}
+ '@storybook/core-common@8.1.11':
+ resolution: {integrity: sha512-Ix0nplD4I4DrV2t9B+62jaw1baKES9UbR/Jz9LVKFF9nsua3ON0aVe73dOjMxFWBngpzBYWe+zYBTZ7aQtDH4Q==}
peerDependencies:
- react: ^16.8.0 || ^17.0.0 || ^18.0.0
- react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+ prettier: ^2 || ^3
+ peerDependenciesMeta:
+ prettier:
+ optional: true
- '@storybook/core-common@8.0.9':
- resolution: {integrity: sha512-Jmue+sfHFb4GTYBzyWYw1MygoJiQSfISIrKmNIzAmZ+oR9EOr+jpu/i/bH+uetZ2Hqg1AGhj1VB7OtJp9HQyWw==}
+ '@storybook/core-events@8.1.11':
+ resolution: {integrity: sha512-vXaNe2KEW9BGlLrg0lzmf5cJ0xt+suPjWmEODH5JqBbrdZ67X6ApA2nb6WcxDQhykesWCuFN5gp1l+JuDOBi7A==}
- '@storybook/core-events@8.0.9':
- resolution: {integrity: sha512-DxSUx7wG9Qe3OFUBnv3OrYq48J8UWNo2DUR5/JecJCtp3n++L4fAEW3J0IF5FfxpQDMQSp1yTNjZ2PaWCMd2ag==}
+ '@storybook/core-events@8.2.6':
+ resolution: {integrity: sha512-bmtm7sHBExKCSGiCIyhwfHKFIsdrRQqd8ZEb/iNWsR93AxHszcf/adYAVynencdWKipw1haIWBNaiDhnsOBVPA==}
+ peerDependencies:
+ storybook: ^8.2.6
+
+ '@storybook/core-server@8.1.11':
+ resolution: {integrity: sha512-L6dzQTmR0np/kagNONvvlm6lSvF1FNc9js3vxsEEPnEypLbhx8bDZaHmuhmBpYUzKyUMpRVQTE/WgjHLuBBuxA==}
- '@storybook/core-server@8.0.9':
- resolution: {integrity: sha512-BIe1T5YUBl0GYxEjRoTQsvXD2pyuzL8rPTUD41zlzSQM0R8U6Iant9SzRms4u0+rKUm2mGxxKuODlUo5ewqaGA==}
+ '@storybook/core@8.2.6':
+ resolution: {integrity: sha512-XY71g3AcpD6IiER9k9Lt+vlUMYfPIYgWekd7e0Ggzz2gJkPuLunKEdQccLGDSHf5OFAobHhrTJc7ZsvWhmDMag==}
- '@storybook/csf-plugin@8.0.9':
- resolution: {integrity: sha512-pXaNCNi++kxKsqSWwvx215fPx8cNqvepLVxQ7B69qXLHj80DHn0Q3DFBO3sLXNiQMJ2JK4OYcTxMfuOiyzszKw==}
+ '@storybook/csf-plugin@8.1.11':
+ resolution: {integrity: sha512-hkA8gjFtSN/tabG0cuvmEqanMXtxPr3qTkp4UNSt1R6jBEgFHRG2y/KYLl367kDwOSFTT987ZgRfJJruU66Fvw==}
+
+ '@storybook/csf-plugin@8.2.6':
+ resolution: {integrity: sha512-USn7E/bMQYVqvFBuW6d9rKoSuCImjk0BAmc/0wIOuMQ/yQNp2Xze0m8eVkNHUIUDokyx0TXDjRjwq10Xxk16ag==}
+ peerDependencies:
+ storybook: ^8.2.6
- '@storybook/csf-tools@8.0.9':
- resolution: {integrity: sha512-PiNMhL97giLytTdQwuhsZ92buVk4gy9H/8DtrDhUc45/1OmF95gogm6T2Yap729SIFwgpOcuq/U3aVo6d6swVQ==}
+ '@storybook/csf-tools@8.1.11':
+ resolution: {integrity: sha512-6qMWAg/dBwCVIHzANM9lSHoirwqSS+wWmv+NwAs0t9S94M75IttHYxD3IyzwaSYCC5llp0EQFvtXXAuSfFbibg==}
- '@storybook/csf@0.1.6':
- resolution: {integrity: sha512-JjWnBptVhBYJ14yq+cHs66BXjykRUWQ5TlD1RhPxMOtavynYyV/Q+QR98/N+XB+mcPtFMm5I2DvNkpj0/Dk8Mw==}
+ '@storybook/csf@0.1.11':
+ resolution: {integrity: sha512-dHYFQH3mA+EtnCkHXzicbLgsvzYjcDJ1JWsogbItZogkPHgSJM/Wr71uMkcvw8v9mmCyP4NpXJuu6bPoVsOnzg==}
- '@storybook/docs-mdx@3.0.0':
- resolution: {integrity: sha512-NmiGXl2HU33zpwTv1XORe9XG9H+dRUC1Jl11u92L4xr062pZtrShLmD4VKIsOQujxhhOrbxpwhNOt+6TdhyIdQ==}
+ '@storybook/csf@0.1.9':
+ resolution: {integrity: sha512-JlZ6v/iFn+iKohKGpYXnMeNeTiiAMeFoDhYnPLIC8GnyyIWqEI9wJYrOK9i9rxlJ8NZAH/ojGC/u/xVC41qSgQ==}
- '@storybook/docs-tools@8.0.9':
- resolution: {integrity: sha512-OzogAeOmeHea/MxSPKRBWtOQVNSpoq+OOpimO9YRA5h5GBRJ2TUOGT44Gny6QT4ll5AvQA8fIiq9KezKcLekAg==}
+ '@storybook/docs-mdx@3.1.0-next.0':
+ resolution: {integrity: sha512-t4syFIeSyufieNovZbLruPt2DmRKpbwL4fERCZ1MifWDRIORCKLc4NCEHy+IqvIqd71/SJV2k4B51nF7vlJfmQ==}
+
+ '@storybook/docs-tools@8.1.11':
+ resolution: {integrity: sha512-mEXtR9rS7Y+OdKtT/QG6JBGYR1L41mcDhIqhnk7RmYl9qJstVAegrCKWR53sPKFdTVOHU7dmu6k+BD+TqHpyyw==}
'@storybook/global@5.0.0':
resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==}
@@ -4024,85 +4322,121 @@ packages:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
- '@storybook/instrumenter@8.0.9':
- resolution: {integrity: sha512-Gw74dgpTU/2p7FG0s7DuVdqCbJ2MEcSuRJjDo7HcXRYcvWp7I6Ly+C0v7N5VaoS+kbBVerAhLKIHZgG/LZf1og==}
+ '@storybook/instrumenter@8.2.6':
+ resolution: {integrity: sha512-RxtpcMTUSq8/wPM6cR6EXVrPEiNuRbC71cIFVFZagOFYvnnOKwSPV+GOLPK0wxMbGB4c5/+Xe8ADefmZTvxOsA==}
+ peerDependencies:
+ storybook: ^8.2.6
- '@storybook/manager-api@8.0.9':
- resolution: {integrity: sha512-99b3yKArDSvfabXL7QE3nA95e4DdW/5H/ZCcr6/E2qCQJayZ6G1v/WWamKXbiaTpkndulFmcb/+ZmnDXcweIIQ==}
+ '@storybook/manager-api@8.1.11':
+ resolution: {integrity: sha512-QSgwKfAw01K9YvvZj30iGBMgQ4YaCT3vojmttuqdH5ukyXkiO7pENLJj4Y+alwUeSi0g+SJeadCI3PXySBHOGg==}
- '@storybook/manager@8.0.9':
- resolution: {integrity: sha512-+NnRo+5JQFGNqveKrLtC0b+Z08Tae4m44iq292bPeZMpr9OkFsIkU0PBPsHTHPkrqC/zZXRNsCsTEgvu3p2OIA==}
+ '@storybook/manager-api@8.2.6':
+ resolution: {integrity: sha512-uv36h/b5RhlajWtEg4cVPBYV8gZs6juux0nIE+6G9i7vt8Ild6gM9tW1KNabgZcaHFiyWJYCNWxJZoKjgUmXDg==}
+ peerDependencies:
+ storybook: ^8.2.6
- '@storybook/node-logger@8.0.9':
- resolution: {integrity: sha512-5ajMdZFrYrjGLJOVDq7dlEQNFsgeLHymt4dCK9MulL/ciXykmXUZXE3Bye0wFy+I2qqDVvrvR8uzCvSFvm5MAQ==}
+ '@storybook/manager@8.1.11':
+ resolution: {integrity: sha512-e02y9dmxowo7cTKYm9am7UO6NOHoHy6Xi7xZf/UA932qLwFZUtk5pnwIEFaZWI3OQsRUCGhP+FL5zizU7uVZeg==}
- '@storybook/preview-api@8.0.9':
- resolution: {integrity: sha512-zHfX34bkAMzzmE7vbDzaqFwSW6ExiBD0HiO1L/IsHF55f0f7xV7IH8uJyFRrDTvAoW3ReSxZDMvvPpeydFPKGA==}
+ '@storybook/node-logger@8.1.11':
+ resolution: {integrity: sha512-wdzFo7B2naGhS52L3n1qBkt5BfvQjs8uax6B741yKRpiGgeAN8nz8+qelkD25MbSukxvbPgDot7WJvsMU/iCzg==}
- '@storybook/preview@8.0.9':
- resolution: {integrity: sha512-tFsR8xc8AYBZZrZw8enklFbSQt7ZAV+rv20BoxwDhd3q7fjXyK7O4moGPqUwBZ7rukTG13nPoISxr+VXAk/HYA==}
+ '@storybook/preview-api@8.1.11':
+ resolution: {integrity: sha512-8ZChmFV56GKppCJ0hnBd/kNTfGn2gWVq1242kuet13pbJtBpvOhyq4W01e/Yo14tAPXvgz8dSnMvWLbJx4QfhQ==}
- '@storybook/react-dom-shim@8.0.9':
- resolution: {integrity: sha512-8011KlRuG3obr5pZZ7bcEyYYNWF3tR596YadoMd267NPoHKvwAbKL1L/DNgb6kiYjZDUf9QfaKSCWW31k0kcRQ==}
+ '@storybook/preview-api@8.2.6':
+ resolution: {integrity: sha512-5vTj2ndX5ng4nDntZYe+r8UwLjCIGFymhq5/r2adAvRKL+Bo4zQDWGO7bhvGJk16do2THb2JvPz49ComW9LLZw==}
peerDependencies:
- react: ^16.8.0 || ^17.0.0 || ^18.0.0
- react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+ storybook: ^8.2.6
+
+ '@storybook/preview@8.1.11':
+ resolution: {integrity: sha512-K/9NZmjnL0D1BROkTNWNoPqgL2UaocALRSqCARmkBLgU2Rn/FuZgEclHkWlYo6pUrmLNK+bZ+XzpNMu12iTbpg==}
+
+ '@storybook/react-dom-shim@8.2.6':
+ resolution: {integrity: sha512-B+x8UAEQPDp1yhN3tMh09NvSL38QNfJB7PAyLgKrfE7xIAzvewq+RLW2DfGkoZCy+Zr7QSHm1p7NOgud8+sQCg==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
+ react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
+ storybook: ^8.2.6
- '@storybook/react-vite@8.0.9':
- resolution: {integrity: sha512-FT5KeulUH6grfzOJOxJCxpv9+81UVDrT9UPcgiFhQT9rKtsgmltezThwbHknByZNw3WWnf+ieidMLEis9hd73A==}
+ '@storybook/react-vite@8.2.6':
+ resolution: {integrity: sha512-BpbteaIzsJZL1QN3iR7uuslrPfdtbZYXPhcU9awpfl5pW5MOQThuvl7728mwT8V7KdANeikJPgsnlETOb/afDA==}
engines: {node: '>=18.0.0'}
peerDependencies:
- react: ^16.8.0 || ^17.0.0 || ^18.0.0
- react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
+ react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
+ storybook: ^8.2.6
vite: ^4.0.0 || ^5.0.0
- '@storybook/react@8.0.9':
- resolution: {integrity: sha512-NeQ6suZG3HKikwe3Tx9cAIaRx7uP8FKCmlVvIiBg4LTTI5orCt94PPakvuZukZcbkqvcCnEBkebAzwUpn8PiJw==}
+ '@storybook/react@8.2.6':
+ resolution: {integrity: sha512-awJlzfiAMrf8l9AgiLhjXEJ+HvS3VKPxNNQaRwBELGq/vigjJe656tMrhvg4OIlJXtlS+6XPshd2knLwjIWNLw==}
engines: {node: '>=18.0.0'}
peerDependencies:
- react: ^16.8.0 || ^17.0.0 || ^18.0.0
- react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
+ react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
+ storybook: ^8.2.6
typescript: '>= 4.2.x'
peerDependenciesMeta:
typescript:
optional: true
- '@storybook/router@8.0.9':
- resolution: {integrity: sha512-aAOWxbM9J4mt+cp4o88T2PB29mgBBTOzU37/pUsTHYnKnR9XI4npXEXdN8Gv+ryqM0kj0AbBpz/llFlnR2MNNA==}
+ '@storybook/router@8.1.11':
+ resolution: {integrity: sha512-nU5lsBvy0L8wBYOkjagh29ztZicDATpZNYrHuavlhQ2jznmmHdJvXKYk+VrMAbthjQ6ZBqfeeMNPR1UlnqR5Rw==}
- '@storybook/source-loader@8.0.9':
- resolution: {integrity: sha512-FDnpxIGE5nIYT15pvYe6rz95TSBrdLcDll7lOHNyZisWt19MI3wZU3YkVsFNRBuFrebo+FjVU3wHyoV81ur1Qw==}
+ '@storybook/source-loader@8.2.6':
+ resolution: {integrity: sha512-mOVf+TJhlQywCymFMs7l604CxEZRKZRKVQojrrgU6CH6EhhLx/q6BT8tf1CakY9JO3Ey+PhUMBBCerYiDaHLcQ==}
+ peerDependencies:
+ storybook: ^8.2.6
- '@storybook/telemetry@8.0.9':
- resolution: {integrity: sha512-AGGfcup06t+wxhBIkHd0iybieOh9PDVZQJ9oPct5JGB39+ni9wvs0WOD+MYlHbsjp8id7+aGkh6mYuYOvfck+Q==}
+ '@storybook/telemetry@8.1.11':
+ resolution: {integrity: sha512-Jqvm7HcZismKzPuebhyLECO6KjGiSk4ycbca1WUM/TUvifxCXqgoUPlHHQEEfaRdHS63/MSqtMNjLsQRLC/vNQ==}
- '@storybook/test@8.0.9':
- resolution: {integrity: sha512-bRd5tBJnPzR6UKbDXONWnFWtdkNOY99HMLDUWe5fTRo50GwkrpFBVqPflhdkruEeof0kAbBUbnoN2CIYgtnAFw==}
+ '@storybook/test@8.2.6':
+ resolution: {integrity: sha512-nTzNxReBcMRlX1+8PNU/MuA9ArFbeQhfZXMBIwJJoHOhnNe1knYpyn1++xINxAHKOh0BBhQ0NIMoKdcGmW3V6w==}
+ peerDependencies:
+ storybook: ^8.2.6
- '@storybook/theming@8.0.9':
- resolution: {integrity: sha512-jgfDuYoiNMMirQiASN3Eg0hGDXsEtpdAcMxyShqYGwu9elxgD9yUnYC2nSckYsM74a3ZQ3JaViZ9ZFSe2FHmeQ==}
+ '@storybook/theming@8.1.11':
+ resolution: {integrity: sha512-Chn/opjO6Rl1isNobutYqAH2PjKNkj09YBw/8noomk6gElSa3JbUTyaG/+JCHA6OG/9kUsqoKDb5cZmAKNq/jA==}
peerDependencies:
- react: ^16.8.0 || ^17.0.0 || ^18.0.0
- react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
+ react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
peerDependenciesMeta:
react:
optional: true
react-dom:
optional: true
- '@storybook/types@8.0.9':
- resolution: {integrity: sha512-ew0EXzk9k4B557P1qIWYrnvUcgaE0WWA5qQS0AU8l+fRTp5nvl9O3SP/zNIB0SN1qDFO7dXr3idTNTyIikTcEQ==}
+ '@storybook/theming@8.2.6':
+ resolution: {integrity: sha512-ICnYuLIVsYifVCMQljdHgrp+5vAquNybHxDGWiPeOxBicotwHF8rLhTckD2CdVQbMp0jk6r6jetvjXbFJ2MbvQ==}
+ peerDependencies:
+ storybook: ^8.2.6
+
+ '@storybook/types@8.1.11':
+ resolution: {integrity: sha512-k9N5iRuY2+t7lVRL6xeu6diNsxO3YI3lS4Juv3RZ2K4QsE/b3yG5ElfJB8DjHDSHwRH4ORyrU71KkOCUVfvtnw==}
+
+ '@storybook/types@8.2.6':
+ resolution: {integrity: sha512-9Kb5+nui8M7TP/EDGwiuOAHYQPg9U6iQl0OWwgbDIYGBpldwlCwVKAoQWzXz/LlhQijULXIpe1cLvEvJN2Uwhg==}
+ peerDependencies:
+ storybook: ^8.2.6
- '@storybook/vue3-vite@8.0.9':
- resolution: {integrity: sha512-IkzYsEyCo5HIvLWbJeGrBu/VIN4u+LvdIAz7vcFqVVXBtTUhy+9/8caLx8fdnM0FWgKcBRQs8HnjBB2V0lOFcg==}
+ '@storybook/vue3-vite@8.1.11':
+ resolution: {integrity: sha512-q0bqh8XEEunaTmp4YiDqM2+YZLwEIevTb5PnNe7G7f2qOiSCE1ncBDnBK717UlCd+iYr34NTztgV2/jIhz1i5w==}
engines: {node: '>=18.0.0'}
peerDependencies:
vite: ^4.0.0 || ^5.0.0
- '@storybook/vue3@8.0.9':
- resolution: {integrity: sha512-EqVdS62YbOCAE0wJrQKW0sHpM90be8N8Mvmj+HzB0QYhJNtFqP9ehwbcTfwEKtaVGudisHgGBOzNoSKDlxFaag==}
+ '@storybook/vue3@8.1.11':
+ resolution: {integrity: sha512-xJtvfLiCOY3UqwDMd0hZdsadPm1q8dwjfM1UN2Q2ssRWNfXzww1oi+Msj902wz9zFZMYVZypfTfgrdRgWmfEjA==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ vue: ^3.0.0
+
+ '@storybook/vue3@8.2.6':
+ resolution: {integrity: sha512-j4gMuWc1ZDzqWSdf79YswcZmcbhmbByq/6upqxwqXtjv1mHAiBnEs8bbnnylDrzg4GOvBC8w+FjArkzlFA7uXg==}
engines: {node: '>=18.0.0'}
peerDependencies:
+ storybook: ^8.2.6
vue: ^3.0.0
'@swc/cli@0.3.12':
@@ -4128,8 +4462,14 @@ packages:
cpu: [arm64]
os: [darwin]
- '@swc/core-darwin-arm64@1.4.17':
- resolution: {integrity: sha512-HVl+W4LezoqHBAYg2JCqR+s9ife9yPfgWSj37iIawLWzOmuuJ7jVdIB7Ee2B75bEisSEKyxRlTl6Y1Oq3owBgw==}
+ '@swc/core-darwin-arm64@1.6.13':
+ resolution: {integrity: sha512-SOF4buAis72K22BGJ3N8y88mLNfxLNprTuJUpzikyMGrvkuBFNcxYtMhmomO0XHsgLDzOJ+hWzcgjRNzjMsUcQ==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@swc/core-darwin-arm64@1.6.6':
+ resolution: {integrity: sha512-5DA8NUGECcbcK1YLKJwNDKqdtTYDVnkfDU1WvQSXq/rU+bjYCLtn5gCe8/yzL7ISXA6rwqPU1RDejhbNt4ARLQ==}
engines: {node: '>=10'}
cpu: [arm64]
os: [darwin]
@@ -4140,8 +4480,14 @@ packages:
cpu: [x64]
os: [darwin]
- '@swc/core-darwin-x64@1.4.17':
- resolution: {integrity: sha512-WYRO9Fdzq4S/he8zjW5I95G1zcvyd9yyD3Tgi4/ic84P5XDlSMpBDpBLbr/dCPjmSg7aUXxNQqKqGkl6dQxYlA==}
+ '@swc/core-darwin-x64@1.6.13':
+ resolution: {integrity: sha512-AW8akFSC+tmPE6YQQvK9S2A1B8pjnXEINg+gGgw0KRUUXunvu1/OEOeC5L2Co1wAwhD7bhnaefi06Qi9AiwOag==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@swc/core-darwin-x64@1.6.6':
+ resolution: {integrity: sha512-2nbh/RHpweNRsJiYDFk1KcX7UtaKgzzTNUjwtvK5cp0wWrpbXmPvdlWOx3yzwoiSASDFx78242JHHXCIOlEdsw==}
engines: {node: '>=10'}
cpu: [x64]
os: [darwin]
@@ -4158,8 +4504,14 @@ packages:
cpu: [arm]
os: [linux]
- '@swc/core-linux-arm-gnueabihf@1.4.17':
- resolution: {integrity: sha512-cgbvpWOvtMH0XFjvwppUCR+Y+nf6QPaGu6AQ5hqCP+5Lv2zO5PG0RfasC4zBIjF53xgwEaaWmGP5/361P30X8Q==}
+ '@swc/core-linux-arm-gnueabihf@1.6.13':
+ resolution: {integrity: sha512-f4gxxvDXVUm2HLYXRd311mSrmbpQF2MZ4Ja6XCQz1hWAxXdhRl1gpnZ+LH/xIfGSwQChrtLLVrkxdYUCVuIjFg==}
+ engines: {node: '>=10'}
+ cpu: [arm]
+ os: [linux]
+
+ '@swc/core-linux-arm-gnueabihf@1.6.6':
+ resolution: {integrity: sha512-YgytuyUfR7b0z0SRHKV+ylr83HmgnROgeT7xryEkth6JGpAEHooCspQ4RrWTU8+WKJ7aXiZlGXPgybQ4TiS+TA==}
engines: {node: '>=10'}
cpu: [arm]
os: [linux]
@@ -4170,8 +4522,14 @@ packages:
cpu: [arm64]
os: [linux]
- '@swc/core-linux-arm64-gnu@1.4.17':
- resolution: {integrity: sha512-l7zHgaIY24cF9dyQ/FOWbmZDsEj2a9gRFbmgx2u19e3FzOPuOnaopFj0fRYXXKCmtdx+anD750iBIYnTR+pq/Q==}
+ '@swc/core-linux-arm64-gnu@1.6.13':
+ resolution: {integrity: sha512-Nf/eoW2CbG8s+9JoLtjl9FByBXyQ5cjdBsA4efO7Zw4p+YSuXDgc8HRPC+E2+ns0praDpKNZtLvDtmF2lL+2Gg==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@swc/core-linux-arm64-gnu@1.6.6':
+ resolution: {integrity: sha512-yGwx9fddzEE0iURqRVwKBQ4IwRHE6hNhl15WliHpi/PcYhzmYkUIpcbRXjr0dssubXAVPVnx6+jZVDSbutvnfg==}
engines: {node: '>=10'}
cpu: [arm64]
os: [linux]
@@ -4182,8 +4540,14 @@ packages:
cpu: [arm64]
os: [linux]
- '@swc/core-linux-arm64-musl@1.4.17':
- resolution: {integrity: sha512-qhH4gr9gAlVk8MBtzXbzTP3BJyqbAfUOATGkyUtohh85fPXQYuzVlbExix3FZXTwFHNidGHY8C+ocscI7uDaYw==}
+ '@swc/core-linux-arm64-musl@1.6.13':
+ resolution: {integrity: sha512-2OysYSYtdw79prJYuKIiux/Gj0iaGEbpS2QZWCIY4X9sGoETJ5iMg+lY+YCrIxdkkNYd7OhIbXdYFyGs/w5LDg==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@swc/core-linux-arm64-musl@1.6.6':
+ resolution: {integrity: sha512-a6fMbqzSAsS5KCxFJyg1mD5kwN3ZFO8qQLyJ75R/htZP/eCt05jrhmOI7h2n+1HjiG332jLnZ9S8lkVE5O8Nqw==}
engines: {node: '>=10'}
cpu: [arm64]
os: [linux]
@@ -4194,8 +4558,14 @@ packages:
cpu: [x64]
os: [linux]
- '@swc/core-linux-x64-gnu@1.4.17':
- resolution: {integrity: sha512-vRDFATL1oN5oZMImkwbgSHEkp8xG1ofEASBypze01W1Tqto8t+yo6gsp69wzCZBlxldsvPpvFZW55Jq0Rn+UnA==}
+ '@swc/core-linux-x64-gnu@1.6.13':
+ resolution: {integrity: sha512-PkR4CZYJNk5hcd2+tMWBpnisnmYsUzazI1O5X7VkIGFcGePTqJ/bWlfUIVVExWxvAI33PQFzLbzmN5scyIUyGQ==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [linux]
+
+ '@swc/core-linux-x64-gnu@1.6.6':
+ resolution: {integrity: sha512-hRGsUKNzzZle28YF0dYIpN0bt9PceR9LaVBq7x8+l9TAaDLFbgksSxcnU/ubTtsy+WsYSYGn+A83w3xWC0O8CQ==}
engines: {node: '>=10'}
cpu: [x64]
os: [linux]
@@ -4206,8 +4576,14 @@ packages:
cpu: [x64]
os: [linux]
- '@swc/core-linux-x64-musl@1.4.17':
- resolution: {integrity: sha512-zQNPXAXn3nmPqv54JVEN8k2JMEcMTQ6veVuU0p5O+A7KscJq+AGle/7ZQXzpXSfUCXlLMX4wvd+rwfGhh3J4cw==}
+ '@swc/core-linux-x64-musl@1.6.13':
+ resolution: {integrity: sha512-OdsY7wryTxCKwGQcwW9jwWg3cxaHBkTTHi91+5nm7hFPpmZMz1HivJrWAMwVE7iXFw+M4l6ugB/wCvpYrUAAjA==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [linux]
+
+ '@swc/core-linux-x64-musl@1.6.6':
+ resolution: {integrity: sha512-NokIUtFxJDVv3LzGeEtYMTV3j2dnGKLac59luTeq36DQLZdJQawQIdTbzzWl2jE7lxxTZme+dhsVOH9LxE3ceg==}
engines: {node: '>=10'}
cpu: [x64]
os: [linux]
@@ -4218,8 +4594,14 @@ packages:
cpu: [arm64]
os: [win32]
- '@swc/core-win32-arm64-msvc@1.4.17':
- resolution: {integrity: sha512-z86n7EhOwyzxwm+DLE5NoLkxCTme2lq7QZlDjbQyfCxOt6isWz8rkW5QowTX8w9Rdmk34ncrjSLvnHOeLY17+w==}
+ '@swc/core-win32-arm64-msvc@1.6.13':
+ resolution: {integrity: sha512-ap6uNmYjwk9M/+bFEuWRNl3hq4VqgQ/Lk+ID/F5WGqczNr0L7vEf+pOsRAn0F6EV+o/nyb3ePt8rLhE/wjHpPg==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@swc/core-win32-arm64-msvc@1.6.6':
+ resolution: {integrity: sha512-lzYdI4qb4k1dFG26yv+9Jaq/bUMAhgs/2JsrLncGjLof86+uj74wKYCQnbzKAsq2hDtS5DqnHnl+//J+miZfGA==}
engines: {node: '>=10'}
cpu: [arm64]
os: [win32]
@@ -4230,8 +4612,14 @@ packages:
cpu: [ia32]
os: [win32]
- '@swc/core-win32-ia32-msvc@1.4.17':
- resolution: {integrity: sha512-JBwuSTJIgiJJX6wtr4wmXbfvOswHFj223AumUrK544QV69k60FJ9q2adPW9Csk+a8wm1hLxq4HKa2K334UHJ/g==}
+ '@swc/core-win32-ia32-msvc@1.6.13':
+ resolution: {integrity: sha512-IJ8KH4yIUHTnS/U1jwQmtbfQals7zWPG0a9hbEfIr4zI0yKzjd83lmtS09lm2Q24QBWOCFGEEbuZxR4tIlvfzA==}
+ engines: {node: '>=10'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@swc/core-win32-ia32-msvc@1.6.6':
+ resolution: {integrity: sha512-bvl7FMaXIJQ76WZU0ER4+RyfKIMGb6S2MgRkBhJOOp0i7VFx4WLOnrmMzaeoPJaJSkityVKAftfNh7NBzTIydQ==}
engines: {node: '>=10'}
cpu: [ia32]
os: [win32]
@@ -4242,17 +4630,32 @@ packages:
cpu: [x64]
os: [win32]
- '@swc/core-win32-x64-msvc@1.4.17':
- resolution: {integrity: sha512-jFkOnGQamtVDBm3MF5Kq1lgW8vx4Rm1UvJWRUfg+0gx7Uc3Jp3QMFeMNw/rDNQYRDYPG3yunCC+2463ycd5+dg==}
+ '@swc/core-win32-x64-msvc@1.6.13':
+ resolution: {integrity: sha512-f6/sx6LMuEnbuxtiSL/EkR0Y6qUHFw1XVrh6rwzKXptTipUdOY+nXpKoh+1UsBm/r7H0/5DtOdrn3q5ZHbFZjQ==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [win32]
+
+ '@swc/core-win32-x64-msvc@1.6.6':
+ resolution: {integrity: sha512-WAP0JoCTfgeYKgOeYJoJV4ZS0sQUmU3OwvXa2dYYtMLF7zsNqOiW4niU7QlThBHgUv/qNZm2p6ITEgh3w1cltw==}
engines: {node: '>=10'}
cpu: [x64]
os: [win32]
- '@swc/core@1.4.17':
- resolution: {integrity: sha512-tq+mdWvodMBNBBZbwFIMTVGYHe9N7zvEaycVVjfvAx20k1XozHbHhRv+9pEVFJjwRxLdXmtvFZd3QZHRAOpoNQ==}
+ '@swc/core@1.6.13':
+ resolution: {integrity: sha512-eailUYex6fkfaQTev4Oa3mwn0/e3mQU4H8y1WPuImYQESOQDtVrowwUGDSc19evpBbHpKtwM+hw8nLlhIsF+Tw==}
engines: {node: '>=10'}
peerDependencies:
- '@swc/helpers': ^0.5.0
+ '@swc/helpers': '*'
+ peerDependenciesMeta:
+ '@swc/helpers':
+ optional: true
+
+ '@swc/core@1.6.6':
+ resolution: {integrity: sha512-sHfmIUPUXNrQTwFMVCY5V5Ena2GTOeaWjS2GFUpjLhAgVfP90OP67DWow7+cYrfFtqBdILHuWnjkTcd0+uPKlg==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@swc/helpers': '*'
peerDependenciesMeta:
'@swc/helpers':
optional: true
@@ -4266,14 +4669,14 @@ packages:
peerDependencies:
'@swc/core': '*'
- '@swc/types@0.1.5':
- resolution: {integrity: sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==}
+ '@swc/types@0.1.9':
+ resolution: {integrity: sha512-qKnCno++jzcJ4lM4NTfYifm1EFSCeIfKiAHAfkENZAV5Kl9PjJIyd2yeeVv6c/2CckuLyv2NmRC5pv6pm2WQBg==}
'@swc/wasm@1.2.130':
resolution: {integrity: sha512-rNcJsBxS70+pv8YUWwf5fRlWX6JoY/HJc25HD/F8m6Kv7XhJdqPPMhyX6TKkUBPAG7TWlZYoxa+rHAjPy4Cj3Q==}
- '@syuilo/aiscript@0.18.0':
- resolution: {integrity: sha512-/iY9Vv4LLjtW/KUzId1QwXC4BlpIEPCMcoT7dyRhYdyxtwhS3Hx4b/4j1HYP+n3Pq9XKyW5zvkY72/+DNu4g6Q==}
+ '@syuilo/aiscript@0.19.0':
+ resolution: {integrity: sha512-ZWG4s1m6RrFjE7NeIMaxFz769YO1jW5ReTrOROrEO4IHheOrjxxJ/Ffe2TUNqX9/XxDloMwfWplKhfSzx8LGMA==}
'@szmarczak/http-timer@4.0.6':
resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==}
@@ -4329,16 +4732,16 @@ packages:
resolution: {integrity: sha512-EmCsnzdvawyk4b+4JKaLLuicHcJQRZtL1zSy9AWJLiiHTbDDseYgLxfaCEfLk8v2bUe7SBXwl3n3B7OjgvH11Q==}
hasBin: true
- '@testing-library/dom@9.3.3':
- resolution: {integrity: sha512-fB0R+fa3AUqbLHWyxXa2kGVtf1Fe1ZZFr0Zp6AIbIAzXb2mKbEXl+PCQNUOaq5lbTab5tfctfXRNsWXxa2f7Aw==}
- engines: {node: '>=14'}
+ '@testing-library/dom@10.1.0':
+ resolution: {integrity: sha512-wdsYKy5zupPyLCW2Je5DLHSxSfbIp6h80WoHOQc+RPtmPGA52O9x5MJEkv92Sjonpq+poOAtUKhh1kBGAXBrNA==}
+ engines: {node: '>=18'}
'@testing-library/dom@9.3.4':
resolution: {integrity: sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==}
engines: {node: '>=14'}
- '@testing-library/jest-dom@6.4.2':
- resolution: {integrity: sha512-CzqH0AFymEMG48CpzXFriYYkOjk6ZGPCLMhW9e9jg3KMCn5OfJecF8GtGW7yGfR/IgCe3SX8BSwjdzI6BBbZLw==}
+ '@testing-library/jest-dom@6.4.5':
+ resolution: {integrity: sha512-AguB9yvTXmCnySBP1lWjfNNUwpbElsaQ567lt2VdGqAdHtpieLgjmcVyv1q7PMIvLbgpDdkWV5Ydv3FEejyp2A==}
engines: {node: '>=14', npm: '>=6', yarn: '>=1'}
peerDependencies:
'@jest/globals': '>= 28'
@@ -4364,8 +4767,8 @@ packages:
peerDependencies:
'@testing-library/dom': '>=7.21.4'
- '@testing-library/vue@8.0.3':
- resolution: {integrity: sha512-wSsbNlZ69ZFQgVlHMtc/ZC/g9BHO7MhyDrd4nHyfEubtMr3kToN/w4/BsSBknGIF8w9UmPbsgbIuq/CbdBHzCA==}
+ '@testing-library/vue@8.1.0':
+ resolution: {integrity: sha512-ls4RiHO1ta4mxqqajWRh8158uFObVrrtAPoxk7cIp4HrnQUj/ScKzqz53HxYpG3X6Zb7H2v+0eTGLSoy8HQ2nA==}
engines: {node: '>=14'}
peerDependencies:
'@vue/compiler-sfc': '>= 3'
@@ -4381,8 +4784,8 @@ packages:
resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
engines: {node: '>=10.13.0'}
- '@tsd/typescript@5.3.3':
- resolution: {integrity: sha512-CQlfzol0ldaU+ftWuG52vH29uRoKboLinLy84wS8TQOu+m+tWoaUfk4svL4ij2V8M5284KymJBlHUusKj6k34w==}
+ '@tsd/typescript@5.4.5':
+ resolution: {integrity: sha512-saiCxzHRhUrRxQV2JhH580aQUZiKQUXI38FcAcikcfOomAil4G4lxT0RfrrKywoAYP/rqAdYXYmNRLppcd+hQQ==}
engines: {node: '>=14.17'}
'@twemoji/parser@15.0.0':
@@ -4427,12 +4830,6 @@ packages:
'@types/cacheable-request@6.0.3':
resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==}
- '@types/chai-subset@1.3.5':
- resolution: {integrity: sha512-c2mPnw+xHtXDoHmdtcCXGwyLMiauiAyxWMzhGpqHC4nqI/Y5G2XhTampslK2rb59kpcuHon03UH8W6iYUzw88A==}
-
- '@types/chai@4.3.11':
- resolution: {integrity: sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==}
-
'@types/color-convert@2.0.3':
resolution: {integrity: sha512-2Q6wzrNiuEvYxVQqhh7sXM2mhIhvZR/Paq4FdsQkOMgWsCIkKvSGj8Le1/XalulrmgOzPMqNa0ix+ePY4hTrfg==}
@@ -4451,9 +4848,6 @@ packages:
'@types/cookie@0.6.0':
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
- '@types/cookies@0.9.0':
- resolution: {integrity: sha512-40Zk8qR147RABiQ7NQnBzWzDcjKzNrntB5BAmeGCb2p/MIyOE+4BVvc17wumsUqUw00bJYqoXFHYygQnEFh4/Q==}
-
'@types/cross-spawn@6.0.2':
resolution: {integrity: sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==}
@@ -4463,6 +4857,9 @@ packages:
'@types/detect-port@1.3.2':
resolution: {integrity: sha512-xxgAGA2SAU4111QefXPSp5eGbDm/hW6zhvYl9IeEPZEry9F4d66QAHm5qpUXjb6IsevZV/7emAEx5MhP6O192g==}
+ '@types/diff@5.2.1':
+ resolution: {integrity: sha512-uxpcuwWJGhe2AR1g8hD9F5OYGCqjqWnBUQFD8gMZsDbv8oPHzxJF6iMO6n8Tk0AdzlxoaaoQhOYlIg/PukVU8g==}
+
'@types/disposable-email-domains@1.0.2':
resolution: {integrity: sha512-SDKwyYTjk3y5aZBxxc38yRecpJPjsqn57STz1bNxYYlv4k11bBe7QB8w4llXDTmQXKT1mFvgGmJv+8Zdu3YmJw==}
@@ -4499,6 +4896,9 @@ packages:
'@types/express@4.17.17':
resolution: {integrity: sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==}
+ '@types/express@4.17.21':
+ resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==}
+
'@types/find-cache-dir@3.2.1':
resolution: {integrity: sha512-frsJrz2t/CeGifcu/6uRo4b+SzAwT4NYCVPu1GN8IB9XTzrpPkGuV0tmh9mN+/L0PklAlsC3u5Fxt0ju00LXIw==}
@@ -4517,17 +4917,11 @@ packages:
'@types/htmlescape@1.1.3':
resolution: {integrity: sha512-tuC81YJXGUe0q8WRtBNW+uyx79rkkzWK651ALIXXYq5/u/IxjX4iHneGF2uUqzsNp+F+9J2mFZOv9jiLTtIq0w==}
- '@types/http-assert@1.5.5':
- resolution: {integrity: sha512-4+tE/lwdAahgZT1g30Jkdm9PzFRde0xwxBNUyRsCitRvCQB90iuA2uJYdUnhnANRcqGXaWOGY4FEoxeElNAK2g==}
-
'@types/http-cache-semantics@4.0.4':
resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==}
- '@types/http-errors@2.0.4':
- resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
-
- '@types/http-link-header@1.0.5':
- resolution: {integrity: sha512-AxhIKR8UbyoqCTNp9rRepkktHuUOw3DjfOfDCaO9kwI8AYzjhxyrvZq4+mRw/2daD3hYDknrtSeV6SsPwmc71w==}
+ '@types/http-link-header@1.0.7':
+ resolution: {integrity: sha512-snm5oLckop0K3cTDAiBnZDy6ncx9DJ3mCRDvs42C884MbVYPP74Tiq2hFsSDRTyjK6RyDYDIulPiW23ge+g5Lw==}
'@types/istanbul-lib-coverage@2.0.4':
resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==}
@@ -4544,8 +4938,8 @@ packages:
'@types/js-yaml@4.0.9':
resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==}
- '@types/jsdom@21.1.6':
- resolution: {integrity: sha512-/7kkMsC+/kMs7gAYmmBR9P0vGTnOoLhQhyhQJSlXGI5bzTHp6xdo0TtKWQAsz6pmSAeVqKSbqeyP6hytqr9FDw==}
+ '@types/jsdom@21.1.7':
+ resolution: {integrity: sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==}
'@types/json-schema@7.0.12':
resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==}
@@ -4556,27 +4950,15 @@ packages:
'@types/json5@0.0.29':
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
- '@types/jsonld@1.5.13':
- resolution: {integrity: sha512-n7fUU6W4kSYK8VQlf/LsE9kddBHPKhODoVOjsZswmve+2qLwBy6naWxs/EiuSZN9NU0N06Ra01FR+j87C62T0A==}
+ '@types/jsonld@1.5.15':
+ resolution: {integrity: sha512-PlAFPZjL+AuGYmwlqwKEL0IMP8M8RexH0NIPGfCVWSQ041H2rR/8OlyZSD7KsCVoN8vCfWdtWDBxX8yBVP+xow==}
'@types/jsrsasign@10.5.14':
resolution: {integrity: sha512-lppSlfK6etu+cuKs40K4rg8As79PH6hzIB+v55zSqImbSH3SE6Fm8MBHCiI91cWlAP3Z4igtJK1VL3fSN09blQ==}
- '@types/keygrip@1.0.6':
- resolution: {integrity: sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==}
-
'@types/keyv@3.1.4':
resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
- '@types/koa-compose@3.2.8':
- resolution: {integrity: sha512-4Olc63RY+MKvxMwVknCUDhRQX1pFQoBZ/lXcRLP69PQkEpze/0cr8LNqJQe5NFb/b19DWi2a5bTi2VAlQzhJuA==}
-
- '@types/koa@2.14.0':
- resolution: {integrity: sha512-DTDUyznHGNHAl+wd1n0z1jxNajduyTh8R53xoewuerdBzGo6Ogj6F2299BFtrexJw4NtgjsI5SMPCmV9gZwGXA==}
-
- '@types/koa__router@12.0.3':
- resolution: {integrity: sha512-5YUJVv6NwM1z7m6FuYpKfNLTZ932Z6EF6xy2BbtpJSyn13DKNQEkXVffFVSnJHxvwwWh2SAeumpjAYUELqgjyw==}
-
'@types/lodash@4.14.191':
resolution: {integrity: sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==}
@@ -4586,14 +4968,17 @@ packages:
'@types/matter-js@0.19.6':
resolution: {integrity: sha512-ffk6tqJM5scla+ThXmnox+mdfCo3qYk6yMjQsNcrbo6eQ5DqorVdtnaL+1agCoYzxUjmHeiNB7poBMAmhuLY7w==}
+ '@types/matter-js@0.19.7':
+ resolution: {integrity: sha512-dlh50YEh1lQS4fiCDGBnK75ocHQIq/1E371Qk6hASJImICIivdZQC2GkOqnfBm0Hac2xLk5+yrqRFDAEfj/yLA==}
+
'@types/mdast@4.0.3':
resolution: {integrity: sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==}
'@types/mdx@2.0.3':
resolution: {integrity: sha512-IgHxcT3RC8LzFLhKwP3gbMPeaK7BM9eBH46OdapPA7yvuIUJ8H6zHZV53J8hGZcTSnt95jANt+rTBNUUc22ACQ==}
- '@types/micromatch@4.0.7':
- resolution: {integrity: sha512-C/FMQ8HJAZhTsDpl4wDKZdMeeW5USjgzOczUwTGbRc1ZopPgOhIEnxY2ZgUrsuyy4DwK1JVOJZKFakv3TbCKiA==}
+ '@types/micromatch@4.0.9':
+ resolution: {integrity: sha512-7V+8ncr22h4UoYRLnLXSpTxjQrNUXtWHGeMPRJt1nULXI57G9bIcpyrHlmrQ7QK24EyyuXvYcSSWAM8GA9nqCg==}
'@types/mime-types@2.1.4':
resolution: {integrity: sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==}
@@ -4616,12 +5001,8 @@ packages:
'@types/mysql@2.15.22':
resolution: {integrity: sha512-wK1pzsJVVAjYCSZWQoWHziQZbNggXFDUEIGf54g4ZM/ERuP86uGdWeKZWMYlqTPMZfHJJvLPyogXGvCOg87yLQ==}
- '@types/node-fetch@2.6.4':
- resolution: {integrity: sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==}
-
- '@types/node-fetch@3.0.3':
- resolution: {integrity: sha512-HhggYPH5N+AQe/OmN6fmhKmRRt2XuNJow+R3pQwJxOOF9GuwM7O2mheyGeIrs5MOIeNjDEdgdoyHBOrFeJBR3g==}
- deprecated: This is a stub types definition. node-fetch provides its own type definitions, so you do not need this installed.
+ '@types/node-fetch@2.6.11':
+ resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==}
'@types/node@18.17.15':
resolution: {integrity: sha512-2yrWpBk32tvV/JAd3HNHWuZn/VDN1P+72hWirHnvsvTGSqbANi+kSeuQR9yAHnbvaBvHDsoTdXV0Fe+iRtHLKA==}
@@ -4629,8 +5010,8 @@ packages:
'@types/node@20.11.5':
resolution: {integrity: sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==}
- '@types/node@20.12.7':
- resolution: {integrity: sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==}
+ '@types/node@20.14.12':
+ resolution: {integrity: sha512-r7wNXakLeSsGT0H1AU863vS2wa5wBOK4bWMjZz2wj+8nBx+m5PeIn0k8AloSLpRuiwdRQZwarZqHE4FNArPuJQ==}
'@types/node@20.9.1':
resolution: {integrity: sha512-HhmzZh5LSJNS5O8jQKpJ/3ZcrrlG6L70hpGqMIAoM9YVD0YBRNWYsfwcXq8VnSjlNpCpgLzMXdiPo+dxcvSmiA==}
@@ -4647,8 +5028,8 @@ packages:
'@types/oauth2orize@1.11.5':
resolution: {integrity: sha512-C6hrRoh9hCnqis39OpeUZSwgw+TIzcV0CsxwJMGfQjTx4I1r+CLmuEPzoDJr5NRTfc7OMwHNLkQwrGFLKrJjMQ==}
- '@types/oauth@0.9.4':
- resolution: {integrity: sha512-qk9orhti499fq5XxKCCEbd0OzdPZuancneyse3KtR+vgMiHRbh+mn8M4G6t64ob/Fg+GZGpa565MF/2dKWY32A==}
+ '@types/oauth@0.9.5':
+ resolution: {integrity: sha512-+oQ3C2Zx6ambINOcdIARF5Z3Tu3x//HipE889/fqo3sgpQZbe9c6ExdQFtN6qlhpR7p83lTZfPJt0tCAW29dog==}
'@types/offscreencanvas@2019.3.0':
resolution: {integrity: sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q==}
@@ -4659,8 +5040,8 @@ packages:
'@types/pg-pool@2.0.4':
resolution: {integrity: sha512-qZAvkv1K3QbmHHFYSNRYPkRjOWRLBYrL4B9c+wG0GSVGBw0NtJwPcgx/DSddeDJvRGMHCEQ4VMEVfuJ/0gZ3XQ==}
- '@types/pg@8.11.5':
- resolution: {integrity: sha512-2xMjVviMxneZHDHX5p5S6tsRRs7TpDHeeK7kTTMe/kAC/mRRNjWHjZg0rkiY+e17jXSZV3zJYDxXV8Cy72/Vuw==}
+ '@types/pg@8.11.6':
+ resolution: {integrity: sha512-/2WmmBXHLsfRqzfHW7BNZ8SbYzE8OSk7i3WjFYvfgRHj7S1xj+16Je5fUKv3lVdVzk/zn9TXOqf+avFCFIE0yQ==}
'@types/pg@8.6.1':
resolution: {integrity: sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w==}
@@ -4713,8 +5094,8 @@ packages:
'@types/scheduler@0.16.2':
resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==}
- '@types/seedrandom@2.4.30':
- resolution: {integrity: sha512-AnxLHewubLVzoF/A4qdxBGHCKifw8cY32iro3DQX9TPcetE95zBeVt3jnsvtvAUf1vwzMfwzp4t/L2yqPlnjkQ==}
+ '@types/seedrandom@2.4.34':
+ resolution: {integrity: sha512-ytDiArvrn/3Xk6/vtylys5tlY6eo7Ane0hvcx++TKo6RxQXuVfW0AF/oeWqAj9dN29SyhtawuXstgmPlwNcv/A==}
'@types/seedrandom@3.0.8':
resolution: {integrity: sha512-TY1eezMU2zH2ozQoAFAQFOPpvP15g+ZgSfTZt31AUUH/Rxtnz3H+A/Sv1Snw2/amp//omibc+AEkTaA8KUeOLQ==}
@@ -4764,9 +5145,15 @@ packages:
'@types/tough-cookie@4.0.2':
resolution: {integrity: sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==}
+ '@types/tough-cookie@4.0.5':
+ resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==}
+
'@types/unist@3.0.2':
resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==}
+ '@types/uuid@10.0.0':
+ resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==}
+
'@types/uuid@9.0.8':
resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==}
@@ -4782,8 +5169,8 @@ packages:
'@types/wrap-ansi@3.0.0':
resolution: {integrity: sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==}
- '@types/ws@8.5.10':
- resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==}
+ '@types/ws@8.5.11':
+ resolution: {integrity: sha512-4+q7P5h3SpJxaBft0Dzpbr6lmMaqh0Jr2tbhJZ/luAwvD7ohSCniYkwz/pLxuT2h0EOa6QADgJj1Ko+TzRfZ+w==}
'@types/yargs-parser@21.0.0':
resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==}
@@ -4816,8 +5203,8 @@ packages:
typescript:
optional: true
- '@typescript-eslint/eslint-plugin@7.7.1':
- resolution: {integrity: sha512-KwfdWXJBOviaBVhxO3p5TJiLpNuh2iyXyjmWN0f1nU87pwyvfS0EmjC6ukQVYVFJd/K1+0NWGPDXiyEyQorn0Q==}
+ '@typescript-eslint/eslint-plugin@7.17.0':
+ resolution: {integrity: sha512-pyiDhEuLM3PuANxH7uNYan1AaFs5XE0zw1hq69JBvGvE7gSuEoQl1ydtEe/XQeoC3GQxLXyOVa5kNOATgM638A==}
engines: {node: ^18.18.0 || >=20.0.0}
peerDependencies:
'@typescript-eslint/parser': ^7.0.0
@@ -4847,8 +5234,8 @@ packages:
typescript:
optional: true
- '@typescript-eslint/parser@7.7.1':
- resolution: {integrity: sha512-vmPzBOOtz48F6JAGVS/kZYk4EkXao6iGrD838sp1w3NQQC0W8ry/q641KU4PrG7AKNAf56NOcR8GOpH8l9FPCw==}
+ '@typescript-eslint/parser@7.17.0':
+ resolution: {integrity: sha512-puiYfGeg5Ydop8eusb/Hy1k7QmOU6X3nvsqCgzrB2K4qMavK//21+PzNE8qeECgNOIoertJPUC1SpegHDI515A==}
engines: {node: ^18.18.0 || >=20.0.0}
peerDependencies:
eslint: ^8.56.0
@@ -4865,8 +5252,8 @@ packages:
resolution: {integrity: sha512-6TmN4OJiohHfoOdGZ3huuLhpiUgOGTpgXNUPJgeZOZR3DnIpdSgtt83RS35OYNNXxM4TScVlpVKC9jyQSETR1A==}
engines: {node: ^16.0.0 || >=18.0.0}
- '@typescript-eslint/scope-manager@7.7.1':
- resolution: {integrity: sha512-PytBif2SF+9SpEUKynYn5g1RHFddJUcyynGpztX3l/ik7KmZEv19WCMhUBkHXPU9es/VWGD3/zg3wg90+Dh2rA==}
+ '@typescript-eslint/scope-manager@7.17.0':
+ resolution: {integrity: sha512-0P2jTTqyxWp9HiKLu/Vemr2Rg1Xb5B7uHItdVZ6iAenXmPo4SZ86yOPCJwMqpCyaMiEHTNqizHfsbmCFT1x9SA==}
engines: {node: ^18.18.0 || >=20.0.0}
'@typescript-eslint/type-utils@6.11.0':
@@ -4889,8 +5276,8 @@ packages:
typescript:
optional: true
- '@typescript-eslint/type-utils@7.7.1':
- resolution: {integrity: sha512-ZksJLW3WF7o75zaBPScdW1Gbkwhd/lyeXGf1kQCxJaOeITscoSl0MjynVvCzuV5boUz/3fOI06Lz8La55mu29Q==}
+ '@typescript-eslint/type-utils@7.17.0':
+ resolution: {integrity: sha512-XD3aaBt+orgkM/7Cei0XNEm1vwUxQ958AOLALzPlbPqb8C1G8PZK85tND7Jpe69Wualri81PLU+Zc48GVKIMMA==}
engines: {node: ^18.18.0 || >=20.0.0}
peerDependencies:
eslint: ^8.56.0
@@ -4907,8 +5294,8 @@ packages:
resolution: {integrity: sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==}
engines: {node: ^16.0.0 || >=18.0.0}
- '@typescript-eslint/types@7.7.1':
- resolution: {integrity: sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w==}
+ '@typescript-eslint/types@7.17.0':
+ resolution: {integrity: sha512-a29Ir0EbyKTKHnZWbNsrc/gqfIBqYPwj3F2M+jWE/9bqfEHg0AMtXzkbUkOG6QgEScxh2+Pz9OXe11jHDnHR7A==}
engines: {node: ^18.18.0 || >=20.0.0}
'@typescript-eslint/typescript-estree@6.11.0':
@@ -4929,8 +5316,8 @@ packages:
typescript:
optional: true
- '@typescript-eslint/typescript-estree@7.7.1':
- resolution: {integrity: sha512-CXe0JHCXru8Fa36dteXqmH2YxngKJjkQLjxzoj6LYwzZ7qZvgsLSc+eqItCrqIop8Vl2UKoAi0StVWu97FQZIQ==}
+ '@typescript-eslint/typescript-estree@7.17.0':
+ resolution: {integrity: sha512-72I3TGq93t2GoSBWI093wmKo0n6/b7O4j9o8U+f65TVD0FS6bI2180X5eGEr8MA8PhKMvYe9myZJquUT2JkCZw==}
engines: {node: ^18.18.0 || >=20.0.0}
peerDependencies:
typescript: '*'
@@ -4950,8 +5337,8 @@ packages:
peerDependencies:
eslint: ^8.56.0
- '@typescript-eslint/utils@7.7.1':
- resolution: {integrity: sha512-QUvBxPEaBXf41ZBbaidKICgVL8Hin0p6prQDu6bbetWo39BKbWJxRsErOzMNT1rXvTll+J7ChrbmMCXM9rsvOQ==}
+ '@typescript-eslint/utils@7.17.0':
+ resolution: {integrity: sha512-r+JFlm5NdB+JXc7aWWZ3fKSm1gn0pkswEwIYsrGPdsT2GjsRATAKXiNtp3vgAAO1xZhX8alIOEQnNMl3kbTgJw==}
engines: {node: ^18.18.0 || >=20.0.0}
peerDependencies:
eslint: ^8.56.0
@@ -4964,87 +5351,84 @@ packages:
resolution: {integrity: sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==}
engines: {node: ^16.0.0 || >=18.0.0}
- '@typescript-eslint/visitor-keys@7.7.1':
- resolution: {integrity: sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw==}
+ '@typescript-eslint/visitor-keys@7.17.0':
+ resolution: {integrity: sha512-RVGC9UhPOCsfCdI9pU++K4nD7to+jTcMIbXTSOcrLqUEW6gF2pU1UUbYJKc9cvcRSK1UDeMJ7pdMxf4bhMpV/A==}
engines: {node: ^18.18.0 || >=20.0.0}
'@ungap/structured-clone@1.2.0':
resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
- '@vitejs/plugin-vue@5.0.4':
- resolution: {integrity: sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==}
+ '@vitejs/plugin-vue@5.1.0':
+ resolution: {integrity: sha512-QMRxARyrdiwi1mj3AW4fLByoHTavreXq0itdEW696EihXglf1MB3D4C2gBvE0jMPH29ZjC3iK8aIaUMLf4EOGA==}
engines: {node: ^18.0.0 || >=20.0.0}
peerDependencies:
vite: ^5.0.0
vue: ^3.2.25
- '@vitest/coverage-v8@0.34.6':
- resolution: {integrity: sha512-fivy/OK2d/EsJFoEoxHFEnNGTg+MmdZBAVK9Ka4qhXR2K3J0DS08vcGVwzDtXSuUMabLv4KtPcpSKkcMXFDViw==}
+ '@vitest/coverage-v8@1.6.0':
+ resolution: {integrity: sha512-KvapcbMY/8GYIG0rlwwOKCVNRc0OL20rrhFkg/CHNzncV03TE2XWvO5w9uZYoxNiMEBacAJt3unSOiZ7svePew==}
peerDependencies:
- vitest: '>=0.32.0 <1'
-
- '@vitest/expect@0.34.6':
- resolution: {integrity: sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==}
-
- '@vitest/expect@1.3.1':
- resolution: {integrity: sha512-xofQFwIzfdmLLlHa6ag0dPV8YsnKOCP1KdAeVVh34vSjN2dcUiXYCD9htu/9eM7t8Xln4v03U9HLxLpPlsXdZw==}
+ vitest: 1.6.0
- '@vitest/runner@0.34.6':
- resolution: {integrity: sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==}
+ '@vitest/expect@1.6.0':
+ resolution: {integrity: sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==}
- '@vitest/snapshot@0.34.6':
- resolution: {integrity: sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==}
+ '@vitest/runner@1.6.0':
+ resolution: {integrity: sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==}
- '@vitest/spy@0.34.6':
- resolution: {integrity: sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==}
-
- '@vitest/spy@1.3.1':
- resolution: {integrity: sha512-xAcW+S099ylC9VLU7eZfdT9myV67Nor9w9zhf0mGCYJSO+zM2839tOeROTdikOi/8Qeusffvxb/MyBSOja1Uig==}
+ '@vitest/snapshot@1.6.0':
+ resolution: {integrity: sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==}
'@vitest/spy@1.6.0':
resolution: {integrity: sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==}
- '@vitest/utils@0.34.6':
- resolution: {integrity: sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==}
-
- '@vitest/utils@1.3.1':
- resolution: {integrity: sha512-d3Waie/299qqRyHTm2DjADeTaNdNSVsnwHPWrs20JMpjh6eiVq7ggggweO8rc4arhf6rRkWuHKwvxGvejUXZZQ==}
-
'@vitest/utils@1.6.0':
resolution: {integrity: sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==}
'@volar/language-core@2.2.0':
resolution: {integrity: sha512-a8WG9+4OdeNDW4ywABZIM6S6UN7em8uIlM/BZ2pWQUYrVmX+m8sj/X+QadvO+Li/t/LjAqbWJQtVgxdpEWLALQ==}
+ '@volar/language-core@2.4.0-alpha.18':
+ resolution: {integrity: sha512-JAYeJvYQQROmVRtSBIczaPjP3DX4QW1fOqW1Ebs0d3Y3EwSNRglz03dSv0Dm61dzd0Yx3WgTW3hndDnTQqgmyg==}
+
'@volar/source-map@2.2.0':
resolution: {integrity: sha512-HQlPRlHOVqCCHK8wI76ZldHkEwKsjp7E6idUc36Ekni+KJDNrqgSqPvyHQixybXPHNU7CI9Uxd9/IkxO7LuNBw==}
+ '@volar/source-map@2.4.0-alpha.18':
+ resolution: {integrity: sha512-MTeCV9MUwwsH0sNFiZwKtFrrVZUK6p8ioZs3xFzHc2cvDXHWlYN3bChdQtwKX+FY2HG6H3CfAu1pKijolzIQ8g==}
+
'@volar/typescript@2.2.0':
resolution: {integrity: sha512-wC6l4zLiiCLxF+FGaHCbWlQYf4vMsnRxYhcI6WgvaNppOD6r1g+Ef1RKRJUApALWU46Yy/JDU/TbdV6w/X6Liw==}
- '@vue/compiler-core@3.4.21':
- resolution: {integrity: sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==}
+ '@volar/typescript@2.4.0-alpha.18':
+ resolution: {integrity: sha512-sXh5Y8sqGUkgxpMWUGvRXggxYHAVxg0Pa1C42lQZuPDrW6vHJPR0VCK8Sr7WJsAW530HuNQT/ZIskmXtxjybMQ==}
+
+ '@vue/compiler-core@3.4.29':
+ resolution: {integrity: sha512-TFKiRkKKsRCKvg/jTSSKK7mYLJEQdUiUfykbG49rubC9SfDyvT2JrzTReopWlz2MxqeLyxh9UZhvxEIBgAhtrg==}
- '@vue/compiler-core@3.4.25':
- resolution: {integrity: sha512-Y2pLLopaElgWnMNolgG8w3C5nNUVev80L7hdQ5iIKPtMJvhVpG0zhnBG/g3UajJmZdvW0fktyZTotEHD1Srhbg==}
+ '@vue/compiler-core@3.4.31':
+ resolution: {integrity: sha512-skOiodXWTV3DxfDhB4rOf3OGalpITLlgCeOwb+Y9GJpfQ8ErigdBUHomBzvG78JoVE8MJoQsb+qhZiHfKeNeEg==}
- '@vue/compiler-core@3.4.26':
- resolution: {integrity: sha512-N9Vil6Hvw7NaiyFUFBPXrAyETIGlQ8KcFMkyk6hW1Cl6NvoqvP+Y8p1Eqvx+UdqsnrnI9+HMUEJegzia3mhXmQ==}
+ '@vue/compiler-core@3.4.34':
+ resolution: {integrity: sha512-Z0izUf32+wAnQewjHu+pQf1yw00EGOmevl1kE+ljjjMe7oEfpQ+BI3/JNK7yMB4IrUsqLDmPecUrpj3mCP+yJQ==}
- '@vue/compiler-dom@3.4.21':
- resolution: {integrity: sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA==}
+ '@vue/compiler-dom@3.4.29':
+ resolution: {integrity: sha512-A6+iZ2fKIEGnfPJejdB7b1FlJzgiD+Y/sxxKwJWg1EbJu6ZPgzaPQQ51ESGNv0CP6jm6Z7/pO6Ia8Ze6IKrX7w==}
- '@vue/compiler-dom@3.4.25':
- resolution: {integrity: sha512-Ugz5DusW57+HjllAugLci19NsDK+VyjGvmbB2TXaTcSlQxwL++2PETHx/+Qv6qFwNLzSt7HKepPe4DcTE3pBWg==}
+ '@vue/compiler-dom@3.4.31':
+ resolution: {integrity: sha512-wK424WMXsG1IGMyDGyLqB+TbmEBFM78hIsOJ9QwUVLGrcSk0ak6zYty7Pj8ftm7nEtdU/DGQxAXp0/lM/2cEpQ==}
- '@vue/compiler-dom@3.4.26':
- resolution: {integrity: sha512-4CWbR5vR9fMg23YqFOhr6t6WB1Fjt62d6xdFPyj8pxrYub7d+OgZaObMsoxaF9yBUHPMiPFK303v61PwAuGvZA==}
+ '@vue/compiler-dom@3.4.34':
+ resolution: {integrity: sha512-3PUOTS1h5cskdOJMExCu2TInXuM0j60DRPpSCJDqOCupCfUZCJoyQmKtRmA8EgDNZ5kcEE7vketamRZfrEuVDw==}
- '@vue/compiler-sfc@3.4.26':
- resolution: {integrity: sha512-It1dp+FAOCgluYSVYlDn5DtZBxk1NCiJJfu2mlQqa/b+k8GL6NG/3/zRbJnHdhV2VhxFghaDq5L4K+1dakW6cw==}
+ '@vue/compiler-sfc@3.4.34':
+ resolution: {integrity: sha512-x6lm0UrM03jjDXTPZgD9Ad8bIVD1ifWNit2EaWQIZB5CULr46+FbLQ5RpK7AXtDHGjx9rmvC7QRCTjsiGkAwRw==}
- '@vue/compiler-ssr@3.4.26':
- resolution: {integrity: sha512-FNwLfk7LlEPRY/g+nw2VqiDKcnDTVdCfBREekF8X74cPLiWHUX6oldktf/Vx28yh4STNy7t+/yuLoMBBF7YDiQ==}
+ '@vue/compiler-ssr@3.4.34':
+ resolution: {integrity: sha512-8TDBcLaTrFm5rnF+Qm4BlliaopJgqJ28Nsrc80qazynm5aJO+Emu7y0RWw34L8dNnTRdcVBpWzJxhGYzsoVu4g==}
+
+ '@vue/compiler-vue2@2.7.16':
+ resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==}
'@vue/devtools-api@6.6.1':
resolution: {integrity: sha512-LgPscpE3Vs0x96PzSSB4IGVSZXZBZHpfxs+ZA1d+VEPwHdOXowy/Y2CsvCAIFrf+ssVU1pD1jidj505EpUnfbA==}
@@ -5057,28 +5441,36 @@ packages:
typescript:
optional: true
- '@vue/reactivity@3.4.26':
- resolution: {integrity: sha512-E/ynEAu/pw0yotJeLdvZEsp5Olmxt+9/WqzvKff0gE67tw73gmbx6tRkiagE/eH0UCubzSlGRebCbidB1CpqZQ==}
+ '@vue/language-core@2.0.29':
+ resolution: {integrity: sha512-o2qz9JPjhdoVj8D2+9bDXbaI4q2uZTHQA/dbyZT4Bj1FR9viZxDJnLcKVHfxdn6wsOzRgpqIzJEEmSSvgMvDTQ==}
+ peerDependencies:
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@vue/reactivity@3.4.34':
+ resolution: {integrity: sha512-ua+Lo+wBRlBEX9TtgPOShE2JwIO7p6BTZ7t1KZVPoaBRfqbC7N3c8Mpzicx173fXxx5VXeU6ykiHo7WgLzJQDA==}
- '@vue/runtime-core@3.4.26':
- resolution: {integrity: sha512-AFJDLpZvhT4ujUgZSIL9pdNcO23qVFh7zWCsNdGQBw8ecLNxOOnPcK9wTTIYCmBJnuPHpukOwo62a2PPivihqw==}
+ '@vue/runtime-core@3.4.34':
+ resolution: {integrity: sha512-PXhkiRPwcPGJ1BnyBZFI96GfInCVskd0HPNIAZn7i3YOmLbtbTZpB7/kDTwC1W7IqdGPkTVC63IS7J2nZs4Ebg==}
- '@vue/runtime-dom@3.4.26':
- resolution: {integrity: sha512-UftYA2hUXR2UOZD/Fc3IndZuCOOJgFxJsWOxDkhfVcwLbsfh2CdXE2tG4jWxBZuDAs9J9PzRTUFt1PgydEtItw==}
+ '@vue/runtime-dom@3.4.34':
+ resolution: {integrity: sha512-dXqIe+RqFAK2Euak4UsvbIupalrhc67OuQKpD7HJ3W2fv8jlqvI7szfBCsAEcE8o/wyNpkloxB6J8viuF/E3gw==}
- '@vue/server-renderer@3.4.26':
- resolution: {integrity: sha512-xoGAqSjYDPGAeRWxeoYwqJFD/gw7mpgzOvSxEmjWaFO2rE6qpbD1PC172YRpvKhrihkyHJkNDADFXTfCyVGhKw==}
+ '@vue/server-renderer@3.4.34':
+ resolution: {integrity: sha512-GeyEUfMVRZMD/mZcNONEqg7MiU10QQ1DB3O/Qr6+8uXpbwdlmVgQ5Qs1/ZUAFX1X2UUtqMoGrDRbxdWfOJFT7Q==}
peerDependencies:
- vue: 3.4.26
+ vue: 3.4.34
- '@vue/shared@3.4.21':
- resolution: {integrity: sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g==}
+ '@vue/shared@3.4.29':
+ resolution: {integrity: sha512-hQ2gAQcBO/CDpC82DCrinJNgOHI2v+FA7BDW4lMSPeBpQ7sRe2OLHWe5cph1s7D8DUQAwRt18dBDfJJ220APEA==}
- '@vue/shared@3.4.25':
- resolution: {integrity: sha512-k0yappJ77g2+KNrIaF0FFnzwLvUBLUYr8VOwz+/6vLsmItFp51AcxLL7Ey3iPd7BIRyWPOcqUjMnm7OkahXllA==}
+ '@vue/shared@3.4.31':
+ resolution: {integrity: sha512-Yp3wtJk//8cO4NItOPpi3QkLExAr/aLBGZMmTtW9WpdwBCJpRM6zj9WgWktXAl8IDIozwNMByT45JP3tO3ACWA==}
- '@vue/shared@3.4.26':
- resolution: {integrity: sha512-Fg4zwR0GNnjzodMt3KRy2AWGMKQXByl56+4HjN87soxLNU9P5xcJkstAlIeEF3cU6UYOzmJl1tV0dVPGIljCnQ==}
+ '@vue/shared@3.4.34':
+ resolution: {integrity: sha512-x5LmiRLpRsd9KTjAB8MPKf0CDPMcuItjP0gbNqFCIgL1I8iYp4zglhj9w9FPCdIbHG2M91RVeIbArFfFTz9I3A==}
'@vue/test-utils@2.4.1':
resolution: {integrity: sha512-VO8nragneNzUZUah6kOjiFmD/gwRjUauG9DROh6oaOeFwX1cZRUNHhdeogE8635cISigXFTtGLUQWx5KCb0xeg==}
@@ -5152,8 +5544,8 @@ packages:
engines: {node: '>=0.4.0'}
hasBin: true
- acorn@8.11.3:
- resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==}
+ acorn@8.12.1:
+ resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==}
engines: {node: '>=0.4.0'}
hasBin: true
@@ -5185,9 +5577,9 @@ packages:
resolution: {integrity: sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==}
engines: {node: '>=18'}
- aiscript-vscode@https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/34bf4e1530efcf1efa855bd04e2dab39735e1b02:
- resolution: {tarball: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/34bf4e1530efcf1efa855bd04e2dab39735e1b02}
- version: 0.1.9
+ aiscript-vscode@https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/e1e1b27f2f72cd28a473e004b6da0d8fc0bd40d9:
+ resolution: {tarball: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/e1e1b27f2f72cd28a473e004b6da0d8fc0bd40d9}
+ version: 0.1.11
engines: {vscode: ^1.83.0}
ajv-draft-04@1.0.0:
@@ -5206,12 +5598,26 @@ packages:
ajv:
optional: true
+ ajv-formats@3.0.1:
+ resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==}
+ peerDependencies:
+ ajv: ^8.0.0
+ peerDependenciesMeta:
+ ajv:
+ optional: true
+
ajv@6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
+ ajv@8.12.0:
+ resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==}
+
ajv@8.13.0:
resolution: {integrity: sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==}
+ ajv@8.17.1:
+ resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
+
ansi-colors@4.1.3:
resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
engines: {node: '>=6'}
@@ -5281,6 +5687,7 @@ packages:
are-we-there-yet@2.0.0:
resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==}
engines: {node: '>=10'}
+ deprecated: This package is no longer supported.
arg@5.0.2:
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
@@ -5294,6 +5701,9 @@ packages:
aria-query@5.1.3:
resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==}
+ aria-query@5.3.0:
+ resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
+
array-buffer-byte-length@1.0.0:
resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==}
@@ -5369,6 +5779,9 @@ packages:
async-mutex@0.5.0:
resolution: {integrity: sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==}
+ async@0.2.10:
+ resolution: {integrity: sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ==}
+
async@3.2.4:
resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==}
@@ -5390,8 +5803,8 @@ packages:
avvio@8.3.0:
resolution: {integrity: sha512-VBVH0jubFr9LdFASy/vNtm5giTrnbVquWBhT0fyizuNK2rQ7e7ONU2plZQWUNqtE1EmxFEb+kbSkFRkstiaS9Q==}
- aws-sdk-client-mock@3.0.1:
- resolution: {integrity: sha512-9VAzJLl8mz99KP9HjOm/93d8vznRRUTpJooPBOunRdUAnVYopCe9xmMuu7eVemu8fQ+w6rP7o5bBK1kAFkB2KQ==}
+ aws-sdk-client-mock@4.0.1:
+ resolution: {integrity: sha512-yD2mmgy73Xce097G5hIpr1k7j50qzvJ49/+6osGZiCyk4m6cwhb+2x7kKFY1gEMwTzaS8+m8fXv9SB29SkRYyQ==}
aws-sign2@0.7.0:
resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==}
@@ -5427,18 +5840,18 @@ packages:
resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- babel-plugin-polyfill-corejs2@0.4.6:
- resolution: {integrity: sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q==}
+ babel-plugin-polyfill-corejs2@0.4.11:
+ resolution: {integrity: sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==}
peerDependencies:
'@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
- babel-plugin-polyfill-corejs3@0.8.6:
- resolution: {integrity: sha512-leDIc4l4tUgU7str5BWLS2h8q2N4Nf6lGZP6UrNDxdtfF2g69eJ5L0H7S8A5Ln/arfFAfHor5InAdZuIOwZdgQ==}
+ babel-plugin-polyfill-corejs3@0.10.4:
+ resolution: {integrity: sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==}
peerDependencies:
'@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
- babel-plugin-polyfill-regenerator@0.5.3:
- resolution: {integrity: sha512-8sHeDOmXC8csczMrYEOf0UTNa4yE2SxV5JGeT/LP1n0OYVDUUFPxG9vdk2AlDlIit4t+Kf0xCtpgXPBwnn/9pw==}
+ babel-plugin-polyfill-regenerator@0.6.2:
+ resolution: {integrity: sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==}
peerDependencies:
'@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
@@ -5511,10 +5924,6 @@ packages:
bn.js@4.12.0:
resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==}
- body-parser@1.20.1:
- resolution: {integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==}
- engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
-
body-parser@1.20.2:
resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==}
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
@@ -5539,15 +5948,16 @@ packages:
resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
engines: {node: '>=8'}
+ braces@3.0.3:
+ resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
+ engines: {node: '>=8'}
+
broadcast-channel@7.0.0:
resolution: {integrity: sha512-a2tW0Ia1pajcPBOGUF2jXlDnvE9d5/dg6BG9h60OmRUcZVr/veUrU8vEQFwwQIhwG3KVzYwSk3v2nRRGFgQDXQ==}
browser-assert@1.2.1:
resolution: {integrity: sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ==}
- browserify-zlib@0.1.4:
- resolution: {integrity: sha512-19OEpq7vWgsH6WkvkBJQDFvJS1uPcbFOQ4v9CU839dO+ZZXUZO6XpE6hNCqvlIIj+4fZvRiJ6DsAQ382GwiyTQ==}
-
browserslist@4.22.2:
resolution: {integrity: sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
@@ -5587,8 +5997,12 @@ packages:
resolution: {integrity: sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==}
engines: {node: '>=6.14.2'}
- bullmq@5.7.8:
- resolution: {integrity: sha512-F/Haeu6AVHkFrfeaU/kLOjhfrH6x3CaKAZlQQ+76fa8l3kfI9oaUHeFMW+1mYVz0NtYPF7PNTWFq4ylAHYcCgA==}
+ bufferutil@4.0.8:
+ resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==}
+ engines: {node: '>=6.14.2'}
+
+ bullmq@5.10.4:
+ resolution: {integrity: sha512-YEssEbWBbPXvSW2YMjIBKZdkIPZsOaTGWo1y2wpCFv/wUY+tRLKiSVuHgv09x0QEieybx844f9//UWuarG1JHg==}
buraha@0.0.1:
resolution: {integrity: sha512-G563A0mTbzknm2jDaNxfZuNKIdeArs8T+XQN6t+KbmgnOoevXSXhKDkyf8Md/36Jrx99ikwbCag37VGe3myExQ==}
@@ -5625,6 +6039,10 @@ packages:
resolution: {integrity: sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==}
engines: {node: '>=14.16'}
+ cacheable-request@12.0.1:
+ resolution: {integrity: sha512-Yo9wGIQUaAfIbk+qY0X4cDQgCosecfBe3V9NSyeY4qPC2SAkbCS4Xj79VP8WOzitpJUZKc/wsRCYF5ariDIwkg==}
+ engines: {node: '>=18'}
+
cacheable-request@7.0.2:
resolution: {integrity: sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==}
engines: {node: '>=8'}
@@ -5714,8 +6132,8 @@ packages:
character-parser@2.2.0:
resolution: {integrity: sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==}
- chart.js@4.4.2:
- resolution: {integrity: sha512-6GD7iKwFpP5kbSD4MeRRRlTnQvxfQREy36uEtm1hzHzcOqwWx0YEHuspuoNlslu+nciLIB7fjjsHkUv/FzFcOg==}
+ chart.js@4.4.3:
+ resolution: {integrity: sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw==}
engines: {pnpm: '>=8'}
chartjs-adapter-date-fns@3.0.0:
@@ -5764,8 +6182,8 @@ packages:
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
engines: {node: '>=10'}
- chromatic@11.3.0:
- resolution: {integrity: sha512-q1ZtJDJrjLGnz60ivpC16gmd7KFzcaA4eTb7gcytCqbaKqlHhCFr1xQmcUDsm14CK7JsqdkFU6S+JQdOd2ZNJg==}
+ chromatic@11.5.6:
+ resolution: {integrity: sha512-ycX/hlZLs69BltwwBNsEXr+As6x5/0rlwp6W/CiHMZ3tpm7dmkd+hQCsb8JGHb1h49W3qPOKQ/Lh9evqcJ1yeQ==}
hasBin: true
peerDependencies:
'@chromatic-com/cypress': ^0.*.* || ^1.0.0
@@ -5800,10 +6218,6 @@ packages:
engines: {node: '>=8.0.0', npm: '>=5.0.0'}
hasBin: true
- cli-spinners@2.7.0:
- resolution: {integrity: sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==}
- engines: {node: '>=6'}
-
cli-spinners@2.9.2:
resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==}
engines: {node: '>=6'}
@@ -5920,8 +6334,8 @@ packages:
commondir@1.0.1:
resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==}
- compare-versions@6.1.0:
- resolution: {integrity: sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==}
+ compare-versions@6.1.1:
+ resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==}
compress-commons@6.0.2:
resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==}
@@ -5983,8 +6397,8 @@ packages:
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
engines: {node: '>= 0.6'}
- core-js-compat@3.33.3:
- resolution: {integrity: sha512-cNzGqFsh3Ot+529GIXacjTJ7kegdt5fPXxCBVS1G0iaZpuo/tBz399ymceLJveQhFFZ8qThHiP3fzuoQjKN2ow==}
+ core-js-compat@3.37.1:
+ resolution: {integrity: sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==}
core-js@3.29.1:
resolution: {integrity: sha512-+jwgnhg6cQxKYIIjGtAHq2nwUOolo9eoFZ4sHfUH09BLXBgxnH4gA0zEd+t+BO2cNB8idaBtZFcFTRjQJRJmAw==}
@@ -6017,8 +6431,8 @@ packages:
resolution: {integrity: sha512-jbokKWGcyU4gl6jAfX97E1gDpY12DJ1cLJZmoDzaAln/shZ+S3KBFBuA2Q6WeUN4gJf/8klnV1EfvhA2lK5IRQ==}
engines: {node: '>=12.0.0'}
- cropperjs@2.0.0-beta.5:
- resolution: {integrity: sha512-8RIynsyHV7KyCxbjV4fCQubGiM6sHMgYvRPKkzuUQSTYHK6shoUNvdvbBekwAwS8QRLsxEBcJ5lvl0W3dvkDQA==}
+ cropperjs@2.0.0-rc.1:
+ resolution: {integrity: sha512-Y9ciurIuK6G1vy0ErHC8Gt6wHWvsHWJ5fgE60GL6vsuF2WzHwDpH7F1yof40XAEheeSN4v3rD09D1VZ7kiiSOA==}
cross-env@7.0.3:
resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==}
@@ -6038,9 +6452,9 @@ packages:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'}
- crypto-random-string@2.0.0:
- resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==}
- engines: {node: '>=8'}
+ crypto-random-string@4.0.0:
+ resolution: {integrity: sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==}
+ engines: {node: '>=12'}
css-declaration-sorter@7.2.0:
resolution: {integrity: sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==}
@@ -6103,13 +6517,8 @@ packages:
cwise-compiler@1.1.3:
resolution: {integrity: sha512-WXlK/m+Di8DMMcCjcWr4i+XzcQra9eCdXIJrgh4TUgh0pIS/yJduLxS9JgefsHJ/YVLdgPtXm9r62W92MvanEQ==}
- cypress@13.7.3:
- resolution: {integrity: sha512-uoecY6FTCAuIEqLUYkTrxamDBjMHTYak/1O7jtgwboHiTnS1NaMOoR08KcTrbRZFCBvYOiS4tEkQRmsV+xcrag==}
- engines: {node: ^16.0.0 || ^18.0.0 || >=20.0.0}
- hasBin: true
-
- cypress@13.8.1:
- resolution: {integrity: sha512-Uk6ovhRbTg6FmXjeZW/TkbRM07KPtvM5gah1BIMp4Y2s+i/NMxgaLw0+PbYTOdw1+egE0FP3mWRiGcRkjjmhzA==}
+ cypress@13.13.1:
+ resolution: {integrity: sha512-8F9UjL5MDUdgC/S5hr8CGLHbS5gGht5UOV184qc2pFny43fnkoaKxlzH/U6//zmGu/xRTaKimNfjknLT8+UDFg==}
engines: {node: ^16.0.0 || ^18.0.0 || >=20.0.0}
hasBin: true
@@ -6163,6 +6572,15 @@ packages:
supports-color:
optional: true
+ debug@4.3.5:
+ resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
decamelize-keys@1.1.1:
resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==}
engines: {node: '>=0.10.0'}
@@ -6236,10 +6654,6 @@ packages:
defu@6.1.4:
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
- del@6.1.1:
- resolution: {integrity: sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==}
- engines: {node: '>=10'}
-
delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
@@ -6267,10 +6681,6 @@ packages:
resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==}
engines: {node: '>=8'}
- detect-libc@2.0.2:
- resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==}
- engines: {node: '>=8'}
-
detect-libc@2.0.3:
resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
engines: {node: '>=8'}
@@ -6301,6 +6711,10 @@ packages:
resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==}
engines: {node: '>=0.3.1'}
+ diff@5.2.0:
+ resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==}
+ engines: {node: '>=0.3.1'}
+
dijkstrajs@1.0.2:
resolution: {integrity: sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg==}
@@ -6352,9 +6766,6 @@ packages:
duplexer@0.1.2:
resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
- duplexify@3.7.1:
- resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==}
-
eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
@@ -6372,8 +6783,8 @@ packages:
ee-first@1.1.1:
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
- ejs@3.1.9:
- resolution: {integrity: sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==}
+ ejs@3.1.10:
+ resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==}
engines: {node: '>=0.10.0'}
hasBin: true
@@ -6439,8 +6850,8 @@ packages:
es-get-iterator@1.1.3:
resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==}
- es-module-lexer@0.9.3:
- resolution: {integrity: sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==}
+ es-module-lexer@1.5.4:
+ resolution: {integrity: sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==}
es-set-tostringtag@2.0.1:
resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==}
@@ -6477,11 +6888,16 @@ packages:
engines: {node: '>=12'}
hasBin: true
- esbuild@0.20.2:
- resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==}
+ esbuild@0.21.5:
+ resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
engines: {node: '>=12'}
hasBin: true
+ esbuild@0.23.0:
+ resolution: {integrity: sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==}
+ engines: {node: '>=18'}
+ hasBin: true
+
escalade@3.1.1:
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
engines: {node: '>=6'}
@@ -6551,8 +6967,8 @@ packages:
'@typescript-eslint/parser':
optional: true
- eslint-plugin-vue@9.25.0:
- resolution: {integrity: sha512-tDWlx14bVe6Bs+Nnh3IGrD+hb11kf2nukfm6jLsmJIhmiRQ1SUaksvwY9U5MvPB0pcrg0QK0xapQkfITs3RKOA==}
+ eslint-plugin-vue@9.27.0:
+ resolution: {integrity: sha512-5Dw3yxEyuBSXTzT5/Ge1X5kIkRTQ3nvBn/VwPwInNiZBSJOO/timWMUaflONnFBzU6NhB68lxnCda7ULV5N7LA==}
engines: {node: ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0
@@ -6564,20 +6980,27 @@ packages:
resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ eslint-scope@8.0.2:
+ resolution: {integrity: sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
eslint-visitor-keys@3.4.3:
resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
- eslint@8.53.0:
- resolution: {integrity: sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
- hasBin: true
+ eslint-visitor-keys@4.0.0:
+ resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- eslint@8.57.0:
- resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ eslint@9.8.0:
+ resolution: {integrity: sha512-K8qnZ/QJzT2dLKdZJVX6W4XOwBzutMYmt0lqUS+JdXgd+HTYFlonFgkJ8s44d/zMPPCnOOk0kMWCApCPhiOy9A==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
hasBin: true
+ espree@10.1.0:
+ resolution: {integrity: sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
espree@9.6.1:
resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -6591,6 +7014,10 @@ packages:
resolution: {integrity: sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng==}
engines: {node: '>=0.10'}
+ esquery@1.6.0:
+ resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
+ engines: {node: '>=0.10'}
+
esrecurse@4.3.0:
resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
engines: {node: '>=4.0'}
@@ -6653,6 +7080,10 @@ packages:
resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
engines: {node: '>=16.17'}
+ execa@9.3.0:
+ resolution: {integrity: sha512-l6JFbqnHEadBoVAVpN5dl2yCyfX28WoBAGaoQcNmLLSedOxTxcn2Qa83s8I/PA5i56vWru2OHOtrwF7Om2vqlg==}
+ engines: {node: ^18.19.0 || >=20.5.0}
+
executable@4.1.1:
resolution: {integrity: sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==}
engines: {node: '>=4'}
@@ -6668,10 +7099,6 @@ packages:
exponential-backoff@3.1.1:
resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==}
- express@4.18.2:
- resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==}
- engines: {node: '>= 0.10.0'}
-
express@4.19.2:
resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==}
engines: {node: '>= 0.10.0'}
@@ -6734,6 +7161,9 @@ packages:
fast-uri@2.2.0:
resolution: {integrity: sha512-cIusKBIt/R/oI6z/1nyfe2FvGKVTohVRfvkOhvx0nCEW+xf5NoCXjAHcWp93uOUBchzYcsvPlrapAdX1uW+YGg==}
+ fast-uri@3.0.1:
+ resolution: {integrity: sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==}
+
fast-xml-parser@4.2.5:
resolution: {integrity: sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==}
hasBin: true
@@ -6745,11 +7175,8 @@ packages:
resolution: {integrity: sha512-F4o8ZIMVx4YoxGfwrZys6wyjl40gF3Yv6AWWRy62ozFAyZBSS831/uyyCAqKYw3tR73g180ryG98yih6To1PUQ==}
engines: {node: '>= 10'}
- fastify@4.26.2:
- resolution: {integrity: sha512-90pjTuPGrfVKtdpLeLzND5nyC4woXZN5VadiNQCicj/iJU4viNHKhsAnb7jmv1vu2IzkLXyBiCzdWuzeXgQ5Ug==}
-
- fastq@1.15.0:
- resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==}
+ fastify@4.28.1:
+ resolution: {integrity: sha512-kFWUtpNr4i7t5vY2EJPCN2KgMVpuqfU4NjnJNCgiNB900oiDeYqaNDRcAfeBbOF5hGixixxcKnOU4KN9z6QncQ==}
fastq@1.17.1:
resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
@@ -6757,6 +7184,9 @@ packages:
fb-watchman@2.0.2:
resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==}
+ fd-package-json@1.2.0:
+ resolution: {integrity: sha512-45LSPmWf+gC5tdCQMNH4s9Sr00bIkiD9aN7dc5hqkrEw1geRYyDQS1v1oMHAW3ysfxfndqGsrDREHHjNNbKUfA==}
+
fd-slicer@1.1.0:
resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==}
@@ -6775,9 +7205,13 @@ packages:
resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==}
engines: {node: '>=8'}
- file-entry-cache@6.0.1:
- resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
- engines: {node: ^10.12.0 || >=12.0.0}
+ figures@6.1.0:
+ resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==}
+ engines: {node: '>=18'}
+
+ file-entry-cache@8.0.0:
+ resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
+ engines: {node: '>=16.0.0'}
file-system-cache@2.3.0:
resolution: {integrity: sha512-l4DMNdsIPsVnKrgEXbJwDJsA5mB8rGwHYERMgqQx/xAUtChPJMre1bXBzDEqqVbWv9AIbFezXMxeEkZDSrXUOQ==}
@@ -6786,8 +7220,8 @@ packages:
resolution: {integrity: sha512-hlDw5Ev+9e883s0pwUsuuYNu4tD7GgpUnOvykjv1Gya0ZIjuKumthDRua90VUn6/nlRKAjcxLUnHNTIUWwWIiw==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
- file-type@19.0.0:
- resolution: {integrity: sha512-s7cxa7/leUWLiXO78DVVfBVse+milos9FitauDLG1pI7lNaJ2+5lzPnr2N24ym+84HVwJL6hVuGfgVE+ALvU8Q==}
+ file-type@19.3.0:
+ resolution: {integrity: sha512-mROwiKLZf/Kwa/2Rol+OOZQn1eyTkPB3ZTwC0ExY6OLFCbgxHYZvBm7xI77NvfZFMKBsmuXfmLJnD4eEftEhrA==}
engines: {node: '>=18'}
filelist@1.0.4:
@@ -6805,6 +7239,10 @@ packages:
resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
engines: {node: '>=8'}
+ fill-range@7.1.1:
+ resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
+ engines: {node: '>=8'}
+
finalhandler@1.2.0:
resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==}
engines: {node: '>= 0.8'}
@@ -6844,20 +7282,20 @@ packages:
resolution: {integrity: sha512-MdYSsbdCaIRjzo5edthZtWmEZVMfr1qrtYZUHIdO3swCE+CoZA8S5l0s4jDsYlTa9ZiXv0pTgpzE7s4N8NeUOA==}
engines: {node: '>=18'}
- flat-cache@3.0.4:
- resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==}
- engines: {node: ^10.12.0 || >=12.0.0}
+ flat-cache@4.0.1:
+ resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
+ engines: {node: '>=16'}
- flatted@3.2.7:
- resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==}
+ flatted@3.3.1:
+ resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==}
flow-parser@0.202.0:
resolution: {integrity: sha512-ZiXxSIXK3zPmY3zrzCofFonM2T+/3Jz5QZKJyPVtUERQEJUnYkXBQ+0H3FzyqiyJs+VXqb/UNU6/K6sziVYdxw==}
engines: {node: '>=0.4.0'}
- fluent-ffmpeg@2.1.2:
- resolution: {integrity: sha512-IZTB4kq5GK0DPp7sGQ0q/BWurGHffRtQQwVkiqDgeO6wYJLLV5ZhgNOQ65loZxxuPMKZKZcICCUnaGtlxBiR0Q==}
- engines: {node: '>=0.8.0'}
+ fluent-ffmpeg@2.1.3:
+ resolution: {integrity: sha512-Be3narBNt2s6bsaqP6Jzq91heDgOEaDCJAXcE3qcma/EJBSy5FB4cvO31XBInuAuKBx8Kptf8dkhjK0IOru39Q==}
+ engines: {node: '>=18'}
follow-redirects@1.15.2:
resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
@@ -6890,10 +7328,6 @@ packages:
resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==}
engines: {node: '>= 0.12'}
- form-data@3.0.1:
- resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==}
- engines: {node: '>= 6'}
-
form-data@4.0.0:
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
engines: {node: '>= 6'}
@@ -6913,9 +7347,6 @@ packages:
from@0.1.7:
resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==}
- fs-constants@1.0.0:
- resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
-
fs-extra@11.1.1:
resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==}
engines: {node: '>=14.14'}
@@ -6939,8 +7370,8 @@ packages:
resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==}
engines: {node: '>= 8'}
- fs-minipass@3.0.2:
- resolution: {integrity: sha512-2GAfyfoaCDRrM6jaOS3UsBts8yJ55VioXdWcOL7dK9zdAuKT71+WBA4ifnNYqVjYv+4SsPxjK0JT4yIIn4cA/g==}
+ fs-minipass@3.0.3:
+ resolution: {integrity: sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
fs.realpath@1.0.0:
@@ -6964,6 +7395,7 @@ packages:
gauge@3.0.2:
resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==}
engines: {node: '>=10'}
+ deprecated: This package is no longer supported.
gensync@1.0.0-beta.2:
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
@@ -6979,10 +7411,6 @@ packages:
get-intrinsic@1.2.1:
resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==}
- get-npm-tarball-url@2.0.3:
- resolution: {integrity: sha512-R/PW6RqyaBQNWYaSyfrh54/qtcnOp22FHCCiRhSSZj0FP3KQWCsxxt0DzIdVTbwTqe9CtQfvl/FPD4UIPt4pqw==}
- engines: {node: '>=12.17'}
-
get-package-type@0.1.0:
resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==}
engines: {node: '>=8.0.0'}
@@ -7006,6 +7434,10 @@ packages:
resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==}
engines: {node: '>=16'}
+ get-stream@9.0.1:
+ resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==}
+ engines: {node: '>=18'}
+
get-symbol-description@1.0.0:
resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==}
engines: {node: '>= 0.4'}
@@ -7052,17 +7484,24 @@ packages:
engines: {node: '>=16 || 14 >=14.17'}
hasBin: true
- glob@10.3.12:
- resolution: {integrity: sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==}
- engines: {node: '>=16 || 14 >=14.17'}
+ glob@10.4.2:
+ resolution: {integrity: sha512-GwMlUF6PkPo3Gk21UxkCohOv0PLcIXVtKyLlpEI28R/cO/4eNOdmLk3CMW1wROV/WR/EsZOWAfBbBOqYvs88/w==}
+ engines: {node: '>=16 || 14 >=14.18'}
+ hasBin: true
+
+ glob@11.0.0:
+ resolution: {integrity: sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==}
+ engines: {node: 20 || >=22}
hasBin: true
glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
+ deprecated: Glob versions prior to v9 are no longer supported
glob@8.1.0:
resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
engines: {node: '>=12'}
+ deprecated: Glob versions prior to v9 are no longer supported
global-dirs@3.0.1:
resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==}
@@ -7072,14 +7511,18 @@ packages:
resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
engines: {node: '>=4'}
- globals@13.19.0:
- resolution: {integrity: sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==}
- engines: {node: '>=8'}
-
globals@13.24.0:
resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
engines: {node: '>=8'}
+ globals@14.0.0:
+ resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
+ engines: {node: '>=18'}
+
+ globals@15.8.0:
+ resolution: {integrity: sha512-VZAJ4cewHTExBWDHR6yptdIBlx9YSSZuwojj9Nt5mBRXQzrKakDsVKQ1J63sklLvzAJm0X5+RpO4i3Y2hcOnFw==}
+ engines: {node: '>=18'}
+
globalthis@1.0.3:
resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==}
engines: {node: '>= 0.4'}
@@ -7088,6 +7531,10 @@ packages:
resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
engines: {node: '>=10'}
+ globby@14.0.1:
+ resolution: {integrity: sha512-jOMLD2Z7MAhyG8aJpNOpmziMOP4rPLcc95oQPKXBazW82z+CEgPFBQvEpRUa1KeIMUJo4Wsm+q6uzO/Q/4BksQ==}
+ engines: {node: '>=18'}
+
google-protobuf@3.21.2:
resolution: {integrity: sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==}
@@ -7102,8 +7549,8 @@ packages:
resolution: {integrity: sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==}
engines: {node: '>=14.16'}
- got@14.2.1:
- resolution: {integrity: sha512-KOaPMremmsvx6l9BLC04LYE6ZFW4x7e4HkTe3LwBmtuYYQwpeS4XKqzhubTIkaQ1Nr+eXxeori0zuwupXMovBQ==}
+ got@14.4.2:
+ resolution: {integrity: sha512-+Te/qEZ6hr7i+f0FNgXx/6WQteSM/QqueGvxeYQQFm0GDfoxLVJ/oiwUKYMTeioColWUTdewZ06hmrBjw6F7tw==}
engines: {node: '>=20'}
graceful-fs@4.2.11:
@@ -7119,10 +7566,6 @@ packages:
resolution: {integrity: sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==}
engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0}
- gunzip-maybe@1.4.2:
- resolution: {integrity: sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw==}
- hasBin: true
-
hammerjs@2.0.8:
resolution: {integrity: sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==}
engines: {node: '>=0.8.0'}
@@ -7257,8 +7700,8 @@ packages:
resolution: {integrity: sha512-3cZ0SRL8fb9MUlU3mKM61FcQvPfXx2dBrZW3Vbg5CXa8jFlK8OaEpePenLe1oEXQduhz8b0QjsqfS59QP4AJDQ==}
engines: {node: '>=6.0.0'}
- http-proxy-agent@7.0.0:
- resolution: {integrity: sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==}
+ http-proxy-agent@7.0.2:
+ resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
engines: {node: '>= 14'}
http-signature@1.2.0:
@@ -7293,6 +7736,14 @@ packages:
resolution: {integrity: sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==}
engines: {node: '>= 14'}
+ https-proxy-agent@7.0.4:
+ resolution: {integrity: sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==}
+ engines: {node: '>= 14'}
+
+ https-proxy-agent@7.0.5:
+ resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==}
+ engines: {node: '>= 14'}
+
human-signals@1.1.1:
resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==}
engines: {node: '>=8.12.0'}
@@ -7309,6 +7760,10 @@ packages:
resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
engines: {node: '>=16.17.0'}
+ human-signals@7.0.0:
+ resolution: {integrity: sha512-74kytxOUSvNbjrT9KisAbaTZ/eJwD/LrbM/kh5j0IhPuJzwuA19dWvniFGwBzN9rVjg+O/e+F310PjObDXS+9Q==}
+ engines: {node: '>=18.18.0'}
+
iconv-lite@0.4.24:
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
engines: {node: '>=0.10.0'}
@@ -7326,8 +7781,8 @@ packages:
ignore-by-default@1.0.1:
resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==}
- ignore-walk@6.0.4:
- resolution: {integrity: sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw==}
+ ignore-walk@6.0.5:
+ resolution: {integrity: sha512-VuuG0wCnjhnylG1ABXT3dAuIpTNDs/G8jlpmwXY03fXoXy/8ZK8/T+hMzt8L4WnrLCJgdybqgPagnF/f97cg3A==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
ignore@5.2.4:
@@ -7345,11 +7800,11 @@ packages:
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
engines: {node: '>=6'}
- import-in-the-middle@1.4.2:
- resolution: {integrity: sha512-9WOz1Yh/cvO/p69sxRmhyQwrIGGSp7EIdcb+fFNVi7CzQGQB8U1/1XrKVSbEd/GNOAeM0peJtmi7+qphe7NvAw==}
+ import-in-the-middle@1.10.0:
+ resolution: {integrity: sha512-Z1jumVdF2GwnnYfM0a/y2ts7mZbwFMgt5rRuVmLgobgahC6iKgN5MBuXjzfTIOUpq5LSU10vJIPpVKe0X89fIw==}
- import-in-the-middle@1.7.4:
- resolution: {integrity: sha512-Lk+qzWmiQuRPPulGQeK5qq0v32k2bHnWrRPFgqyvhw7Kkov5L6MOLOIU3pcWeujc9W4q54Cp3Q2WV16eQkc7Bg==}
+ import-in-the-middle@1.7.1:
+ resolution: {integrity: sha512-1LrZPDtW+atAxH42S6288qyDFNQ2YCty+2mxEPRtfazH6Z5QwkaBSTS2ods7hnVJioF6rkRfNoA6A/MstpFXLg==}
import-lazy@4.0.0:
resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==}
@@ -7406,13 +7861,13 @@ packages:
iota-array@1.0.0:
resolution: {integrity: sha512-pZ2xT+LOHckCatGQ3DcG/a+QuEqvoxqkiL7tvE8nn3uuu+f6i1TtpB5/FtWFbxUuVr5PZCx8KskuGatbJDXOWA==}
- ip-address@7.1.0:
- resolution: {integrity: sha512-V9pWC/VJf2lsXqP7IWJ+pe3P1/HCYGBMZrrnT62niLGjAfCbeiwXMUxaeHvnVlz19O27pvXP4azs+Pj/A0x+SQ==}
- engines: {node: '>= 10'}
+ ip-address@9.0.5:
+ resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==}
+ engines: {node: '>= 12'}
- ip-cidr@3.1.0:
- resolution: {integrity: sha512-HUCn4snshEX1P8cja/IyU3qk8FVDW8T5zZcegDFbu4w7NojmAhk5NcOgj3M8+0fmumo1afJTPDtJlzsxLdOjtg==}
- engines: {node: '>=10.0.0'}
+ ip-cidr@4.0.1:
+ resolution: {integrity: sha512-V5Nce94SVJ7NtyT/UKUeTM7sY3V7TEk48hURhtBgTiGduOa5t6p9Hd+zBOGvr4Gu7iWPxFVYNl017p0akQA84w==}
+ engines: {node: '>=16.14.0'}
ip-regex@4.3.0:
resolution: {integrity: sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==}
@@ -7479,9 +7934,6 @@ packages:
resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
engines: {node: '>= 0.4'}
- is-deflate@1.0.0:
- resolution: {integrity: sha512-YDoFpuZWu1VRXlsnlYMzKyVRITXj7Ej/V9gXQ2/pAe7X1J7M/RNOqaIYi6qUn+B7nGyB9pDXrv02dsB58d2ZAQ==}
-
is-docker@2.2.1:
resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==}
engines: {node: '>=8'}
@@ -7513,10 +7965,6 @@ packages:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
- is-gzip@1.0.0:
- resolution: {integrity: sha512-rcfALRIb1YewtnksfRIHGcIY93QnK8BIQ/2c9yDYcG/Y6+vRoJuTWBmmSEbyLLYtXm7q35pHOHbZFQBaLrhlWQ==}
- engines: {node: '>=0.10.0'}
-
is-installed-globally@0.4.0:
resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==}
engines: {node: '>=10'}
@@ -7554,10 +8002,6 @@ packages:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
- is-path-cwd@2.2.0:
- resolution: {integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==}
- engines: {node: '>=6'}
-
is-path-inside@3.0.3:
resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
engines: {node: '>=8'}
@@ -7606,12 +8050,16 @@ packages:
resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ is-stream@4.0.1:
+ resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==}
+ engines: {node: '>=18'}
+
is-string@1.0.7:
resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
engines: {node: '>= 0.4'}
- is-svg@5.0.0:
- resolution: {integrity: sha512-sRl7J0oX9yUNamSdc8cwgzh9KBLnQXNzGmW0RVHwg/jEYjGNYHC6UvnYD8+hAeut9WwxRvhG9biK7g/wDGxcMw==}
+ is-svg@5.0.1:
+ resolution: {integrity: sha512-mLYxDsfisQWdS4+gSblAwhATDoNMS/tx8G7BKA+aBIf7F0m1iUwMvuKAo6mW4WMleQAEE50I1Zqef9yMMfHk3w==}
engines: {node: '>=14.16'}
is-symbol@1.0.4:
@@ -7629,6 +8077,10 @@ packages:
resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
engines: {node: '>=10'}
+ is-unicode-supported@2.0.0:
+ resolution: {integrity: sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q==}
+ engines: {node: '>=18'}
+
is-weakmap@2.0.1:
resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==}
@@ -7685,6 +8137,10 @@ packages:
resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==}
engines: {node: '>=10'}
+ istanbul-lib-source-maps@5.0.4:
+ resolution: {integrity: sha512-wHOoEsNJTVltaJp8eVkm8w+GVkVNHT2YDYo53YdzQEL2gWm1hBX5cGFR9hQJtuGLebidVX7et3+dmDZrmclduw==}
+ engines: {node: '>=10'}
+
istanbul-reports@3.1.6:
resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==}
engines: {node: '>=8'}
@@ -7697,6 +8153,14 @@ packages:
resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==}
engines: {node: '>=14'}
+ jackspeak@3.4.0:
+ resolution: {integrity: sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==}
+ engines: {node: '>=14'}
+
+ jackspeak@4.0.1:
+ resolution: {integrity: sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==}
+ engines: {node: 20 || >=22}
+
jake@10.8.5:
resolution: {integrity: sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==}
engines: {node: '>=10'}
@@ -7857,6 +8321,9 @@ packages:
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+ js-tokens@9.0.0:
+ resolution: {integrity: sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==}
+
js-yaml@3.14.1:
resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
hasBin: true
@@ -7884,8 +8351,8 @@ packages:
'@babel/preset-env':
optional: true
- jsdom@24.0.0:
- resolution: {integrity: sha512-UDS2NayCvmXSXVP6mpTj+73JnNQadZlr9N68189xib2tx5Mls7swlTNao26IoHv46BZJFvXygyRtyXd1feAk1A==}
+ jsdom@24.1.1:
+ resolution: {integrity: sha512-5O1wWV99Jhq4DV7rCLIoZ/UIhyQeDR7wHVyZAHAshbrvZsLs+Xzz7gtwnlJTJDjleiTKh54F4dXrX70vJQTyJQ==}
engines: {node: '>=18'}
peerDependencies:
canvas: ^2.11.2
@@ -7967,9 +8434,6 @@ packages:
jsrsasign@11.1.0:
resolution: {integrity: sha512-Ov74K9GihaK9/9WncTe1mPmvrO7Py665TUfUKvraXBpu+xcTWitrtuOwcjf4KMU9maPaYn0OuaWy0HOzy/GBXg==}
- jssha@3.3.1:
- resolution: {integrity: sha512-VCMZj12FCFMQYcFLPRm/0lOBbLi8uM2BhXPTqw3U4YAfs4AZfiApOoBLoN8cQE60Z50m1MYMTQVCfgF/KaCVhQ==}
-
jstransformer@1.0.0:
resolution: {integrity: sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==}
@@ -8046,8 +8510,8 @@ packages:
enquirer:
optional: true
- local-pkg@0.4.3:
- resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==}
+ local-pkg@0.5.0:
+ resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==}
engines: {node: '>=14'}
locate-path@3.0.0:
@@ -8074,9 +8538,6 @@ packages:
lodash.isarguments@3.1.0:
resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==}
- lodash.isequal@4.5.0:
- resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
-
lodash.memoize@4.1.2:
resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
@@ -8129,6 +8590,10 @@ packages:
resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==}
engines: {node: 14 || >=16.14}
+ lru-cache@11.0.0:
+ resolution: {integrity: sha512-Qv32eSV1RSCfhY3fpPE2GNZ8jgM9X7rdAfemLWqTUxwiyIC4jJ6Sy0fZ8H+oLWevO6i4/bizg7c8d8i6bxrzbA==}
+ engines: {node: 20 || >=22}
+
lru-cache@4.1.5:
resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
@@ -8158,9 +8623,8 @@ packages:
magic-string@0.30.10:
resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==}
- magic-string@0.30.7:
- resolution: {integrity: sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==}
- engines: {node: '>=12'}
+ magicast@0.3.4:
+ resolution: {integrity: sha512-TyDF/Pn36bBji9rWKHlZe+PZb6Mx5V8IHCSxk7X4aljM4e/vyDvZZYwHewdVaqiA0nb3ghfHU/6AUpDxWoER2Q==}
mailcheck@1.1.1:
resolution: {integrity: sha512-3WjL8+ZDouZwKlyJBMp/4LeziLFXgleOdsYu87piGcMLqhBzCsy2QFdbtAwv757TFC/rtqd738fgJw1tFQCSgA==}
@@ -8201,8 +8665,8 @@ packages:
markdown-table@3.0.3:
resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==}
- markdown-to-jsx@7.3.2:
- resolution: {integrity: sha512-B+28F5ucp83aQm+OxNrPkS8z0tMKaeHiy0lHJs3LqCyDQFtWuenaIrkaVTgAm1pf1AU85LXltva86hlaT17i8Q==}
+ markdown-to-jsx@7.4.7:
+ resolution: {integrity: sha512-0+ls1IQZdU6cwM1yu0ZjjiVWYtkbExSyUIFU2ZeDIFuZM1W42Mh4OlJ4nb4apX4H8smxDHRdFaoIVJGwfv5hkg==}
engines: {node: '>= 10'}
peerDependencies:
react: '>= 0.14.0'
@@ -8253,8 +8717,8 @@ packages:
resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
engines: {node: '>= 0.6'}
- meilisearch@0.38.0:
- resolution: {integrity: sha512-bHaq8nYxSKw9/Qslq1Zes5g9tHgFkxy/I9o8942wv2PqlNOT0CzptIkh/x98N52GikoSZOXSQkgt6oMjtf5uZw==}
+ meilisearch@0.41.0:
+ resolution: {integrity: sha512-5KcGLxEXD7E+uNO7R68rCbGSHgCqeM3Q3RFFLSsN7ZrIgr8HPDXVAIlP4LHggAZfk0FkSzo8VSXifHCwa2k80g==}
memoizerific@1.11.3:
resolution: {integrity: sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==}
@@ -8368,8 +8832,8 @@ packages:
micromark@4.0.0:
resolution: {integrity: sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==}
- micromatch@4.0.5:
- resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
+ micromatch@4.0.7:
+ resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==}
engines: {node: '>=8.6'}
mime-db@1.52.0:
@@ -8417,6 +8881,10 @@ packages:
minimalistic-assert@1.0.1:
resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==}
+ minimatch@10.0.1:
+ resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==}
+ engines: {node: 20 || >=22}
+
minimatch@3.0.8:
resolution: {integrity: sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==}
@@ -8481,6 +8949,10 @@ packages:
resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==}
engines: {node: '>=16 || 14 >=14.17'}
+ minipass@7.1.2:
+ resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
+ engines: {node: '>=16 || 14 >=14.17'}
+
minizlib@1.3.3:
resolution: {integrity: sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==}
@@ -8488,9 +8960,6 @@ packages:
resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==}
engines: {node: '>= 8'}
- mkdirp-classic@0.5.3:
- resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
-
mkdirp@0.5.6:
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
hasBin: true
@@ -8542,13 +9011,13 @@ packages:
msgpackr@1.10.1:
resolution: {integrity: sha512-r5VRLv9qouXuLiIBrLpl2d5ZvPt8svdQTl5/vMvE4nzDMyEX4sgW5yWhuBBj5UmgwOTWj8CIdSXn5sAfsHAWIQ==}
- msw-storybook-addon@2.0.1:
- resolution: {integrity: sha512-pZ3JDQ9HkGQ3XDMIHvMcDSI4Vbp/LHmwHwiZu+pHLzimtI1vhAo1swjFEDAEJuBcozljYvREEC4sS7rQHPNtWg==}
+ msw-storybook-addon@2.0.3:
+ resolution: {integrity: sha512-CzHmGO32JeOPnyUnRWnB0PFTXCY1HKfHiEB/6fYoUYiFm2NYosLjzs9aBd3XJUryYEN0avJqMNh7nCRDxE5JjQ==}
peerDependencies:
msw: ^2.0.0
- msw@2.2.14:
- resolution: {integrity: sha512-64i8rNCa1xzDK8ZYsTrVMli05D687jty8+Th+PU5VTbJ2/4P7fkQFVyDQ6ZFT5FrNR8z2BHhbY47fKNvfHrumA==}
+ msw@2.3.4:
+ resolution: {integrity: sha512-sHMlwrajgmZSA2l1o7qRSe+azm/I+x9lvVVcOxAzi4vCtH8uVPJk1K5BQYDkzGl+tt0RvM9huEXXdeGrgcc79g==}
engines: {node: '>=18'}
hasBin: true
peerDependencies:
@@ -8578,8 +9047,8 @@ packages:
mz@2.7.0:
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
- nan@2.18.0:
- resolution: {integrity: sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==}
+ nan@2.20.0:
+ resolution: {integrity: sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==}
nanoid@3.3.7:
resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
@@ -8661,8 +9130,8 @@ packages:
node-fetch-native@1.0.2:
resolution: {integrity: sha512-KIkvH1jl6b3O7es/0ShyCgWLcfXxlBrLBbP3rOr23WArC66IMcU4DeZEeYEOwnopYhawLTn7/y+YtmASe8DFVQ==}
- node-fetch@2.6.11:
- resolution: {integrity: sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==}
+ node-fetch@2.6.13:
+ resolution: {integrity: sha512-StxNAxh15zr77QvvkmveSQ8uCQ4+v5FkvNTj0OESmiHu+VRi/gXArXtkWMElOsOUNLtUEvI4yS+rdtOHZTwlQA==}
engines: {node: 4.x || >=6.0.0}
peerDependencies:
encoding: ^0.1.0
@@ -8691,8 +9160,8 @@ packages:
resolution: {integrity: sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==}
hasBin: true
- node-gyp@10.0.1:
- resolution: {integrity: sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg==}
+ node-gyp@10.1.0:
+ resolution: {integrity: sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA==}
engines: {node: ^16.14.0 || >=18.0.0}
hasBin: true
@@ -8702,8 +9171,8 @@ packages:
node-releases@2.0.14:
resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
- nodemailer@6.9.13:
- resolution: {integrity: sha512-7o38Yogx6krdoBf3jCAqnIN4oSQFx+fMa0I7dK1D+me9kBxx12D+/33wSb+fhOCtIxvYJ+4x4IMEhmhCKfAiOA==}
+ nodemailer@6.9.14:
+ resolution: {integrity: sha512-Dobp/ebDKBvz91sbtRKhcznLThrKxKt97GI2FAlAyy+fk19j73Uz3sBXolVtmcXjaorivqsbbbjDY+Jkt4/bQA==}
engines: {node: '>=6.0.0'}
nodemon@3.0.2:
@@ -8711,8 +9180,8 @@ packages:
engines: {node: '>=10'}
hasBin: true
- nodemon@3.1.0:
- resolution: {integrity: sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==}
+ nodemon@3.1.4:
+ resolution: {integrity: sha512-wjPBbFhtpJwmIeY2yP7QF+UKzPfltVGtfce1g/bB15/8vCGZj8uxD62b/b9M9/WVgme0NZudpownKN+c0plXlQ==}
engines: {node: '>=10'}
hasBin: true
@@ -8758,6 +9227,10 @@ packages:
resolution: {integrity: sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==}
engines: {node: '>=14.16'}
+ normalize-url@8.0.1:
+ resolution: {integrity: sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==}
+ engines: {node: '>=14.16'}
+
npm-run-path@2.0.2:
resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==}
engines: {node: '>=4'}
@@ -8770,8 +9243,13 @@ packages:
resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ npm-run-path@5.3.0:
+ resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
npmlog@5.0.1:
resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==}
+ deprecated: This package is no longer supported.
nsfwjs@2.4.2:
resolution: {integrity: sha512-i4Pp2yt59qPQgeZFyg3wXFBX52uSeu/hkDoqdZfe+sILRxNBUu0VDogj7Lmqak0GlrXviS/wLiVeIx40IDUu7A==}
@@ -8781,8 +9259,8 @@ packages:
nth-check@2.1.1:
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
- nwsapi@2.2.9:
- resolution: {integrity: sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg==}
+ nwsapi@2.2.12:
+ resolution: {integrity: sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==}
oauth-sign@0.9.0:
resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==}
@@ -8873,12 +9351,14 @@ packages:
resolution: {integrity: sha512-es3mGcDXV6TKPo6n3aohzHm0qxhLyR39MhF6mkD1FwFGjhxnqMqfSIgM0eCpInZvqatve4CxmXcMZw3jnnsaXw==}
hasBin: true
- opentelemetry-instrumentation-fetch-node@1.2.0:
- resolution: {integrity: sha512-aiSt/4ubOTyb1N5C2ZbGrBvaJOXIZhZvpRPYuUVxQJe27wJZqf/o65iPrqgLcgfeOLaQ8cS2Q+762jrYvniTrA==}
+ opentelemetry-instrumentation-fetch-node@1.2.3:
+ resolution: {integrity: sha512-Qb11T7KvoCevMaSeuamcLsAD+pZnavkhDnlVL0kRozfhl42dKG5Q3anUklAFKJZjY3twLR+BnRa6DlwwkIE/+A==}
engines: {node: '>18.0.0'}
+ peerDependencies:
+ '@opentelemetry/api': ^1.6.0
- optionator@0.9.3:
- resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
+ optionator@0.9.4:
+ resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
engines: {node: '>= 0.8.0'}
ora@5.4.1:
@@ -8895,8 +9375,8 @@ packages:
ospath@1.2.2:
resolution: {integrity: sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==}
- otpauth@9.2.3:
- resolution: {integrity: sha512-oAG55Ch4MBL5Jdg+RXfKiRCZ2lCwa/UIQKsmSfYbGGLSI4dErY1HPZv0JGPPESIYGyDO3s9iJqM4HU/1IppMoQ==}
+ otpauth@9.3.1:
+ resolution: {integrity: sha512-E6d2tMxPofHNk4sRFp+kqW7vQ+WJGO9VLI2N/W00DnI+ThskU12Qa10kyNSGklrzhN5c+wRUsN4GijVgCU2N9w==}
outvariant@1.4.2:
resolution: {integrity: sha512-Ou3dJ6bA/UJ5GVHxah4LnqDwZRwAmWxrG3wtrHrbGnP4RnLCtA64A4F+ae7Y8ww660JaddSoArUR5HjipWSHAQ==}
@@ -8925,9 +9405,9 @@ packages:
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
engines: {node: '>=10'}
- p-limit@4.0.0:
- resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ p-limit@5.0.0:
+ resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==}
+ engines: {node: '>=18'}
p-locate@3.0.0:
resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==}
@@ -8957,8 +9437,8 @@ packages:
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
engines: {node: '>=6'}
- pako@0.2.9:
- resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==}
+ package-json-from-dist@1.0.0:
+ resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==}
parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
@@ -8971,6 +9451,10 @@ packages:
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
engines: {node: '>=8'}
+ parse-ms@4.0.0:
+ resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==}
+ engines: {node: '>=18'}
+
parse-srcset@1.0.2:
resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==}
@@ -9027,9 +9511,13 @@ packages:
resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==}
engines: {node: '>=16 || 14 >=14.17'}
- path-scurry@1.10.2:
- resolution: {integrity: sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==}
- engines: {node: '>=16 || 14 >=14.17'}
+ path-scurry@1.11.1:
+ resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
+ engines: {node: '>=16 || 14 >=14.18'}
+
+ path-scurry@2.0.0:
+ resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==}
+ engines: {node: 20 || >=22}
path-to-regexp@0.1.7:
resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==}
@@ -9047,6 +9535,10 @@ packages:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
+ path-type@5.0.0:
+ resolution: {integrity: sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==}
+ engines: {node: '>=12'}
+
pathe@1.1.2:
resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==}
@@ -9060,8 +9552,9 @@ packages:
resolution: {integrity: sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==}
engines: {node: '>=14.16'}
- peek-stream@1.1.3:
- resolution: {integrity: sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA==}
+ peek-readable@5.1.3:
+ resolution: {integrity: sha512-kCsc9HwH5RgVA3H3VqkWFyGQwsxUxLdiSX1d5nqAm7hnMFjNFX1VhBLmJoUY0hZNc8gmDNgBkLjfhiWPsziXWA==}
+ engines: {node: '>=14.16'}
pend@1.2.0:
resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
@@ -9088,9 +9581,6 @@ packages:
peerDependencies:
pg: '>=8.0'
- pg-protocol@1.6.0:
- resolution: {integrity: sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==}
-
pg-protocol@1.6.1:
resolution: {integrity: sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==}
@@ -9102,8 +9592,8 @@ packages:
resolution: {integrity: sha512-hRCSDuLII9/LE3smys1hRHcu5QGcLs9ggT7I/TCs0IE+2Eesxi9+9RWAAwZ0yaGjxoWICF/YHLOEjydGujoJ+g==}
engines: {node: '>=10'}
- pg@8.11.5:
- resolution: {integrity: sha512-jqgNHSKL5cbDjFlHyYsCXmQDrfIX/3RsNwYqpd4N0Kt8niLuNoRNH+aazv6cOd43gPh9Y4DjQCtb+X0MH0Hvnw==}
+ pg@8.12.0:
+ resolution: {integrity: sha512-A+LHUSnwnxrnL/tZ+OLfqR1SxLN3c/pgDztZ47Rpbsd4jUytsTtwQo/TLPRzPJMp/1pbhYVhH9cuSZLAajNfjQ==}
engines: {node: '>= 8.0.0'}
peerDependencies:
pg-native: '>=3.0.1'
@@ -9114,13 +9604,16 @@ packages:
pgpass@1.0.5:
resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==}
- photoswipe@5.4.3:
- resolution: {integrity: sha512-9UC6oJBK4oXFZ5HcdlcvGkfEHsVrmE4csUdCQhEjHYb3PvPLO3PG7UhnPuOgjxwmhq5s17Un5NUdum01LgBDng==}
+ photoswipe@5.4.4:
+ resolution: {integrity: sha512-WNFHoKrkZNnvFFhbHL93WDkW3ifwVOXSW3w1UuZZelSmgXpIGiZSNlZJq37rR8YejqME2rHs9EhH9ZvlvFH2NA==}
engines: {node: '>= 0.12.0'}
picocolors@1.0.0:
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
+ picocolors@1.0.1:
+ resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
+
picomatch@2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
@@ -9137,14 +9630,14 @@ packages:
resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==}
engines: {node: '>=6'}
- pino-abstract-transport@1.1.0:
- resolution: {integrity: sha512-lsleG3/2a/JIWUtf9Q5gUNErBqwIu1tUKTT3dUzaf5DySw9ra1wcqKjJjLX1VTY64Wk1eEOYsVGSaGfCK85ekA==}
+ pino-abstract-transport@1.2.0:
+ resolution: {integrity: sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==}
- pino-std-serializers@6.1.0:
- resolution: {integrity: sha512-KO0m2f1HkrPe9S0ldjx7za9BJjeHqBku5Ch8JyxETxT8dEFGz1PwgrHaOQupVYitpzbFSYm7nnljxD8dik2c+g==}
+ pino-std-serializers@7.0.0:
+ resolution: {integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==}
- pino@8.17.0:
- resolution: {integrity: sha512-ey+Mku+PVPhvxglLXMg1l1zQMwSHuNrKC3MD40EDZbkckJmmuY7DYZLIOwwjZ8ix/Nvhe9dZt5H99cgkot9bAw==}
+ pino@9.2.0:
+ resolution: {integrity: sha512-g3/hpwfujK5a4oVbaefoJxezLzsDgLcNJeITvC6yrfwYeT9la+edCK42j5QpEQSQCZgTKapXvnQIdgZwvRaZug==}
hasBin: true
pirates@4.0.5:
@@ -9373,6 +9866,10 @@ packages:
resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==}
engines: {node: ^10 || ^12 || >=14}
+ postcss@8.4.40:
+ resolution: {integrity: sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==}
+ engines: {node: ^10 || ^12 || >=14}
+
postgres-array@2.0.0:
resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==}
engines: {node: '>=4'}
@@ -9412,8 +9909,8 @@ packages:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
- prettier@3.2.5:
- resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==}
+ prettier@3.3.3:
+ resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==}
engines: {node: '>=14'}
hasBin: true
@@ -9433,6 +9930,10 @@ packages:
resolution: {integrity: sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==}
engines: {node: '>= 0.8'}
+ pretty-ms@9.0.0:
+ resolution: {integrity: sha512-E9e9HJ9R9NasGOgPaPE8VMeiPKAyWR5jcFpNnwIejslIhWqdqOrb2wShBsncMPUb+BcCd2OPYfh7p2W6oemTng==}
+ engines: {node: '>=18'}
+
private-ip@2.3.3:
resolution: {integrity: sha512-5zyFfekIVUOTVbL92hc8LJOtE/gyGHeREHkJ2yTyByP8Q2YZVoBqLg3EfYLeF0oVvGqtaEX2t2Qovja0/gStXw==}
@@ -9518,12 +10019,15 @@ packages:
pug-attrs@3.0.0:
resolution: {integrity: sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==}
- pug-code-gen@3.0.2:
- resolution: {integrity: sha512-nJMhW16MbiGRiyR4miDTQMRWDgKplnHyeLvioEJYbk1RsPI3FuA3saEP8uwnTb2nTJEKBU90NFVWJBk4OU5qyg==}
+ pug-code-gen@3.0.3:
+ resolution: {integrity: sha512-cYQg0JW0w32Ux+XTeZnBEeuWrAY7/HNE6TWnhiHGnnRYlCgyAUPoyh9KzCMa9WhcJlJ1AtQqpEYHc+vbCzA+Aw==}
pug-error@2.0.0:
resolution: {integrity: sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ==}
+ pug-error@2.1.0:
+ resolution: {integrity: sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg==}
+
pug-filters@4.0.0:
resolution: {integrity: sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==}
@@ -9548,18 +10052,12 @@ packages:
pug-walk@2.0.0:
resolution: {integrity: sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==}
- pug@3.0.2:
- resolution: {integrity: sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw==}
-
- pump@2.0.1:
- resolution: {integrity: sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==}
+ pug@3.0.3:
+ resolution: {integrity: sha512-uBi6kmc9f3SZ3PXxqcHiUZLmIXgfgWooKWXcwSGwQd2Zi5Rb0bT14+8CJjJgI8AB+nndLaNgHGrcc6bPIB665g==}
pump@3.0.0:
resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==}
- pumpify@1.5.1:
- resolution: {integrity: sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==}
-
punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
@@ -9632,10 +10130,6 @@ packages:
ratelimiter@3.4.1:
resolution: {integrity: sha512-5FJbRW/Jkkdk29ksedAfWFkQkhbUrMx3QJGwMKAypeIiQf4yrLW+gtPKZiaWt4zPrtw1uGufOjGO7UGM6VllsQ==}
- raw-body@2.5.1:
- resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==}
- engines: {node: '>= 0.8'}
-
raw-body@2.5.2:
resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
engines: {node: '>= 0.8'}
@@ -9644,8 +10138,8 @@ packages:
resolution: {integrity: sha512-fUeWjrkOO0t1rg7B2fdyDTvngj+9RlUyL92vOdiB7c0FPguWVsniIMjEtHH+meLBO9rzkUlUzBVXgWrjI8P9LA==}
engines: {node: '>=12'}
- re2@1.20.10:
- resolution: {integrity: sha512-/5JjSPXobSDaKFL6rD5Gb4qD4CVBITQb7NAxfQ/NA7o0HER3SJAPV3lPO2kvzw0/PN1pVJNVATEUk4y9j7oIIA==}
+ re2@1.21.3:
+ resolution: {integrity: sha512-GI+KoGkHT4kxTaX+9p0FgNB1XUnCndO9slG5qqeEoZ7kbf6Dk6ohQVpmwKVeSp7LPLn+g6Q3BaCopz4oHuBDuQ==}
react-colorful@5.6.1:
resolution: {integrity: sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==}
@@ -9726,10 +10220,6 @@ packages:
resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==}
engines: {node: '>= 12.13.0'}
- recast@0.23.4:
- resolution: {integrity: sha512-qtEDqIZGVcSZCHniWwZWbRy79Dc6Wp3kT/UmDA2RJKBPg7+7k51aQBZirHmUGn5uvHf2rg8DkjizrN26k61ATw==}
- engines: {node: '>= 4'}
-
recast@0.23.6:
resolution: {integrity: sha512-9FHoNjX1yjuesMwuthAmPKabxYQdOgihFYmT5ebXfYGBcnqXZf3WOVz+5foEZ8Y83P4ZY6yQD5GMmtV+pgCCAQ==}
engines: {node: '>= 4'}
@@ -9853,9 +10343,6 @@ packages:
resolution: {integrity: sha512-6K/gDlqgQscOlg9fSRpWstA8sYe8rbELsSTNpx+3kTrsVCzvSl0zIvRErM7fdl9ERWDsKnrLnwB+Ne89918XOg==}
engines: {node: '>=10'}
- resolve@1.19.0:
- resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==}
-
resolve@1.22.8:
resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
hasBin: true
@@ -9888,24 +10375,30 @@ packages:
rimraf@2.6.3:
resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==}
+ deprecated: Rimraf versions prior to v4 are no longer supported
hasBin: true
rimraf@2.7.1:
resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==}
+ deprecated: Rimraf versions prior to v4 are no longer supported
hasBin: true
rimraf@3.0.2:
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
+ deprecated: Rimraf versions prior to v4 are no longer supported
hasBin: true
- rollup@4.17.2:
- resolution: {integrity: sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==}
+ rollup@4.19.1:
+ resolution: {integrity: sha512-K5vziVlg7hTpYfFBI+91zHBEMo6jafYXpkMlqZjg7/zhIG9iHqazBf4xz9AVdjS9BruRn280ROqLI7G3OFRIlw==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
rrweb-cssom@0.6.0:
resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==}
+ rrweb-cssom@0.7.1:
+ resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==}
+
rss-parser@3.13.0:
resolution: {integrity: sha512-7jWUBV5yGN3rqMMj7CZufl/291QAhvrrGpDNE4k/02ZchL0npisiYYqULF71jCEKoIiHvK/Q2e6IkDwPziT7+w==}
@@ -9941,8 +10434,8 @@ packages:
sanitize-html@2.13.0:
resolution: {integrity: sha512-Xff91Z+4Mz5QiNSLdLWwjgBDm5b1RU6xBT0+12rapjiaR7SwfRdjw8f+6Rir2MXKLrDicRFHdb51hGOAxmsUIA==}
- sass@1.76.0:
- resolution: {integrity: sha512-nc3LeqvF2FNW5xGF1zxZifdW3ffIz5aBb7I7tSvOoNu7z1RQ6pFt9MBuiPtjgaI62YWrM/txjWlOCFiGtf2xpw==}
+ sass@1.77.8:
+ resolution: {integrity: sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ==}
engines: {node: '>=14.0.0'}
hasBin: true
@@ -10016,8 +10509,8 @@ packages:
resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==}
engines: {node: '>=8'}
- sharp@0.33.3:
- resolution: {integrity: sha512-vHUeXJU1UvlO/BNwTpT0x/r53WkLUVxrmb5JTgW92fdFCFk0ispLMAeu/jPO2vjkXM1fYUi3K7/qcLF47pwM1A==}
+ sharp@0.33.4:
+ resolution: {integrity: sha512-7i/dt5kGl7qR4gwPRD2biwD2/SvBn3O04J77XKFgL2OnZtQw+AG9wnuS/csmu80nPRHLYE9E41fyEiG8nhH6/Q==}
engines: {libvips: '>=8.15.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0}
shebang-command@1.2.0:
@@ -10036,8 +10529,8 @@ packages:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
- shiki@1.4.0:
- resolution: {integrity: sha512-5WIn0OL8PWm7JhnTwRWXniy6eEDY234mRrERVlFa646V2ErQqwIFd2UML7e0Pq9eqSKLoMa3Ke+xbsF+DAuy+Q==}
+ shiki@1.12.0:
+ resolution: {integrity: sha512-BuAxWOm5JhRcbSOl7XCei8wGjgJJonnV0oipUupPY58iULxUGyHhW5CF+9FRMuM1pcJ5cGEJGll1LusX6FwpPA==}
shimmer@1.2.1:
resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==}
@@ -10055,8 +10548,8 @@ packages:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
- simple-oauth2@5.0.0:
- resolution: {integrity: sha512-8291lo/z5ZdpmiOFzOs1kF3cxn22bMj5FFH+DNUppLJrpoIlM1QnFiE7KpshHu3J3i21TVcx4yW+gXYjdCKDLQ==}
+ simple-oauth2@5.1.0:
+ resolution: {integrity: sha512-gWDa38Ccm4MwlG5U7AlcJxPv3lvr80dU7ARJWrGdgvOKyzSj1gr3GBPN1rABTedAYvC/LsGYoFuFxwDBPtGEbw==}
simple-swizzle@0.2.2:
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
@@ -10156,6 +10649,10 @@ packages:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'}
+ slash@5.1.0:
+ resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==}
+ engines: {node: '>=14.16'}
+
slice-ansi@3.0.0:
resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==}
engines: {node: '>=8'}
@@ -10176,8 +10673,8 @@ packages:
resolution: {integrity: sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==}
engines: {node: '>= 10.13.0', npm: '>= 3.0.0'}
- sonic-boom@3.7.0:
- resolution: {integrity: sha512-IudtNvSqA/ObjN97tfgNmOKyDOs4dNcg4cUUsHDebqsgb8wGBBwb31LIgShNO8fye0dFI52X1+tFoKKI6Rq1Gg==}
+ sonic-boom@4.0.1:
+ resolution: {integrity: sha512-hTSD/6JMLyT4r9zeof6UtuBDpjJ9sO08/nmS5djaA9eozT9oOlNdpXSnzcgj4FTqpk3nkLrs61l4gip9r1HCrQ==}
sort-keys-length@1.0.1:
resolution: {integrity: sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==}
@@ -10237,8 +10734,8 @@ packages:
sprintf-js@1.0.3:
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
- sprintf-js@1.1.2:
- resolution: {integrity: sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==}
+ sprintf-js@1.1.3:
+ resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==}
sshpk@1.17.0:
resolution: {integrity: sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==}
@@ -10259,8 +10756,8 @@ packages:
standard-as-callback@2.1.0:
resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==}
- start-server-and-test@2.0.3:
- resolution: {integrity: sha512-QsVObjfjFZKJE6CS6bSKNwWZCKBG6975/jKRPPGFfFh+yOQglSeGXiNWjzgQNXdphcBI9nXbyso9tPfX4YAUhg==}
+ start-server-and-test@2.0.4:
+ resolution: {integrity: sha512-CKNeBTcP0hVqIlNismHMudb9q3lLdAjcVPO13/7gfI66fcJpeIb/o4NzQd1JK/CD+lfWVqr10ZH9Y14+OwlJuw==}
engines: {node: '>=16'}
hasBin: true
@@ -10297,8 +10794,8 @@ packages:
react-dom:
optional: true
- storybook@8.0.9:
- resolution: {integrity: sha512-/Mvij0Br5bUwJpCvqAUZMEDIWmdRxEyllvVj8Ukw5lIWJePxfpSsz4px5jg9+R6B9tO8sQSqjg4HJvQ/pZk8Tg==}
+ storybook@8.2.6:
+ resolution: {integrity: sha512-8j30wDxQmkcqI0fWcSYFsUCjErsY1yTWbTW+yjbwM8DyW18Cud6CwbFRCxjFsH+2M0CjP6Pqs/m1PGI0vcQscQ==}
hasBin: true
stream-browserify@3.0.0:
@@ -10310,9 +10807,6 @@ packages:
stream-parser@0.3.1:
resolution: {integrity: sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==}
- stream-shift@1.0.1:
- resolution: {integrity: sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==}
-
stream-wormhole@1.1.0:
resolution: {integrity: sha512-gHFfL3px0Kctd6Po0M8TzEvt3De/xu6cnRrjlfYNhwbhLPLwigI2t1nc6jrzNuaYg5C4YF78PPFuQPzRiqn9ew==}
engines: {node: '>=4.0.0'}
@@ -10396,6 +10890,10 @@ packages:
resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
engines: {node: '>=12'}
+ strip-final-newline@4.0.0:
+ resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==}
+ engines: {node: '>=18'}
+
strip-indent@3.0.0:
resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
engines: {node: '>=8'}
@@ -10408,8 +10906,8 @@ packages:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
- strip-literal@1.3.0:
- resolution: {integrity: sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==}
+ strip-literal@2.1.0:
+ resolution: {integrity: sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==}
strip-outer@2.0.0:
resolution: {integrity: sha512-A21Xsm1XzUkK0qK1ZrytDUvqsQWict2Cykhvi0fBQntGG5JSprESasEyV1EZ/4CiR5WB5KjzLTrP/bO37B0wPg==}
@@ -10422,6 +10920,10 @@ packages:
resolution: {integrity: sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==}
engines: {node: '>=14.16'}
+ strtok3@8.0.1:
+ resolution: {integrity: sha512-HNkTAnNWQj2YBzfTtoC5OQyu1QwPsMwiB7VyQmNvQKCrmEDSvFB857Vh97UY9InGLNRAB91sdS1ztifRo/3hdA==}
+ engines: {node: '>=16'}
+
stylehacks@6.1.1:
resolution: {integrity: sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg==}
engines: {node: ^14 || ^16 || >=18.0}
@@ -10460,19 +10962,12 @@ packages:
symbol-tree@3.2.4:
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
- systeminformation@5.22.7:
- resolution: {integrity: sha512-AWxlP05KeHbpGdgvZkcudJpsmChc2Y5Eo/GvxG/iUA/Aws5LZKHAMSeAo+V+nD+nxWZaxrwpWcnx4SH3oxNL3A==}
+ systeminformation@5.22.11:
+ resolution: {integrity: sha512-aLws5yi4KCHTb0BVvbodQY5bY8eW4asMRDTxTW46hqw9lGjACX6TlLdJrkdoHYRB0qs+MekqEq1zG7WDnWE8Ug==}
engines: {node: '>=8.0.0'}
os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos, android]
hasBin: true
- tar-fs@2.1.1:
- resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==}
-
- tar-stream@2.2.0:
- resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
- engines: {node: '>=6'}
-
tar-stream@3.1.6:
resolution: {integrity: sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==}
@@ -10491,20 +10986,20 @@ packages:
telejson@7.2.0:
resolution: {integrity: sha512-1QTEcJkJEhc8OnStBx/ILRu5J2p0GjvWsBx56bmZRqnrkdBMUe+nX92jxV+p3dB4CP6PZCdJMQJwCggkNBMzkQ==}
- temp-dir@2.0.0:
- resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==}
- engines: {node: '>=8'}
+ temp-dir@3.0.0:
+ resolution: {integrity: sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==}
+ engines: {node: '>=14.16'}
temp@0.8.4:
resolution: {integrity: sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==}
engines: {node: '>=6.0.0'}
- tempy@1.0.1:
- resolution: {integrity: sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==}
- engines: {node: '>=10'}
+ tempy@3.1.0:
+ resolution: {integrity: sha512-7jDLIdD2Zp0bDe5r3D2qtkd1QOCacylBuL7oa4udvN6v2pqr4+LcCr67C8DR1zkpaZ8XosF5m1yQSabKAW6f2g==}
+ engines: {node: '>=14.16'}
- terser@5.30.3:
- resolution: {integrity: sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA==}
+ terser@5.31.3:
+ resolution: {integrity: sha512-pAfYn3NIZLyZpa83ZKigvj6Rn9c/vd5KfYGX7cN1mnzqgDcxWvrU5ZtAfIKhEXz9nRecw4z3LXkjaq96/qZqAA==}
engines: {node: '>=10'}
hasBin: true
@@ -10525,31 +11020,25 @@ packages:
thenify@3.3.1:
resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
- thread-stream@2.3.0:
- resolution: {integrity: sha512-kaDqm1DET9pp3NXwR8382WHbnpXnRkN9xGN9dQt3B2+dmXiW8X1SOwmFOxAErEQ47ObhZ96J6yhZNXuyCOL7KA==}
+ thread-stream@3.1.0:
+ resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==}
- three@0.164.1:
- resolution: {integrity: sha512-iC/hUBbl1vzFny7f5GtqzVXYjMJKaTPxiCxXfrvVdBi1Sf+jhd1CAkitiFwC7mIBFCo3MrDLJG97yisoaWig0w==}
+ three@0.167.0:
+ resolution: {integrity: sha512-9Y1a66fpjqF3rhq7ivKTaKtjQLZ97Hj/lZ00DmZWaKHaQFH4uzYT1znwRDWQOcgMmCcOloQzo61gDmqO8l9xmA==}
- throttle-debounce@5.0.0:
- resolution: {integrity: sha512-2iQTSgkkc1Zyk0MeVrt/3BvuOXYPl/R8Z0U2xxo9rjwNciaHDG3R+Lm6dh4EeUci49DanvBnuqI6jshoQQRGEg==}
+ throttle-debounce@5.0.2:
+ resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==}
engines: {node: '>=12.22'}
throttleit@1.0.0:
resolution: {integrity: sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==}
- through2@2.0.5:
- resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==}
-
through@2.3.4:
resolution: {integrity: sha512-DwbmSAcABsMazNkLOJJSLRC3gfh4cPxUxJCn9npmvbcI6undhgoJ2ShvEOgZrW8BH62Gyr9jKboGbfFcmY5VsQ==}
through@2.3.8:
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
- tiny-invariant@1.3.1:
- resolution: {integrity: sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==}
-
tiny-invariant@1.3.3:
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
@@ -10563,8 +11052,8 @@ packages:
tinycolor2@1.6.0:
resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==}
- tinypool@0.7.0:
- resolution: {integrity: sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==}
+ tinypool@0.8.4:
+ resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==}
engines: {node: '>=14.0.0'}
tinyspy@2.2.0:
@@ -10589,17 +11078,10 @@ packages:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
- toad-cache@3.3.0:
- resolution: {integrity: sha512-3oDzcogWGHZdkwrHyvJVpPjA7oNzY6ENOV3PsWJY9XYPZ6INo94Yd47s5may1U+nleBPwDhrRiTPMIvKaa3MQg==}
- engines: {node: '>=12'}
-
toad-cache@3.7.0:
resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==}
engines: {node: '>=12'}
- tocbot@4.21.1:
- resolution: {integrity: sha512-IfajhBTeg0HlMXu1f+VMbPef05QpDTsZ9X2Yn1+8npdaXsXg/+wrm9Ze1WG5OS1UDC3qJ5EQN/XOZ3gfXjPFCw==}
-
toidentifier@1.0.1:
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
engines: {node: '>=0.6'}
@@ -10611,6 +11093,10 @@ packages:
resolution: {integrity: sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==}
engines: {node: '>=14.16'}
+ token-types@6.0.0:
+ resolution: {integrity: sha512-lbDrTLVsHhOMljPscd0yitpozq7Ga2M5Cvez5AjGg8GASBjtt6iERCAJ93yommPmz62fb45oFIXHEZ3u9bfJEA==}
+ engines: {node: '>=14.16'}
+
touch@3.1.0:
resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==}
hasBin: true
@@ -10619,8 +11105,8 @@ packages:
resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==}
engines: {node: '>=0.8'}
- tough-cookie@4.1.3:
- resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==}
+ tough-cookie@4.1.4:
+ resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==}
engines: {node: '>=6'}
tr46@0.0.3:
@@ -10667,8 +11153,8 @@ packages:
ts-map@1.0.3:
resolution: {integrity: sha512-vDWbsl26LIcPGmDpoVzjEP6+hvHZkBkLW7JpvwbCv/5IYPJlsbzCVXY3wsCeAxAUeTclNOUZxnLdGh3VBD/J6w==}
- tsc-alias@1.8.8:
- resolution: {integrity: sha512-OYUOd2wl0H858NvABWr/BoSKNERw3N9GTi3rHPK8Iv4O1UyUXIrTTOAZNHsjlVpXFOhpJBVARI1s+rzwLivN3Q==}
+ tsc-alias@1.8.10:
+ resolution: {integrity: sha512-Ibv4KAWfFkFdKJxnWfVtdOmB0Zi1RJVxcbPGiCDsFpCQSsmpWyuzHG3rQyI5YkobWwxFPEyQfu1hdo4qLG2zPw==}
hasBin: true
tsconfig-paths@3.15.0:
@@ -10678,8 +11164,8 @@ packages:
resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==}
engines: {node: '>=6'}
- tsd@0.30.7:
- resolution: {integrity: sha512-oTiJ28D6B/KXoU3ww/Eji+xqHJojiuPVMwA12g4KYX1O72N93Nb6P3P3h2OAhhf92Xl8NIhb/xFmBZd5zw/xUw==}
+ tsd@0.31.1:
+ resolution: {integrity: sha512-sSL84A0SFwx2xGMWrxlGaarKFSQszWjJS2vgNDDLwatytzg2aq6ShlwHsBYxRNmjzXISODwMva5ZOdAg/4AoOA==}
engines: {node: '>=14.16'}
hasBin: true
@@ -10689,6 +11175,9 @@ packages:
tslib@2.6.2:
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
+ tslib@2.6.3:
+ resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==}
+
tsx@4.4.0:
resolution: {integrity: sha512-4fwcEjRUxW20ciSaMB8zkpGwCPxuRGnadDuj/pBk5S9uT29zvWz15PK36GrKJo45mSJomDxVejZ73c6lr3811Q==}
engines: {node: '>=18.0.0'}
@@ -10708,10 +11197,6 @@ packages:
resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
engines: {node: '>=4'}
- type-fest@0.16.0:
- resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==}
- engines: {node: '>=10'}
-
type-fest@0.18.1:
resolution: {integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==}
engines: {node: '>=10'}
@@ -10732,12 +11217,16 @@ packages:
resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==}
engines: {node: '>=8'}
+ type-fest@1.4.0:
+ resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==}
+ engines: {node: '>=10'}
+
type-fest@2.19.0:
resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==}
engines: {node: '>=12.20'}
- type-fest@4.9.0:
- resolution: {integrity: sha512-KS/6lh/ynPGiHD/LnAobrEFq3Ad4pBzOlJ1wAnJx9N4EYoqFhMfLIBjUT2UEx4wg5ZE+cC1ob6DCSpppVo+rtg==}
+ type-fest@4.20.1:
+ resolution: {integrity: sha512-R6wDsVsoS9xYOpy8vgeBlqpdOyzJ12HNfQhC/aAKWM3YoCV9TtunJzh/QpkMgeDhkoynDcw5f1y+qF9yc/HHyg==}
engines: {node: '>=16'}
type-is@1.6.18:
@@ -10830,8 +11319,8 @@ packages:
engines: {node: '>=14.17'}
hasBin: true
- typescript@5.4.5:
- resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==}
+ typescript@5.5.4:
+ resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==}
engines: {node: '>=14.17'}
hasBin: true
@@ -10850,6 +11339,10 @@ packages:
resolution: {integrity: sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==}
engines: {node: '>=8'}
+ uint8array-extras@1.4.0:
+ resolution: {integrity: sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ==}
+ engines: {node: '>=18'}
+
ulid@2.3.0:
resolution: {integrity: sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw==}
hasBin: true
@@ -10883,6 +11376,10 @@ packages:
resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==}
engines: {node: '>=4'}
+ unicorn-magic@0.1.0:
+ resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==}
+ engines: {node: '>=18'}
+
unified@11.0.4:
resolution: {integrity: sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==}
@@ -10897,9 +11394,9 @@ packages:
resolution: {integrity: sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
- unique-string@2.0.0:
- resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==}
- engines: {node: '>=8'}
+ unique-string@3.0.0:
+ resolution: {integrity: sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==}
+ engines: {node: '>=12'}
unist-util-is@6.0.0:
resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==}
@@ -10955,6 +11452,10 @@ packages:
resolution: {integrity: sha512-uIuGf9TWQ/y+0Lp+KGZCMuJWc3N9BHA+l/UmHd/oUHwJJDeysyTRxNQVkbzsIWfGFbRe3OcgML/i0mvVRPOyDA==}
engines: {node: '>=6.14.2'}
+ utf-8-validate@6.0.4:
+ resolution: {integrity: sha512-xu9GQDeFp+eZ6LnCywXN/zBancWvOpUMzgjLPSjy4BRHSmTelvn2E0DG0o1sTiw5hkCKBHo8rwSKncfRfv2EEQ==}
+ engines: {node: '>=6.14.2'}
+
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
@@ -10965,6 +11466,10 @@ packages:
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
engines: {node: '>= 0.4.0'}
+ uuid@10.0.0:
+ resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==}
+ hasBin: true
+
uuid@3.4.0:
resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==}
deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.
@@ -10978,8 +11483,8 @@ packages:
resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
hasBin: true
- v-code-diff@1.11.0:
- resolution: {integrity: sha512-lBlO+FXw3I3qFKbnlorXZ4sb5cFnrdxlc6lj3Y1CWrbn2LC7PoVbGlwH0W+nvAVX1rdJhhc15rKIQdHyMkXe/w==}
+ v-code-diff@1.12.0:
+ resolution: {integrity: sha512-vvdCBG02mIIiW6Gx6jF119hzxELt+6TlJIwchglR1JYzboHePNxIkVBjR/aoAOVlsGa+5Vtb77cd/N84nrXWPA==}
peerDependencies:
'@vue/composition-api': ^1.4.9
vue: ^2.6.0 || >=3.0.0
@@ -10994,10 +11499,6 @@ packages:
validate-npm-package-license@3.0.4:
resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
- validator@13.9.0:
- resolution: {integrity: sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA==}
- engines: {node: '>= 0.10'}
-
vary@1.1.2:
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
engines: {node: '>= 0.8'}
@@ -11012,16 +11513,16 @@ packages:
vfile@6.0.1:
resolution: {integrity: sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==}
- vite-node@0.34.6:
- resolution: {integrity: sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==}
- engines: {node: '>=v14.18.0'}
+ vite-node@1.6.0:
+ resolution: {integrity: sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==}
+ engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
vite-plugin-turbosnap@1.0.3:
resolution: {integrity: sha512-p4D8CFVhZS412SyQX125qxyzOgIFouwOcvjZWk6bQbNPR1wtaEzFT6jZxAjf1dejlGqa6fqHcuCvQea6EWUkUA==}
- vite@5.2.11:
- resolution: {integrity: sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==}
+ vite@5.3.5:
+ resolution: {integrity: sha512-MdjglKR6AQXQb9JGiS7Rc2wC6uMjcm7Go/NHNO63EwiJXfuk9PgqiP/n5IDJCziMkfw9n4Ubp7lttNwz+8ZVKA==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
@@ -11054,22 +11555,22 @@ packages:
peerDependencies:
vitest: '>=0.16.0'
- vitest@0.34.6:
- resolution: {integrity: sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==}
- engines: {node: '>=v14.18.0'}
+ vitest@1.6.0:
+ resolution: {integrity: sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==}
+ engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
'@edge-runtime/vm': '*'
- '@vitest/browser': '*'
- '@vitest/ui': '*'
+ '@types/node': ^18.0.0 || >=20.0.0
+ '@vitest/browser': 1.6.0
+ '@vitest/ui': 1.6.0
happy-dom: '*'
jsdom: '*'
- playwright: '*'
- safaridriver: '*'
- webdriverio: '*'
peerDependenciesMeta:
'@edge-runtime/vm':
optional: true
+ '@types/node':
+ optional: true
'@vitest/browser':
optional: true
'@vitest/ui':
@@ -11078,12 +11579,6 @@ packages:
optional: true
jsdom:
optional: true
- playwright:
- optional: true
- safaridriver:
- optional: true
- webdriverio:
- optional: true
void-elements@3.1.0:
resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==}
@@ -11110,6 +11605,9 @@ packages:
resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==}
hasBin: true
+ vscode-uri@3.0.8:
+ resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==}
+
vue-component-meta@2.0.16:
resolution: {integrity: sha512-IyIMClUMYcKxAL34GqdPbR4V45MUeHXqQiZlHxeYMV5Qcqp4M+CEmtGpF//XBSS138heDkYkceHAtJQjLUB1Lw==}
peerDependencies:
@@ -11124,8 +11622,8 @@ packages:
vue-component-type-helpers@2.0.16:
resolution: {integrity: sha512-qisL/iAfdO++7w+SsfYQJVPj6QKvxp4i1MMxvsNO41z/8zu3KuAw9LkhKUfP/kcOWGDxESp+pQObWppXusejCA==}
- vue-component-type-helpers@2.0.19:
- resolution: {integrity: sha512-cN3f1aTxxKo4lzNeQAkVopswuImUrb5Iurll9Gaw5cqpnbTAxtEMM1mgi6ou4X79OCyqYv1U1mzBHJkzmiK82w==}
+ vue-component-type-helpers@2.0.29:
+ resolution: {integrity: sha512-58i+ZhUAUpwQ+9h5Hck0D+jr1qbYl4voRt5KffBx8qzELViQ4XdT/Tuo+mzq8u63teAG8K0lLaOiL5ofqW38rg==}
vue-demi@0.14.7:
resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==}
@@ -11143,8 +11641,8 @@ packages:
peerDependencies:
vue: '>=2'
- vue-eslint-parser@9.4.2:
- resolution: {integrity: sha512-Ry9oiGmCAK91HrKMtCrKFWmSFWvYkpGglCeFAIqDdr9zdXmMMpJOmUJS7WWsW7fX81h6mwHmUZCQQ1E0PkSwYQ==}
+ vue-eslint-parser@9.4.3:
+ resolution: {integrity: sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==}
engines: {node: ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: '>=6.0.0'
@@ -11163,14 +11661,14 @@ packages:
vue-template-compiler@2.7.14:
resolution: {integrity: sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==}
- vue-tsc@2.0.16:
- resolution: {integrity: sha512-/gHAWJa216PeEhfxtAToIbxdWgw01wuQzo48ZUqMYVEyNqDp+OYV9xMO5HaPS2P3Ls0+EsjguMZLY4cGobX4Ew==}
+ vue-tsc@2.0.29:
+ resolution: {integrity: sha512-MHhsfyxO3mYShZCGYNziSbc63x7cQ5g9kvijV7dRe1TTXBRLxXyL0FnXWpUF1xII2mJ86mwYpYsUmMwkmerq7Q==}
hasBin: true
peerDependencies:
- typescript: '*'
+ typescript: '>=5.0.0'
- vue@3.4.26:
- resolution: {integrity: sha512-bUIq/p+VB+0xrJubaemrfhk1/FiW9iX+pDV+62I/XJ6EkspAO9/DXEjbDFoe8pIfOZBqfk45i9BMc41ptP/uRg==}
+ vue@3.4.34:
+ resolution: {integrity: sha512-VZze05HWlA3ItreQ/ka7Sx7PoD0/3St8FEiSlSTVgb6l4hL+RjtP2/8g5WQBzZgyf8WG2f+g1bXzC7zggLhAJA==}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
@@ -11191,6 +11689,9 @@ packages:
engines: {node: '>=12.0.0'}
hasBin: true
+ walk-up-path@3.0.1:
+ resolution: {integrity: sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==}
+
walker@1.0.8:
resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
@@ -11210,6 +11711,10 @@ packages:
resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==}
engines: {node: '>= 8'}
+ web-streams-polyfill@4.0.0:
+ resolution: {integrity: sha512-0zJXHRAYEjM2tUfZ2DiSOHAa2aw1tisnnhU3ufD57R8iefL+DcdJyRBRyJpG+NUimDgbTI/lH+gAE1PAvV3Cgw==}
+ engines: {node: '>= 8'}
+
webidl-conversions@3.0.1:
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
@@ -11286,6 +11791,10 @@ packages:
resolution: {integrity: sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==}
engines: {node: '>= 10.0.0'}
+ word-wrap@1.2.5:
+ resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
+ engines: {node: '>=0.10.0'}
+
wordwrap@1.0.0:
resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==}
@@ -11311,8 +11820,8 @@ packages:
resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
- ws@8.17.0:
- resolution: {integrity: sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==}
+ ws@8.18.0:
+ resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
@@ -11404,10 +11913,9 @@ packages:
resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==}
engines: {node: '>=12.20'}
- z-schema@5.0.5:
- resolution: {integrity: sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==}
- engines: {node: '>=8.0.0'}
- hasBin: true
+ yoctocolors@2.0.2:
+ resolution: {integrity: sha512-Ct97huExsu7cWeEjmrXlofevF8CvzUglJ4iGUet5B8xn1oumtAZBpHU4GzYuoE6PVqcZ5hghtBrSlhwHuR1Jmw==}
+ engines: {node: '>=18'}
zip-stream@6.0.1:
resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==}
@@ -11418,8 +11926,6 @@ packages:
snapshots:
- '@aashutoshrathi/word-wrap@1.2.6': {}
-
'@adobe/css-tools@4.3.3': {}
'@aiscript-dev/aiscript-languageserver@https://github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.6/aiscript-dev-aiscript-languageserver-0.1.6.tgz':
@@ -11443,467 +11949,527 @@ snapshots:
dependencies:
default-browser-id: 3.0.0
- '@aws-crypto/crc32@3.0.0':
+ '@aws-crypto/crc32@5.2.0':
dependencies:
- '@aws-crypto/util': 3.0.0
- '@aws-sdk/types': 3.413.0
- tslib: 1.14.1
+ '@aws-crypto/util': 5.2.0
+ '@aws-sdk/types': 3.609.0
+ tslib: 2.6.3
- '@aws-crypto/crc32c@3.0.0':
+ '@aws-crypto/crc32c@5.2.0':
dependencies:
- '@aws-crypto/util': 3.0.0
- '@aws-sdk/types': 3.413.0
- tslib: 1.14.1
+ '@aws-crypto/util': 5.2.0
+ '@aws-sdk/types': 3.609.0
+ tslib: 2.6.3
- '@aws-crypto/ie11-detection@3.0.0':
+ '@aws-crypto/sha1-browser@5.2.0':
dependencies:
- tslib: 1.14.1
+ '@aws-crypto/supports-web-crypto': 5.2.0
+ '@aws-crypto/util': 5.2.0
+ '@aws-sdk/types': 3.609.0
+ '@aws-sdk/util-locate-window': 3.208.0
+ '@smithy/util-utf8': 2.0.0
+ tslib: 2.6.3
- '@aws-crypto/sha1-browser@3.0.0':
+ '@aws-crypto/sha256-browser@5.2.0':
dependencies:
- '@aws-crypto/ie11-detection': 3.0.0
- '@aws-crypto/supports-web-crypto': 3.0.0
- '@aws-crypto/util': 3.0.0
- '@aws-sdk/types': 3.413.0
+ '@aws-crypto/sha256-js': 5.2.0
+ '@aws-crypto/supports-web-crypto': 5.2.0
+ '@aws-crypto/util': 5.2.0
+ '@aws-sdk/types': 3.609.0
'@aws-sdk/util-locate-window': 3.208.0
- '@aws-sdk/util-utf8-browser': 3.259.0
- tslib: 1.14.1
+ '@smithy/util-utf8': 2.0.0
+ tslib: 2.6.3
- '@aws-crypto/sha256-browser@3.0.0':
+ '@aws-crypto/sha256-js@5.2.0':
dependencies:
- '@aws-crypto/ie11-detection': 3.0.0
- '@aws-crypto/sha256-js': 3.0.0
- '@aws-crypto/supports-web-crypto': 3.0.0
- '@aws-crypto/util': 3.0.0
- '@aws-sdk/types': 3.413.0
- '@aws-sdk/util-locate-window': 3.208.0
- '@aws-sdk/util-utf8-browser': 3.259.0
- tslib: 1.14.1
+ '@aws-crypto/util': 5.2.0
+ '@aws-sdk/types': 3.609.0
+ tslib: 2.6.3
- '@aws-crypto/sha256-js@3.0.0':
+ '@aws-crypto/supports-web-crypto@5.2.0':
dependencies:
- '@aws-crypto/util': 3.0.0
- '@aws-sdk/types': 3.413.0
- tslib: 1.14.1
+ tslib: 2.6.3
- '@aws-crypto/supports-web-crypto@3.0.0':
+ '@aws-crypto/util@5.2.0':
dependencies:
- tslib: 1.14.1
+ '@aws-sdk/types': 3.609.0
+ '@smithy/util-utf8': 2.0.0
+ tslib: 2.6.3
- '@aws-crypto/util@3.0.0':
+ '@aws-sdk/client-s3@3.620.0':
dependencies:
- '@aws-sdk/types': 3.413.0
- '@aws-sdk/util-utf8-browser': 3.259.0
- tslib: 1.14.1
+ '@aws-crypto/sha1-browser': 5.2.0
+ '@aws-crypto/sha256-browser': 5.2.0
+ '@aws-crypto/sha256-js': 5.2.0
+ '@aws-sdk/client-sso-oidc': 3.620.0(@aws-sdk/client-sts@3.620.0)
+ '@aws-sdk/client-sts': 3.620.0
+ '@aws-sdk/core': 3.620.0
+ '@aws-sdk/credential-provider-node': 3.620.0(@aws-sdk/client-sso-oidc@3.620.0(@aws-sdk/client-sts@3.620.0))(@aws-sdk/client-sts@3.620.0)
+ '@aws-sdk/middleware-bucket-endpoint': 3.620.0
+ '@aws-sdk/middleware-expect-continue': 3.620.0
+ '@aws-sdk/middleware-flexible-checksums': 3.620.0
+ '@aws-sdk/middleware-host-header': 3.620.0
+ '@aws-sdk/middleware-location-constraint': 3.609.0
+ '@aws-sdk/middleware-logger': 3.609.0
+ '@aws-sdk/middleware-recursion-detection': 3.620.0
+ '@aws-sdk/middleware-sdk-s3': 3.620.0
+ '@aws-sdk/middleware-signing': 3.620.0
+ '@aws-sdk/middleware-ssec': 3.609.0
+ '@aws-sdk/middleware-user-agent': 3.620.0
+ '@aws-sdk/region-config-resolver': 3.614.0
+ '@aws-sdk/signature-v4-multi-region': 3.620.0
+ '@aws-sdk/types': 3.609.0
+ '@aws-sdk/util-endpoints': 3.614.0
+ '@aws-sdk/util-user-agent-browser': 3.609.0
+ '@aws-sdk/util-user-agent-node': 3.614.0
+ '@aws-sdk/xml-builder': 3.609.0
+ '@smithy/config-resolver': 3.0.5
+ '@smithy/core': 2.3.1
+ '@smithy/eventstream-serde-browser': 3.0.5
+ '@smithy/eventstream-serde-config-resolver': 3.0.3
+ '@smithy/eventstream-serde-node': 3.0.4
+ '@smithy/fetch-http-handler': 3.2.4
+ '@smithy/hash-blob-browser': 3.1.2
+ '@smithy/hash-node': 3.0.3
+ '@smithy/hash-stream-node': 3.1.2
+ '@smithy/invalid-dependency': 3.0.3
+ '@smithy/md5-js': 3.0.3
+ '@smithy/middleware-content-length': 3.0.5
+ '@smithy/middleware-endpoint': 3.1.0
+ '@smithy/middleware-retry': 3.0.13
+ '@smithy/middleware-serde': 3.0.3
+ '@smithy/middleware-stack': 3.0.3
+ '@smithy/node-config-provider': 3.1.4
+ '@smithy/node-http-handler': 3.1.4
+ '@smithy/protocol-http': 4.1.0
+ '@smithy/smithy-client': 3.1.11
+ '@smithy/types': 3.3.0
+ '@smithy/url-parser': 3.0.3
+ '@smithy/util-base64': 3.0.0
+ '@smithy/util-body-length-browser': 3.0.0
+ '@smithy/util-body-length-node': 3.0.0
+ '@smithy/util-defaults-mode-browser': 3.0.13
+ '@smithy/util-defaults-mode-node': 3.0.13
+ '@smithy/util-endpoints': 2.0.5
+ '@smithy/util-retry': 3.0.3
+ '@smithy/util-stream': 3.1.3
+ '@smithy/util-utf8': 3.0.0
+ '@smithy/util-waiter': 3.1.2
+ tslib: 2.6.3
+ transitivePeerDependencies:
+ - aws-crt
- '@aws-sdk/client-s3@3.412.0':
+ '@aws-sdk/client-sso-oidc@3.620.0(@aws-sdk/client-sts@3.620.0)':
dependencies:
- '@aws-crypto/sha1-browser': 3.0.0
- '@aws-crypto/sha256-browser': 3.0.0
- '@aws-crypto/sha256-js': 3.0.0
- '@aws-sdk/client-sts': 3.410.0
- '@aws-sdk/credential-provider-node': 3.410.0
- '@aws-sdk/middleware-bucket-endpoint': 3.410.0
- '@aws-sdk/middleware-expect-continue': 3.410.0
- '@aws-sdk/middleware-flexible-checksums': 3.410.0
- '@aws-sdk/middleware-host-header': 3.410.0
- '@aws-sdk/middleware-location-constraint': 3.410.0
- '@aws-sdk/middleware-logger': 3.410.0
- '@aws-sdk/middleware-recursion-detection': 3.410.0
- '@aws-sdk/middleware-sdk-s3': 3.410.0
- '@aws-sdk/middleware-signing': 3.410.0
- '@aws-sdk/middleware-ssec': 3.410.0
- '@aws-sdk/middleware-user-agent': 3.410.0
- '@aws-sdk/signature-v4-multi-region': 3.412.0
- '@aws-sdk/types': 3.410.0
- '@aws-sdk/util-endpoints': 3.410.0
- '@aws-sdk/util-user-agent-browser': 3.410.0
- '@aws-sdk/util-user-agent-node': 3.410.0
- '@aws-sdk/xml-builder': 3.310.0
- '@smithy/config-resolver': 2.0.9
- '@smithy/eventstream-serde-browser': 2.0.8
- '@smithy/eventstream-serde-config-resolver': 2.0.8
- '@smithy/eventstream-serde-node': 2.0.8
- '@smithy/fetch-http-handler': 2.1.4
- '@smithy/hash-blob-browser': 2.0.8
- '@smithy/hash-node': 2.0.8
- '@smithy/hash-stream-node': 2.0.8
- '@smithy/invalid-dependency': 2.0.8
- '@smithy/md5-js': 2.0.8
- '@smithy/middleware-content-length': 2.0.10
- '@smithy/middleware-endpoint': 2.0.8
- '@smithy/middleware-retry': 2.0.11
- '@smithy/middleware-serde': 2.0.8
- '@smithy/middleware-stack': 2.0.1
- '@smithy/node-config-provider': 2.0.11
- '@smithy/node-http-handler': 2.5.0
- '@smithy/protocol-http': 3.0.10
- '@smithy/smithy-client': 2.1.5
- '@smithy/types': 2.6.0
- '@smithy/url-parser': 2.0.8
- '@smithy/util-base64': 2.0.0
- '@smithy/util-body-length-browser': 2.0.0
- '@smithy/util-body-length-node': 2.1.0
- '@smithy/util-defaults-mode-browser': 2.0.9
- '@smithy/util-defaults-mode-node': 2.0.11
- '@smithy/util-retry': 2.0.1
- '@smithy/util-stream': 2.0.11
- '@smithy/util-utf8': 2.0.0
- '@smithy/util-waiter': 2.0.8
- fast-xml-parser: 4.2.5
- tslib: 2.6.2
+ '@aws-crypto/sha256-browser': 5.2.0
+ '@aws-crypto/sha256-js': 5.2.0
+ '@aws-sdk/client-sts': 3.620.0
+ '@aws-sdk/core': 3.620.0
+ '@aws-sdk/credential-provider-node': 3.620.0(@aws-sdk/client-sso-oidc@3.620.0(@aws-sdk/client-sts@3.620.0))(@aws-sdk/client-sts@3.620.0)
+ '@aws-sdk/middleware-host-header': 3.620.0
+ '@aws-sdk/middleware-logger': 3.609.0
+ '@aws-sdk/middleware-recursion-detection': 3.620.0
+ '@aws-sdk/middleware-user-agent': 3.620.0
+ '@aws-sdk/region-config-resolver': 3.614.0
+ '@aws-sdk/types': 3.609.0
+ '@aws-sdk/util-endpoints': 3.614.0
+ '@aws-sdk/util-user-agent-browser': 3.609.0
+ '@aws-sdk/util-user-agent-node': 3.614.0
+ '@smithy/config-resolver': 3.0.5
+ '@smithy/core': 2.3.1
+ '@smithy/fetch-http-handler': 3.2.4
+ '@smithy/hash-node': 3.0.3
+ '@smithy/invalid-dependency': 3.0.3
+ '@smithy/middleware-content-length': 3.0.5
+ '@smithy/middleware-endpoint': 3.1.0
+ '@smithy/middleware-retry': 3.0.13
+ '@smithy/middleware-serde': 3.0.3
+ '@smithy/middleware-stack': 3.0.3
+ '@smithy/node-config-provider': 3.1.4
+ '@smithy/node-http-handler': 3.1.4
+ '@smithy/protocol-http': 4.1.0
+ '@smithy/smithy-client': 3.1.11
+ '@smithy/types': 3.3.0
+ '@smithy/url-parser': 3.0.3
+ '@smithy/util-base64': 3.0.0
+ '@smithy/util-body-length-browser': 3.0.0
+ '@smithy/util-body-length-node': 3.0.0
+ '@smithy/util-defaults-mode-browser': 3.0.13
+ '@smithy/util-defaults-mode-node': 3.0.13
+ '@smithy/util-endpoints': 2.0.5
+ '@smithy/util-middleware': 3.0.3
+ '@smithy/util-retry': 3.0.3
+ '@smithy/util-utf8': 3.0.0
+ tslib: 2.6.3
transitivePeerDependencies:
- aws-crt
- '@aws-sdk/client-sso@3.410.0':
+ '@aws-sdk/client-sso@3.620.0':
dependencies:
- '@aws-crypto/sha256-browser': 3.0.0
- '@aws-crypto/sha256-js': 3.0.0
- '@aws-sdk/middleware-host-header': 3.410.0
- '@aws-sdk/middleware-logger': 3.410.0
- '@aws-sdk/middleware-recursion-detection': 3.410.0
- '@aws-sdk/middleware-user-agent': 3.410.0
- '@aws-sdk/types': 3.410.0
- '@aws-sdk/util-endpoints': 3.410.0
- '@aws-sdk/util-user-agent-browser': 3.410.0
- '@aws-sdk/util-user-agent-node': 3.410.0
- '@smithy/config-resolver': 2.0.9
- '@smithy/fetch-http-handler': 2.1.4
- '@smithy/hash-node': 2.0.8
- '@smithy/invalid-dependency': 2.0.8
- '@smithy/middleware-content-length': 2.0.10
- '@smithy/middleware-endpoint': 2.0.8
- '@smithy/middleware-retry': 2.0.11
- '@smithy/middleware-serde': 2.0.8
- '@smithy/middleware-stack': 2.0.1
- '@smithy/node-config-provider': 2.0.11
- '@smithy/node-http-handler': 2.5.0
- '@smithy/protocol-http': 3.0.10
- '@smithy/smithy-client': 2.1.5
- '@smithy/types': 2.6.0
- '@smithy/url-parser': 2.0.8
- '@smithy/util-base64': 2.0.0
- '@smithy/util-body-length-browser': 2.0.0
- '@smithy/util-body-length-node': 2.1.0
- '@smithy/util-defaults-mode-browser': 2.0.9
- '@smithy/util-defaults-mode-node': 2.0.11
- '@smithy/util-retry': 2.0.1
- '@smithy/util-utf8': 2.0.0
- tslib: 2.6.2
+ '@aws-crypto/sha256-browser': 5.2.0
+ '@aws-crypto/sha256-js': 5.2.0
+ '@aws-sdk/core': 3.620.0
+ '@aws-sdk/middleware-host-header': 3.620.0
+ '@aws-sdk/middleware-logger': 3.609.0
+ '@aws-sdk/middleware-recursion-detection': 3.620.0
+ '@aws-sdk/middleware-user-agent': 3.620.0
+ '@aws-sdk/region-config-resolver': 3.614.0
+ '@aws-sdk/types': 3.609.0
+ '@aws-sdk/util-endpoints': 3.614.0
+ '@aws-sdk/util-user-agent-browser': 3.609.0
+ '@aws-sdk/util-user-agent-node': 3.614.0
+ '@smithy/config-resolver': 3.0.5
+ '@smithy/core': 2.3.1
+ '@smithy/fetch-http-handler': 3.2.4
+ '@smithy/hash-node': 3.0.3
+ '@smithy/invalid-dependency': 3.0.3
+ '@smithy/middleware-content-length': 3.0.5
+ '@smithy/middleware-endpoint': 3.1.0
+ '@smithy/middleware-retry': 3.0.13
+ '@smithy/middleware-serde': 3.0.3
+ '@smithy/middleware-stack': 3.0.3
+ '@smithy/node-config-provider': 3.1.4
+ '@smithy/node-http-handler': 3.1.4
+ '@smithy/protocol-http': 4.1.0
+ '@smithy/smithy-client': 3.1.11
+ '@smithy/types': 3.3.0
+ '@smithy/url-parser': 3.0.3
+ '@smithy/util-base64': 3.0.0
+ '@smithy/util-body-length-browser': 3.0.0
+ '@smithy/util-body-length-node': 3.0.0
+ '@smithy/util-defaults-mode-browser': 3.0.13
+ '@smithy/util-defaults-mode-node': 3.0.13
+ '@smithy/util-endpoints': 2.0.5
+ '@smithy/util-middleware': 3.0.3
+ '@smithy/util-retry': 3.0.3
+ '@smithy/util-utf8': 3.0.0
+ tslib: 2.6.3
transitivePeerDependencies:
- aws-crt
- '@aws-sdk/client-sts@3.410.0':
+ '@aws-sdk/client-sts@3.620.0':
dependencies:
- '@aws-crypto/sha256-browser': 3.0.0
- '@aws-crypto/sha256-js': 3.0.0
- '@aws-sdk/credential-provider-node': 3.410.0
- '@aws-sdk/middleware-host-header': 3.410.0
- '@aws-sdk/middleware-logger': 3.410.0
- '@aws-sdk/middleware-recursion-detection': 3.410.0
- '@aws-sdk/middleware-sdk-sts': 3.410.0
- '@aws-sdk/middleware-signing': 3.410.0
- '@aws-sdk/middleware-user-agent': 3.410.0
- '@aws-sdk/types': 3.410.0
- '@aws-sdk/util-endpoints': 3.410.0
- '@aws-sdk/util-user-agent-browser': 3.410.0
- '@aws-sdk/util-user-agent-node': 3.410.0
- '@smithy/config-resolver': 2.0.9
- '@smithy/fetch-http-handler': 2.1.4
- '@smithy/hash-node': 2.0.8
- '@smithy/invalid-dependency': 2.0.8
- '@smithy/middleware-content-length': 2.0.10
- '@smithy/middleware-endpoint': 2.0.8
- '@smithy/middleware-retry': 2.0.11
- '@smithy/middleware-serde': 2.0.8
- '@smithy/middleware-stack': 2.0.1
- '@smithy/node-config-provider': 2.0.11
- '@smithy/node-http-handler': 2.5.0
- '@smithy/protocol-http': 3.0.10
- '@smithy/smithy-client': 2.1.5
- '@smithy/types': 2.6.0
- '@smithy/url-parser': 2.0.8
- '@smithy/util-base64': 2.0.0
- '@smithy/util-body-length-browser': 2.0.0
- '@smithy/util-body-length-node': 2.1.0
- '@smithy/util-defaults-mode-browser': 2.0.9
- '@smithy/util-defaults-mode-node': 2.0.11
- '@smithy/util-retry': 2.0.1
- '@smithy/util-utf8': 2.0.0
- fast-xml-parser: 4.2.5
- tslib: 2.6.2
+ '@aws-crypto/sha256-browser': 5.2.0
+ '@aws-crypto/sha256-js': 5.2.0
+ '@aws-sdk/client-sso-oidc': 3.620.0(@aws-sdk/client-sts@3.620.0)
+ '@aws-sdk/core': 3.620.0
+ '@aws-sdk/credential-provider-node': 3.620.0(@aws-sdk/client-sso-oidc@3.620.0(@aws-sdk/client-sts@3.620.0))(@aws-sdk/client-sts@3.620.0)
+ '@aws-sdk/middleware-host-header': 3.620.0
+ '@aws-sdk/middleware-logger': 3.609.0
+ '@aws-sdk/middleware-recursion-detection': 3.620.0
+ '@aws-sdk/middleware-user-agent': 3.620.0
+ '@aws-sdk/region-config-resolver': 3.614.0
+ '@aws-sdk/types': 3.609.0
+ '@aws-sdk/util-endpoints': 3.614.0
+ '@aws-sdk/util-user-agent-browser': 3.609.0
+ '@aws-sdk/util-user-agent-node': 3.614.0
+ '@smithy/config-resolver': 3.0.5
+ '@smithy/core': 2.3.1
+ '@smithy/fetch-http-handler': 3.2.4
+ '@smithy/hash-node': 3.0.3
+ '@smithy/invalid-dependency': 3.0.3
+ '@smithy/middleware-content-length': 3.0.5
+ '@smithy/middleware-endpoint': 3.1.0
+ '@smithy/middleware-retry': 3.0.13
+ '@smithy/middleware-serde': 3.0.3
+ '@smithy/middleware-stack': 3.0.3
+ '@smithy/node-config-provider': 3.1.4
+ '@smithy/node-http-handler': 3.1.4
+ '@smithy/protocol-http': 4.1.0
+ '@smithy/smithy-client': 3.1.11
+ '@smithy/types': 3.3.0
+ '@smithy/url-parser': 3.0.3
+ '@smithy/util-base64': 3.0.0
+ '@smithy/util-body-length-browser': 3.0.0
+ '@smithy/util-body-length-node': 3.0.0
+ '@smithy/util-defaults-mode-browser': 3.0.13
+ '@smithy/util-defaults-mode-node': 3.0.13
+ '@smithy/util-endpoints': 2.0.5
+ '@smithy/util-middleware': 3.0.3
+ '@smithy/util-retry': 3.0.3
+ '@smithy/util-utf8': 3.0.0
+ tslib: 2.6.3
transitivePeerDependencies:
- aws-crt
- '@aws-sdk/credential-provider-env@3.410.0':
+ '@aws-sdk/core@3.620.0':
dependencies:
- '@aws-sdk/types': 3.410.0
- '@smithy/property-provider': 2.0.9
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@smithy/core': 2.3.1
+ '@smithy/protocol-http': 4.1.0
+ '@smithy/signature-v4': 4.1.0
+ '@smithy/smithy-client': 3.1.11
+ '@smithy/types': 3.3.0
+ fast-xml-parser: 4.2.5
+ tslib: 2.6.3
- '@aws-sdk/credential-provider-ini@3.410.0':
+ '@aws-sdk/credential-provider-env@3.609.0':
dependencies:
- '@aws-sdk/credential-provider-env': 3.410.0
- '@aws-sdk/credential-provider-process': 3.410.0
- '@aws-sdk/credential-provider-sso': 3.410.0
- '@aws-sdk/credential-provider-web-identity': 3.410.0
- '@aws-sdk/types': 3.410.0
- '@smithy/credential-provider-imds': 2.0.11
- '@smithy/property-provider': 2.0.9
- '@smithy/shared-ini-file-loader': 2.0.10
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@aws-sdk/types': 3.609.0
+ '@smithy/property-provider': 3.1.3
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
+
+ '@aws-sdk/credential-provider-http@3.620.0':
+ dependencies:
+ '@aws-sdk/types': 3.609.0
+ '@smithy/fetch-http-handler': 3.2.4
+ '@smithy/node-http-handler': 3.1.4
+ '@smithy/property-provider': 3.1.3
+ '@smithy/protocol-http': 4.1.0
+ '@smithy/smithy-client': 3.1.11
+ '@smithy/types': 3.3.0
+ '@smithy/util-stream': 3.1.3
+ tslib: 2.6.3
+
+ '@aws-sdk/credential-provider-ini@3.620.0(@aws-sdk/client-sso-oidc@3.620.0(@aws-sdk/client-sts@3.620.0))(@aws-sdk/client-sts@3.620.0)':
+ dependencies:
+ '@aws-sdk/client-sts': 3.620.0
+ '@aws-sdk/credential-provider-env': 3.609.0
+ '@aws-sdk/credential-provider-http': 3.620.0
+ '@aws-sdk/credential-provider-process': 3.614.0
+ '@aws-sdk/credential-provider-sso': 3.620.0(@aws-sdk/client-sso-oidc@3.620.0(@aws-sdk/client-sts@3.620.0))
+ '@aws-sdk/credential-provider-web-identity': 3.609.0(@aws-sdk/client-sts@3.620.0)
+ '@aws-sdk/types': 3.609.0
+ '@smithy/credential-provider-imds': 3.2.0
+ '@smithy/property-provider': 3.1.3
+ '@smithy/shared-ini-file-loader': 3.1.4
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
transitivePeerDependencies:
+ - '@aws-sdk/client-sso-oidc'
- aws-crt
- '@aws-sdk/credential-provider-node@3.410.0':
+ '@aws-sdk/credential-provider-node@3.620.0(@aws-sdk/client-sso-oidc@3.620.0(@aws-sdk/client-sts@3.620.0))(@aws-sdk/client-sts@3.620.0)':
dependencies:
- '@aws-sdk/credential-provider-env': 3.410.0
- '@aws-sdk/credential-provider-ini': 3.410.0
- '@aws-sdk/credential-provider-process': 3.410.0
- '@aws-sdk/credential-provider-sso': 3.410.0
- '@aws-sdk/credential-provider-web-identity': 3.410.0
- '@aws-sdk/types': 3.410.0
- '@smithy/credential-provider-imds': 2.0.11
- '@smithy/property-provider': 2.0.9
- '@smithy/shared-ini-file-loader': 2.0.10
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@aws-sdk/credential-provider-env': 3.609.0
+ '@aws-sdk/credential-provider-http': 3.620.0
+ '@aws-sdk/credential-provider-ini': 3.620.0(@aws-sdk/client-sso-oidc@3.620.0(@aws-sdk/client-sts@3.620.0))(@aws-sdk/client-sts@3.620.0)
+ '@aws-sdk/credential-provider-process': 3.614.0
+ '@aws-sdk/credential-provider-sso': 3.620.0(@aws-sdk/client-sso-oidc@3.620.0(@aws-sdk/client-sts@3.620.0))
+ '@aws-sdk/credential-provider-web-identity': 3.609.0(@aws-sdk/client-sts@3.620.0)
+ '@aws-sdk/types': 3.609.0
+ '@smithy/credential-provider-imds': 3.2.0
+ '@smithy/property-provider': 3.1.3
+ '@smithy/shared-ini-file-loader': 3.1.4
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
transitivePeerDependencies:
+ - '@aws-sdk/client-sso-oidc'
+ - '@aws-sdk/client-sts'
- aws-crt
- '@aws-sdk/credential-provider-process@3.410.0':
+ '@aws-sdk/credential-provider-process@3.614.0':
dependencies:
- '@aws-sdk/types': 3.410.0
- '@smithy/property-provider': 2.0.9
- '@smithy/shared-ini-file-loader': 2.0.10
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@aws-sdk/types': 3.609.0
+ '@smithy/property-provider': 3.1.3
+ '@smithy/shared-ini-file-loader': 3.1.4
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@aws-sdk/credential-provider-sso@3.410.0':
+ '@aws-sdk/credential-provider-sso@3.620.0(@aws-sdk/client-sso-oidc@3.620.0(@aws-sdk/client-sts@3.620.0))':
dependencies:
- '@aws-sdk/client-sso': 3.410.0
- '@aws-sdk/token-providers': 3.410.0
- '@aws-sdk/types': 3.410.0
- '@smithy/property-provider': 2.0.9
- '@smithy/shared-ini-file-loader': 2.0.10
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@aws-sdk/client-sso': 3.620.0
+ '@aws-sdk/token-providers': 3.614.0(@aws-sdk/client-sso-oidc@3.620.0(@aws-sdk/client-sts@3.620.0))
+ '@aws-sdk/types': 3.609.0
+ '@smithy/property-provider': 3.1.3
+ '@smithy/shared-ini-file-loader': 3.1.4
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
transitivePeerDependencies:
+ - '@aws-sdk/client-sso-oidc'
- aws-crt
- '@aws-sdk/credential-provider-web-identity@3.410.0':
+ '@aws-sdk/credential-provider-web-identity@3.609.0(@aws-sdk/client-sts@3.620.0)':
dependencies:
- '@aws-sdk/types': 3.410.0
- '@smithy/property-provider': 2.0.9
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@aws-sdk/client-sts': 3.620.0
+ '@aws-sdk/types': 3.609.0
+ '@smithy/property-provider': 3.1.3
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@aws-sdk/lib-storage@3.412.0(@aws-sdk/client-s3@3.412.0)':
+ '@aws-sdk/lib-storage@3.620.0(@aws-sdk/client-s3@3.620.0)':
dependencies:
- '@aws-sdk/client-s3': 3.412.0
- '@smithy/abort-controller': 2.0.14
- '@smithy/middleware-endpoint': 2.0.8
- '@smithy/smithy-client': 2.1.5
+ '@aws-sdk/client-s3': 3.620.0
+ '@smithy/abort-controller': 3.1.1
+ '@smithy/middleware-endpoint': 3.1.0
+ '@smithy/smithy-client': 3.1.11
buffer: 5.6.0
events: 3.3.0
stream-browserify: 3.0.0
- tslib: 2.6.2
+ tslib: 2.6.3
- '@aws-sdk/middleware-bucket-endpoint@3.410.0':
+ '@aws-sdk/middleware-bucket-endpoint@3.620.0':
dependencies:
- '@aws-sdk/types': 3.410.0
- '@aws-sdk/util-arn-parser': 3.310.0
- '@smithy/node-config-provider': 2.0.11
- '@smithy/protocol-http': 3.0.10
- '@smithy/types': 2.6.0
- '@smithy/util-config-provider': 2.0.0
- tslib: 2.6.2
+ '@aws-sdk/types': 3.609.0
+ '@aws-sdk/util-arn-parser': 3.568.0
+ '@smithy/node-config-provider': 3.1.4
+ '@smithy/protocol-http': 4.1.0
+ '@smithy/types': 3.3.0
+ '@smithy/util-config-provider': 3.0.0
+ tslib: 2.6.3
- '@aws-sdk/middleware-expect-continue@3.410.0':
+ '@aws-sdk/middleware-expect-continue@3.620.0':
dependencies:
- '@aws-sdk/types': 3.410.0
- '@smithy/protocol-http': 3.0.10
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@aws-sdk/types': 3.609.0
+ '@smithy/protocol-http': 4.1.0
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@aws-sdk/middleware-flexible-checksums@3.410.0':
+ '@aws-sdk/middleware-flexible-checksums@3.620.0':
dependencies:
- '@aws-crypto/crc32': 3.0.0
- '@aws-crypto/crc32c': 3.0.0
- '@aws-sdk/types': 3.410.0
- '@smithy/is-array-buffer': 2.0.0
- '@smithy/protocol-http': 3.0.10
- '@smithy/types': 2.6.0
- '@smithy/util-utf8': 2.0.0
- tslib: 2.6.2
+ '@aws-crypto/crc32': 5.2.0
+ '@aws-crypto/crc32c': 5.2.0
+ '@aws-sdk/types': 3.609.0
+ '@smithy/is-array-buffer': 3.0.0
+ '@smithy/protocol-http': 4.1.0
+ '@smithy/types': 3.3.0
+ '@smithy/util-utf8': 3.0.0
+ tslib: 2.6.3
- '@aws-sdk/middleware-host-header@3.410.0':
+ '@aws-sdk/middleware-host-header@3.620.0':
dependencies:
- '@aws-sdk/types': 3.410.0
- '@smithy/protocol-http': 3.0.10
- '@smithy/types': 2.6.0
- tslib: 2.6.2
-
- '@aws-sdk/middleware-location-constraint@3.410.0':
- dependencies:
- '@aws-sdk/types': 3.410.0
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@aws-sdk/types': 3.609.0
+ '@smithy/protocol-http': 4.1.0
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@aws-sdk/middleware-logger@3.410.0':
+ '@aws-sdk/middleware-location-constraint@3.609.0':
dependencies:
- '@aws-sdk/types': 3.410.0
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@aws-sdk/types': 3.609.0
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@aws-sdk/middleware-recursion-detection@3.410.0':
+ '@aws-sdk/middleware-logger@3.609.0':
dependencies:
- '@aws-sdk/types': 3.410.0
- '@smithy/protocol-http': 3.0.10
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@aws-sdk/types': 3.609.0
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@aws-sdk/middleware-sdk-s3@3.410.0':
+ '@aws-sdk/middleware-recursion-detection@3.620.0':
dependencies:
- '@aws-sdk/types': 3.410.0
- '@aws-sdk/util-arn-parser': 3.310.0
- '@smithy/protocol-http': 3.0.10
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@aws-sdk/types': 3.609.0
+ '@smithy/protocol-http': 4.1.0
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@aws-sdk/middleware-sdk-sts@3.410.0':
+ '@aws-sdk/middleware-sdk-s3@3.620.0':
dependencies:
- '@aws-sdk/middleware-signing': 3.410.0
- '@aws-sdk/types': 3.410.0
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@aws-sdk/types': 3.609.0
+ '@aws-sdk/util-arn-parser': 3.568.0
+ '@smithy/node-config-provider': 3.1.4
+ '@smithy/protocol-http': 4.1.0
+ '@smithy/signature-v4': 4.1.0
+ '@smithy/smithy-client': 3.1.11
+ '@smithy/types': 3.3.0
+ '@smithy/util-config-provider': 3.0.0
+ '@smithy/util-stream': 3.1.3
+ '@smithy/util-utf8': 3.0.0
+ tslib: 2.6.3
- '@aws-sdk/middleware-signing@3.410.0':
+ '@aws-sdk/middleware-signing@3.620.0':
dependencies:
- '@aws-sdk/types': 3.410.0
- '@smithy/property-provider': 2.0.9
- '@smithy/protocol-http': 3.0.10
- '@smithy/signature-v4': 2.0.5
- '@smithy/types': 2.6.0
- '@smithy/util-middleware': 2.0.1
- tslib: 2.6.2
+ '@aws-sdk/types': 3.609.0
+ '@smithy/property-provider': 3.1.3
+ '@smithy/protocol-http': 4.1.0
+ '@smithy/signature-v4': 4.1.0
+ '@smithy/types': 3.3.0
+ '@smithy/util-middleware': 3.0.3
+ tslib: 2.6.3
- '@aws-sdk/middleware-ssec@3.410.0':
+ '@aws-sdk/middleware-ssec@3.609.0':
dependencies:
- '@aws-sdk/types': 3.410.0
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@aws-sdk/types': 3.609.0
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@aws-sdk/middleware-user-agent@3.410.0':
+ '@aws-sdk/middleware-user-agent@3.620.0':
dependencies:
- '@aws-sdk/types': 3.410.0
- '@aws-sdk/util-endpoints': 3.410.0
- '@smithy/protocol-http': 3.0.10
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@aws-sdk/types': 3.609.0
+ '@aws-sdk/util-endpoints': 3.614.0
+ '@smithy/protocol-http': 4.1.0
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@aws-sdk/signature-v4-multi-region@3.412.0':
+ '@aws-sdk/region-config-resolver@3.614.0':
dependencies:
- '@aws-sdk/types': 3.410.0
- '@smithy/protocol-http': 3.0.10
- '@smithy/signature-v4': 2.0.5
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@aws-sdk/types': 3.609.0
+ '@smithy/node-config-provider': 3.1.4
+ '@smithy/types': 3.3.0
+ '@smithy/util-config-provider': 3.0.0
+ '@smithy/util-middleware': 3.0.3
+ tslib: 2.6.3
- '@aws-sdk/token-providers@3.410.0':
+ '@aws-sdk/signature-v4-multi-region@3.620.0':
dependencies:
- '@aws-crypto/sha256-browser': 3.0.0
- '@aws-crypto/sha256-js': 3.0.0
- '@aws-sdk/middleware-host-header': 3.410.0
- '@aws-sdk/middleware-logger': 3.410.0
- '@aws-sdk/middleware-recursion-detection': 3.410.0
- '@aws-sdk/middleware-user-agent': 3.410.0
- '@aws-sdk/types': 3.410.0
- '@aws-sdk/util-endpoints': 3.410.0
- '@aws-sdk/util-user-agent-browser': 3.410.0
- '@aws-sdk/util-user-agent-node': 3.410.0
- '@smithy/config-resolver': 2.0.9
- '@smithy/fetch-http-handler': 2.1.4
- '@smithy/hash-node': 2.0.8
- '@smithy/invalid-dependency': 2.0.8
- '@smithy/middleware-content-length': 2.0.10
- '@smithy/middleware-endpoint': 2.0.8
- '@smithy/middleware-retry': 2.0.11
- '@smithy/middleware-serde': 2.0.8
- '@smithy/middleware-stack': 2.0.1
- '@smithy/node-config-provider': 2.0.11
- '@smithy/node-http-handler': 2.5.0
- '@smithy/property-provider': 2.0.9
- '@smithy/protocol-http': 3.0.10
- '@smithy/shared-ini-file-loader': 2.0.10
- '@smithy/smithy-client': 2.1.5
- '@smithy/types': 2.6.0
- '@smithy/url-parser': 2.0.8
- '@smithy/util-base64': 2.0.0
- '@smithy/util-body-length-browser': 2.0.0
- '@smithy/util-body-length-node': 2.1.0
- '@smithy/util-defaults-mode-browser': 2.0.9
- '@smithy/util-defaults-mode-node': 2.0.11
- '@smithy/util-retry': 2.0.1
- '@smithy/util-utf8': 2.0.0
- tslib: 2.6.2
- transitivePeerDependencies:
- - aws-crt
+ '@aws-sdk/middleware-sdk-s3': 3.620.0
+ '@aws-sdk/types': 3.609.0
+ '@smithy/protocol-http': 4.1.0
+ '@smithy/signature-v4': 4.1.0
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@aws-sdk/types@3.410.0':
+ '@aws-sdk/token-providers@3.614.0(@aws-sdk/client-sso-oidc@3.620.0(@aws-sdk/client-sts@3.620.0))':
dependencies:
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@aws-sdk/client-sso-oidc': 3.620.0(@aws-sdk/client-sts@3.620.0)
+ '@aws-sdk/types': 3.609.0
+ '@smithy/property-provider': 3.1.3
+ '@smithy/shared-ini-file-loader': 3.1.4
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@aws-sdk/types@3.413.0':
+ '@aws-sdk/types@3.609.0':
dependencies:
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@aws-sdk/util-arn-parser@3.310.0':
+ '@aws-sdk/util-arn-parser@3.568.0':
dependencies:
- tslib: 2.6.2
+ tslib: 2.6.3
- '@aws-sdk/util-endpoints@3.410.0':
+ '@aws-sdk/util-endpoints@3.614.0':
dependencies:
- '@aws-sdk/types': 3.410.0
- tslib: 2.6.2
+ '@aws-sdk/types': 3.609.0
+ '@smithy/types': 3.3.0
+ '@smithy/util-endpoints': 2.0.5
+ tslib: 2.6.3
'@aws-sdk/util-locate-window@3.208.0':
dependencies:
- tslib: 2.6.2
+ tslib: 2.6.3
- '@aws-sdk/util-user-agent-browser@3.410.0':
+ '@aws-sdk/util-user-agent-browser@3.609.0':
dependencies:
- '@aws-sdk/types': 3.410.0
- '@smithy/types': 2.6.0
+ '@aws-sdk/types': 3.609.0
+ '@smithy/types': 3.3.0
bowser: 2.11.0
- tslib: 2.6.2
-
- '@aws-sdk/util-user-agent-node@3.410.0':
- dependencies:
- '@aws-sdk/types': 3.410.0
- '@smithy/node-config-provider': 2.0.11
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ tslib: 2.6.3
- '@aws-sdk/util-utf8-browser@3.259.0':
+ '@aws-sdk/util-user-agent-node@3.614.0':
dependencies:
- tslib: 2.6.2
+ '@aws-sdk/types': 3.609.0
+ '@smithy/node-config-provider': 3.1.4
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@aws-sdk/xml-builder@3.310.0':
+ '@aws-sdk/xml-builder@3.609.0':
dependencies:
- tslib: 2.6.2
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
'@babel/code-frame@7.23.5':
dependencies:
'@babel/highlight': 7.23.4
chalk: 2.4.2
+ '@babel/code-frame@7.24.7':
+ dependencies:
+ '@babel/highlight': 7.24.7
+ picocolors: 1.0.0
+
'@babel/compat-data@7.23.5': {}
+ '@babel/compat-data@7.24.7': {}
+
'@babel/core@7.23.5':
dependencies:
'@ampproject/remapping': 2.2.1
@@ -11917,27 +12483,27 @@ snapshots:
'@babel/traverse': 7.23.5
'@babel/types': 7.23.5
convert-source-map: 2.0.0
- debug: 4.3.4(supports-color@8.1.1)
+ debug: 4.3.5(supports-color@8.1.1)
gensync: 1.0.0-beta.2
json5: 2.2.3
semver: 6.3.1
transitivePeerDependencies:
- supports-color
- '@babel/core@7.24.0':
+ '@babel/core@7.24.7':
dependencies:
'@ampproject/remapping': 2.2.1
- '@babel/code-frame': 7.23.5
- '@babel/generator': 7.23.6
- '@babel/helper-compilation-targets': 7.23.6
- '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0)
- '@babel/helpers': 7.24.0
- '@babel/parser': 7.24.0
- '@babel/template': 7.24.0
- '@babel/traverse': 7.24.0
- '@babel/types': 7.24.0
+ '@babel/code-frame': 7.24.7
+ '@babel/generator': 7.24.7
+ '@babel/helper-compilation-targets': 7.24.7
+ '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7)
+ '@babel/helpers': 7.24.7
+ '@babel/parser': 7.24.7
+ '@babel/template': 7.24.7
+ '@babel/traverse': 7.24.7
+ '@babel/types': 7.24.7
convert-source-map: 2.0.0
- debug: 4.3.4(supports-color@8.1.1)
+ debug: 4.3.5(supports-color@8.1.1)
gensync: 1.0.0-beta.2
json5: 2.2.3
semver: 6.3.1
@@ -11951,20 +12517,23 @@ snapshots:
'@jridgewell/trace-mapping': 0.3.18
jsesc: 2.5.2
- '@babel/generator@7.23.6':
+ '@babel/generator@7.24.7':
dependencies:
- '@babel/types': 7.24.0
- '@jridgewell/gen-mapping': 0.3.2
- '@jridgewell/trace-mapping': 0.3.18
+ '@babel/types': 7.24.7
+ '@jridgewell/gen-mapping': 0.3.5
+ '@jridgewell/trace-mapping': 0.3.25
jsesc: 2.5.2
- '@babel/helper-annotate-as-pure@7.22.5':
+ '@babel/helper-annotate-as-pure@7.24.7':
dependencies:
- '@babel/types': 7.24.0
+ '@babel/types': 7.24.7
- '@babel/helper-builder-binary-assignment-operator-visitor@7.22.15':
+ '@babel/helper-builder-binary-assignment-operator-visitor@7.24.7':
dependencies:
- '@babel/types': 7.24.0
+ '@babel/traverse': 7.24.7
+ '@babel/types': 7.24.7
+ transitivePeerDependencies:
+ - supports-color
'@babel/helper-compilation-targets@7.22.15':
dependencies:
@@ -11974,40 +12543,42 @@ snapshots:
lru-cache: 5.1.1
semver: 6.3.1
- '@babel/helper-compilation-targets@7.23.6':
+ '@babel/helper-compilation-targets@7.24.7':
dependencies:
- '@babel/compat-data': 7.23.5
- '@babel/helper-validator-option': 7.23.5
+ '@babel/compat-data': 7.24.7
+ '@babel/helper-validator-option': 7.24.7
browserslist: 4.23.0
lru-cache: 5.1.1
semver: 6.3.1
- '@babel/helper-create-class-features-plugin@7.23.5(@babel/core@7.24.0)':
+ '@babel/helper-create-class-features-plugin@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-annotate-as-pure': 7.22.5
- '@babel/helper-environment-visitor': 7.22.20
- '@babel/helper-function-name': 7.23.0
- '@babel/helper-member-expression-to-functions': 7.23.0
- '@babel/helper-optimise-call-expression': 7.22.5
- '@babel/helper-replace-supers': 7.22.20(@babel/core@7.24.0)
- '@babel/helper-skip-transparent-expression-wrappers': 7.22.5
- '@babel/helper-split-export-declaration': 7.22.6
+ '@babel/core': 7.24.7
+ '@babel/helper-annotate-as-pure': 7.24.7
+ '@babel/helper-environment-visitor': 7.24.7
+ '@babel/helper-function-name': 7.24.7
+ '@babel/helper-member-expression-to-functions': 7.24.7
+ '@babel/helper-optimise-call-expression': 7.24.7
+ '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.7)
+ '@babel/helper-skip-transparent-expression-wrappers': 7.24.7
+ '@babel/helper-split-export-declaration': 7.24.7
semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
- '@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.24.0)':
+ '@babel/helper-create-regexp-features-plugin@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-annotate-as-pure': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-annotate-as-pure': 7.24.7
regexpu-core: 5.3.2
semver: 6.3.1
- '@babel/helper-define-polyfill-provider@0.4.3(@babel/core@7.24.0)':
+ '@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-compilation-targets': 7.23.6
- '@babel/helper-plugin-utils': 7.22.5
- debug: 4.3.4(supports-color@8.1.1)
+ '@babel/core': 7.24.7
+ '@babel/helper-compilation-targets': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
+ debug: 4.3.5(supports-color@8.1.1)
lodash.debounce: 4.0.8
resolve: 1.22.8
transitivePeerDependencies:
@@ -12015,23 +12586,46 @@ snapshots:
'@babel/helper-environment-visitor@7.22.20': {}
+ '@babel/helper-environment-visitor@7.24.7':
+ dependencies:
+ '@babel/types': 7.24.7
+
'@babel/helper-function-name@7.23.0':
dependencies:
- '@babel/template': 7.24.0
- '@babel/types': 7.24.0
+ '@babel/template': 7.24.7
+ '@babel/types': 7.24.7
+
+ '@babel/helper-function-name@7.24.7':
+ dependencies:
+ '@babel/template': 7.24.7
+ '@babel/types': 7.24.7
'@babel/helper-hoist-variables@7.22.5':
dependencies:
- '@babel/types': 7.24.0
+ '@babel/types': 7.24.7
- '@babel/helper-member-expression-to-functions@7.23.0':
+ '@babel/helper-hoist-variables@7.24.7':
dependencies:
- '@babel/types': 7.24.0
+ '@babel/types': 7.24.7
+
+ '@babel/helper-member-expression-to-functions@7.24.7':
+ dependencies:
+ '@babel/traverse': 7.24.7
+ '@babel/types': 7.24.7
+ transitivePeerDependencies:
+ - supports-color
'@babel/helper-module-imports@7.22.15':
dependencies:
'@babel/types': 7.23.5
+ '@babel/helper-module-imports@7.24.7':
+ dependencies:
+ '@babel/traverse': 7.24.7
+ '@babel/types': 7.24.7
+ transitivePeerDependencies:
+ - supports-color
+
'@babel/helper-module-transforms@7.23.3(@babel/core@7.23.5)':
dependencies:
'@babel/core': 7.23.5
@@ -12041,58 +12635,89 @@ snapshots:
'@babel/helper-split-export-declaration': 7.22.6
'@babel/helper-validator-identifier': 7.22.20
- '@babel/helper-module-transforms@7.23.3(@babel/core@7.24.0)':
+ '@babel/helper-module-transforms@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-environment-visitor': 7.22.20
- '@babel/helper-module-imports': 7.22.15
- '@babel/helper-simple-access': 7.22.5
- '@babel/helper-split-export-declaration': 7.22.6
- '@babel/helper-validator-identifier': 7.22.20
+ '@babel/core': 7.24.7
+ '@babel/helper-environment-visitor': 7.24.7
+ '@babel/helper-module-imports': 7.24.7
+ '@babel/helper-simple-access': 7.24.7
+ '@babel/helper-split-export-declaration': 7.24.7
+ '@babel/helper-validator-identifier': 7.24.7
+ transitivePeerDependencies:
+ - supports-color
- '@babel/helper-optimise-call-expression@7.22.5':
+ '@babel/helper-optimise-call-expression@7.24.7':
dependencies:
- '@babel/types': 7.24.0
+ '@babel/types': 7.24.7
'@babel/helper-plugin-utils@7.22.5': {}
- '@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.24.0)':
+ '@babel/helper-plugin-utils@7.24.7': {}
+
+ '@babel/helper-remap-async-to-generator@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-annotate-as-pure': 7.22.5
- '@babel/helper-environment-visitor': 7.22.20
- '@babel/helper-wrap-function': 7.22.20
+ '@babel/core': 7.24.7
+ '@babel/helper-annotate-as-pure': 7.24.7
+ '@babel/helper-environment-visitor': 7.24.7
+ '@babel/helper-wrap-function': 7.24.7
+ transitivePeerDependencies:
+ - supports-color
- '@babel/helper-replace-supers@7.22.20(@babel/core@7.24.0)':
+ '@babel/helper-replace-supers@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-environment-visitor': 7.22.20
- '@babel/helper-member-expression-to-functions': 7.23.0
- '@babel/helper-optimise-call-expression': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-environment-visitor': 7.24.7
+ '@babel/helper-member-expression-to-functions': 7.24.7
+ '@babel/helper-optimise-call-expression': 7.24.7
+ transitivePeerDependencies:
+ - supports-color
'@babel/helper-simple-access@7.22.5':
dependencies:
'@babel/types': 7.23.5
- '@babel/helper-skip-transparent-expression-wrappers@7.22.5':
+ '@babel/helper-simple-access@7.24.7':
dependencies:
- '@babel/types': 7.24.0
+ '@babel/traverse': 7.24.7
+ '@babel/types': 7.24.7
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-skip-transparent-expression-wrappers@7.24.7':
+ dependencies:
+ '@babel/traverse': 7.24.7
+ '@babel/types': 7.24.7
+ transitivePeerDependencies:
+ - supports-color
'@babel/helper-split-export-declaration@7.22.6':
dependencies:
'@babel/types': 7.23.5
+ '@babel/helper-split-export-declaration@7.24.7':
+ dependencies:
+ '@babel/types': 7.24.7
+
'@babel/helper-string-parser@7.23.4': {}
+ '@babel/helper-string-parser@7.24.7': {}
+
'@babel/helper-validator-identifier@7.22.20': {}
+ '@babel/helper-validator-identifier@7.24.7': {}
+
'@babel/helper-validator-option@7.23.5': {}
- '@babel/helper-wrap-function@7.22.20':
+ '@babel/helper-validator-option@7.24.7': {}
+
+ '@babel/helper-wrap-function@7.24.7':
dependencies:
- '@babel/helper-function-name': 7.23.0
- '@babel/template': 7.24.0
- '@babel/types': 7.24.0
+ '@babel/helper-function-name': 7.24.7
+ '@babel/template': 7.24.7
+ '@babel/traverse': 7.24.7
+ '@babel/types': 7.24.7
+ transitivePeerDependencies:
+ - supports-color
'@babel/helpers@7.23.5':
dependencies:
@@ -12102,13 +12727,10 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@babel/helpers@7.24.0':
+ '@babel/helpers@7.24.7':
dependencies:
- '@babel/template': 7.24.0
- '@babel/traverse': 7.24.0
- '@babel/types': 7.24.0
- transitivePeerDependencies:
- - supports-color
+ '@babel/template': 7.24.7
+ '@babel/types': 7.24.7
'@babel/highlight@7.23.4':
dependencies:
@@ -12116,48 +12738,63 @@ snapshots:
chalk: 2.4.2
js-tokens: 4.0.0
+ '@babel/highlight@7.24.7':
+ dependencies:
+ '@babel/helper-validator-identifier': 7.24.7
+ chalk: 2.4.2
+ js-tokens: 4.0.0
+ picocolors: 1.0.0
+
'@babel/parser@7.23.9':
dependencies:
'@babel/types': 7.23.5
- '@babel/parser@7.24.0':
+ '@babel/parser@7.24.5':
dependencies:
'@babel/types': 7.24.0
- '@babel/parser@7.24.5':
+ '@babel/parser@7.24.7':
dependencies:
- '@babel/types': 7.24.0
+ '@babel/types': 7.24.7
- '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-environment-visitor': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/helper-skip-transparent-expression-wrappers': 7.22.5
- '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.24.0)
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-environment-visitor': 7.22.20
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/helper-skip-transparent-expression-wrappers': 7.24.7
+ '@babel/plugin-transform-optional-chaining': 7.24.7(@babel/core@7.24.7)
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.24.7(@babel/core@7.24.7)':
+ dependencies:
+ '@babel/core': 7.24.7
+ '@babel/helper-environment-visitor': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.0)':
+ '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
+ '@babel/core': 7.24.7
'@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.5)':
dependencies:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.0)':
+ '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
+ '@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.23.5)':
@@ -12170,49 +12807,49 @@ snapshots:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.0)':
+ '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
+ '@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.0)':
+ '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.0)':
+ '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.0)':
+ '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-syntax-flow@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-syntax-flow@7.23.3(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-syntax-import-assertions@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-syntax-import-attributes@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
'@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.5)':
dependencies:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.0)':
+ '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
+ '@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.5)':
@@ -12220,9 +12857,9 @@ snapshots:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.0)':
+ '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
+ '@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.5)':
@@ -12230,9 +12867,9 @@ snapshots:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
+ '@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.5)':
@@ -12240,9 +12877,9 @@ snapshots:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.0)':
+ '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
+ '@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.5)':
@@ -12250,9 +12887,9 @@ snapshots:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.0)':
+ '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
+ '@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.5)':
@@ -12260,9 +12897,9 @@ snapshots:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.0)':
+ '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
+ '@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.5)':
@@ -12270,9 +12907,9 @@ snapshots:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.0)':
+ '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
+ '@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.5)':
@@ -12280,9 +12917,9 @@ snapshots:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.0)':
+ '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
+ '@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.5)':
@@ -12290,24 +12927,24 @@ snapshots:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.0)':
+ '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
+ '@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.24.0)':
+ '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
'@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.5)':
dependencies:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.0)':
+ '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
+ '@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.5)':
@@ -12315,435 +12952,471 @@ snapshots:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
+ '@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.0)':
+ '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0)
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.7)
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-arrow-functions@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-transform-async-generator-functions@7.23.4(@babel/core@7.24.0)':
+ '@babel/plugin-transform-async-generator-functions@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-environment-visitor': 7.22.20
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.0)
- '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.0)
+ '@babel/core': 7.24.7
+ '@babel/helper-environment-visitor': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/helper-remap-async-to-generator': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.7)
+ transitivePeerDependencies:
+ - supports-color
- '@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-async-to-generator@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-module-imports': 7.22.15
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.0)
+ '@babel/core': 7.24.7
+ '@babel/helper-module-imports': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/helper-remap-async-to-generator': 7.24.7(@babel/core@7.24.7)
+ transitivePeerDependencies:
+ - supports-color
- '@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-block-scoped-functions@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.24.0)':
+ '@babel/plugin-transform-block-scoping@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-class-properties@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.24.0)
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7)
+ '@babel/helper-plugin-utils': 7.24.7
+ transitivePeerDependencies:
+ - supports-color
- '@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.24.0)':
+ '@babel/plugin-transform-class-static-block@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.24.0)
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.0)
+ '@babel/core': 7.24.7
+ '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7)
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.7)
+ transitivePeerDependencies:
+ - supports-color
- '@babel/plugin-transform-classes@7.23.5(@babel/core@7.24.0)':
+ '@babel/plugin-transform-classes@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-annotate-as-pure': 7.22.5
- '@babel/helper-compilation-targets': 7.23.6
- '@babel/helper-environment-visitor': 7.22.20
- '@babel/helper-function-name': 7.23.0
- '@babel/helper-optimise-call-expression': 7.22.5
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/helper-replace-supers': 7.22.20(@babel/core@7.24.0)
- '@babel/helper-split-export-declaration': 7.22.6
+ '@babel/core': 7.24.7
+ '@babel/helper-annotate-as-pure': 7.24.7
+ '@babel/helper-compilation-targets': 7.24.7
+ '@babel/helper-environment-visitor': 7.24.7
+ '@babel/helper-function-name': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.7)
+ '@babel/helper-split-export-declaration': 7.24.7
globals: 11.12.0
+ transitivePeerDependencies:
+ - supports-color
- '@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-computed-properties@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/template': 7.24.0
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/template': 7.24.7
- '@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-destructuring@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-dotall-regex@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0)
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.7)
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-duplicate-keys@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.24.0)':
+ '@babel/plugin-transform-dynamic-import@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.0)
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.7)
- '@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-exponentiation-operator@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-builder-binary-assignment-operator-visitor': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
+ transitivePeerDependencies:
+ - supports-color
- '@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.24.0)':
+ '@babel/plugin-transform-export-namespace-from@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.0)
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.7)
- '@babel/plugin-transform-flow-strip-types@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-flow-strip-types@7.23.3(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.24.0)
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.24.7)
- '@babel/plugin-transform-for-of@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-for-of@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/helper-skip-transparent-expression-wrappers': 7.24.7
+ transitivePeerDependencies:
+ - supports-color
- '@babel/plugin-transform-function-name@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-function-name@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-compilation-targets': 7.23.6
- '@babel/helper-function-name': 7.23.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-compilation-targets': 7.24.7
+ '@babel/helper-function-name': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.24.0)':
+ '@babel/plugin-transform-json-strings@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.0)
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.7)
- '@babel/plugin-transform-literals@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-literals@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.24.0)':
+ '@babel/plugin-transform-logical-assignment-operators@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.0)
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.7)
- '@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-member-expression-literals@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-modules-amd@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0)
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7)
+ '@babel/helper-plugin-utils': 7.24.7
+ transitivePeerDependencies:
+ - supports-color
- '@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-modules-commonjs@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0)
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/helper-simple-access': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7)
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/helper-simple-access': 7.24.7
+ transitivePeerDependencies:
+ - supports-color
- '@babel/plugin-transform-modules-systemjs@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-modules-systemjs@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-hoist-variables': 7.22.5
- '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0)
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/helper-validator-identifier': 7.22.20
+ '@babel/core': 7.24.7
+ '@babel/helper-hoist-variables': 7.24.7
+ '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7)
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/helper-validator-identifier': 7.24.7
+ transitivePeerDependencies:
+ - supports-color
- '@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-modules-umd@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0)
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7)
+ '@babel/helper-plugin-utils': 7.24.7
+ transitivePeerDependencies:
+ - supports-color
- '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.24.0)':
+ '@babel/plugin-transform-named-capturing-groups-regex@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0)
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.7)
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-transform-new-target@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-new-target@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.24.0)':
+ '@babel/plugin-transform-nullish-coalescing-operator@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.0)
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.7)
- '@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.24.0)':
+ '@babel/plugin-transform-numeric-separator@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.0)
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.7)
- '@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.24.0)':
+ '@babel/plugin-transform-object-rest-spread@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/compat-data': 7.23.5
- '@babel/core': 7.24.0
- '@babel/helper-compilation-targets': 7.23.6
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.0)
- '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.24.0)
+ '@babel/core': 7.24.7
+ '@babel/helper-compilation-targets': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.7)
+ '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-object-super@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-object-super@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/helper-replace-supers': 7.22.20(@babel/core@7.24.0)
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.7)
+ transitivePeerDependencies:
+ - supports-color
- '@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.24.0)':
+ '@babel/plugin-transform-optional-catch-binding@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.0)
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.7)
- '@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.24.0)':
+ '@babel/plugin-transform-optional-chaining@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/helper-skip-transparent-expression-wrappers': 7.22.5
- '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.0)
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/helper-skip-transparent-expression-wrappers': 7.24.7
+ '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.7)
+ transitivePeerDependencies:
+ - supports-color
- '@babel/plugin-transform-parameters@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-parameters@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-private-methods@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.24.0)
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7)
+ '@babel/helper-plugin-utils': 7.24.7
+ transitivePeerDependencies:
+ - supports-color
- '@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.24.0)':
+ '@babel/plugin-transform-private-property-in-object@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-annotate-as-pure': 7.22.5
- '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.24.0)
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.0)
+ '@babel/core': 7.24.7
+ '@babel/helper-annotate-as-pure': 7.24.7
+ '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7)
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.7)
+ transitivePeerDependencies:
+ - supports-color
- '@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-property-literals@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-regenerator@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
regenerator-transform: 0.15.2
- '@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-reserved-words@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-shorthand-properties@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-transform-spread@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-spread@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/helper-skip-transparent-expression-wrappers': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/helper-skip-transparent-expression-wrappers': 7.24.7
+ transitivePeerDependencies:
+ - supports-color
- '@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-sticky-regex@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-template-literals@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-typeof-symbol@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-transform-typescript@7.23.5(@babel/core@7.24.0)':
+ '@babel/plugin-transform-typescript@7.23.5(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-annotate-as-pure': 7.22.5
- '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.24.0)
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.24.0)
+ '@babel/core': 7.24.7
+ '@babel/helper-annotate-as-pure': 7.24.7
+ '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7)
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.24.7)
+ transitivePeerDependencies:
+ - supports-color
- '@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-unicode-escapes@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-unicode-property-regex@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0)
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.7)
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-unicode-regex@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0)
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.7)
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.24.0)':
+ '@babel/plugin-transform-unicode-sets-regex@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0)
- '@babel/helper-plugin-utils': 7.22.5
+ '@babel/core': 7.24.7
+ '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.7)
+ '@babel/helper-plugin-utils': 7.24.7
- '@babel/preset-env@7.23.5(@babel/core@7.24.0)':
+ '@babel/preset-env@7.24.7(@babel/core@7.24.7)':
dependencies:
- '@babel/compat-data': 7.23.5
- '@babel/core': 7.24.0
- '@babel/helper-compilation-targets': 7.23.6
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/helper-validator-option': 7.23.5
- '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.0)
- '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.0)
- '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.0)
- '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.0)
- '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.0)
- '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.0)
- '@babel/plugin-syntax-import-assertions': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-syntax-import-attributes': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.0)
- '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.0)
- '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.0)
- '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.0)
- '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.0)
- '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.0)
- '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.0)
- '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.0)
- '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.0)
- '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.0)
- '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.24.0)
- '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-async-generator-functions': 7.23.4(@babel/core@7.24.0)
- '@babel/plugin-transform-async-to-generator': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-block-scoped-functions': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.24.0)
- '@babel/plugin-transform-class-properties': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-class-static-block': 7.23.4(@babel/core@7.24.0)
- '@babel/plugin-transform-classes': 7.23.5(@babel/core@7.24.0)
- '@babel/plugin-transform-computed-properties': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-dotall-regex': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-duplicate-keys': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-dynamic-import': 7.23.4(@babel/core@7.24.0)
- '@babel/plugin-transform-exponentiation-operator': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-export-namespace-from': 7.23.4(@babel/core@7.24.0)
- '@babel/plugin-transform-for-of': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-function-name': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-json-strings': 7.23.4(@babel/core@7.24.0)
- '@babel/plugin-transform-literals': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-logical-assignment-operators': 7.23.4(@babel/core@7.24.0)
- '@babel/plugin-transform-member-expression-literals': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-modules-amd': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-modules-systemjs': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-modules-umd': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.24.0)
- '@babel/plugin-transform-new-target': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-nullish-coalescing-operator': 7.23.4(@babel/core@7.24.0)
- '@babel/plugin-transform-numeric-separator': 7.23.4(@babel/core@7.24.0)
- '@babel/plugin-transform-object-rest-spread': 7.23.4(@babel/core@7.24.0)
- '@babel/plugin-transform-object-super': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-optional-catch-binding': 7.23.4(@babel/core@7.24.0)
- '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.24.0)
- '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-private-property-in-object': 7.23.4(@babel/core@7.24.0)
- '@babel/plugin-transform-property-literals': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-regenerator': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-reserved-words': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-sticky-regex': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-template-literals': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-typeof-symbol': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-unicode-escapes': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-unicode-property-regex': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-unicode-regex': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-unicode-sets-regex': 7.23.3(@babel/core@7.24.0)
- '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.24.0)
- babel-plugin-polyfill-corejs2: 0.4.6(@babel/core@7.24.0)
- babel-plugin-polyfill-corejs3: 0.8.6(@babel/core@7.24.0)
- babel-plugin-polyfill-regenerator: 0.5.3(@babel/core@7.24.0)
- core-js-compat: 3.33.3
+ '@babel/compat-data': 7.24.7
+ '@babel/core': 7.24.7
+ '@babel/helper-compilation-targets': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/helper-validator-option': 7.24.7
+ '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.7)
+ '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.7)
+ '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.7)
+ '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.7)
+ '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.7)
+ '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.7)
+ '@babel/plugin-syntax-import-assertions': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-syntax-import-attributes': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.7)
+ '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.7)
+ '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.7)
+ '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.7)
+ '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.7)
+ '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.7)
+ '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.7)
+ '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.7)
+ '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.7)
+ '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.7)
+ '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.24.7)
+ '@babel/plugin-transform-arrow-functions': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-async-generator-functions': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-async-to-generator': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-block-scoped-functions': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-block-scoping': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-class-properties': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-class-static-block': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-classes': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-computed-properties': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-destructuring': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-dotall-regex': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-duplicate-keys': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-dynamic-import': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-exponentiation-operator': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-export-namespace-from': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-for-of': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-function-name': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-json-strings': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-literals': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-logical-assignment-operators': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-member-expression-literals': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-modules-amd': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-modules-commonjs': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-modules-systemjs': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-modules-umd': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-named-capturing-groups-regex': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-new-target': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-nullish-coalescing-operator': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-numeric-separator': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-object-rest-spread': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-object-super': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-optional-catch-binding': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-optional-chaining': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-private-methods': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-private-property-in-object': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-property-literals': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-regenerator': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-reserved-words': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-shorthand-properties': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-spread': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-sticky-regex': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-template-literals': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-typeof-symbol': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-unicode-escapes': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-unicode-property-regex': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-unicode-regex': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-unicode-sets-regex': 7.24.7(@babel/core@7.24.7)
+ '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.24.7)
+ babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.24.7)
+ babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.7)
+ babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.24.7)
+ core-js-compat: 3.37.1
semver: 6.3.1
transitivePeerDependencies:
- supports-color
- '@babel/preset-flow@7.23.3(@babel/core@7.24.0)':
+ '@babel/preset-flow@7.23.3(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/helper-validator-option': 7.23.5
- '@babel/plugin-transform-flow-strip-types': 7.23.3(@babel/core@7.24.0)
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/helper-validator-option': 7.24.7
+ '@babel/plugin-transform-flow-strip-types': 7.23.3(@babel/core@7.24.7)
- '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.0)':
+ '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/types': 7.24.0
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/types': 7.24.7
esutils: 2.0.3
- '@babel/preset-typescript@7.23.3(@babel/core@7.24.0)':
+ '@babel/preset-typescript@7.23.3(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-plugin-utils': 7.22.5
- '@babel/helper-validator-option': 7.23.5
- '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-typescript': 7.23.5(@babel/core@7.24.0)
+ '@babel/core': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.7
+ '@babel/helper-validator-option': 7.24.7
+ '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.24.7)
+ '@babel/plugin-transform-modules-commonjs': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-typescript': 7.23.5(@babel/core@7.24.7)
+ transitivePeerDependencies:
+ - supports-color
- '@babel/register@7.22.15(@babel/core@7.24.0)':
+ '@babel/register@7.22.15(@babel/core@7.24.7)':
dependencies:
- '@babel/core': 7.24.0
+ '@babel/core': 7.24.7
clone-deep: 4.0.1
find-cache-dir: 2.1.0
make-dir: 2.1.0
@@ -12764,9 +13437,15 @@ snapshots:
'@babel/template@7.24.0':
dependencies:
- '@babel/code-frame': 7.23.5
- '@babel/parser': 7.24.0
- '@babel/types': 7.24.0
+ '@babel/code-frame': 7.24.7
+ '@babel/parser': 7.24.7
+ '@babel/types': 7.24.7
+
+ '@babel/template@7.24.7':
+ dependencies:
+ '@babel/code-frame': 7.24.7
+ '@babel/parser': 7.24.7
+ '@babel/types': 7.24.7
'@babel/traverse@7.23.5':
dependencies:
@@ -12778,22 +13457,22 @@ snapshots:
'@babel/helper-split-export-declaration': 7.22.6
'@babel/parser': 7.23.9
'@babel/types': 7.23.5
- debug: 4.3.4(supports-color@8.1.1)
+ debug: 4.3.5(supports-color@8.1.1)
globals: 11.12.0
transitivePeerDependencies:
- supports-color
- '@babel/traverse@7.24.0':
+ '@babel/traverse@7.24.7':
dependencies:
- '@babel/code-frame': 7.23.5
- '@babel/generator': 7.23.6
- '@babel/helper-environment-visitor': 7.22.20
- '@babel/helper-function-name': 7.23.0
- '@babel/helper-hoist-variables': 7.22.5
- '@babel/helper-split-export-declaration': 7.22.6
- '@babel/parser': 7.24.0
- '@babel/types': 7.24.0
- debug: 4.3.4(supports-color@8.1.1)
+ '@babel/code-frame': 7.24.7
+ '@babel/generator': 7.24.7
+ '@babel/helper-environment-visitor': 7.24.7
+ '@babel/helper-function-name': 7.24.7
+ '@babel/helper-hoist-variables': 7.24.7
+ '@babel/helper-split-export-declaration': 7.24.7
+ '@babel/parser': 7.24.7
+ '@babel/types': 7.24.7
+ debug: 4.3.5(supports-color@8.1.1)
globals: 11.12.0
transitivePeerDependencies:
- supports-color
@@ -12810,26 +13489,32 @@ snapshots:
'@babel/helper-validator-identifier': 7.22.20
to-fast-properties: 2.0.0
+ '@babel/types@7.24.7':
+ dependencies:
+ '@babel/helper-string-parser': 7.24.7
+ '@babel/helper-validator-identifier': 7.24.7
+ to-fast-properties: 2.0.0
+
'@base2/pretty-print-object@1.0.1': {}
'@bcoe/v8-coverage@0.2.3': {}
- '@bull-board/api@5.17.0(@bull-board/ui@5.17.0)':
+ '@bull-board/api@5.21.1(@bull-board/ui@5.21.1)':
dependencies:
- '@bull-board/ui': 5.17.0
+ '@bull-board/ui': 5.21.1
redis-info: 3.1.0
- '@bull-board/fastify@5.17.0':
+ '@bull-board/fastify@5.21.1':
dependencies:
- '@bull-board/api': 5.17.0(@bull-board/ui@5.17.0)
- '@bull-board/ui': 5.17.0
+ '@bull-board/api': 5.21.1(@bull-board/ui@5.21.1)
+ '@bull-board/ui': 5.21.1
'@fastify/static': 6.12.0
'@fastify/view': 8.2.0
- ejs: 3.1.9
+ ejs: 3.1.10
- '@bull-board/ui@5.17.0':
+ '@bull-board/ui@5.21.1':
dependencies:
- '@bull-board/api': 5.17.0(@bull-board/ui@5.17.0)
+ '@bull-board/api': 5.21.1(@bull-board/ui@5.21.1)
'@bundled-es-modules/cookie@2.0.0':
dependencies:
@@ -12839,76 +13524,81 @@ snapshots:
dependencies:
statuses: 2.0.1
+ '@bundled-es-modules/tough-cookie@0.1.6':
+ dependencies:
+ '@types/tough-cookie': 4.0.5
+ tough-cookie: 4.1.4
+
'@canvas/image-data@1.0.0': {}
'@colors/colors@1.5.0':
optional: true
- '@cropper/element-canvas@2.0.0-beta.5':
+ '@cropper/element-canvas@2.0.0-rc.1':
dependencies:
- '@cropper/element': 2.0.0-beta.5
- '@cropper/utils': 2.0.0-beta.5
+ '@cropper/element': 2.0.0-rc.1
+ '@cropper/utils': 2.0.0-rc.1
- '@cropper/element-crosshair@2.0.0-beta.5':
+ '@cropper/element-crosshair@2.0.0-rc.1':
dependencies:
- '@cropper/element': 2.0.0-beta.5
- '@cropper/utils': 2.0.0-beta.5
+ '@cropper/element': 2.0.0-rc.1
+ '@cropper/utils': 2.0.0-rc.1
- '@cropper/element-grid@2.0.0-beta.5':
+ '@cropper/element-grid@2.0.0-rc.1':
dependencies:
- '@cropper/element': 2.0.0-beta.5
- '@cropper/utils': 2.0.0-beta.5
+ '@cropper/element': 2.0.0-rc.1
+ '@cropper/utils': 2.0.0-rc.1
- '@cropper/element-handle@2.0.0-beta.5':
+ '@cropper/element-handle@2.0.0-rc.1':
dependencies:
- '@cropper/element': 2.0.0-beta.5
- '@cropper/utils': 2.0.0-beta.5
+ '@cropper/element': 2.0.0-rc.1
+ '@cropper/utils': 2.0.0-rc.1
- '@cropper/element-image@2.0.0-beta.5':
+ '@cropper/element-image@2.0.0-rc.1':
dependencies:
- '@cropper/element': 2.0.0-beta.5
- '@cropper/element-canvas': 2.0.0-beta.5
- '@cropper/utils': 2.0.0-beta.5
+ '@cropper/element': 2.0.0-rc.1
+ '@cropper/element-canvas': 2.0.0-rc.1
+ '@cropper/utils': 2.0.0-rc.1
- '@cropper/element-selection@2.0.0-beta.5':
+ '@cropper/element-selection@2.0.0-rc.1':
dependencies:
- '@cropper/element': 2.0.0-beta.5
- '@cropper/element-canvas': 2.0.0-beta.5
- '@cropper/element-image': 2.0.0-beta.5
- '@cropper/utils': 2.0.0-beta.5
+ '@cropper/element': 2.0.0-rc.1
+ '@cropper/element-canvas': 2.0.0-rc.1
+ '@cropper/element-image': 2.0.0-rc.1
+ '@cropper/utils': 2.0.0-rc.1
- '@cropper/element-shade@2.0.0-beta.5':
+ '@cropper/element-shade@2.0.0-rc.1':
dependencies:
- '@cropper/element': 2.0.0-beta.5
- '@cropper/element-canvas': 2.0.0-beta.5
- '@cropper/element-selection': 2.0.0-beta.5
- '@cropper/utils': 2.0.0-beta.5
+ '@cropper/element': 2.0.0-rc.1
+ '@cropper/element-canvas': 2.0.0-rc.1
+ '@cropper/element-selection': 2.0.0-rc.1
+ '@cropper/utils': 2.0.0-rc.1
- '@cropper/element-viewer@2.0.0-beta.5':
+ '@cropper/element-viewer@2.0.0-rc.1':
dependencies:
- '@cropper/element': 2.0.0-beta.5
- '@cropper/element-canvas': 2.0.0-beta.5
- '@cropper/element-image': 2.0.0-beta.5
- '@cropper/element-selection': 2.0.0-beta.5
- '@cropper/utils': 2.0.0-beta.5
+ '@cropper/element': 2.0.0-rc.1
+ '@cropper/element-canvas': 2.0.0-rc.1
+ '@cropper/element-image': 2.0.0-rc.1
+ '@cropper/element-selection': 2.0.0-rc.1
+ '@cropper/utils': 2.0.0-rc.1
- '@cropper/element@2.0.0-beta.5':
+ '@cropper/element@2.0.0-rc.1':
dependencies:
- '@cropper/utils': 2.0.0-beta.5
+ '@cropper/utils': 2.0.0-rc.1
- '@cropper/elements@2.0.0-beta.5':
+ '@cropper/elements@2.0.0-rc.1':
dependencies:
- '@cropper/element': 2.0.0-beta.5
- '@cropper/element-canvas': 2.0.0-beta.5
- '@cropper/element-crosshair': 2.0.0-beta.5
- '@cropper/element-grid': 2.0.0-beta.5
- '@cropper/element-handle': 2.0.0-beta.5
- '@cropper/element-image': 2.0.0-beta.5
- '@cropper/element-selection': 2.0.0-beta.5
- '@cropper/element-shade': 2.0.0-beta.5
- '@cropper/element-viewer': 2.0.0-beta.5
+ '@cropper/element': 2.0.0-rc.1
+ '@cropper/element-canvas': 2.0.0-rc.1
+ '@cropper/element-crosshair': 2.0.0-rc.1
+ '@cropper/element-grid': 2.0.0-rc.1
+ '@cropper/element-handle': 2.0.0-rc.1
+ '@cropper/element-image': 2.0.0-rc.1
+ '@cropper/element-selection': 2.0.0-rc.1
+ '@cropper/element-shade': 2.0.0-rc.1
+ '@cropper/element-viewer': 2.0.0-rc.1
- '@cropper/utils@2.0.0-beta.5': {}
+ '@cropper/utils@2.0.0-rc.1': {}
'@cypress/request@3.0.0':
dependencies:
@@ -12927,7 +13617,7 @@ snapshots:
performance-now: 2.1.0
qs: 6.10.4
safe-buffer: 5.2.1
- tough-cookie: 4.1.3
+ tough-cookie: 4.1.4
tunnel-agent: 0.6.0
uuid: 8.3.2
@@ -12938,10 +13628,10 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@digitalbazaar/http-client@3.4.1(web-streams-polyfill@3.2.1)':
+ '@digitalbazaar/http-client@3.4.1(web-streams-polyfill@4.0.0)':
dependencies:
ky: 0.33.3
- ky-universal: 0.11.0(ky@0.33.3)(web-streams-polyfill@3.2.1)
+ ky-universal: 0.11.0(ky@0.33.3)(web-streams-polyfill@4.0.0)
undici: 5.28.2
transitivePeerDependencies:
- web-streams-polyfill
@@ -12957,7 +13647,7 @@ snapshots:
'@emnapi/runtime@1.1.1':
dependencies:
- tslib: 2.6.2
+ tslib: 2.6.3
optional: true
'@emotion/use-insertion-effect-with-fallbacks@1.0.1(react@18.3.1)':
@@ -12967,7 +13657,10 @@ snapshots:
'@esbuild/aix-ppc64@0.19.11':
optional: true
- '@esbuild/aix-ppc64@0.20.2':
+ '@esbuild/aix-ppc64@0.21.5':
+ optional: true
+
+ '@esbuild/aix-ppc64@0.23.0':
optional: true
'@esbuild/android-arm64@0.18.20':
@@ -12976,7 +13669,10 @@ snapshots:
'@esbuild/android-arm64@0.19.11':
optional: true
- '@esbuild/android-arm64@0.20.2':
+ '@esbuild/android-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/android-arm64@0.23.0':
optional: true
'@esbuild/android-arm@0.18.20':
@@ -12985,7 +13681,10 @@ snapshots:
'@esbuild/android-arm@0.19.11':
optional: true
- '@esbuild/android-arm@0.20.2':
+ '@esbuild/android-arm@0.21.5':
+ optional: true
+
+ '@esbuild/android-arm@0.23.0':
optional: true
'@esbuild/android-x64@0.18.20':
@@ -12994,7 +13693,10 @@ snapshots:
'@esbuild/android-x64@0.19.11':
optional: true
- '@esbuild/android-x64@0.20.2':
+ '@esbuild/android-x64@0.21.5':
+ optional: true
+
+ '@esbuild/android-x64@0.23.0':
optional: true
'@esbuild/darwin-arm64@0.18.20':
@@ -13003,7 +13705,10 @@ snapshots:
'@esbuild/darwin-arm64@0.19.11':
optional: true
- '@esbuild/darwin-arm64@0.20.2':
+ '@esbuild/darwin-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/darwin-arm64@0.23.0':
optional: true
'@esbuild/darwin-x64@0.18.20':
@@ -13012,7 +13717,10 @@ snapshots:
'@esbuild/darwin-x64@0.19.11':
optional: true
- '@esbuild/darwin-x64@0.20.2':
+ '@esbuild/darwin-x64@0.21.5':
+ optional: true
+
+ '@esbuild/darwin-x64@0.23.0':
optional: true
'@esbuild/freebsd-arm64@0.18.20':
@@ -13021,7 +13729,10 @@ snapshots:
'@esbuild/freebsd-arm64@0.19.11':
optional: true
- '@esbuild/freebsd-arm64@0.20.2':
+ '@esbuild/freebsd-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/freebsd-arm64@0.23.0':
optional: true
'@esbuild/freebsd-x64@0.18.20':
@@ -13030,7 +13741,10 @@ snapshots:
'@esbuild/freebsd-x64@0.19.11':
optional: true
- '@esbuild/freebsd-x64@0.20.2':
+ '@esbuild/freebsd-x64@0.21.5':
+ optional: true
+
+ '@esbuild/freebsd-x64@0.23.0':
optional: true
'@esbuild/linux-arm64@0.18.20':
@@ -13039,7 +13753,10 @@ snapshots:
'@esbuild/linux-arm64@0.19.11':
optional: true
- '@esbuild/linux-arm64@0.20.2':
+ '@esbuild/linux-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-arm64@0.23.0':
optional: true
'@esbuild/linux-arm@0.18.20':
@@ -13048,7 +13765,10 @@ snapshots:
'@esbuild/linux-arm@0.19.11':
optional: true
- '@esbuild/linux-arm@0.20.2':
+ '@esbuild/linux-arm@0.21.5':
+ optional: true
+
+ '@esbuild/linux-arm@0.23.0':
optional: true
'@esbuild/linux-ia32@0.18.20':
@@ -13057,7 +13777,10 @@ snapshots:
'@esbuild/linux-ia32@0.19.11':
optional: true
- '@esbuild/linux-ia32@0.20.2':
+ '@esbuild/linux-ia32@0.21.5':
+ optional: true
+
+ '@esbuild/linux-ia32@0.23.0':
optional: true
'@esbuild/linux-loong64@0.18.20':
@@ -13066,7 +13789,10 @@ snapshots:
'@esbuild/linux-loong64@0.19.11':
optional: true
- '@esbuild/linux-loong64@0.20.2':
+ '@esbuild/linux-loong64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-loong64@0.23.0':
optional: true
'@esbuild/linux-mips64el@0.18.20':
@@ -13075,7 +13801,10 @@ snapshots:
'@esbuild/linux-mips64el@0.19.11':
optional: true
- '@esbuild/linux-mips64el@0.20.2':
+ '@esbuild/linux-mips64el@0.21.5':
+ optional: true
+
+ '@esbuild/linux-mips64el@0.23.0':
optional: true
'@esbuild/linux-ppc64@0.18.20':
@@ -13084,7 +13813,10 @@ snapshots:
'@esbuild/linux-ppc64@0.19.11':
optional: true
- '@esbuild/linux-ppc64@0.20.2':
+ '@esbuild/linux-ppc64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-ppc64@0.23.0':
optional: true
'@esbuild/linux-riscv64@0.18.20':
@@ -13093,7 +13825,10 @@ snapshots:
'@esbuild/linux-riscv64@0.19.11':
optional: true
- '@esbuild/linux-riscv64@0.20.2':
+ '@esbuild/linux-riscv64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-riscv64@0.23.0':
optional: true
'@esbuild/linux-s390x@0.18.20':
@@ -13102,7 +13837,10 @@ snapshots:
'@esbuild/linux-s390x@0.19.11':
optional: true
- '@esbuild/linux-s390x@0.20.2':
+ '@esbuild/linux-s390x@0.21.5':
+ optional: true
+
+ '@esbuild/linux-s390x@0.23.0':
optional: true
'@esbuild/linux-x64@0.18.20':
@@ -13111,7 +13849,10 @@ snapshots:
'@esbuild/linux-x64@0.19.11':
optional: true
- '@esbuild/linux-x64@0.20.2':
+ '@esbuild/linux-x64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-x64@0.23.0':
optional: true
'@esbuild/netbsd-x64@0.18.20':
@@ -13120,7 +13861,13 @@ snapshots:
'@esbuild/netbsd-x64@0.19.11':
optional: true
- '@esbuild/netbsd-x64@0.20.2':
+ '@esbuild/netbsd-x64@0.21.5':
+ optional: true
+
+ '@esbuild/netbsd-x64@0.23.0':
+ optional: true
+
+ '@esbuild/openbsd-arm64@0.23.0':
optional: true
'@esbuild/openbsd-x64@0.18.20':
@@ -13129,7 +13876,10 @@ snapshots:
'@esbuild/openbsd-x64@0.19.11':
optional: true
- '@esbuild/openbsd-x64@0.20.2':
+ '@esbuild/openbsd-x64@0.21.5':
+ optional: true
+
+ '@esbuild/openbsd-x64@0.23.0':
optional: true
'@esbuild/sunos-x64@0.18.20':
@@ -13138,7 +13888,10 @@ snapshots:
'@esbuild/sunos-x64@0.19.11':
optional: true
- '@esbuild/sunos-x64@0.20.2':
+ '@esbuild/sunos-x64@0.21.5':
+ optional: true
+
+ '@esbuild/sunos-x64@0.23.0':
optional: true
'@esbuild/win32-arm64@0.18.20':
@@ -13147,7 +13900,10 @@ snapshots:
'@esbuild/win32-arm64@0.19.11':
optional: true
- '@esbuild/win32-arm64@0.20.2':
+ '@esbuild/win32-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/win32-arm64@0.23.0':
optional: true
'@esbuild/win32-ia32@0.18.20':
@@ -13156,7 +13912,10 @@ snapshots:
'@esbuild/win32-ia32@0.19.11':
optional: true
- '@esbuild/win32-ia32@0.20.2':
+ '@esbuild/win32-ia32@0.21.5':
+ optional: true
+
+ '@esbuild/win32-ia32@0.23.0':
optional: true
'@esbuild/win32-x64@0.18.20':
@@ -13165,30 +13924,38 @@ snapshots:
'@esbuild/win32-x64@0.19.11':
optional: true
- '@esbuild/win32-x64@0.20.2':
+ '@esbuild/win32-x64@0.21.5':
optional: true
- '@eslint-community/eslint-utils@4.4.0(eslint@8.53.0)':
- dependencies:
- eslint: 8.53.0
- eslint-visitor-keys: 3.4.3
+ '@esbuild/win32-x64@0.23.0':
+ optional: true
- '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)':
+ '@eslint-community/eslint-utils@4.4.0(eslint@9.8.0)':
dependencies:
- eslint: 8.57.0
+ eslint: 9.8.0
eslint-visitor-keys: 3.4.3
- '@eslint-community/regexpp@4.10.0': {}
+ '@eslint-community/regexpp@4.11.0': {}
'@eslint-community/regexpp@4.6.2': {}
- '@eslint/eslintrc@2.1.4':
+ '@eslint/compat@1.1.1': {}
+
+ '@eslint/config-array@0.17.1':
+ dependencies:
+ '@eslint/object-schema': 2.1.4
+ debug: 4.3.5(supports-color@8.1.1)
+ minimatch: 3.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@eslint/eslintrc@3.1.0':
dependencies:
ajv: 6.12.6
- debug: 4.3.4(supports-color@8.1.1)
- espree: 9.6.1
- globals: 13.19.0
- ignore: 5.2.4
+ debug: 4.3.5(supports-color@8.1.1)
+ espree: 10.1.0
+ globals: 14.0.0
+ ignore: 5.3.1
import-fresh: 3.3.0
js-yaml: 4.1.0
minimatch: 3.1.2
@@ -13196,9 +13963,9 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@eslint/js@8.53.0': {}
+ '@eslint/js@9.8.0': {}
- '@eslint/js@8.57.0': {}
+ '@eslint/object-schema@2.1.4': {}
'@fal-works/esbuild-plugin-global-externals@2.1.2': {}
@@ -13211,8 +13978,8 @@ snapshots:
'@fastify/ajv-compiler@3.5.0':
dependencies:
- ajv: 8.13.0
- ajv-formats: 2.1.1(ajv@8.13.0)
+ ajv: 8.17.1
+ ajv-formats: 2.1.1(ajv@8.17.1)
fast-uri: 2.2.0
'@fastify/busboy@2.1.0': {}
@@ -13247,12 +14014,12 @@ snapshots:
'@fastify/reply-from': 9.0.1
fast-querystring: 1.1.2
fastify-plugin: 4.5.0
- ws: 8.17.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
+ ws: 8.18.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
transitivePeerDependencies:
- bufferutil
- utf-8-validate
- '@fastify/multipart@8.2.0':
+ '@fastify/multipart@8.3.0':
dependencies:
'@fastify/busboy': 2.1.0
'@fastify/deepmerge': 1.3.0
@@ -13288,14 +14055,14 @@ snapshots:
glob: 8.1.0
p-limit: 3.1.0
- '@fastify/static@7.0.3':
+ '@fastify/static@7.0.4':
dependencies:
'@fastify/accept-negotiator': 1.0.0
'@fastify/send': 2.0.1
content-disposition: 0.5.4
fastify-plugin: 4.5.0
fastq: 1.17.1
- glob: 10.3.12
+ glob: 10.4.2
'@fastify/view@8.2.0':
dependencies:
@@ -13311,13 +14078,11 @@ snapshots:
'@hapi/boom@10.0.1':
dependencies:
- '@hapi/hoek': 11.0.2
+ '@hapi/hoek': 11.0.4
'@hapi/bourne@3.0.0': {}
- '@hapi/hoek@10.0.1': {}
-
- '@hapi/hoek@11.0.2': {}
+ '@hapi/hoek@11.0.4': {}
'@hapi/hoek@9.3.0': {}
@@ -13329,40 +14094,22 @@ snapshots:
dependencies:
'@hapi/boom': 10.0.1
'@hapi/bourne': 3.0.0
- '@hapi/hoek': 11.0.2
+ '@hapi/hoek': 11.0.4
'@hexagon/base64@1.1.27': {}
- '@humanwhocodes/config-array@0.11.13':
- dependencies:
- '@humanwhocodes/object-schema': 2.0.1
- debug: 4.3.4(supports-color@8.1.1)
- minimatch: 3.1.2
- transitivePeerDependencies:
- - supports-color
-
- '@humanwhocodes/config-array@0.11.14':
- dependencies:
- '@humanwhocodes/object-schema': 2.0.2
- debug: 4.3.4(supports-color@8.1.1)
- minimatch: 3.1.2
- transitivePeerDependencies:
- - supports-color
-
'@humanwhocodes/module-importer@1.0.1': {}
'@humanwhocodes/momoa@2.0.4': {}
- '@humanwhocodes/object-schema@2.0.1': {}
+ '@humanwhocodes/retry@0.3.0': {}
- '@humanwhocodes/object-schema@2.0.2': {}
-
- '@img/sharp-darwin-arm64@0.33.3':
+ '@img/sharp-darwin-arm64@0.33.4':
optionalDependencies:
'@img/sharp-libvips-darwin-arm64': 1.0.2
optional: true
- '@img/sharp-darwin-x64@0.33.3':
+ '@img/sharp-darwin-x64@0.33.4':
optionalDependencies:
'@img/sharp-libvips-darwin-x64': 1.0.2
optional: true
@@ -13391,45 +14138,45 @@ snapshots:
'@img/sharp-libvips-linuxmusl-x64@1.0.2':
optional: true
- '@img/sharp-linux-arm64@0.33.3':
+ '@img/sharp-linux-arm64@0.33.4':
optionalDependencies:
'@img/sharp-libvips-linux-arm64': 1.0.2
optional: true
- '@img/sharp-linux-arm@0.33.3':
+ '@img/sharp-linux-arm@0.33.4':
optionalDependencies:
'@img/sharp-libvips-linux-arm': 1.0.2
optional: true
- '@img/sharp-linux-s390x@0.33.3':
+ '@img/sharp-linux-s390x@0.33.4':
optionalDependencies:
'@img/sharp-libvips-linux-s390x': 1.0.2
optional: true
- '@img/sharp-linux-x64@0.33.3':
+ '@img/sharp-linux-x64@0.33.4':
optionalDependencies:
'@img/sharp-libvips-linux-x64': 1.0.2
optional: true
- '@img/sharp-linuxmusl-arm64@0.33.3':
+ '@img/sharp-linuxmusl-arm64@0.33.4':
optionalDependencies:
'@img/sharp-libvips-linuxmusl-arm64': 1.0.2
optional: true
- '@img/sharp-linuxmusl-x64@0.33.3':
+ '@img/sharp-linuxmusl-x64@0.33.4':
optionalDependencies:
'@img/sharp-libvips-linuxmusl-x64': 1.0.2
optional: true
- '@img/sharp-wasm32@0.33.3':
+ '@img/sharp-wasm32@0.33.4':
dependencies:
'@emnapi/runtime': 1.1.1
optional: true
- '@img/sharp-win32-ia32@0.33.3':
+ '@img/sharp-win32-ia32@0.33.4':
optional: true
- '@img/sharp-win32-x64@0.33.3':
+ '@img/sharp-win32-x64@0.33.4':
optional: true
'@inquirer/confirm@3.1.6':
@@ -13442,7 +14189,7 @@ snapshots:
'@inquirer/figures': 1.0.1
'@inquirer/type': 1.3.1
'@types/mute-stream': 0.0.4
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
'@types/wrap-ansi': 3.0.0
ansi-escapes: 4.3.2
chalk: 4.1.2
@@ -13465,7 +14212,7 @@ snapshots:
'@intlify/message-compiler@9.13.1':
dependencies:
'@intlify/shared': 9.13.1
- source-map-js: 1.0.2
+ source-map-js: 1.2.0
'@intlify/shared@9.13.1': {}
@@ -13493,7 +14240,7 @@ snapshots:
'@jest/console@29.7.0':
dependencies:
'@jest/types': 29.6.3
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
chalk: 4.1.2
jest-message-util: 29.7.0
jest-util: 29.7.0
@@ -13506,14 +14253,14 @@ snapshots:
'@jest/test-result': 29.7.0
'@jest/transform': 29.7.0
'@jest/types': 29.6.3
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
ansi-escapes: 4.3.2
chalk: 4.1.2
ci-info: 3.7.1
exit: 0.1.2
graceful-fs: 4.2.11
jest-changed-files: 29.7.0
- jest-config: 29.7.0(@types/node@20.12.7)
+ jest-config: 29.7.0(@types/node@20.14.12)
jest-haste-map: 29.7.0
jest-message-util: 29.7.0
jest-regex-util: 29.6.3
@@ -13525,7 +14272,7 @@ snapshots:
jest-util: 29.7.0
jest-validate: 29.7.0
jest-watcher: 29.7.0
- micromatch: 4.0.5
+ micromatch: 4.0.7
pretty-format: 29.7.0
slash: 3.0.0
strip-ansi: 6.0.1
@@ -13542,7 +14289,7 @@ snapshots:
dependencies:
'@jest/fake-timers': 29.7.0
'@jest/types': 29.6.3
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
jest-mock: 29.7.0
'@jest/expect-utils@29.7.0':
@@ -13560,7 +14307,7 @@ snapshots:
dependencies:
'@jest/types': 29.6.3
'@sinonjs/fake-timers': 10.3.0
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
jest-message-util: 29.7.0
jest-mock: 29.7.0
jest-util: 29.7.0
@@ -13582,7 +14329,7 @@ snapshots:
'@jest/transform': 29.7.0
'@jest/types': 29.6.3
'@jridgewell/trace-mapping': 0.3.18
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
chalk: 4.1.2
collect-v8-coverage: 1.0.1
exit: 0.1.2
@@ -13629,7 +14376,7 @@ snapshots:
'@jest/transform@29.7.0':
dependencies:
- '@babel/core': 7.23.5
+ '@babel/core': 7.24.7
'@jest/types': 29.6.3
'@jridgewell/trace-mapping': 0.3.18
babel-plugin-istanbul: 6.1.1
@@ -13640,7 +14387,7 @@ snapshots:
jest-haste-map: 29.7.0
jest-regex-util: 29.6.3
jest-util: 29.7.0
- micromatch: 4.0.5
+ micromatch: 4.0.7
pirates: 4.0.5
slash: 3.0.0
write-file-atomic: 4.0.2
@@ -13652,19 +14399,19 @@ snapshots:
'@jest/schemas': 29.6.3
'@types/istanbul-lib-coverage': 2.0.4
'@types/istanbul-reports': 3.0.1
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
'@types/yargs': 17.0.19
chalk: 4.1.2
- '@joshwooding/vite-plugin-react-docgen-typescript@0.3.0(typescript@5.4.5)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))':
+ '@joshwooding/vite-plugin-react-docgen-typescript@0.3.1(typescript@5.5.4)(vite@5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3))':
dependencies:
glob: 7.2.3
glob-promise: 4.2.2(glob@7.2.3)
magic-string: 0.27.0
- react-docgen-typescript: 2.2.2(typescript@5.4.5)
- vite: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3)
+ react-docgen-typescript: 2.2.2(typescript@5.5.4)
+ vite: 5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3)
optionalDependencies:
- typescript: 5.4.5
+ typescript: 5.5.4
'@jridgewell/gen-mapping@0.3.2':
dependencies:
@@ -13672,14 +14419,22 @@ snapshots:
'@jridgewell/sourcemap-codec': 1.4.15
'@jridgewell/trace-mapping': 0.3.18
+ '@jridgewell/gen-mapping@0.3.5':
+ dependencies:
+ '@jridgewell/set-array': 1.2.1
+ '@jridgewell/sourcemap-codec': 1.4.15
+ '@jridgewell/trace-mapping': 0.3.25
+
'@jridgewell/resolve-uri@3.1.0': {}
'@jridgewell/set-array@1.1.2': {}
- '@jridgewell/source-map@0.3.5':
+ '@jridgewell/set-array@1.2.1': {}
+
+ '@jridgewell/source-map@0.3.6':
dependencies:
- '@jridgewell/gen-mapping': 0.3.2
- '@jridgewell/trace-mapping': 0.3.18
+ '@jridgewell/gen-mapping': 0.3.5
+ '@jridgewell/trace-mapping': 0.3.25
'@jridgewell/sourcemap-codec@1.4.14': {}
@@ -13690,6 +14445,11 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.0
'@jridgewell/sourcemap-codec': 1.4.14
+ '@jridgewell/trace-mapping@0.3.25':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.0
+ '@jridgewell/sourcemap-codec': 1.4.15
+
'@jsdevtools/ono@7.1.3': {}
'@kurkle/color@0.3.2': {}
@@ -13702,14 +14462,14 @@ snapshots:
'@mapbox/node-pre-gyp@1.0.9(encoding@0.1.13)':
dependencies:
- detect-libc: 2.0.2
+ detect-libc: 2.0.3
https-proxy-agent: 5.0.1
make-dir: 3.1.0
node-fetch: 2.7.0(encoding@0.1.13)
nopt: 5.0.0
npmlog: 5.0.1
rimraf: 3.0.2
- semver: 7.5.4
+ semver: 7.6.0
tar: 6.2.1
transitivePeerDependencies:
- encoding
@@ -13728,23 +14488,23 @@ snapshots:
'@types/react': 18.0.28
react: 18.3.1
- '@microsoft/api-extractor-model@7.28.14(@types/node@20.12.7)':
+ '@microsoft/api-extractor-model@7.29.4(@types/node@20.14.12)':
dependencies:
- '@microsoft/tsdoc': 0.14.2
- '@microsoft/tsdoc-config': 0.16.2
- '@rushstack/node-core-library': 4.1.0(@types/node@20.12.7)
+ '@microsoft/tsdoc': 0.15.0
+ '@microsoft/tsdoc-config': 0.17.0
+ '@rushstack/node-core-library': 5.5.1(@types/node@20.14.12)
transitivePeerDependencies:
- '@types/node'
- '@microsoft/api-extractor@7.43.1(@types/node@20.12.7)':
+ '@microsoft/api-extractor@7.47.4(@types/node@20.14.12)':
dependencies:
- '@microsoft/api-extractor-model': 7.28.14(@types/node@20.12.7)
- '@microsoft/tsdoc': 0.14.2
- '@microsoft/tsdoc-config': 0.16.2
- '@rushstack/node-core-library': 4.1.0(@types/node@20.12.7)
- '@rushstack/rig-package': 0.5.2
- '@rushstack/terminal': 0.10.1(@types/node@20.12.7)
- '@rushstack/ts-command-line': 4.19.2(@types/node@20.12.7)
+ '@microsoft/api-extractor-model': 7.29.4(@types/node@20.14.12)
+ '@microsoft/tsdoc': 0.15.0
+ '@microsoft/tsdoc-config': 0.17.0
+ '@rushstack/node-core-library': 5.5.1(@types/node@20.14.12)
+ '@rushstack/rig-package': 0.5.3
+ '@rushstack/terminal': 0.13.3(@types/node@20.14.12)
+ '@rushstack/ts-command-line': 4.22.3(@types/node@20.14.12)
lodash: 4.17.21
minimatch: 3.0.8
resolve: 1.22.8
@@ -13754,43 +14514,31 @@ snapshots:
transitivePeerDependencies:
- '@types/node'
- '@microsoft/tsdoc-config@0.16.2':
+ '@microsoft/tsdoc-config@0.17.0':
dependencies:
- '@microsoft/tsdoc': 0.14.2
- ajv: 6.12.6
+ '@microsoft/tsdoc': 0.15.0
+ ajv: 8.12.0
jju: 1.4.0
- resolve: 1.19.0
+ resolve: 1.22.8
- '@microsoft/tsdoc@0.14.2': {}
+ '@microsoft/tsdoc@0.15.0': {}
'@misskey-dev/browser-image-resizer@2024.1.0': {}
- '@misskey-dev/eslint-plugin@1.0.0(@typescript-eslint/eslint-plugin@6.11.0(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0)(typescript@5.3.3))(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0))(eslint@8.53.0)':
- dependencies:
- '@typescript-eslint/eslint-plugin': 6.11.0(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0)(typescript@5.3.3)
- '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.3.3)
- eslint: 8.53.0
- eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0)
-
- '@misskey-dev/eslint-plugin@1.0.0(@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3))(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0))(eslint@8.57.0)':
+ '@misskey-dev/eslint-plugin@2.0.2(@eslint/compat@1.1.1)(@typescript-eslint/eslint-plugin@7.17.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.5.4))(eslint@9.8.0)(typescript@5.5.4))(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.5.4))(eslint@9.8.0))(eslint@9.8.0)(globals@15.8.0)':
dependencies:
- '@typescript-eslint/eslint-plugin': 7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3)
- '@typescript-eslint/parser': 7.1.0(eslint@8.57.0)(typescript@5.3.3)
- eslint: 8.57.0
- eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)
-
- '@misskey-dev/eslint-plugin@1.0.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0)':
- dependencies:
- '@typescript-eslint/eslint-plugin': 7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
- '@typescript-eslint/parser': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
- eslint: 8.57.0
- eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)
+ '@eslint/compat': 1.1.1
+ '@typescript-eslint/eslint-plugin': 7.17.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.5.4))(eslint@9.8.0)(typescript@5.5.4)
+ '@typescript-eslint/parser': 7.17.0(eslint@9.8.0)(typescript@5.5.4)
+ eslint: 9.8.0
+ eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.5.4))(eslint@9.8.0)
+ globals: 15.8.0
'@misskey-dev/sharp-read-bmp@1.2.0':
dependencies:
decode-bmp: 0.2.1
decode-ico: 0.4.1
- sharp: 0.33.3
+ sharp: 0.33.4
'@misskey-dev/summaly@5.1.0':
dependencies:
@@ -13832,9 +14580,7 @@ snapshots:
'@msgpackr-extract/msgpackr-extract-win32-x64@3.0.2':
optional: true
- '@mswjs/cookies@1.1.0': {}
-
- '@mswjs/interceptors@0.26.15':
+ '@mswjs/interceptors@0.29.1':
dependencies:
'@open-draft/deferred-promise': 2.2.0
'@open-draft/logger': 0.3.0
@@ -13843,94 +14589,90 @@ snapshots:
outvariant: 1.4.2
strict-event-emitter: 0.5.1
- '@napi-rs/canvas-android-arm64@0.1.52':
+ '@napi-rs/canvas-android-arm64@0.1.53':
optional: true
- '@napi-rs/canvas-darwin-arm64@0.1.52':
+ '@napi-rs/canvas-darwin-arm64@0.1.53':
optional: true
- '@napi-rs/canvas-darwin-x64@0.1.52':
+ '@napi-rs/canvas-darwin-x64@0.1.53':
optional: true
- '@napi-rs/canvas-linux-arm-gnueabihf@0.1.52':
+ '@napi-rs/canvas-linux-arm-gnueabihf@0.1.53':
optional: true
- '@napi-rs/canvas-linux-arm64-gnu@0.1.52':
+ '@napi-rs/canvas-linux-arm64-gnu@0.1.53':
optional: true
- '@napi-rs/canvas-linux-arm64-musl@0.1.52':
+ '@napi-rs/canvas-linux-arm64-musl@0.1.53':
optional: true
- '@napi-rs/canvas-linux-x64-gnu@0.1.52':
+ '@napi-rs/canvas-linux-x64-gnu@0.1.53':
optional: true
- '@napi-rs/canvas-linux-x64-musl@0.1.52':
+ '@napi-rs/canvas-linux-x64-musl@0.1.53':
optional: true
- '@napi-rs/canvas-win32-x64-msvc@0.1.52':
+ '@napi-rs/canvas-win32-x64-msvc@0.1.53':
optional: true
- '@napi-rs/canvas@0.1.52':
+ '@napi-rs/canvas@0.1.53':
optionalDependencies:
- '@napi-rs/canvas-android-arm64': 0.1.52
- '@napi-rs/canvas-darwin-arm64': 0.1.52
- '@napi-rs/canvas-darwin-x64': 0.1.52
- '@napi-rs/canvas-linux-arm-gnueabihf': 0.1.52
- '@napi-rs/canvas-linux-arm64-gnu': 0.1.52
- '@napi-rs/canvas-linux-arm64-musl': 0.1.52
- '@napi-rs/canvas-linux-x64-gnu': 0.1.52
- '@napi-rs/canvas-linux-x64-musl': 0.1.52
- '@napi-rs/canvas-win32-x64-msvc': 0.1.52
+ '@napi-rs/canvas-android-arm64': 0.1.53
+ '@napi-rs/canvas-darwin-arm64': 0.1.53
+ '@napi-rs/canvas-darwin-x64': 0.1.53
+ '@napi-rs/canvas-linux-arm-gnueabihf': 0.1.53
+ '@napi-rs/canvas-linux-arm64-gnu': 0.1.53
+ '@napi-rs/canvas-linux-arm64-musl': 0.1.53
+ '@napi-rs/canvas-linux-x64-gnu': 0.1.53
+ '@napi-rs/canvas-linux-x64-musl': 0.1.53
+ '@napi-rs/canvas-win32-x64-msvc': 0.1.53
- '@ndelangen/get-tarball@3.0.7':
- dependencies:
- gunzip-maybe: 1.4.2
- pump: 3.0.0
- tar-fs: 2.1.1
-
- '@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1)':
+ '@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1)':
dependencies:
iterare: 1.2.1
reflect-metadata: 0.2.2
rxjs: 7.8.1
- tslib: 2.6.2
+ tslib: 2.6.3
uid: 2.0.2
- '@nestjs/core@10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1)':
+ '@nestjs/core@10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.10)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1)':
dependencies:
- '@nestjs/common': 10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/common': 10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1)
'@nuxtjs/opencollective': 0.3.2(encoding@0.1.13)
fast-safe-stringify: 2.1.1
iterare: 1.2.1
path-to-regexp: 3.2.0
reflect-metadata: 0.2.2
rxjs: 7.8.1
- tslib: 2.6.2
+ tslib: 2.6.3
uid: 2.0.2
optionalDependencies:
- '@nestjs/platform-express': 10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8)
+ '@nestjs/platform-express': 10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.10)
transitivePeerDependencies:
- encoding
- '@nestjs/platform-express@10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8)':
+ '@nestjs/platform-express@10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.10)':
dependencies:
- '@nestjs/common': 10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1)
- '@nestjs/core': 10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/common': 10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/core': 10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.10)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1)
body-parser: 1.20.2
cors: 2.8.5
express: 4.19.2
multer: 1.4.4-lts.1
- tslib: 2.6.2
+ tslib: 2.6.3
transitivePeerDependencies:
- supports-color
- '@nestjs/testing@10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8))':
+ '@nestjs/testing@10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.10)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.10))':
dependencies:
- '@nestjs/common': 10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1)
- '@nestjs/core': 10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1)
- tslib: 2.6.2
+ '@nestjs/common': 10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/core': 10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.10)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ tslib: 2.6.3
optionalDependencies:
- '@nestjs/platform-express': 10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8)
+ '@nestjs/platform-express': 10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.10)
+
+ '@noble/hashes@1.4.0': {}
'@nodelib/fs.scandir@2.1.5':
dependencies:
@@ -13942,14 +14684,14 @@ snapshots:
'@nodelib/fs.walk@1.2.8':
dependencies:
'@nodelib/fs.scandir': 2.1.5
- fastq: 1.15.0
+ fastq: 1.17.1
'@npmcli/agent@2.2.0':
dependencies:
agent-base: 7.1.0
- http-proxy-agent: 7.0.0
- https-proxy-agent: 7.0.2
- lru-cache: 10.0.2
+ http-proxy-agent: 7.0.2
+ https-proxy-agent: 7.0.4
+ lru-cache: 10.2.2
socks-proxy-agent: 8.0.2
transitivePeerDependencies:
- supports-color
@@ -13991,155 +14733,167 @@ snapshots:
'@open-draft/until@2.1.0': {}
- '@opentelemetry/api-logs@0.51.1':
+ '@opentelemetry/api-logs@0.52.1':
dependencies:
- '@opentelemetry/api': 1.8.0
+ '@opentelemetry/api': 1.9.0
- '@opentelemetry/api@1.8.0': {}
+ '@opentelemetry/api@1.9.0': {}
- '@opentelemetry/context-async-hooks@1.24.1(@opentelemetry/api@1.8.0)':
+ '@opentelemetry/context-async-hooks@1.25.1(@opentelemetry/api@1.9.0)':
dependencies:
- '@opentelemetry/api': 1.8.0
+ '@opentelemetry/api': 1.9.0
- '@opentelemetry/core@1.24.1(@opentelemetry/api@1.8.0)':
+ '@opentelemetry/core@1.24.1(@opentelemetry/api@1.9.0)':
dependencies:
- '@opentelemetry/api': 1.8.0
+ '@opentelemetry/api': 1.9.0
'@opentelemetry/semantic-conventions': 1.24.1
- '@opentelemetry/instrumentation-connect@0.36.0(@opentelemetry/api@1.8.0)':
+ '@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0)':
dependencies:
- '@opentelemetry/api': 1.8.0
- '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/semantic-conventions': 1.24.1
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/semantic-conventions': 1.25.1
+
+ '@opentelemetry/instrumentation-connect@0.38.0(@opentelemetry/api@1.9.0)':
+ dependencies:
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/semantic-conventions': 1.25.1
'@types/connect': 3.4.36
transitivePeerDependencies:
- supports-color
- '@opentelemetry/instrumentation-express@0.39.0(@opentelemetry/api@1.8.0)':
+ '@opentelemetry/instrumentation-express@0.41.0(@opentelemetry/api@1.9.0)':
dependencies:
- '@opentelemetry/api': 1.8.0
- '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/semantic-conventions': 1.24.1
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/semantic-conventions': 1.25.1
transitivePeerDependencies:
- supports-color
- '@opentelemetry/instrumentation-fastify@0.36.1(@opentelemetry/api@1.8.0)':
+ '@opentelemetry/instrumentation-fastify@0.38.0(@opentelemetry/api@1.9.0)':
dependencies:
- '@opentelemetry/api': 1.8.0
- '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/semantic-conventions': 1.24.1
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/semantic-conventions': 1.25.1
transitivePeerDependencies:
- supports-color
- '@opentelemetry/instrumentation-graphql@0.40.0(@opentelemetry/api@1.8.0)':
+ '@opentelemetry/instrumentation-graphql@0.42.0(@opentelemetry/api@1.9.0)':
dependencies:
- '@opentelemetry/api': 1.8.0
- '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0)
transitivePeerDependencies:
- supports-color
- '@opentelemetry/instrumentation-hapi@0.38.0(@opentelemetry/api@1.8.0)':
+ '@opentelemetry/instrumentation-hapi@0.40.0(@opentelemetry/api@1.9.0)':
dependencies:
- '@opentelemetry/api': 1.8.0
- '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/semantic-conventions': 1.24.1
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/semantic-conventions': 1.25.1
transitivePeerDependencies:
- supports-color
- '@opentelemetry/instrumentation-http@0.51.1(@opentelemetry/api@1.8.0)':
+ '@opentelemetry/instrumentation-http@0.52.1(@opentelemetry/api@1.9.0)':
dependencies:
- '@opentelemetry/api': 1.8.0
- '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/semantic-conventions': 1.24.1
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/semantic-conventions': 1.25.1
semver: 7.6.0
transitivePeerDependencies:
- supports-color
- '@opentelemetry/instrumentation-ioredis@0.40.0(@opentelemetry/api@1.8.0)':
+ '@opentelemetry/instrumentation-ioredis@0.42.0(@opentelemetry/api@1.9.0)':
dependencies:
- '@opentelemetry/api': 1.8.0
- '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0)
'@opentelemetry/redis-common': 0.36.2
- '@opentelemetry/semantic-conventions': 1.24.1
+ '@opentelemetry/semantic-conventions': 1.25.1
transitivePeerDependencies:
- supports-color
- '@opentelemetry/instrumentation-koa@0.40.0(@opentelemetry/api@1.8.0)':
+ '@opentelemetry/instrumentation-koa@0.42.0(@opentelemetry/api@1.9.0)':
dependencies:
- '@opentelemetry/api': 1.8.0
- '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/semantic-conventions': 1.24.1
- '@types/koa': 2.14.0
- '@types/koa__router': 12.0.3
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/semantic-conventions': 1.25.1
transitivePeerDependencies:
- supports-color
- '@opentelemetry/instrumentation-mongodb@0.43.0(@opentelemetry/api@1.8.0)':
+ '@opentelemetry/instrumentation-mongodb@0.46.0(@opentelemetry/api@1.9.0)':
dependencies:
- '@opentelemetry/api': 1.8.0
- '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/sdk-metrics': 1.24.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/semantic-conventions': 1.24.1
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/sdk-metrics': 1.24.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/semantic-conventions': 1.25.1
transitivePeerDependencies:
- supports-color
- '@opentelemetry/instrumentation-mongoose@0.38.1(@opentelemetry/api@1.8.0)':
+ '@opentelemetry/instrumentation-mongoose@0.40.0(@opentelemetry/api@1.9.0)':
dependencies:
- '@opentelemetry/api': 1.8.0
- '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/semantic-conventions': 1.24.1
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/semantic-conventions': 1.25.1
transitivePeerDependencies:
- supports-color
- '@opentelemetry/instrumentation-mysql2@0.38.1(@opentelemetry/api@1.8.0)':
+ '@opentelemetry/instrumentation-mysql2@0.40.0(@opentelemetry/api@1.9.0)':
dependencies:
- '@opentelemetry/api': 1.8.0
- '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/semantic-conventions': 1.24.1
- '@opentelemetry/sql-common': 0.40.1(@opentelemetry/api@1.8.0)
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/semantic-conventions': 1.25.1
+ '@opentelemetry/sql-common': 0.40.1(@opentelemetry/api@1.9.0)
transitivePeerDependencies:
- supports-color
- '@opentelemetry/instrumentation-mysql@0.38.1(@opentelemetry/api@1.8.0)':
+ '@opentelemetry/instrumentation-mysql@0.40.0(@opentelemetry/api@1.9.0)':
dependencies:
- '@opentelemetry/api': 1.8.0
- '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/semantic-conventions': 1.24.1
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/semantic-conventions': 1.25.1
'@types/mysql': 2.15.22
transitivePeerDependencies:
- supports-color
- '@opentelemetry/instrumentation-nestjs-core@0.37.1(@opentelemetry/api@1.8.0)':
+ '@opentelemetry/instrumentation-nestjs-core@0.39.0(@opentelemetry/api@1.9.0)':
dependencies:
- '@opentelemetry/api': 1.8.0
- '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/semantic-conventions': 1.24.1
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/semantic-conventions': 1.25.1
transitivePeerDependencies:
- supports-color
- '@opentelemetry/instrumentation-pg@0.41.0(@opentelemetry/api@1.8.0)':
+ '@opentelemetry/instrumentation-pg@0.43.0(@opentelemetry/api@1.9.0)':
dependencies:
- '@opentelemetry/api': 1.8.0
- '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/semantic-conventions': 1.24.1
- '@opentelemetry/sql-common': 0.40.1(@opentelemetry/api@1.8.0)
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/semantic-conventions': 1.25.1
+ '@opentelemetry/sql-common': 0.40.1(@opentelemetry/api@1.9.0)
'@types/pg': 8.6.1
'@types/pg-pool': 2.0.4
transitivePeerDependencies:
- supports-color
- '@opentelemetry/instrumentation@0.43.0(@opentelemetry/api@1.8.0)':
+ '@opentelemetry/instrumentation-redis-4@0.41.0(@opentelemetry/api@1.9.0)':
+ dependencies:
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/redis-common': 0.36.2
+ '@opentelemetry/semantic-conventions': 1.25.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@opentelemetry/instrumentation@0.46.0(@opentelemetry/api@1.9.0)':
dependencies:
- '@opentelemetry/api': 1.8.0
+ '@opentelemetry/api': 1.9.0
'@types/shimmer': 1.0.5
- import-in-the-middle: 1.4.2
+ import-in-the-middle: 1.7.1
require-in-the-middle: 7.3.0
semver: 7.6.0
shimmer: 1.2.1
@@ -14147,12 +14901,12 @@ snapshots:
- supports-color
optional: true
- '@opentelemetry/instrumentation@0.51.1(@opentelemetry/api@1.8.0)':
+ '@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0)':
dependencies:
- '@opentelemetry/api': 1.8.0
- '@opentelemetry/api-logs': 0.51.1
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/api-logs': 0.52.1
'@types/shimmer': 1.0.5
- import-in-the-middle: 1.7.4
+ import-in-the-middle: 1.10.0
require-in-the-middle: 7.3.0
semver: 7.6.0
shimmer: 1.2.1
@@ -14161,58 +14915,66 @@ snapshots:
'@opentelemetry/redis-common@0.36.2': {}
- '@opentelemetry/resources@1.24.1(@opentelemetry/api@1.8.0)':
+ '@opentelemetry/resources@1.24.1(@opentelemetry/api@1.9.0)':
dependencies:
- '@opentelemetry/api': 1.8.0
- '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.9.0)
'@opentelemetry/semantic-conventions': 1.24.1
- '@opentelemetry/sdk-metrics@1.24.1(@opentelemetry/api@1.8.0)':
+ '@opentelemetry/resources@1.25.1(@opentelemetry/api@1.9.0)':
+ dependencies:
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/semantic-conventions': 1.25.1
+
+ '@opentelemetry/sdk-metrics@1.24.1(@opentelemetry/api@1.9.0)':
dependencies:
- '@opentelemetry/api': 1.8.0
- '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/resources': 1.24.1(@opentelemetry/api@1.8.0)
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/resources': 1.24.1(@opentelemetry/api@1.9.0)
lodash.merge: 4.6.2
- '@opentelemetry/sdk-trace-base@1.24.1(@opentelemetry/api@1.8.0)':
+ '@opentelemetry/sdk-trace-base@1.25.1(@opentelemetry/api@1.9.0)':
dependencies:
- '@opentelemetry/api': 1.8.0
- '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/resources': 1.24.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/semantic-conventions': 1.24.1
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/resources': 1.25.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/semantic-conventions': 1.25.1
'@opentelemetry/semantic-conventions@1.24.1': {}
- '@opentelemetry/sql-common@0.40.1(@opentelemetry/api@1.8.0)':
+ '@opentelemetry/semantic-conventions@1.25.1': {}
+
+ '@opentelemetry/sql-common@0.40.1(@opentelemetry/api@1.9.0)':
dependencies:
- '@opentelemetry/api': 1.8.0
- '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0)
'@peculiar/asn1-android@2.3.10':
dependencies:
'@peculiar/asn1-schema': 2.3.8
asn1js: 3.0.5
- tslib: 2.6.2
+ tslib: 2.6.3
'@peculiar/asn1-ecc@2.3.8':
dependencies:
'@peculiar/asn1-schema': 2.3.8
'@peculiar/asn1-x509': 2.3.8
asn1js: 3.0.5
- tslib: 2.6.2
+ tslib: 2.6.3
'@peculiar/asn1-rsa@2.3.8':
dependencies:
'@peculiar/asn1-schema': 2.3.8
'@peculiar/asn1-x509': 2.3.8
asn1js: 3.0.5
- tslib: 2.6.2
+ tslib: 2.6.3
'@peculiar/asn1-schema@2.3.8':
dependencies:
asn1js: 3.0.5
pvtsutils: 1.3.5
- tslib: 2.6.2
+ tslib: 2.6.3
'@peculiar/asn1-x509@2.3.8':
dependencies:
@@ -14220,7 +14982,7 @@ snapshots:
asn1js: 3.0.5
ipaddr.js: 2.2.0
pvtsutils: 1.3.5
- tslib: 2.6.2
+ tslib: 2.6.3
'@peertube/http-signature@1.7.0':
dependencies:
@@ -14231,35 +14993,20 @@ snapshots:
'@pkgjs/parseargs@0.11.0':
optional: true
- '@prisma/instrumentation@5.14.0':
+ '@prisma/instrumentation@5.17.0':
dependencies:
- '@opentelemetry/api': 1.8.0
- '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/sdk-trace-base': 1.24.1(@opentelemetry/api@1.8.0)
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.0)
transitivePeerDependencies:
- supports-color
- '@radix-ui/react-compose-refs@1.0.1(@types/react@18.0.28)(react@18.3.1)':
- dependencies:
- '@babel/runtime': 7.23.4
- react: 18.3.1
- optionalDependencies:
- '@types/react': 18.0.28
-
- '@radix-ui/react-slot@1.0.2(@types/react@18.0.28)(react@18.3.1)':
- dependencies:
- '@babel/runtime': 7.23.4
- '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.0.28)(react@18.3.1)
- react: 18.3.1
- optionalDependencies:
- '@types/react': 18.0.28
-
- '@readme/better-ajv-errors@1.6.0(ajv@8.13.0)':
+ '@readme/better-ajv-errors@1.6.0(ajv@8.17.1)':
dependencies:
'@babel/code-frame': 7.23.5
'@babel/runtime': 7.23.4
'@humanwhocodes/momoa': 2.0.4
- ajv: 8.13.0
+ ajv: 8.17.1
chalk: 4.1.2
json-to-ast: 2.1.0
jsonpointer: 5.0.1
@@ -14277,181 +15024,189 @@ snapshots:
'@apidevtools/openapi-schemas': 2.1.0
'@apidevtools/swagger-methods': 3.0.2
'@jsdevtools/ono': 7.1.3
- '@readme/better-ajv-errors': 1.6.0(ajv@8.13.0)
+ '@readme/better-ajv-errors': 1.6.0(ajv@8.17.1)
'@readme/json-schema-ref-parser': 1.2.0
- ajv: 8.13.0
- ajv-draft-04: 1.0.0(ajv@8.13.0)
+ ajv: 8.17.1
+ ajv-draft-04: 1.0.0(ajv@8.17.1)
call-me-maybe: 1.0.2
openapi-types: 12.1.3
- '@rollup/plugin-json@6.1.0(rollup@4.17.2)':
+ '@rollup/plugin-json@6.1.0(rollup@4.19.1)':
dependencies:
- '@rollup/pluginutils': 5.1.0(rollup@4.17.2)
+ '@rollup/pluginutils': 5.1.0(rollup@4.19.1)
optionalDependencies:
- rollup: 4.17.2
+ rollup: 4.19.1
- '@rollup/plugin-replace@5.0.5(rollup@4.17.2)':
+ '@rollup/plugin-replace@5.0.7(rollup@4.19.1)':
dependencies:
- '@rollup/pluginutils': 5.1.0(rollup@4.17.2)
- magic-string: 0.30.7
+ '@rollup/pluginutils': 5.1.0(rollup@4.19.1)
+ magic-string: 0.30.10
optionalDependencies:
- rollup: 4.17.2
+ rollup: 4.19.1
- '@rollup/pluginutils@5.1.0(rollup@4.17.2)':
+ '@rollup/pluginutils@5.1.0(rollup@4.19.1)':
dependencies:
'@types/estree': 1.0.5
estree-walker: 2.0.2
picomatch: 2.3.1
optionalDependencies:
- rollup: 4.17.2
+ rollup: 4.19.1
- '@rollup/rollup-android-arm-eabi@4.17.2':
+ '@rollup/rollup-android-arm-eabi@4.19.1':
optional: true
- '@rollup/rollup-android-arm64@4.17.2':
+ '@rollup/rollup-android-arm64@4.19.1':
optional: true
- '@rollup/rollup-darwin-arm64@4.17.2':
+ '@rollup/rollup-darwin-arm64@4.19.1':
optional: true
- '@rollup/rollup-darwin-x64@4.17.2':
+ '@rollup/rollup-darwin-x64@4.19.1':
optional: true
- '@rollup/rollup-linux-arm-gnueabihf@4.17.2':
+ '@rollup/rollup-linux-arm-gnueabihf@4.19.1':
optional: true
- '@rollup/rollup-linux-arm-musleabihf@4.17.2':
+ '@rollup/rollup-linux-arm-musleabihf@4.19.1':
optional: true
- '@rollup/rollup-linux-arm64-gnu@4.17.2':
+ '@rollup/rollup-linux-arm64-gnu@4.19.1':
optional: true
- '@rollup/rollup-linux-arm64-musl@4.17.2':
+ '@rollup/rollup-linux-arm64-musl@4.19.1':
optional: true
- '@rollup/rollup-linux-powerpc64le-gnu@4.17.2':
+ '@rollup/rollup-linux-powerpc64le-gnu@4.19.1':
optional: true
- '@rollup/rollup-linux-riscv64-gnu@4.17.2':
+ '@rollup/rollup-linux-riscv64-gnu@4.19.1':
optional: true
- '@rollup/rollup-linux-s390x-gnu@4.17.2':
+ '@rollup/rollup-linux-s390x-gnu@4.19.1':
optional: true
- '@rollup/rollup-linux-x64-gnu@4.17.2':
+ '@rollup/rollup-linux-x64-gnu@4.19.1':
optional: true
- '@rollup/rollup-linux-x64-musl@4.17.2':
+ '@rollup/rollup-linux-x64-musl@4.19.1':
optional: true
- '@rollup/rollup-win32-arm64-msvc@4.17.2':
+ '@rollup/rollup-win32-arm64-msvc@4.19.1':
optional: true
- '@rollup/rollup-win32-ia32-msvc@4.17.2':
+ '@rollup/rollup-win32-ia32-msvc@4.19.1':
optional: true
- '@rollup/rollup-win32-x64-msvc@4.17.2':
+ '@rollup/rollup-win32-x64-msvc@4.19.1':
optional: true
- '@rushstack/node-core-library@4.1.0(@types/node@20.12.7)':
+ '@rushstack/node-core-library@5.5.1(@types/node@20.14.12)':
dependencies:
+ ajv: 8.13.0
+ ajv-draft-04: 1.0.0(ajv@8.13.0)
+ ajv-formats: 3.0.1(ajv@8.13.0)
fs-extra: 7.0.1
import-lazy: 4.0.0
jju: 1.4.0
resolve: 1.22.8
semver: 7.5.4
- z-schema: 5.0.5
optionalDependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
- '@rushstack/rig-package@0.5.2':
+ '@rushstack/rig-package@0.5.3':
dependencies:
resolve: 1.22.8
strip-json-comments: 3.1.1
- '@rushstack/terminal@0.10.1(@types/node@20.12.7)':
+ '@rushstack/terminal@0.13.3(@types/node@20.14.12)':
dependencies:
- '@rushstack/node-core-library': 4.1.0(@types/node@20.12.7)
+ '@rushstack/node-core-library': 5.5.1(@types/node@20.14.12)
supports-color: 8.1.1
optionalDependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
- '@rushstack/ts-command-line@4.19.2(@types/node@20.12.7)':
+ '@rushstack/ts-command-line@4.22.3(@types/node@20.14.12)':
dependencies:
- '@rushstack/terminal': 0.10.1(@types/node@20.12.7)
+ '@rushstack/terminal': 0.13.3(@types/node@20.14.12)
'@types/argparse': 1.0.38
argparse: 1.0.10
string-argv: 0.3.1
transitivePeerDependencies:
- '@types/node'
- '@sentry/core@8.5.0':
+ '@sec-ant/readable-stream@0.4.1': {}
+
+ '@sentry/core@8.20.0':
dependencies:
- '@sentry/types': 8.5.0
- '@sentry/utils': 8.5.0
+ '@sentry/types': 8.20.0
+ '@sentry/utils': 8.20.0
- '@sentry/node@8.5.0':
+ '@sentry/node@8.20.0':
dependencies:
- '@opentelemetry/api': 1.8.0
- '@opentelemetry/context-async-hooks': 1.24.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/instrumentation-connect': 0.36.0(@opentelemetry/api@1.8.0)
- '@opentelemetry/instrumentation-express': 0.39.0(@opentelemetry/api@1.8.0)
- '@opentelemetry/instrumentation-fastify': 0.36.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/instrumentation-graphql': 0.40.0(@opentelemetry/api@1.8.0)
- '@opentelemetry/instrumentation-hapi': 0.38.0(@opentelemetry/api@1.8.0)
- '@opentelemetry/instrumentation-http': 0.51.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/instrumentation-ioredis': 0.40.0(@opentelemetry/api@1.8.0)
- '@opentelemetry/instrumentation-koa': 0.40.0(@opentelemetry/api@1.8.0)
- '@opentelemetry/instrumentation-mongodb': 0.43.0(@opentelemetry/api@1.8.0)
- '@opentelemetry/instrumentation-mongoose': 0.38.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/instrumentation-mysql': 0.38.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/instrumentation-mysql2': 0.38.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/instrumentation-nestjs-core': 0.37.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/instrumentation-pg': 0.41.0(@opentelemetry/api@1.8.0)
- '@opentelemetry/resources': 1.24.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/sdk-trace-base': 1.24.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/semantic-conventions': 1.24.1
- '@prisma/instrumentation': 5.14.0
- '@sentry/core': 8.5.0
- '@sentry/opentelemetry': 8.5.0(@opentelemetry/api@1.8.0)(@opentelemetry/core@1.24.1(@opentelemetry/api@1.8.0))(@opentelemetry/instrumentation@0.51.1(@opentelemetry/api@1.8.0))(@opentelemetry/sdk-trace-base@1.24.1(@opentelemetry/api@1.8.0))(@opentelemetry/semantic-conventions@1.24.1)
- '@sentry/types': 8.5.0
- '@sentry/utils': 8.5.0
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/context-async-hooks': 1.25.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation-connect': 0.38.0(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation-express': 0.41.0(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation-fastify': 0.38.0(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation-graphql': 0.42.0(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation-hapi': 0.40.0(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation-http': 0.52.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation-ioredis': 0.42.0(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation-koa': 0.42.0(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation-mongodb': 0.46.0(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation-mongoose': 0.40.0(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation-mysql': 0.40.0(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation-mysql2': 0.40.0(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation-nestjs-core': 0.39.0(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation-pg': 0.43.0(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation-redis-4': 0.41.0(@opentelemetry/api@1.9.0)
+ '@opentelemetry/resources': 1.25.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/semantic-conventions': 1.25.1
+ '@prisma/instrumentation': 5.17.0
+ '@sentry/core': 8.20.0
+ '@sentry/opentelemetry': 8.20.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.25.1)
+ '@sentry/types': 8.20.0
+ '@sentry/utils': 8.20.0
+ import-in-the-middle: 1.10.0
optionalDependencies:
- opentelemetry-instrumentation-fetch-node: 1.2.0
+ opentelemetry-instrumentation-fetch-node: 1.2.3(@opentelemetry/api@1.9.0)
transitivePeerDependencies:
- supports-color
- '@sentry/opentelemetry@8.5.0(@opentelemetry/api@1.8.0)(@opentelemetry/core@1.24.1(@opentelemetry/api@1.8.0))(@opentelemetry/instrumentation@0.51.1(@opentelemetry/api@1.8.0))(@opentelemetry/sdk-trace-base@1.24.1(@opentelemetry/api@1.8.0))(@opentelemetry/semantic-conventions@1.24.1)':
+ '@sentry/opentelemetry@8.20.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.25.1)':
dependencies:
- '@opentelemetry/api': 1.8.0
- '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/sdk-trace-base': 1.24.1(@opentelemetry/api@1.8.0)
- '@opentelemetry/semantic-conventions': 1.24.1
- '@sentry/core': 8.5.0
- '@sentry/types': 8.5.0
- '@sentry/utils': 8.5.0
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/semantic-conventions': 1.25.1
+ '@sentry/core': 8.20.0
+ '@sentry/types': 8.20.0
+ '@sentry/utils': 8.20.0
- '@sentry/profiling-node@8.5.0':
+ '@sentry/profiling-node@8.20.0':
dependencies:
- '@sentry/core': 8.5.0
- '@sentry/node': 8.5.0
- '@sentry/types': 8.5.0
- '@sentry/utils': 8.5.0
+ '@sentry/core': 8.20.0
+ '@sentry/node': 8.20.0
+ '@sentry/types': 8.20.0
+ '@sentry/utils': 8.20.0
detect-libc: 2.0.3
node-abi: 3.62.0
transitivePeerDependencies:
- supports-color
- '@sentry/types@8.5.0': {}
+ '@sentry/types@8.20.0': {}
- '@sentry/utils@8.5.0':
+ '@sentry/utils@8.20.0':
dependencies:
- '@sentry/types': 8.5.0
+ '@sentry/types': 8.20.0
- '@shikijs/core@1.4.0': {}
+ '@shikijs/core@1.12.0':
+ dependencies:
+ '@types/hast': 3.0.4
'@sideway/address@4.1.4':
dependencies:
@@ -14461,7 +15216,7 @@ snapshots:
'@sideway/pinpoint@2.0.0': {}
- '@simplewebauthn/server@10.0.0(encoding@0.1.13)':
+ '@simplewebauthn/server@10.0.1(encoding@0.1.13)':
dependencies:
'@hexagon/base64': 1.1.27
'@levischuck/tiny-cbor': 0.2.2
@@ -14483,7 +15238,11 @@ snapshots:
'@sindresorhus/is@5.3.0': {}
- '@sindresorhus/is@6.1.0': {}
+ '@sindresorhus/is@7.0.0': {}
+
+ '@sindresorhus/merge-streams@2.3.0': {}
+
+ '@sindresorhus/merge-streams@4.0.0': {}
'@sinonjs/commons@2.0.0':
dependencies:
@@ -14509,155 +15268,173 @@ snapshots:
'@sinonjs/text-encoding@0.7.2': {}
- '@smithy/abort-controller@2.0.14':
- dependencies:
- '@smithy/types': 2.6.0
- tslib: 2.6.2
-
'@smithy/abort-controller@2.2.0':
dependencies:
'@smithy/types': 2.12.0
tslib: 2.6.2
- '@smithy/chunked-blob-reader-native@2.0.0':
+ '@smithy/abort-controller@3.1.1':
dependencies:
- '@smithy/util-base64': 2.0.0
- tslib: 2.6.2
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@smithy/chunked-blob-reader@2.0.0':
+ '@smithy/chunked-blob-reader-native@3.0.0':
dependencies:
- tslib: 2.6.2
+ '@smithy/util-base64': 3.0.0
+ tslib: 2.6.3
- '@smithy/config-resolver@2.0.9':
+ '@smithy/chunked-blob-reader@3.0.0':
dependencies:
- '@smithy/node-config-provider': 2.0.11
- '@smithy/types': 2.6.0
- '@smithy/util-config-provider': 2.0.0
- '@smithy/util-middleware': 2.0.1
- tslib: 2.6.2
+ tslib: 2.6.3
- '@smithy/credential-provider-imds@2.0.11':
+ '@smithy/config-resolver@3.0.5':
dependencies:
- '@smithy/node-config-provider': 2.0.11
- '@smithy/property-provider': 2.0.9
- '@smithy/types': 2.6.0
- '@smithy/url-parser': 2.0.8
- tslib: 2.6.2
+ '@smithy/node-config-provider': 3.1.4
+ '@smithy/types': 3.3.0
+ '@smithy/util-config-provider': 3.0.0
+ '@smithy/util-middleware': 3.0.3
+ tslib: 2.6.3
- '@smithy/eventstream-codec@2.0.8':
+ '@smithy/core@2.3.1':
dependencies:
- '@aws-crypto/crc32': 3.0.0
- '@smithy/types': 2.6.0
- '@smithy/util-hex-encoding': 2.0.0
- tslib: 2.6.2
+ '@smithy/middleware-endpoint': 3.1.0
+ '@smithy/middleware-retry': 3.0.13
+ '@smithy/middleware-serde': 3.0.3
+ '@smithy/protocol-http': 4.1.0
+ '@smithy/smithy-client': 3.1.11
+ '@smithy/types': 3.3.0
+ '@smithy/util-middleware': 3.0.3
+ tslib: 2.6.3
- '@smithy/eventstream-serde-browser@2.0.8':
+ '@smithy/credential-provider-imds@3.2.0':
dependencies:
- '@smithy/eventstream-serde-universal': 2.0.8
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@smithy/node-config-provider': 3.1.4
+ '@smithy/property-provider': 3.1.3
+ '@smithy/types': 3.3.0
+ '@smithy/url-parser': 3.0.3
+ tslib: 2.6.3
- '@smithy/eventstream-serde-config-resolver@2.0.8':
+ '@smithy/eventstream-codec@3.1.2':
dependencies:
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@aws-crypto/crc32': 5.2.0
+ '@smithy/types': 3.3.0
+ '@smithy/util-hex-encoding': 3.0.0
+ tslib: 2.6.3
- '@smithy/eventstream-serde-node@2.0.8':
+ '@smithy/eventstream-serde-browser@3.0.5':
dependencies:
- '@smithy/eventstream-serde-universal': 2.0.8
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@smithy/eventstream-serde-universal': 3.0.4
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@smithy/eventstream-serde-universal@2.0.8':
+ '@smithy/eventstream-serde-config-resolver@3.0.3':
dependencies:
- '@smithy/eventstream-codec': 2.0.8
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@smithy/fetch-http-handler@2.1.4':
+ '@smithy/eventstream-serde-node@3.0.4':
dependencies:
- '@smithy/protocol-http': 3.0.10
- '@smithy/querystring-builder': 2.0.14
- '@smithy/types': 2.6.0
- '@smithy/util-base64': 2.0.0
- tslib: 2.6.2
+ '@smithy/eventstream-serde-universal': 3.0.4
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@smithy/hash-blob-browser@2.0.8':
+ '@smithy/eventstream-serde-universal@3.0.4':
dependencies:
- '@smithy/chunked-blob-reader': 2.0.0
- '@smithy/chunked-blob-reader-native': 2.0.0
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@smithy/eventstream-codec': 3.1.2
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@smithy/hash-node@2.0.8':
+ '@smithy/fetch-http-handler@3.2.4':
dependencies:
- '@smithy/types': 2.6.0
- '@smithy/util-buffer-from': 2.0.0
- '@smithy/util-utf8': 2.0.0
- tslib: 2.6.2
+ '@smithy/protocol-http': 4.1.0
+ '@smithy/querystring-builder': 3.0.3
+ '@smithy/types': 3.3.0
+ '@smithy/util-base64': 3.0.0
+ tslib: 2.6.3
- '@smithy/hash-stream-node@2.0.8':
+ '@smithy/hash-blob-browser@3.1.2':
dependencies:
- '@smithy/types': 2.6.0
- '@smithy/util-utf8': 2.0.0
- tslib: 2.6.2
+ '@smithy/chunked-blob-reader': 3.0.0
+ '@smithy/chunked-blob-reader-native': 3.0.0
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@smithy/invalid-dependency@2.0.8':
+ '@smithy/hash-node@3.0.3':
dependencies:
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@smithy/types': 3.3.0
+ '@smithy/util-buffer-from': 3.0.0
+ '@smithy/util-utf8': 3.0.0
+ tslib: 2.6.3
+
+ '@smithy/hash-stream-node@3.1.2':
+ dependencies:
+ '@smithy/types': 3.3.0
+ '@smithy/util-utf8': 3.0.0
+ tslib: 2.6.3
+
+ '@smithy/invalid-dependency@3.0.3':
+ dependencies:
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
'@smithy/is-array-buffer@2.0.0':
dependencies:
- tslib: 2.6.2
+ tslib: 2.6.3
- '@smithy/md5-js@2.0.8':
+ '@smithy/is-array-buffer@3.0.0':
dependencies:
- '@smithy/types': 2.6.0
- '@smithy/util-utf8': 2.0.0
- tslib: 2.6.2
+ tslib: 2.6.3
- '@smithy/middleware-content-length@2.0.10':
+ '@smithy/md5-js@3.0.3':
dependencies:
- '@smithy/protocol-http': 3.0.10
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@smithy/types': 3.3.0
+ '@smithy/util-utf8': 3.0.0
+ tslib: 2.6.3
- '@smithy/middleware-endpoint@2.0.8':
+ '@smithy/middleware-content-length@3.0.5':
dependencies:
- '@smithy/middleware-serde': 2.0.8
- '@smithy/types': 2.6.0
- '@smithy/url-parser': 2.0.8
- '@smithy/util-middleware': 2.0.1
- tslib: 2.6.2
+ '@smithy/protocol-http': 4.1.0
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@smithy/middleware-retry@2.0.11':
+ '@smithy/middleware-endpoint@3.1.0':
dependencies:
- '@smithy/node-config-provider': 2.0.11
- '@smithy/protocol-http': 3.0.10
- '@smithy/service-error-classification': 2.0.1
- '@smithy/types': 2.6.0
- '@smithy/util-middleware': 2.0.1
- '@smithy/util-retry': 2.0.1
- tslib: 2.6.2
- uuid: 8.3.2
+ '@smithy/middleware-serde': 3.0.3
+ '@smithy/node-config-provider': 3.1.4
+ '@smithy/shared-ini-file-loader': 3.1.4
+ '@smithy/types': 3.3.0
+ '@smithy/url-parser': 3.0.3
+ '@smithy/util-middleware': 3.0.3
+ tslib: 2.6.3
- '@smithy/middleware-serde@2.0.8':
+ '@smithy/middleware-retry@3.0.13':
dependencies:
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@smithy/node-config-provider': 3.1.4
+ '@smithy/protocol-http': 4.1.0
+ '@smithy/service-error-classification': 3.0.3
+ '@smithy/smithy-client': 3.1.11
+ '@smithy/types': 3.3.0
+ '@smithy/util-middleware': 3.0.3
+ '@smithy/util-retry': 3.0.3
+ tslib: 2.6.3
+ uuid: 9.0.1
- '@smithy/middleware-stack@2.0.1':
+ '@smithy/middleware-serde@3.0.3':
dependencies:
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@smithy/node-config-provider@2.0.11':
+ '@smithy/middleware-stack@3.0.3':
dependencies:
- '@smithy/property-provider': 2.0.9
- '@smithy/shared-ini-file-loader': 2.0.10
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
+
+ '@smithy/node-config-provider@3.1.4':
+ dependencies:
+ '@smithy/property-provider': 3.1.3
+ '@smithy/shared-ini-file-loader': 3.1.4
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
'@smithy/node-http-handler@2.5.0':
dependencies:
@@ -14667,26 +15444,28 @@ snapshots:
'@smithy/types': 2.12.0
tslib: 2.6.2
- '@smithy/property-provider@2.0.9':
+ '@smithy/node-http-handler@3.1.4':
dependencies:
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@smithy/abort-controller': 3.1.1
+ '@smithy/protocol-http': 4.1.0
+ '@smithy/querystring-builder': 3.0.3
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@smithy/protocol-http@3.0.10':
+ '@smithy/property-provider@3.1.3':
dependencies:
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
'@smithy/protocol-http@3.3.0':
dependencies:
'@smithy/types': 2.12.0
tslib: 2.6.2
- '@smithy/querystring-builder@2.0.14':
+ '@smithy/protocol-http@4.1.0':
dependencies:
- '@smithy/types': 2.6.0
- '@smithy/util-uri-escape': 2.0.0
- tslib: 2.6.2
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
'@smithy/querystring-builder@2.2.0':
dependencies:
@@ -14694,226 +15473,234 @@ snapshots:
'@smithy/util-uri-escape': 2.2.0
tslib: 2.6.2
- '@smithy/querystring-parser@2.0.8':
+ '@smithy/querystring-builder@3.0.3':
dependencies:
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@smithy/types': 3.3.0
+ '@smithy/util-uri-escape': 3.0.0
+ tslib: 2.6.3
- '@smithy/service-error-classification@2.0.1':
+ '@smithy/querystring-parser@3.0.3':
dependencies:
- '@smithy/types': 2.6.0
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@smithy/shared-ini-file-loader@2.0.10':
+ '@smithy/service-error-classification@3.0.3':
dependencies:
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@smithy/types': 3.3.0
- '@smithy/signature-v4@2.0.5':
+ '@smithy/shared-ini-file-loader@3.1.4':
dependencies:
- '@smithy/eventstream-codec': 2.0.8
- '@smithy/is-array-buffer': 2.0.0
- '@smithy/types': 2.6.0
- '@smithy/util-hex-encoding': 2.0.0
- '@smithy/util-middleware': 2.0.1
- '@smithy/util-uri-escape': 2.0.0
- '@smithy/util-utf8': 2.0.0
- tslib: 2.6.2
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@smithy/smithy-client@2.1.5':
+ '@smithy/signature-v4@4.1.0':
dependencies:
- '@smithy/middleware-stack': 2.0.1
- '@smithy/types': 2.6.0
- '@smithy/util-stream': 2.0.11
- tslib: 2.6.2
+ '@smithy/is-array-buffer': 3.0.0
+ '@smithy/protocol-http': 4.1.0
+ '@smithy/types': 3.3.0
+ '@smithy/util-hex-encoding': 3.0.0
+ '@smithy/util-middleware': 3.0.3
+ '@smithy/util-uri-escape': 3.0.0
+ '@smithy/util-utf8': 3.0.0
+ tslib: 2.6.3
+
+ '@smithy/smithy-client@3.1.11':
+ dependencies:
+ '@smithy/middleware-endpoint': 3.1.0
+ '@smithy/middleware-stack': 3.0.3
+ '@smithy/protocol-http': 4.1.0
+ '@smithy/types': 3.3.0
+ '@smithy/util-stream': 3.1.3
+ tslib: 2.6.3
'@smithy/types@2.12.0':
dependencies:
tslib: 2.6.2
- '@smithy/types@2.6.0':
+ '@smithy/types@3.3.0':
dependencies:
- tslib: 2.6.2
+ tslib: 2.6.3
- '@smithy/url-parser@2.0.8':
+ '@smithy/url-parser@3.0.3':
dependencies:
- '@smithy/querystring-parser': 2.0.8
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@smithy/querystring-parser': 3.0.3
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@smithy/util-base64@2.0.0':
+ '@smithy/util-base64@3.0.0':
dependencies:
- '@smithy/util-buffer-from': 2.0.0
- tslib: 2.6.2
+ '@smithy/util-buffer-from': 3.0.0
+ '@smithy/util-utf8': 3.0.0
+ tslib: 2.6.3
- '@smithy/util-body-length-browser@2.0.0':
+ '@smithy/util-body-length-browser@3.0.0':
dependencies:
- tslib: 2.6.2
+ tslib: 2.6.3
- '@smithy/util-body-length-node@2.1.0':
+ '@smithy/util-body-length-node@3.0.0':
dependencies:
- tslib: 2.6.2
+ tslib: 2.6.3
'@smithy/util-buffer-from@2.0.0':
dependencies:
'@smithy/is-array-buffer': 2.0.0
- tslib: 2.6.2
+ tslib: 2.6.3
- '@smithy/util-config-provider@2.0.0':
+ '@smithy/util-buffer-from@3.0.0':
dependencies:
- tslib: 2.6.2
+ '@smithy/is-array-buffer': 3.0.0
+ tslib: 2.6.3
+
+ '@smithy/util-config-provider@3.0.0':
+ dependencies:
+ tslib: 2.6.3
- '@smithy/util-defaults-mode-browser@2.0.9':
+ '@smithy/util-defaults-mode-browser@3.0.13':
dependencies:
- '@smithy/property-provider': 2.0.9
- '@smithy/smithy-client': 2.1.5
- '@smithy/types': 2.6.0
+ '@smithy/property-provider': 3.1.3
+ '@smithy/smithy-client': 3.1.11
+ '@smithy/types': 3.3.0
bowser: 2.11.0
- tslib: 2.6.2
+ tslib: 2.6.3
- '@smithy/util-defaults-mode-node@2.0.11':
+ '@smithy/util-defaults-mode-node@3.0.13':
dependencies:
- '@smithy/config-resolver': 2.0.9
- '@smithy/credential-provider-imds': 2.0.11
- '@smithy/node-config-provider': 2.0.11
- '@smithy/property-provider': 2.0.9
- '@smithy/smithy-client': 2.1.5
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@smithy/config-resolver': 3.0.5
+ '@smithy/credential-provider-imds': 3.2.0
+ '@smithy/node-config-provider': 3.1.4
+ '@smithy/property-provider': 3.1.3
+ '@smithy/smithy-client': 3.1.11
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@smithy/util-hex-encoding@2.0.0':
+ '@smithy/util-endpoints@2.0.5':
dependencies:
- tslib: 2.6.2
+ '@smithy/node-config-provider': 3.1.4
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@smithy/util-middleware@2.0.1':
+ '@smithy/util-hex-encoding@3.0.0':
dependencies:
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ tslib: 2.6.3
- '@smithy/util-retry@2.0.1':
+ '@smithy/util-middleware@3.0.3':
dependencies:
- '@smithy/service-error-classification': 2.0.1
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@smithy/util-stream@2.0.11':
+ '@smithy/util-retry@3.0.3':
dependencies:
- '@smithy/fetch-http-handler': 2.1.4
- '@smithy/node-http-handler': 2.5.0
- '@smithy/types': 2.6.0
- '@smithy/util-base64': 2.0.0
- '@smithy/util-buffer-from': 2.0.0
- '@smithy/util-hex-encoding': 2.0.0
- '@smithy/util-utf8': 2.0.0
- tslib: 2.6.2
+ '@smithy/service-error-classification': 3.0.3
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
- '@smithy/util-uri-escape@2.0.0':
+ '@smithy/util-stream@3.1.3':
dependencies:
- tslib: 2.6.2
+ '@smithy/fetch-http-handler': 3.2.4
+ '@smithy/node-http-handler': 3.1.4
+ '@smithy/types': 3.3.0
+ '@smithy/util-base64': 3.0.0
+ '@smithy/util-buffer-from': 3.0.0
+ '@smithy/util-hex-encoding': 3.0.0
+ '@smithy/util-utf8': 3.0.0
+ tslib: 2.6.3
'@smithy/util-uri-escape@2.2.0':
dependencies:
tslib: 2.6.2
+ '@smithy/util-uri-escape@3.0.0':
+ dependencies:
+ tslib: 2.6.3
+
'@smithy/util-utf8@2.0.0':
dependencies:
'@smithy/util-buffer-from': 2.0.0
- tslib: 2.6.2
+ tslib: 2.6.3
- '@smithy/util-waiter@2.0.8':
+ '@smithy/util-utf8@3.0.0':
dependencies:
- '@smithy/abort-controller': 2.0.14
- '@smithy/types': 2.6.0
- tslib: 2.6.2
+ '@smithy/util-buffer-from': 3.0.0
+ tslib: 2.6.3
+
+ '@smithy/util-waiter@3.1.2':
+ dependencies:
+ '@smithy/abort-controller': 3.1.1
+ '@smithy/types': 3.3.0
+ tslib: 2.6.3
'@sqltools/formatter@1.2.5': {}
- '@storybook/addon-actions@8.0.9':
+ '@storybook/addon-actions@8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))':
dependencies:
- '@storybook/core-events': 8.0.9
'@storybook/global': 5.0.0
'@types/uuid': 9.0.8
dequal: 2.0.3
polished: 4.2.2
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
uuid: 9.0.1
- '@storybook/addon-backgrounds@8.0.9':
+ '@storybook/addon-backgrounds@8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))':
dependencies:
'@storybook/global': 5.0.0
memoizerific: 1.11.3
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
ts-dedent: 2.2.0
- '@storybook/addon-controls@8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@storybook/addon-controls@8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))':
dependencies:
- '@storybook/blocks': 8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ dequal: 2.0.3
lodash: 4.17.21
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
ts-dedent: 2.2.0
- transitivePeerDependencies:
- - '@types/react'
- - encoding
- - react
- - react-dom
- - supports-color
- '@storybook/addon-docs@8.0.9(encoding@0.1.13)':
+ '@storybook/addon-docs@8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))':
dependencies:
- '@babel/core': 7.24.0
+ '@babel/core': 7.24.7
'@mdx-js/react': 3.0.1(@types/react@18.0.28)(react@18.3.1)
- '@storybook/blocks': 8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@storybook/client-logger': 8.0.9
- '@storybook/components': 8.0.9(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@storybook/csf-plugin': 8.0.9
- '@storybook/csf-tools': 8.0.9
+ '@storybook/blocks': 8.2.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@storybook/csf-plugin': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
'@storybook/global': 5.0.0
- '@storybook/node-logger': 8.0.9
- '@storybook/preview-api': 8.0.9
- '@storybook/react-dom-shim': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@storybook/theming': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@storybook/types': 8.0.9
+ '@storybook/react-dom-shim': 8.2.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
'@types/react': 18.0.28
fs-extra: 11.1.1
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
rehype-external-links: 3.0.0
rehype-slug: 6.0.0
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
ts-dedent: 2.2.0
transitivePeerDependencies:
- - encoding
- supports-color
- '@storybook/addon-essentials@8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@storybook/addon-essentials@8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))':
dependencies:
- '@storybook/addon-actions': 8.0.9
- '@storybook/addon-backgrounds': 8.0.9
- '@storybook/addon-controls': 8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@storybook/addon-docs': 8.0.9(encoding@0.1.13)
- '@storybook/addon-highlight': 8.0.9
- '@storybook/addon-measure': 8.0.9
- '@storybook/addon-outline': 8.0.9
- '@storybook/addon-toolbars': 8.0.9
- '@storybook/addon-viewport': 8.0.9
- '@storybook/core-common': 8.0.9(encoding@0.1.13)
- '@storybook/manager-api': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@storybook/node-logger': 8.0.9
- '@storybook/preview-api': 8.0.9
+ '@storybook/addon-actions': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@storybook/addon-backgrounds': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@storybook/addon-controls': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@storybook/addon-docs': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@storybook/addon-highlight': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@storybook/addon-measure': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@storybook/addon-outline': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@storybook/addon-toolbars': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@storybook/addon-viewport': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
ts-dedent: 2.2.0
transitivePeerDependencies:
- - '@types/react'
- - encoding
- - react
- - react-dom
- supports-color
- '@storybook/addon-highlight@8.0.9':
+ '@storybook/addon-highlight@8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))':
dependencies:
'@storybook/global': 5.0.0
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
- '@storybook/addon-interactions@8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))':
+ '@storybook/addon-interactions@8.2.6(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.14.12))(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.8)(terser@5.31.3))':
dependencies:
'@storybook/global': 5.0.0
- '@storybook/instrumenter': 8.0.9
- '@storybook/test': 8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))
- '@storybook/types': 8.0.9
+ '@storybook/instrumenter': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@storybook/test': 8.2.6(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.14.12))(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.8)(terser@5.31.3))
polished: 4.2.2
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
ts-dedent: 2.2.0
transitivePeerDependencies:
- '@jest/globals'
@@ -14922,89 +15709,83 @@ snapshots:
- jest
- vitest
- '@storybook/addon-links@8.0.9(react@18.3.1)':
+ '@storybook/addon-links@8.2.6(react@18.3.1)(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))':
dependencies:
- '@storybook/csf': 0.1.6
+ '@storybook/csf': 0.1.11
'@storybook/global': 5.0.0
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
ts-dedent: 2.2.0
optionalDependencies:
react: 18.3.1
- '@storybook/addon-mdx-gfm@8.0.9':
+ '@storybook/addon-mdx-gfm@8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))':
dependencies:
- '@storybook/node-logger': 8.0.9
remark-gfm: 4.0.0
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
ts-dedent: 2.2.0
transitivePeerDependencies:
- supports-color
- '@storybook/addon-measure@8.0.9':
+ '@storybook/addon-measure@8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))':
dependencies:
'@storybook/global': 5.0.0
- tiny-invariant: 1.3.1
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
+ tiny-invariant: 1.3.3
- '@storybook/addon-outline@8.0.9':
+ '@storybook/addon-outline@8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))':
dependencies:
'@storybook/global': 5.0.0
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
ts-dedent: 2.2.0
- '@storybook/addon-storysource@8.0.9':
+ '@storybook/addon-storysource@8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))':
dependencies:
- '@storybook/source-loader': 8.0.9
+ '@storybook/source-loader': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
estraverse: 5.3.0
- tiny-invariant: 1.3.1
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
+ tiny-invariant: 1.3.3
- '@storybook/addon-toolbars@8.0.9': {}
+ '@storybook/addon-toolbars@8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))':
+ dependencies:
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
- '@storybook/addon-viewport@8.0.9':
+ '@storybook/addon-viewport@8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))':
dependencies:
memoizerific: 1.11.3
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
- '@storybook/blocks@8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@storybook/blocks@8.2.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))':
dependencies:
- '@storybook/channels': 8.0.9
- '@storybook/client-logger': 8.0.9
- '@storybook/components': 8.0.9(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@storybook/core-events': 8.0.9
- '@storybook/csf': 0.1.6
- '@storybook/docs-tools': 8.0.9(encoding@0.1.13)
+ '@storybook/csf': 0.1.11
'@storybook/global': 5.0.0
'@storybook/icons': 1.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@storybook/manager-api': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@storybook/preview-api': 8.0.9
- '@storybook/theming': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@storybook/types': 8.0.9
'@types/lodash': 4.14.191
color-convert: 2.0.1
dequal: 2.0.3
lodash: 4.17.21
- markdown-to-jsx: 7.3.2(react@18.3.1)
+ markdown-to-jsx: 7.4.7(react@18.3.1)
memoizerific: 1.11.3
polished: 4.2.2
react-colorful: 5.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
telejson: 7.2.0
- tocbot: 4.21.1
ts-dedent: 2.2.0
util-deprecate: 1.0.2
optionalDependencies:
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- transitivePeerDependencies:
- - '@types/react'
- - encoding
- - supports-color
- '@storybook/builder-manager@8.0.9(encoding@0.1.13)':
+ '@storybook/builder-manager@8.1.11(encoding@0.1.13)(prettier@3.3.3)':
dependencies:
'@fal-works/esbuild-plugin-global-externals': 2.1.2
- '@storybook/core-common': 8.0.9(encoding@0.1.13)
- '@storybook/manager': 8.0.9
- '@storybook/node-logger': 8.0.9
+ '@storybook/core-common': 8.1.11(encoding@0.1.13)(prettier@3.3.3)
+ '@storybook/manager': 8.1.11
+ '@storybook/node-logger': 8.1.11
'@types/ejs': 3.1.2
- '@yarnpkg/esbuild-plugin-pnp': 3.0.0-rc.15(esbuild@0.20.2)
+ '@yarnpkg/esbuild-plugin-pnp': 3.0.0-rc.15(esbuild@0.19.11)
browser-assert: 1.2.1
- ejs: 3.1.9
- esbuild: 0.20.2
+ ejs: 3.1.10
+ esbuild: 0.19.11
esbuild-plugin-alias: 0.2.1
express: 4.19.2
fs-extra: 11.1.1
@@ -15012,187 +15793,158 @@ snapshots:
util: 0.12.5
transitivePeerDependencies:
- encoding
+ - prettier
- supports-color
- '@storybook/builder-vite@8.0.9(encoding@0.1.13)(typescript@5.4.5)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))':
+ '@storybook/builder-vite@8.1.11(encoding@0.1.13)(prettier@3.3.3)(typescript@5.5.4)(vite@5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3))':
dependencies:
- '@storybook/channels': 8.0.9
- '@storybook/client-logger': 8.0.9
- '@storybook/core-common': 8.0.9(encoding@0.1.13)
- '@storybook/core-events': 8.0.9
- '@storybook/csf-plugin': 8.0.9
- '@storybook/node-logger': 8.0.9
- '@storybook/preview': 8.0.9
- '@storybook/preview-api': 8.0.9
- '@storybook/types': 8.0.9
+ '@storybook/channels': 8.1.11
+ '@storybook/client-logger': 8.1.11
+ '@storybook/core-common': 8.1.11(encoding@0.1.13)(prettier@3.3.3)
+ '@storybook/core-events': 8.1.11
+ '@storybook/csf-plugin': 8.1.11
+ '@storybook/node-logger': 8.1.11
+ '@storybook/preview': 8.1.11
+ '@storybook/preview-api': 8.1.11
+ '@storybook/types': 8.1.11
'@types/find-cache-dir': 3.2.1
browser-assert: 1.2.1
- es-module-lexer: 0.9.3
- express: 4.18.2
+ es-module-lexer: 1.5.4
+ express: 4.19.2
find-cache-dir: 3.3.2
fs-extra: 11.1.1
- magic-string: 0.30.7
+ magic-string: 0.30.10
ts-dedent: 2.2.0
- vite: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3)
+ vite: 5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3)
optionalDependencies:
- typescript: 5.4.5
+ typescript: 5.5.4
transitivePeerDependencies:
- encoding
+ - prettier
- supports-color
- '@storybook/channels@8.0.9':
- dependencies:
- '@storybook/client-logger': 8.0.9
- '@storybook/core-events': 8.0.9
- '@storybook/global': 5.0.0
- telejson: 7.2.0
- tiny-invariant: 1.3.1
-
- '@storybook/cli@8.0.9(@babel/preset-env@7.23.5(@babel/core@7.24.0))(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3)':
+ '@storybook/builder-vite@8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))(typescript@5.5.4)(vite@5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3))':
dependencies:
- '@babel/core': 7.24.0
- '@babel/types': 7.24.0
- '@ndelangen/get-tarball': 3.0.7
- '@storybook/codemod': 8.0.9
- '@storybook/core-common': 8.0.9(encoding@0.1.13)
- '@storybook/core-events': 8.0.9
- '@storybook/core-server': 8.0.9(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3)
- '@storybook/csf-tools': 8.0.9
- '@storybook/node-logger': 8.0.9
- '@storybook/telemetry': 8.0.9(encoding@0.1.13)
- '@storybook/types': 8.0.9
- '@types/semver': 7.5.8
- '@yarnpkg/fslib': 2.10.3
- '@yarnpkg/libzip': 2.3.0
- chalk: 4.1.2
- commander: 6.2.1
- cross-spawn: 7.0.3
- detect-indent: 6.1.0
- envinfo: 7.8.1
- execa: 5.1.1
- find-up: 5.0.0
+ '@storybook/csf-plugin': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@types/find-cache-dir': 3.2.1
+ browser-assert: 1.2.1
+ es-module-lexer: 1.5.4
+ express: 4.19.2
+ find-cache-dir: 3.3.2
fs-extra: 11.1.1
- get-npm-tarball-url: 2.0.3
- giget: 1.1.2
- globby: 11.1.0
- jscodeshift: 0.15.1(@babel/preset-env@7.23.5(@babel/core@7.24.0))
- leven: 3.1.0
- ora: 5.4.1
- prettier: 3.2.5
- prompts: 2.4.2
- read-pkg-up: 7.0.1
- semver: 7.6.0
- strip-json-comments: 3.1.1
- tempy: 1.0.1
- tiny-invariant: 1.3.1
+ magic-string: 0.30.10
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
ts-dedent: 2.2.0
+ vite: 5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3)
+ optionalDependencies:
+ typescript: 5.5.4
transitivePeerDependencies:
- - '@babel/preset-env'
- - bufferutil
- - encoding
- - react
- - react-dom
- supports-color
- - utf-8-validate
- '@storybook/client-logger@8.0.9':
+ '@storybook/channels@8.1.11':
dependencies:
+ '@storybook/client-logger': 8.1.11
+ '@storybook/core-events': 8.1.11
'@storybook/global': 5.0.0
+ telejson: 7.2.0
+ tiny-invariant: 1.3.3
- '@storybook/codemod@8.0.9':
+ '@storybook/client-logger@8.1.11':
dependencies:
- '@babel/core': 7.24.0
- '@babel/preset-env': 7.23.5(@babel/core@7.24.0)
- '@babel/types': 7.24.0
- '@storybook/csf': 0.1.6
- '@storybook/csf-tools': 8.0.9
- '@storybook/node-logger': 8.0.9
- '@storybook/types': 8.0.9
+ '@storybook/global': 5.0.0
+
+ '@storybook/codemod@8.2.6(bufferutil@4.0.8)(utf-8-validate@6.0.4)':
+ dependencies:
+ '@babel/core': 7.24.7
+ '@babel/preset-env': 7.24.7(@babel/core@7.24.7)
+ '@babel/types': 7.24.7
+ '@storybook/core': 8.2.6(bufferutil@4.0.8)(utf-8-validate@6.0.4)
+ '@storybook/csf': 0.1.11
'@types/cross-spawn': 6.0.2
cross-spawn: 7.0.3
- globby: 11.1.0
- jscodeshift: 0.15.1(@babel/preset-env@7.23.5(@babel/core@7.24.0))
+ globby: 14.0.1
+ jscodeshift: 0.15.1(@babel/preset-env@7.24.7(@babel/core@7.24.7))
lodash: 4.17.21
- prettier: 3.2.5
+ prettier: 3.3.3
recast: 0.23.6
- tiny-invariant: 1.3.1
+ tiny-invariant: 1.3.3
transitivePeerDependencies:
+ - bufferutil
- supports-color
+ - utf-8-validate
- '@storybook/components@8.0.9(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@storybook/components@8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))':
dependencies:
- '@radix-ui/react-slot': 1.0.2(@types/react@18.0.28)(react@18.3.1)
- '@storybook/client-logger': 8.0.9
- '@storybook/csf': 0.1.6
- '@storybook/global': 5.0.0
- '@storybook/icons': 1.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@storybook/theming': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@storybook/types': 8.0.9
- memoizerific: 1.11.3
- react: 18.3.1
- react-dom: 18.3.1(react@18.3.1)
- util-deprecate: 1.0.2
- transitivePeerDependencies:
- - '@types/react'
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
- '@storybook/core-common@8.0.9(encoding@0.1.13)':
+ '@storybook/core-common@8.1.11(encoding@0.1.13)(prettier@3.3.3)':
dependencies:
- '@storybook/core-events': 8.0.9
- '@storybook/csf-tools': 8.0.9
- '@storybook/node-logger': 8.0.9
- '@storybook/types': 8.0.9
+ '@storybook/core-events': 8.1.11
+ '@storybook/csf-tools': 8.1.11
+ '@storybook/node-logger': 8.1.11
+ '@storybook/types': 8.1.11
'@yarnpkg/fslib': 2.10.3
'@yarnpkg/libzip': 2.3.0
chalk: 4.1.2
cross-spawn: 7.0.3
- esbuild: 0.20.2
- esbuild-register: 3.5.0(esbuild@0.20.2)
+ esbuild: 0.19.11
+ esbuild-register: 3.5.0(esbuild@0.19.11)
execa: 5.1.1
file-system-cache: 2.3.0
find-cache-dir: 3.3.2
find-up: 5.0.0
fs-extra: 11.1.1
- glob: 10.3.12
+ glob: 10.3.10
handlebars: 4.7.7
lazy-universal-dotenv: 4.0.0
node-fetch: 2.7.0(encoding@0.1.13)
picomatch: 2.3.1
pkg-dir: 5.0.0
+ prettier-fallback: prettier@3.3.3
pretty-hrtime: 1.0.3
resolve-from: 5.0.0
semver: 7.6.0
- tempy: 1.0.1
- tiny-invariant: 1.3.1
+ tempy: 3.1.0
+ tiny-invariant: 1.3.3
ts-dedent: 2.2.0
util: 0.12.5
+ optionalDependencies:
+ prettier: 3.3.3
transitivePeerDependencies:
- encoding
- supports-color
- '@storybook/core-events@8.0.9':
+ '@storybook/core-events@8.1.11':
dependencies:
+ '@storybook/csf': 0.1.9
ts-dedent: 2.2.0
- '@storybook/core-server@8.0.9(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3)':
+ '@storybook/core-events@8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))':
+ dependencies:
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
+
+ '@storybook/core-server@8.1.11(bufferutil@4.0.8)(encoding@0.1.13)(prettier@3.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.4)':
dependencies:
'@aw-web-design/x-default-browser': 1.4.126
- '@babel/core': 7.24.0
+ '@babel/core': 7.24.7
+ '@babel/parser': 7.24.7
'@discoveryjs/json-ext': 0.5.7
- '@storybook/builder-manager': 8.0.9(encoding@0.1.13)
- '@storybook/channels': 8.0.9
- '@storybook/core-common': 8.0.9(encoding@0.1.13)
- '@storybook/core-events': 8.0.9
- '@storybook/csf': 0.1.6
- '@storybook/csf-tools': 8.0.9
- '@storybook/docs-mdx': 3.0.0
+ '@storybook/builder-manager': 8.1.11(encoding@0.1.13)(prettier@3.3.3)
+ '@storybook/channels': 8.1.11
+ '@storybook/core-common': 8.1.11(encoding@0.1.13)(prettier@3.3.3)
+ '@storybook/core-events': 8.1.11
+ '@storybook/csf': 0.1.9
+ '@storybook/csf-tools': 8.1.11
+ '@storybook/docs-mdx': 3.1.0-next.0
'@storybook/global': 5.0.0
- '@storybook/manager': 8.0.9
- '@storybook/manager-api': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@storybook/node-logger': 8.0.9
- '@storybook/preview-api': 8.0.9
- '@storybook/telemetry': 8.0.9(encoding@0.1.13)
- '@storybook/types': 8.0.9
+ '@storybook/manager': 8.1.11
+ '@storybook/manager-api': 8.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@storybook/node-logger': 8.1.11
+ '@storybook/preview-api': 8.1.11
+ '@storybook/telemetry': 8.1.11(encoding@0.1.13)(prettier@3.3.3)
+ '@storybook/types': 8.1.11
'@types/detect-port': 1.3.2
+ '@types/diff': 5.2.1
'@types/node': 18.17.15
'@types/pretty-hrtime': 1.0.1
'@types/semver': 7.5.8
@@ -15201,10 +15953,10 @@ snapshots:
cli-table3: 0.6.3
compression: 1.7.4
detect-port: 1.5.1
- express: 4.18.2
+ diff: 5.2.0
+ express: 4.19.2
fs-extra: 11.1.1
- globby: 11.1.0
- ip: 2.0.1
+ globby: 14.0.1
lodash: 4.17.21
open: 8.4.2
pretty-hrtime: 1.0.3
@@ -15212,59 +15964,88 @@ snapshots:
read-pkg-up: 7.0.1
semver: 7.6.0
telejson: 7.2.0
- tiny-invariant: 1.3.1
+ tiny-invariant: 1.3.3
ts-dedent: 2.2.0
util: 0.12.5
util-deprecate: 1.0.2
watchpack: 2.4.0
- ws: 8.17.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
+ ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
transitivePeerDependencies:
- bufferutil
- encoding
+ - prettier
- react
- react-dom
- supports-color
- utf-8-validate
- '@storybook/csf-plugin@8.0.9':
+ '@storybook/core@8.2.6(bufferutil@4.0.8)(utf-8-validate@6.0.4)':
dependencies:
- '@storybook/csf-tools': 8.0.9
+ '@storybook/csf': 0.1.11
+ '@types/express': 4.17.21
+ '@types/node': 18.17.15
+ browser-assert: 1.2.1
+ esbuild: 0.19.11
+ esbuild-register: 3.5.0(esbuild@0.19.11)
+ express: 4.19.2
+ process: 0.11.10
+ recast: 0.23.6
+ util: 0.12.5
+ ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
+ transitivePeerDependencies:
+ - bufferutil
+ - supports-color
+ - utf-8-validate
+
+ '@storybook/csf-plugin@8.1.11':
+ dependencies:
+ '@storybook/csf-tools': 8.1.11
unplugin: 1.4.0
transitivePeerDependencies:
- supports-color
- '@storybook/csf-tools@8.0.9':
+ '@storybook/csf-plugin@8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))':
dependencies:
- '@babel/generator': 7.23.6
- '@babel/parser': 7.24.0
- '@babel/traverse': 7.24.0
- '@babel/types': 7.24.0
- '@storybook/csf': 0.1.6
- '@storybook/types': 8.0.9
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
+ unplugin: 1.4.0
+
+ '@storybook/csf-tools@8.1.11':
+ dependencies:
+ '@babel/generator': 7.24.7
+ '@babel/parser': 7.24.7
+ '@babel/traverse': 7.24.7
+ '@babel/types': 7.24.7
+ '@storybook/csf': 0.1.9
+ '@storybook/types': 8.1.11
fs-extra: 11.1.1
recast: 0.23.6
ts-dedent: 2.2.0
transitivePeerDependencies:
- supports-color
- '@storybook/csf@0.1.6':
+ '@storybook/csf@0.1.11':
+ dependencies:
+ type-fest: 2.19.0
+
+ '@storybook/csf@0.1.9':
dependencies:
type-fest: 2.19.0
- '@storybook/docs-mdx@3.0.0': {}
+ '@storybook/docs-mdx@3.1.0-next.0': {}
- '@storybook/docs-tools@8.0.9(encoding@0.1.13)':
+ '@storybook/docs-tools@8.1.11(encoding@0.1.13)(prettier@3.3.3)':
dependencies:
- '@storybook/core-common': 8.0.9(encoding@0.1.13)
- '@storybook/core-events': 8.0.9
- '@storybook/preview-api': 8.0.9
- '@storybook/types': 8.0.9
+ '@storybook/core-common': 8.1.11(encoding@0.1.13)(prettier@3.3.3)
+ '@storybook/core-events': 8.1.11
+ '@storybook/preview-api': 8.1.11
+ '@storybook/types': 8.1.11
'@types/doctrine': 0.0.3
assert: 2.1.0
doctrine: 3.0.0
lodash: 4.17.21
transitivePeerDependencies:
- encoding
+ - prettier
- supports-color
'@storybook/global@5.0.0': {}
@@ -15274,27 +16055,24 @@ snapshots:
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- '@storybook/instrumenter@8.0.9':
+ '@storybook/instrumenter@8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))':
dependencies:
- '@storybook/channels': 8.0.9
- '@storybook/client-logger': 8.0.9
- '@storybook/core-events': 8.0.9
'@storybook/global': 5.0.0
- '@storybook/preview-api': 8.0.9
'@vitest/utils': 1.6.0
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
util: 0.12.5
- '@storybook/manager-api@8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@storybook/manager-api@8.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@storybook/channels': 8.0.9
- '@storybook/client-logger': 8.0.9
- '@storybook/core-events': 8.0.9
- '@storybook/csf': 0.1.6
+ '@storybook/channels': 8.1.11
+ '@storybook/client-logger': 8.1.11
+ '@storybook/core-events': 8.1.11
+ '@storybook/csf': 0.1.9
'@storybook/global': 5.0.0
'@storybook/icons': 1.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@storybook/router': 8.0.9
- '@storybook/theming': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@storybook/types': 8.0.9
+ '@storybook/router': 8.1.11
+ '@storybook/theming': 8.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@storybook/types': 8.1.11
dequal: 2.0.3
lodash: 4.17.21
memoizerific: 1.11.3
@@ -15305,65 +16083,73 @@ snapshots:
- react
- react-dom
- '@storybook/manager@8.0.9': {}
+ '@storybook/manager-api@8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))':
+ dependencies:
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
+
+ '@storybook/manager@8.1.11': {}
- '@storybook/node-logger@8.0.9': {}
+ '@storybook/node-logger@8.1.11': {}
- '@storybook/preview-api@8.0.9':
+ '@storybook/preview-api@8.1.11':
dependencies:
- '@storybook/channels': 8.0.9
- '@storybook/client-logger': 8.0.9
- '@storybook/core-events': 8.0.9
- '@storybook/csf': 0.1.6
+ '@storybook/channels': 8.1.11
+ '@storybook/client-logger': 8.1.11
+ '@storybook/core-events': 8.1.11
+ '@storybook/csf': 0.1.9
'@storybook/global': 5.0.0
- '@storybook/types': 8.0.9
+ '@storybook/types': 8.1.11
'@types/qs': 6.9.7
dequal: 2.0.3
lodash: 4.17.21
memoizerific: 1.11.3
qs: 6.11.1
- tiny-invariant: 1.3.1
+ tiny-invariant: 1.3.3
ts-dedent: 2.2.0
util-deprecate: 1.0.2
- '@storybook/preview@8.0.9': {}
+ '@storybook/preview-api@8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))':
+ dependencies:
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
+
+ '@storybook/preview@8.1.11': {}
- '@storybook/react-dom-shim@8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@storybook/react-dom-shim@8.2.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))':
dependencies:
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
- '@storybook/react-vite@8.0.9(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.17.2)(typescript@5.4.5)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))':
+ '@storybook/react-vite@8.2.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.19.1)(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))(typescript@5.5.4)(vite@5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3))':
dependencies:
- '@joshwooding/vite-plugin-react-docgen-typescript': 0.3.0(typescript@5.4.5)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))
- '@rollup/pluginutils': 5.1.0(rollup@4.17.2)
- '@storybook/builder-vite': 8.0.9(encoding@0.1.13)(typescript@5.4.5)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))
- '@storybook/node-logger': 8.0.9
- '@storybook/react': 8.0.9(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
+ '@joshwooding/vite-plugin-react-docgen-typescript': 0.3.1(typescript@5.5.4)(vite@5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3))
+ '@rollup/pluginutils': 5.1.0(rollup@4.19.1)
+ '@storybook/builder-vite': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))(typescript@5.5.4)(vite@5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3))
+ '@storybook/react': 8.2.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))(typescript@5.5.4)
find-up: 5.0.0
- magic-string: 0.30.7
+ magic-string: 0.30.10
react: 18.3.1
react-docgen: 7.0.1
react-dom: 18.3.1(react@18.3.1)
resolve: 1.22.8
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
tsconfig-paths: 4.2.0
- vite: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3)
+ vite: 5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3)
transitivePeerDependencies:
- '@preact/preset-vite'
- - encoding
- rollup
- supports-color
- typescript
- vite-plugin-glimmerx
- '@storybook/react@8.0.9(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)':
+ '@storybook/react@8.2.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))(typescript@5.5.4)':
dependencies:
- '@storybook/client-logger': 8.0.9
- '@storybook/docs-tools': 8.0.9(encoding@0.1.13)
+ '@storybook/components': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
'@storybook/global': 5.0.0
- '@storybook/preview-api': 8.0.9
- '@storybook/react-dom-shim': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@storybook/types': 8.0.9
+ '@storybook/manager-api': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@storybook/preview-api': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@storybook/react-dom-shim': 8.2.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@storybook/theming': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
'@types/escodegen': 0.0.6
'@types/estree': 0.0.51
'@types/node': 18.17.15
@@ -15378,34 +16164,32 @@ snapshots:
react-dom: 18.3.1(react@18.3.1)
react-element-to-jsx-string: 15.0.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
semver: 7.6.0
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
ts-dedent: 2.2.0
type-fest: 2.19.0
util-deprecate: 1.0.2
optionalDependencies:
- typescript: 5.4.5
- transitivePeerDependencies:
- - encoding
- - supports-color
+ typescript: 5.5.4
- '@storybook/router@8.0.9':
+ '@storybook/router@8.1.11':
dependencies:
- '@storybook/client-logger': 8.0.9
+ '@storybook/client-logger': 8.1.11
memoizerific: 1.11.3
qs: 6.11.1
- '@storybook/source-loader@8.0.9':
+ '@storybook/source-loader@8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))':
dependencies:
- '@storybook/csf': 0.1.6
- '@storybook/types': 8.0.9
+ '@storybook/csf': 0.1.11
estraverse: 5.3.0
lodash: 4.17.21
- prettier: 3.2.5
+ prettier: 3.3.3
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
- '@storybook/telemetry@8.0.9(encoding@0.1.13)':
+ '@storybook/telemetry@8.1.11(encoding@0.1.13)(prettier@3.3.3)':
dependencies:
- '@storybook/client-logger': 8.0.9
- '@storybook/core-common': 8.0.9(encoding@0.1.13)
- '@storybook/csf-tools': 8.0.9
+ '@storybook/client-logger': 8.1.11
+ '@storybook/core-common': 8.1.11(encoding@0.1.13)(prettier@3.3.3)
+ '@storybook/csf-tools': 8.1.11
chalk: 4.1.2
detect-package-manager: 2.0.1
fetch-retry: 5.0.4
@@ -15413,19 +16197,19 @@ snapshots:
read-pkg-up: 7.0.1
transitivePeerDependencies:
- encoding
+ - prettier
- supports-color
- '@storybook/test@8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))':
+ '@storybook/test@8.2.6(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.14.12))(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.8)(terser@5.31.3))':
dependencies:
- '@storybook/client-logger': 8.0.9
- '@storybook/core-events': 8.0.9
- '@storybook/instrumenter': 8.0.9
- '@storybook/preview-api': 8.0.9
- '@testing-library/dom': 9.3.4
- '@testing-library/jest-dom': 6.4.2(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))
- '@testing-library/user-event': 14.5.2(@testing-library/dom@9.3.4)
- '@vitest/expect': 1.3.1
+ '@storybook/csf': 0.1.11
+ '@storybook/instrumenter': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@testing-library/dom': 10.1.0
+ '@testing-library/jest-dom': 6.4.5(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.14.12))(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.8)(terser@5.31.3))
+ '@testing-library/user-event': 14.5.2(@testing-library/dom@10.1.0)
+ '@vitest/expect': 1.6.0
'@vitest/spy': 1.6.0
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
util: 0.12.5
transitivePeerDependencies:
- '@jest/globals'
@@ -15434,37 +16218,47 @@ snapshots:
- jest
- vitest
- '@storybook/theming@8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@storybook/theming@8.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@emotion/use-insertion-effect-with-fallbacks': 1.0.1(react@18.3.1)
- '@storybook/client-logger': 8.0.9
+ '@storybook/client-logger': 8.1.11
'@storybook/global': 5.0.0
memoizerific: 1.11.3
optionalDependencies:
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- '@storybook/types@8.0.9':
+ '@storybook/theming@8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))':
+ dependencies:
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
+
+ '@storybook/types@8.1.11':
dependencies:
- '@storybook/channels': 8.0.9
+ '@storybook/channels': 8.1.11
'@types/express': 4.17.17
file-system-cache: 2.3.0
- '@storybook/vue3-vite@8.0.9(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))(vue@3.4.26(typescript@5.4.5))':
+ '@storybook/types@8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))':
+ dependencies:
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
+
+ '@storybook/vue3-vite@8.1.11(bufferutil@4.0.8)(encoding@0.1.13)(prettier@3.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.4)(vite@5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3))(vue@3.4.34(typescript@5.5.4))':
dependencies:
- '@storybook/builder-vite': 8.0.9(encoding@0.1.13)(typescript@5.4.5)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))
- '@storybook/core-server': 8.0.9(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3)
- '@storybook/vue3': 8.0.9(encoding@0.1.13)(vue@3.4.26(typescript@5.4.5))
+ '@storybook/builder-vite': 8.1.11(encoding@0.1.13)(prettier@3.3.3)(typescript@5.5.4)(vite@5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3))
+ '@storybook/core-server': 8.1.11(bufferutil@4.0.8)(encoding@0.1.13)(prettier@3.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.4)
+ '@storybook/types': 8.1.11
+ '@storybook/vue3': 8.1.11(encoding@0.1.13)(prettier@3.3.3)(vue@3.4.34(typescript@5.5.4))
find-package-json: 1.2.0
- magic-string: 0.30.7
- typescript: 5.4.5
- vite: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3)
- vue-component-meta: 2.0.16(typescript@5.4.5)
- vue-docgen-api: 4.75.1(vue@3.4.26(typescript@5.4.5))
+ magic-string: 0.30.10
+ typescript: 5.5.4
+ vite: 5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3)
+ vue-component-meta: 2.0.16(typescript@5.5.4)
+ vue-docgen-api: 4.75.1(vue@3.4.34(typescript@5.5.4))
transitivePeerDependencies:
- '@preact/preset-vite'
- bufferutil
- encoding
+ - prettier
- react
- react-dom
- supports-color
@@ -15472,26 +16266,42 @@ snapshots:
- vite-plugin-glimmerx
- vue
- '@storybook/vue3@8.0.9(encoding@0.1.13)(vue@3.4.26(typescript@5.4.5))':
+ '@storybook/vue3@8.1.11(encoding@0.1.13)(prettier@3.3.3)(vue@3.4.34(typescript@5.5.4))':
dependencies:
- '@storybook/docs-tools': 8.0.9(encoding@0.1.13)
+ '@storybook/docs-tools': 8.1.11(encoding@0.1.13)(prettier@3.3.3)
'@storybook/global': 5.0.0
- '@storybook/preview-api': 8.0.9
- '@storybook/types': 8.0.9
- '@vue/compiler-core': 3.4.21
+ '@storybook/preview-api': 8.1.11
+ '@storybook/types': 8.1.11
+ '@vue/compiler-core': 3.4.29
lodash: 4.17.21
ts-dedent: 2.2.0
type-fest: 2.19.0
- vue: 3.4.26(typescript@5.4.5)
- vue-component-type-helpers: 2.0.19
+ vue: 3.4.34(typescript@5.5.4)
+ vue-component-type-helpers: 2.0.29
transitivePeerDependencies:
- encoding
+ - prettier
- supports-color
- '@swc/cli@0.3.12(@swc/core@1.4.17)(chokidar@3.5.3)':
+ '@storybook/vue3@8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))(vue@3.4.34(typescript@5.5.4))':
+ dependencies:
+ '@storybook/components': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@storybook/global': 5.0.0
+ '@storybook/manager-api': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@storybook/preview-api': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@storybook/theming': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@vue/compiler-core': 3.4.31
+ lodash: 4.17.21
+ storybook: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4)
+ ts-dedent: 2.2.0
+ type-fest: 2.19.0
+ vue: 3.4.34(typescript@5.5.4)
+ vue-component-type-helpers: 2.0.29
+
+ '@swc/cli@0.3.12(@swc/core@1.6.6)(chokidar@3.5.3)':
dependencies:
'@mole-inc/bin-wrapper': 8.0.1
- '@swc/core': 1.4.17
+ '@swc/core': 1.6.6
'@swc/counter': 0.1.3
commander: 8.3.0
fast-glob: 3.3.2
@@ -15511,13 +16321,19 @@ snapshots:
'@swc/core-darwin-arm64@1.3.56':
optional: true
- '@swc/core-darwin-arm64@1.4.17':
+ '@swc/core-darwin-arm64@1.6.13':
+ optional: true
+
+ '@swc/core-darwin-arm64@1.6.6':
optional: true
'@swc/core-darwin-x64@1.3.56':
optional: true
- '@swc/core-darwin-x64@1.4.17':
+ '@swc/core-darwin-x64@1.6.13':
+ optional: true
+
+ '@swc/core-darwin-x64@1.6.6':
optional: true
'@swc/core-freebsd-x64@1.3.11':
@@ -15528,82 +16344,131 @@ snapshots:
'@swc/core-linux-arm-gnueabihf@1.3.56':
optional: true
- '@swc/core-linux-arm-gnueabihf@1.4.17':
+ '@swc/core-linux-arm-gnueabihf@1.6.13':
+ optional: true
+
+ '@swc/core-linux-arm-gnueabihf@1.6.6':
optional: true
'@swc/core-linux-arm64-gnu@1.3.56':
optional: true
- '@swc/core-linux-arm64-gnu@1.4.17':
+ '@swc/core-linux-arm64-gnu@1.6.13':
+ optional: true
+
+ '@swc/core-linux-arm64-gnu@1.6.6':
optional: true
'@swc/core-linux-arm64-musl@1.3.56':
optional: true
- '@swc/core-linux-arm64-musl@1.4.17':
+ '@swc/core-linux-arm64-musl@1.6.13':
+ optional: true
+
+ '@swc/core-linux-arm64-musl@1.6.6':
optional: true
'@swc/core-linux-x64-gnu@1.3.56':
optional: true
- '@swc/core-linux-x64-gnu@1.4.17':
+ '@swc/core-linux-x64-gnu@1.6.13':
+ optional: true
+
+ '@swc/core-linux-x64-gnu@1.6.6':
optional: true
'@swc/core-linux-x64-musl@1.3.56':
optional: true
- '@swc/core-linux-x64-musl@1.4.17':
+ '@swc/core-linux-x64-musl@1.6.13':
+ optional: true
+
+ '@swc/core-linux-x64-musl@1.6.6':
optional: true
'@swc/core-win32-arm64-msvc@1.3.56':
optional: true
- '@swc/core-win32-arm64-msvc@1.4.17':
+ '@swc/core-win32-arm64-msvc@1.6.13':
+ optional: true
+
+ '@swc/core-win32-arm64-msvc@1.6.6':
optional: true
'@swc/core-win32-ia32-msvc@1.3.56':
optional: true
- '@swc/core-win32-ia32-msvc@1.4.17':
+ '@swc/core-win32-ia32-msvc@1.6.13':
+ optional: true
+
+ '@swc/core-win32-ia32-msvc@1.6.6':
optional: true
'@swc/core-win32-x64-msvc@1.3.56':
optional: true
- '@swc/core-win32-x64-msvc@1.4.17':
+ '@swc/core-win32-x64-msvc@1.6.13':
optional: true
- '@swc/core@1.4.17':
+ '@swc/core-win32-x64-msvc@1.6.6':
+ optional: true
+
+ '@swc/core@1.6.13':
dependencies:
'@swc/counter': 0.1.3
- '@swc/types': 0.1.5
+ '@swc/types': 0.1.9
optionalDependencies:
- '@swc/core-darwin-arm64': 1.4.17
- '@swc/core-darwin-x64': 1.4.17
- '@swc/core-linux-arm-gnueabihf': 1.4.17
- '@swc/core-linux-arm64-gnu': 1.4.17
- '@swc/core-linux-arm64-musl': 1.4.17
- '@swc/core-linux-x64-gnu': 1.4.17
- '@swc/core-linux-x64-musl': 1.4.17
- '@swc/core-win32-arm64-msvc': 1.4.17
- '@swc/core-win32-ia32-msvc': 1.4.17
- '@swc/core-win32-x64-msvc': 1.4.17
+ '@swc/core-darwin-arm64': 1.6.13
+ '@swc/core-darwin-x64': 1.6.13
+ '@swc/core-linux-arm-gnueabihf': 1.6.13
+ '@swc/core-linux-arm64-gnu': 1.6.13
+ '@swc/core-linux-arm64-musl': 1.6.13
+ '@swc/core-linux-x64-gnu': 1.6.13
+ '@swc/core-linux-x64-musl': 1.6.13
+ '@swc/core-win32-arm64-msvc': 1.6.13
+ '@swc/core-win32-ia32-msvc': 1.6.13
+ '@swc/core-win32-x64-msvc': 1.6.13
+
+ '@swc/core@1.6.6':
+ dependencies:
+ '@swc/counter': 0.1.3
+ '@swc/types': 0.1.9
+ optionalDependencies:
+ '@swc/core-darwin-arm64': 1.6.6
+ '@swc/core-darwin-x64': 1.6.6
+ '@swc/core-linux-arm-gnueabihf': 1.6.6
+ '@swc/core-linux-arm64-gnu': 1.6.6
+ '@swc/core-linux-arm64-musl': 1.6.6
+ '@swc/core-linux-x64-gnu': 1.6.6
+ '@swc/core-linux-x64-musl': 1.6.6
+ '@swc/core-win32-arm64-msvc': 1.6.6
+ '@swc/core-win32-ia32-msvc': 1.6.6
+ '@swc/core-win32-x64-msvc': 1.6.6
'@swc/counter@0.1.3': {}
- '@swc/jest@0.2.36(@swc/core@1.4.17)':
+ '@swc/jest@0.2.36(@swc/core@1.6.13)':
dependencies:
'@jest/create-cache-key-function': 29.7.0
- '@swc/core': 1.4.17
+ '@swc/core': 1.6.13
'@swc/counter': 0.1.3
jsonc-parser: 3.2.0
- '@swc/types@0.1.5': {}
+ '@swc/jest@0.2.36(@swc/core@1.6.6)':
+ dependencies:
+ '@jest/create-cache-key-function': 29.7.0
+ '@swc/core': 1.6.6
+ '@swc/counter': 0.1.3
+ jsonc-parser: 3.2.0
+
+ '@swc/types@0.1.9':
+ dependencies:
+ '@swc/counter': 0.1.3
'@swc/wasm@1.2.130':
optional: true
- '@syuilo/aiscript@0.18.0':
+ '@syuilo/aiscript@0.19.0':
dependencies:
seedrandom: 3.0.5
stringz: 2.1.0
@@ -15626,7 +16491,7 @@ snapshots:
'@tensorflow/tfjs-backend-cpu@4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13))':
dependencies:
'@tensorflow/tfjs-core': 4.4.0(encoding@0.1.13)
- '@types/seedrandom': 2.4.30
+ '@types/seedrandom': 2.4.34
seedrandom: 3.0.5
'@tensorflow/tfjs-backend-webgl@4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13))':
@@ -15634,7 +16499,7 @@ snapshots:
'@tensorflow/tfjs-backend-cpu': 4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13))
'@tensorflow/tfjs-core': 4.4.0(encoding@0.1.13)
'@types/offscreencanvas': 2019.3.0
- '@types/seedrandom': 2.4.30
+ '@types/seedrandom': 2.4.34
'@types/webgl-ext': 0.0.30
seedrandom: 3.0.5
@@ -15646,11 +16511,11 @@ snapshots:
dependencies:
'@types/long': 4.0.2
'@types/offscreencanvas': 2019.7.0
- '@types/seedrandom': 2.4.30
+ '@types/seedrandom': 2.4.34
'@types/webgl-ext': 0.0.30
'@webgpu/types': 0.1.30
long: 4.0.0
- node-fetch: 2.6.11(encoding@0.1.13)
+ node-fetch: 2.6.13(encoding@0.1.13)
seedrandom: 3.0.5
transitivePeerDependencies:
- encoding
@@ -15658,8 +16523,8 @@ snapshots:
'@tensorflow/tfjs-data@4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13))(encoding@0.1.13)(seedrandom@3.0.5)':
dependencies:
'@tensorflow/tfjs-core': 4.4.0(encoding@0.1.13)
- '@types/node-fetch': 2.6.4
- node-fetch: 2.6.11(encoding@0.1.13)
+ '@types/node-fetch': 2.6.11
+ node-fetch: 2.6.13(encoding@0.1.13)
seedrandom: 3.0.5
string_decoder: 1.3.0
transitivePeerDependencies:
@@ -15702,12 +16567,12 @@ snapshots:
- encoding
- seedrandom
- '@testing-library/dom@9.3.3':
+ '@testing-library/dom@10.1.0':
dependencies:
- '@babel/code-frame': 7.23.5
+ '@babel/code-frame': 7.24.7
'@babel/runtime': 7.23.4
'@types/aria-query': 5.0.1
- aria-query: 5.1.3
+ aria-query: 5.3.0
chalk: 4.1.2
dom-accessibility-api: 0.5.16
lz-string: 1.5.0
@@ -15724,11 +16589,11 @@ snapshots:
lz-string: 1.5.0
pretty-format: 27.5.1
- '@testing-library/jest-dom@6.4.2(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))':
+ '@testing-library/jest-dom@6.4.5(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.14.12))(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.8)(terser@5.31.3))':
dependencies:
'@adobe/css-tools': 4.3.3
'@babel/runtime': 7.23.4
- aria-query: 5.1.3
+ aria-query: 5.3.0
chalk: 3.0.0
css.escape: 1.5.1
dom-accessibility-api: 0.6.3
@@ -15737,21 +16602,21 @@ snapshots:
optionalDependencies:
'@jest/globals': 29.7.0
'@types/jest': 29.5.12
- jest: 29.7.0(@types/node@20.12.7)
- vitest: 0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)
+ jest: 29.7.0(@types/node@20.14.12)
+ vitest: 1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.8)(terser@5.31.3)
- '@testing-library/user-event@14.5.2(@testing-library/dom@9.3.4)':
+ '@testing-library/user-event@14.5.2(@testing-library/dom@10.1.0)':
dependencies:
- '@testing-library/dom': 9.3.4
+ '@testing-library/dom': 10.1.0
- '@testing-library/vue@8.0.3(@vue/compiler-sfc@3.4.26)(@vue/server-renderer@3.4.26(vue@3.4.26(typescript@5.4.5)))(vue@3.4.26(typescript@5.4.5))':
+ '@testing-library/vue@8.1.0(@vue/compiler-sfc@3.4.34)(@vue/server-renderer@3.4.34(vue@3.4.34(typescript@5.5.4)))(vue@3.4.34(typescript@5.5.4))':
dependencies:
'@babel/runtime': 7.23.4
- '@testing-library/dom': 9.3.3
- '@vue/test-utils': 2.4.1(@vue/server-renderer@3.4.26(vue@3.4.26(typescript@5.4.5)))(vue@3.4.26(typescript@5.4.5))
- vue: 3.4.26(typescript@5.4.5)
+ '@testing-library/dom': 9.3.4
+ '@vue/test-utils': 2.4.1(@vue/server-renderer@3.4.34(vue@3.4.34(typescript@5.5.4)))(vue@3.4.34(typescript@5.5.4))
+ vue: 3.4.34(typescript@5.5.4)
optionalDependencies:
- '@vue/compiler-sfc': 3.4.26
+ '@vue/compiler-sfc': 3.4.34
transitivePeerDependencies:
- '@vue/server-renderer'
@@ -15759,7 +16624,7 @@ snapshots:
'@trysound/sax@0.2.0': {}
- '@tsd/typescript@5.3.3': {}
+ '@tsd/typescript@5.4.5': {}
'@twemoji/parser@15.0.0': {}
@@ -15767,7 +16632,7 @@ snapshots:
'@types/accepts@1.3.7':
dependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
'@types/archiver@6.0.2':
dependencies:
@@ -15779,31 +16644,31 @@ snapshots:
'@types/babel__core@7.20.0':
dependencies:
- '@babel/parser': 7.24.0
- '@babel/types': 7.24.0
+ '@babel/parser': 7.24.7
+ '@babel/types': 7.24.7
'@types/babel__generator': 7.6.4
'@types/babel__template': 7.4.1
'@types/babel__traverse': 7.20.0
'@types/babel__generator@7.6.4':
dependencies:
- '@babel/types': 7.24.0
+ '@babel/types': 7.24.7
'@types/babel__template@7.4.1':
dependencies:
- '@babel/parser': 7.24.0
- '@babel/types': 7.24.0
+ '@babel/parser': 7.24.7
+ '@babel/types': 7.24.7
'@types/babel__traverse@7.20.0':
dependencies:
- '@babel/types': 7.24.0
+ '@babel/types': 7.24.7
'@types/bcryptjs@2.4.6': {}
'@types/body-parser@1.19.5':
dependencies:
'@types/connect': 3.4.35
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
'@types/braces@3.0.1': {}
@@ -15811,15 +16676,9 @@ snapshots:
dependencies:
'@types/http-cache-semantics': 4.0.4
'@types/keyv': 3.1.4
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
'@types/responselike': 1.0.0
- '@types/chai-subset@1.3.5':
- dependencies:
- '@types/chai': 4.3.11
-
- '@types/chai@4.3.11': {}
-
'@types/color-convert@2.0.3':
dependencies:
'@types/color-name': 1.1.1
@@ -15828,26 +16687,19 @@ snapshots:
'@types/connect@3.4.35':
dependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
'@types/connect@3.4.36':
dependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
'@types/content-disposition@0.5.8': {}
'@types/cookie@0.6.0': {}
- '@types/cookies@0.9.0':
- dependencies:
- '@types/connect': 3.4.35
- '@types/express': 4.17.17
- '@types/keygrip': 1.0.6
- '@types/node': 20.12.7
-
'@types/cross-spawn@6.0.2':
dependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
'@types/debug@4.1.12':
dependencies:
@@ -15855,6 +16707,8 @@ snapshots:
'@types/detect-port@1.3.2': {}
+ '@types/diff@5.2.1': {}
+
'@types/disposable-email-domains@1.0.2': {}
'@types/doctrine@0.0.3': {}
@@ -15872,7 +16726,7 @@ snapshots:
'@types/eslint@7.29.0':
dependencies:
'@types/estree': 1.0.5
- '@types/json-schema': 7.0.12
+ '@types/json-schema': 7.0.15
'@types/estree@0.0.51': {}
@@ -15880,7 +16734,7 @@ snapshots:
'@types/express-serve-static-core@4.17.33':
dependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
'@types/qs': 6.9.7
'@types/range-parser': 1.2.4
@@ -15891,20 +16745,27 @@ snapshots:
'@types/qs': 6.9.7
'@types/serve-static': 1.15.1
+ '@types/express@4.17.21':
+ dependencies:
+ '@types/body-parser': 1.19.5
+ '@types/express-serve-static-core': 4.17.33
+ '@types/qs': 6.9.7
+ '@types/serve-static': 1.15.1
+
'@types/find-cache-dir@3.2.1': {}
'@types/fluent-ffmpeg@2.1.24':
dependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
'@types/glob@7.2.0':
dependencies:
'@types/minimatch': 5.1.2
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
'@types/graceful-fs@4.1.6':
dependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
'@types/hast@3.0.4':
dependencies:
@@ -15912,15 +16773,11 @@ snapshots:
'@types/htmlescape@1.1.3': {}
- '@types/http-assert@1.5.5': {}
-
'@types/http-cache-semantics@4.0.4': {}
- '@types/http-errors@2.0.4': {}
-
- '@types/http-link-header@1.0.5':
+ '@types/http-link-header@1.0.7':
dependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
'@types/istanbul-lib-coverage@2.0.4': {}
@@ -15939,9 +16796,9 @@ snapshots:
'@types/js-yaml@4.0.9': {}
- '@types/jsdom@21.1.6':
+ '@types/jsdom@21.1.7':
dependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
'@types/tough-cookie': 4.0.2
parse5: 7.1.2
@@ -15951,34 +16808,13 @@ snapshots:
'@types/json5@0.0.29': {}
- '@types/jsonld@1.5.13': {}
+ '@types/jsonld@1.5.15': {}
'@types/jsrsasign@10.5.14': {}
- '@types/keygrip@1.0.6': {}
-
'@types/keyv@3.1.4':
dependencies:
- '@types/node': 20.12.7
-
- '@types/koa-compose@3.2.8':
- dependencies:
- '@types/koa': 2.14.0
-
- '@types/koa@2.14.0':
- dependencies:
- '@types/accepts': 1.3.7
- '@types/content-disposition': 0.5.8
- '@types/cookies': 0.9.0
- '@types/http-assert': 1.5.5
- '@types/http-errors': 2.0.4
- '@types/keygrip': 1.0.6
- '@types/koa-compose': 3.2.8
- '@types/node': 20.12.7
-
- '@types/koa__router@12.0.3':
- dependencies:
- '@types/koa': 2.14.0
+ '@types/node': 20.14.12
'@types/lodash@4.14.191': {}
@@ -15986,13 +16822,15 @@ snapshots:
'@types/matter-js@0.19.6': {}
+ '@types/matter-js@0.19.7': {}
+
'@types/mdast@4.0.3':
dependencies:
'@types/unist': 3.0.2
'@types/mdx@2.0.3': {}
- '@types/micromatch@4.0.7':
+ '@types/micromatch@4.0.9':
dependencies:
'@types/braces': 3.0.1
@@ -16008,20 +16846,16 @@ snapshots:
'@types/mute-stream@0.0.4':
dependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
'@types/mysql@2.15.22':
dependencies:
- '@types/node': 20.12.7
-
- '@types/node-fetch@2.6.4':
- dependencies:
- '@types/node': 20.12.7
- form-data: 3.0.1
+ '@types/node': 20.14.12
- '@types/node-fetch@3.0.3':
+ '@types/node-fetch@2.6.11':
dependencies:
- node-fetch: 3.3.2
+ '@types/node': 20.14.12
+ form-data: 4.0.0
'@types/node@18.17.15': {}
@@ -16029,7 +16863,7 @@ snapshots:
dependencies:
undici-types: 5.26.5
- '@types/node@20.12.7':
+ '@types/node@20.14.12':
dependencies:
undici-types: 5.26.5
@@ -16039,7 +16873,7 @@ snapshots:
'@types/nodemailer@6.4.15':
dependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
'@types/normalize-package-data@2.4.1': {}
@@ -16050,11 +16884,11 @@ snapshots:
'@types/oauth2orize@1.11.5':
dependencies:
'@types/express': 4.17.17
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
- '@types/oauth@0.9.4':
+ '@types/oauth@0.9.5':
dependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
'@types/offscreencanvas@2019.3.0': {}
@@ -16062,17 +16896,17 @@ snapshots:
'@types/pg-pool@2.0.4':
dependencies:
- '@types/pg': 8.11.5
+ '@types/pg': 8.11.6
- '@types/pg@8.11.5':
+ '@types/pg@8.11.6':
dependencies:
- '@types/node': 20.12.7
- pg-protocol: 1.6.0
+ '@types/node': 20.14.12
+ pg-protocol: 1.6.1
pg-types: 4.0.1
'@types/pg@8.6.1':
dependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
pg-protocol: 1.6.1
pg-types: 2.2.0
@@ -16086,7 +16920,7 @@ snapshots:
'@types/qrcode@1.5.5':
dependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
'@types/qs@6.9.7': {}
@@ -16104,7 +16938,7 @@ snapshots:
'@types/readdir-glob@1.1.1':
dependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
'@types/rename@1.0.7': {}
@@ -16112,7 +16946,7 @@ snapshots:
'@types/responselike@1.0.0':
dependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
'@types/sanitize-html@2.11.0':
dependencies:
@@ -16120,7 +16954,7 @@ snapshots:
'@types/scheduler@0.16.2': {}
- '@types/seedrandom@2.4.30': {}
+ '@types/seedrandom@2.4.34': {}
'@types/seedrandom@3.0.8': {}
@@ -16129,7 +16963,7 @@ snapshots:
'@types/serve-static@1.15.1':
dependencies:
'@types/mime': 3.0.1
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
'@types/serviceworker@0.0.67': {}
@@ -16159,25 +16993,29 @@ snapshots:
'@types/tough-cookie@4.0.2': {}
+ '@types/tough-cookie@4.0.5': {}
+
'@types/unist@3.0.2': {}
+ '@types/uuid@10.0.0': {}
+
'@types/uuid@9.0.8': {}
'@types/vary@1.1.3':
dependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
'@types/web-push@3.6.3':
dependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
'@types/webgl-ext@0.0.30': {}
'@types/wrap-ansi@3.0.0': {}
- '@types/ws@8.5.10':
+ '@types/ws@8.5.11':
dependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
'@types/yargs-parser@21.0.0': {}
@@ -16187,19 +17025,19 @@ snapshots:
'@types/yauzl@2.10.0':
dependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
optional: true
- '@typescript-eslint/eslint-plugin@6.11.0(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0)(typescript@5.3.3)':
+ '@typescript-eslint/eslint-plugin@6.11.0(@typescript-eslint/parser@6.11.0(eslint@9.8.0)(typescript@5.3.3))(eslint@9.8.0)(typescript@5.3.3)':
dependencies:
'@eslint-community/regexpp': 4.6.2
- '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.3.3)
+ '@typescript-eslint/parser': 6.11.0(eslint@9.8.0)(typescript@5.3.3)
'@typescript-eslint/scope-manager': 6.11.0
- '@typescript-eslint/type-utils': 6.11.0(eslint@8.53.0)(typescript@5.3.3)
- '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.3.3)
+ '@typescript-eslint/type-utils': 6.11.0(eslint@9.8.0)(typescript@5.3.3)
+ '@typescript-eslint/utils': 6.11.0(eslint@9.8.0)(typescript@5.3.3)
'@typescript-eslint/visitor-keys': 6.11.0
- debug: 4.3.4(supports-color@8.1.1)
- eslint: 8.53.0
+ debug: 4.3.4(supports-color@5.5.0)
+ eslint: 9.8.0
graphemer: 1.4.0
ignore: 5.2.4
natural-compare: 1.4.0
@@ -16210,16 +17048,16 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3)':
+ '@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0(eslint@9.8.0)(typescript@5.3.3))(eslint@9.8.0)(typescript@5.3.3)':
dependencies:
'@eslint-community/regexpp': 4.6.2
- '@typescript-eslint/parser': 7.1.0(eslint@8.57.0)(typescript@5.3.3)
+ '@typescript-eslint/parser': 7.1.0(eslint@9.8.0)(typescript@5.3.3)
'@typescript-eslint/scope-manager': 7.1.0
- '@typescript-eslint/type-utils': 7.1.0(eslint@8.57.0)(typescript@5.3.3)
- '@typescript-eslint/utils': 7.1.0(eslint@8.57.0)(typescript@5.3.3)
+ '@typescript-eslint/type-utils': 7.1.0(eslint@9.8.0)(typescript@5.3.3)
+ '@typescript-eslint/utils': 7.1.0(eslint@9.8.0)(typescript@5.3.3)
'@typescript-eslint/visitor-keys': 7.1.0
- debug: 4.3.4(supports-color@8.1.1)
- eslint: 8.57.0
+ debug: 4.3.4(supports-color@5.5.0)
+ eslint: 9.8.0
graphemer: 1.4.0
ignore: 5.2.4
natural-compare: 1.4.0
@@ -16230,62 +17068,60 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)':
+ '@typescript-eslint/eslint-plugin@7.17.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.5.4))(eslint@9.8.0)(typescript@5.5.4)':
dependencies:
- '@eslint-community/regexpp': 4.10.0
- '@typescript-eslint/parser': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
- '@typescript-eslint/scope-manager': 7.7.1
- '@typescript-eslint/type-utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
- '@typescript-eslint/utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
- '@typescript-eslint/visitor-keys': 7.7.1
- debug: 4.3.4(supports-color@8.1.1)
- eslint: 8.57.0
+ '@eslint-community/regexpp': 4.11.0
+ '@typescript-eslint/parser': 7.17.0(eslint@9.8.0)(typescript@5.5.4)
+ '@typescript-eslint/scope-manager': 7.17.0
+ '@typescript-eslint/type-utils': 7.17.0(eslint@9.8.0)(typescript@5.5.4)
+ '@typescript-eslint/utils': 7.17.0(eslint@9.8.0)(typescript@5.5.4)
+ '@typescript-eslint/visitor-keys': 7.17.0
+ eslint: 9.8.0
graphemer: 1.4.0
ignore: 5.3.1
natural-compare: 1.4.0
- semver: 7.6.0
- ts-api-utils: 1.3.0(typescript@5.4.5)
+ ts-api-utils: 1.3.0(typescript@5.5.4)
optionalDependencies:
- typescript: 5.4.5
+ typescript: 5.5.4
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3)':
+ '@typescript-eslint/parser@6.11.0(eslint@9.8.0)(typescript@5.3.3)':
dependencies:
'@typescript-eslint/scope-manager': 6.11.0
'@typescript-eslint/types': 6.11.0
'@typescript-eslint/typescript-estree': 6.11.0(typescript@5.3.3)
'@typescript-eslint/visitor-keys': 6.11.0
- debug: 4.3.4(supports-color@8.1.1)
- eslint: 8.53.0
+ debug: 4.3.4(supports-color@5.5.0)
+ eslint: 9.8.0
optionalDependencies:
typescript: 5.3.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3)':
+ '@typescript-eslint/parser@7.1.0(eslint@9.8.0)(typescript@5.3.3)':
dependencies:
'@typescript-eslint/scope-manager': 7.1.0
'@typescript-eslint/types': 7.1.0
'@typescript-eslint/typescript-estree': 7.1.0(typescript@5.3.3)
'@typescript-eslint/visitor-keys': 7.1.0
- debug: 4.3.4(supports-color@8.1.1)
- eslint: 8.57.0
+ debug: 4.3.4(supports-color@5.5.0)
+ eslint: 9.8.0
optionalDependencies:
typescript: 5.3.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5)':
+ '@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.5.4)':
dependencies:
- '@typescript-eslint/scope-manager': 7.7.1
- '@typescript-eslint/types': 7.7.1
- '@typescript-eslint/typescript-estree': 7.7.1(typescript@5.4.5)
- '@typescript-eslint/visitor-keys': 7.7.1
- debug: 4.3.4(supports-color@8.1.1)
- eslint: 8.57.0
+ '@typescript-eslint/scope-manager': 7.17.0
+ '@typescript-eslint/types': 7.17.0
+ '@typescript-eslint/typescript-estree': 7.17.0(typescript@5.5.4)
+ '@typescript-eslint/visitor-keys': 7.17.0
+ debug: 4.3.5(supports-color@8.1.1)
+ eslint: 9.8.0
optionalDependencies:
- typescript: 5.4.5
+ typescript: 5.5.4
transitivePeerDependencies:
- supports-color
@@ -16299,44 +17135,44 @@ snapshots:
'@typescript-eslint/types': 7.1.0
'@typescript-eslint/visitor-keys': 7.1.0
- '@typescript-eslint/scope-manager@7.7.1':
+ '@typescript-eslint/scope-manager@7.17.0':
dependencies:
- '@typescript-eslint/types': 7.7.1
- '@typescript-eslint/visitor-keys': 7.7.1
+ '@typescript-eslint/types': 7.17.0
+ '@typescript-eslint/visitor-keys': 7.17.0
- '@typescript-eslint/type-utils@6.11.0(eslint@8.53.0)(typescript@5.3.3)':
+ '@typescript-eslint/type-utils@6.11.0(eslint@9.8.0)(typescript@5.3.3)':
dependencies:
'@typescript-eslint/typescript-estree': 6.11.0(typescript@5.3.3)
- '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.3.3)
- debug: 4.3.4(supports-color@8.1.1)
- eslint: 8.53.0
+ '@typescript-eslint/utils': 6.11.0(eslint@9.8.0)(typescript@5.3.3)
+ debug: 4.3.5(supports-color@8.1.1)
+ eslint: 9.8.0
ts-api-utils: 1.0.1(typescript@5.3.3)
optionalDependencies:
typescript: 5.3.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/type-utils@7.1.0(eslint@8.57.0)(typescript@5.3.3)':
+ '@typescript-eslint/type-utils@7.1.0(eslint@9.8.0)(typescript@5.3.3)':
dependencies:
'@typescript-eslint/typescript-estree': 7.1.0(typescript@5.3.3)
- '@typescript-eslint/utils': 7.1.0(eslint@8.57.0)(typescript@5.3.3)
- debug: 4.3.4(supports-color@8.1.1)
- eslint: 8.57.0
+ '@typescript-eslint/utils': 7.1.0(eslint@9.8.0)(typescript@5.3.3)
+ debug: 4.3.4(supports-color@5.5.0)
+ eslint: 9.8.0
ts-api-utils: 1.0.1(typescript@5.3.3)
optionalDependencies:
typescript: 5.3.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/type-utils@7.7.1(eslint@8.57.0)(typescript@5.4.5)':
+ '@typescript-eslint/type-utils@7.17.0(eslint@9.8.0)(typescript@5.5.4)':
dependencies:
- '@typescript-eslint/typescript-estree': 7.7.1(typescript@5.4.5)
- '@typescript-eslint/utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
- debug: 4.3.4(supports-color@8.1.1)
- eslint: 8.57.0
- ts-api-utils: 1.3.0(typescript@5.4.5)
+ '@typescript-eslint/typescript-estree': 7.17.0(typescript@5.5.4)
+ '@typescript-eslint/utils': 7.17.0(eslint@9.8.0)(typescript@5.5.4)
+ debug: 4.3.5(supports-color@8.1.1)
+ eslint: 9.8.0
+ ts-api-utils: 1.3.0(typescript@5.5.4)
optionalDependencies:
- typescript: 5.4.5
+ typescript: 5.5.4
transitivePeerDependencies:
- supports-color
@@ -16344,13 +17180,13 @@ snapshots:
'@typescript-eslint/types@7.1.0': {}
- '@typescript-eslint/types@7.7.1': {}
+ '@typescript-eslint/types@7.17.0': {}
'@typescript-eslint/typescript-estree@6.11.0(typescript@5.3.3)':
dependencies:
'@typescript-eslint/types': 6.11.0
'@typescript-eslint/visitor-keys': 6.11.0
- debug: 4.3.4(supports-color@8.1.1)
+ debug: 4.3.5(supports-color@8.1.1)
globby: 11.1.0
is-glob: 4.0.3
semver: 7.5.4
@@ -16364,7 +17200,7 @@ snapshots:
dependencies:
'@typescript-eslint/types': 7.1.0
'@typescript-eslint/visitor-keys': 7.1.0
- debug: 4.3.4(supports-color@8.1.1)
+ debug: 4.3.4(supports-color@5.5.0)
globby: 11.1.0
is-glob: 4.0.3
minimatch: 9.0.3
@@ -16375,59 +17211,56 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/typescript-estree@7.7.1(typescript@5.4.5)':
+ '@typescript-eslint/typescript-estree@7.17.0(typescript@5.5.4)':
dependencies:
- '@typescript-eslint/types': 7.7.1
- '@typescript-eslint/visitor-keys': 7.7.1
- debug: 4.3.4(supports-color@8.1.1)
+ '@typescript-eslint/types': 7.17.0
+ '@typescript-eslint/visitor-keys': 7.17.0
+ debug: 4.3.5(supports-color@8.1.1)
globby: 11.1.0
is-glob: 4.0.3
minimatch: 9.0.4
semver: 7.6.0
- ts-api-utils: 1.3.0(typescript@5.4.5)
+ ts-api-utils: 1.3.0(typescript@5.5.4)
optionalDependencies:
- typescript: 5.4.5
+ typescript: 5.5.4
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/utils@6.11.0(eslint@8.53.0)(typescript@5.3.3)':
+ '@typescript-eslint/utils@6.11.0(eslint@9.8.0)(typescript@5.3.3)':
dependencies:
- '@eslint-community/eslint-utils': 4.4.0(eslint@8.53.0)
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.8.0)
'@types/json-schema': 7.0.12
'@types/semver': 7.5.8
'@typescript-eslint/scope-manager': 6.11.0
'@typescript-eslint/types': 6.11.0
'@typescript-eslint/typescript-estree': 6.11.0(typescript@5.3.3)
- eslint: 8.53.0
+ eslint: 9.8.0
semver: 7.5.4
transitivePeerDependencies:
- supports-color
- typescript
- '@typescript-eslint/utils@7.1.0(eslint@8.57.0)(typescript@5.3.3)':
+ '@typescript-eslint/utils@7.1.0(eslint@9.8.0)(typescript@5.3.3)':
dependencies:
- '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.8.0)
'@types/json-schema': 7.0.12
'@types/semver': 7.5.8
'@typescript-eslint/scope-manager': 7.1.0
'@typescript-eslint/types': 7.1.0
'@typescript-eslint/typescript-estree': 7.1.0(typescript@5.3.3)
- eslint: 8.57.0
+ eslint: 9.8.0
semver: 7.6.0
transitivePeerDependencies:
- supports-color
- typescript
- '@typescript-eslint/utils@7.7.1(eslint@8.57.0)(typescript@5.4.5)':
+ '@typescript-eslint/utils@7.17.0(eslint@9.8.0)(typescript@5.5.4)':
dependencies:
- '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
- '@types/json-schema': 7.0.15
- '@types/semver': 7.5.8
- '@typescript-eslint/scope-manager': 7.7.1
- '@typescript-eslint/types': 7.7.1
- '@typescript-eslint/typescript-estree': 7.7.1(typescript@5.4.5)
- eslint: 8.57.0
- semver: 7.6.0
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.8.0)
+ '@typescript-eslint/scope-manager': 7.17.0
+ '@typescript-eslint/types': 7.17.0
+ '@typescript-eslint/typescript-estree': 7.17.0(typescript@5.5.4)
+ eslint: 9.8.0
transitivePeerDependencies:
- supports-color
- typescript
@@ -16442,84 +17275,59 @@ snapshots:
'@typescript-eslint/types': 7.1.0
eslint-visitor-keys: 3.4.3
- '@typescript-eslint/visitor-keys@7.7.1':
+ '@typescript-eslint/visitor-keys@7.17.0':
dependencies:
- '@typescript-eslint/types': 7.7.1
+ '@typescript-eslint/types': 7.17.0
eslint-visitor-keys: 3.4.3
'@ungap/structured-clone@1.2.0': {}
- '@vitejs/plugin-vue@5.0.4(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))(vue@3.4.26(typescript@5.4.5))':
+ '@vitejs/plugin-vue@5.1.0(vite@5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3))(vue@3.4.34(typescript@5.5.4))':
dependencies:
- vite: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3)
- vue: 3.4.26(typescript@5.4.5)
+ vite: 5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3)
+ vue: 3.4.34(typescript@5.5.4)
- '@vitest/coverage-v8@0.34.6(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))':
+ '@vitest/coverage-v8@1.6.0(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.8)(terser@5.31.3))':
dependencies:
'@ampproject/remapping': 2.2.1
'@bcoe/v8-coverage': 0.2.3
+ debug: 4.3.4(supports-color@5.5.0)
istanbul-lib-coverage: 3.2.2
istanbul-lib-report: 3.0.1
- istanbul-lib-source-maps: 4.0.1
+ istanbul-lib-source-maps: 5.0.4
istanbul-reports: 3.1.6
- magic-string: 0.30.7
+ magic-string: 0.30.10
+ magicast: 0.3.4
picocolors: 1.0.0
std-env: 3.7.0
+ strip-literal: 2.1.0
test-exclude: 6.0.0
- v8-to-istanbul: 9.2.0
- vitest: 0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)
+ vitest: 1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.8)(terser@5.31.3)
transitivePeerDependencies:
- supports-color
- '@vitest/expect@0.34.6':
+ '@vitest/expect@1.6.0':
dependencies:
- '@vitest/spy': 0.34.6
- '@vitest/utils': 0.34.6
- chai: 4.3.10
-
- '@vitest/expect@1.3.1':
- dependencies:
- '@vitest/spy': 1.3.1
- '@vitest/utils': 1.3.1
+ '@vitest/spy': 1.6.0
+ '@vitest/utils': 1.6.0
chai: 4.3.10
- '@vitest/runner@0.34.6':
+ '@vitest/runner@1.6.0':
dependencies:
- '@vitest/utils': 0.34.6
- p-limit: 4.0.0
+ '@vitest/utils': 1.6.0
+ p-limit: 5.0.0
pathe: 1.1.2
- '@vitest/snapshot@0.34.6':
+ '@vitest/snapshot@1.6.0':
dependencies:
- magic-string: 0.30.7
+ magic-string: 0.30.10
pathe: 1.1.2
pretty-format: 29.7.0
- '@vitest/spy@0.34.6':
- dependencies:
- tinyspy: 2.2.0
-
- '@vitest/spy@1.3.1':
- dependencies:
- tinyspy: 2.2.0
-
'@vitest/spy@1.6.0':
dependencies:
tinyspy: 2.2.0
- '@vitest/utils@0.34.6':
- dependencies:
- diff-sequences: 29.6.3
- loupe: 2.3.7
- pretty-format: 29.7.0
-
- '@vitest/utils@1.3.1':
- dependencies:
- diff-sequences: 29.6.3
- estree-walker: 3.0.3
- loupe: 2.3.7
- pretty-format: 29.7.0
-
'@vitest/utils@1.6.0':
dependencies:
diff-sequences: 29.6.3
@@ -16531,126 +17339,157 @@ snapshots:
dependencies:
'@volar/source-map': 2.2.0
+ '@volar/language-core@2.4.0-alpha.18':
+ dependencies:
+ '@volar/source-map': 2.4.0-alpha.18
+
'@volar/source-map@2.2.0':
dependencies:
muggle-string: 0.4.1
+ '@volar/source-map@2.4.0-alpha.18': {}
+
'@volar/typescript@2.2.0':
dependencies:
'@volar/language-core': 2.2.0
path-browserify: 1.0.1
- '@vue/compiler-core@3.4.21':
+ '@volar/typescript@2.4.0-alpha.18':
dependencies:
- '@babel/parser': 7.24.0
- '@vue/shared': 3.4.21
+ '@volar/language-core': 2.4.0-alpha.18
+ path-browserify: 1.0.1
+ vscode-uri: 3.0.8
+
+ '@vue/compiler-core@3.4.29':
+ dependencies:
+ '@babel/parser': 7.24.7
+ '@vue/shared': 3.4.29
entities: 4.5.0
estree-walker: 2.0.2
- source-map-js: 1.0.2
+ source-map-js: 1.2.0
- '@vue/compiler-core@3.4.25':
+ '@vue/compiler-core@3.4.31':
dependencies:
- '@babel/parser': 7.24.5
- '@vue/shared': 3.4.25
+ '@babel/parser': 7.24.7
+ '@vue/shared': 3.4.31
entities: 4.5.0
estree-walker: 2.0.2
source-map-js: 1.2.0
- '@vue/compiler-core@3.4.26':
+ '@vue/compiler-core@3.4.34':
dependencies:
- '@babel/parser': 7.24.5
- '@vue/shared': 3.4.26
+ '@babel/parser': 7.24.7
+ '@vue/shared': 3.4.34
entities: 4.5.0
estree-walker: 2.0.2
source-map-js: 1.2.0
- '@vue/compiler-dom@3.4.21':
+ '@vue/compiler-dom@3.4.29':
dependencies:
- '@vue/compiler-core': 3.4.21
- '@vue/shared': 3.4.21
+ '@vue/compiler-core': 3.4.29
+ '@vue/shared': 3.4.29
- '@vue/compiler-dom@3.4.25':
+ '@vue/compiler-dom@3.4.31':
dependencies:
- '@vue/compiler-core': 3.4.25
- '@vue/shared': 3.4.25
+ '@vue/compiler-core': 3.4.31
+ '@vue/shared': 3.4.31
- '@vue/compiler-dom@3.4.26':
+ '@vue/compiler-dom@3.4.34':
dependencies:
- '@vue/compiler-core': 3.4.26
- '@vue/shared': 3.4.26
+ '@vue/compiler-core': 3.4.34
+ '@vue/shared': 3.4.34
- '@vue/compiler-sfc@3.4.26':
+ '@vue/compiler-sfc@3.4.34':
dependencies:
- '@babel/parser': 7.24.5
- '@vue/compiler-core': 3.4.26
- '@vue/compiler-dom': 3.4.26
- '@vue/compiler-ssr': 3.4.26
- '@vue/shared': 3.4.26
+ '@babel/parser': 7.24.7
+ '@vue/compiler-core': 3.4.34
+ '@vue/compiler-dom': 3.4.34
+ '@vue/compiler-ssr': 3.4.34
+ '@vue/shared': 3.4.34
estree-walker: 2.0.2
magic-string: 0.30.10
- postcss: 8.4.38
+ postcss: 8.4.40
source-map-js: 1.2.0
- '@vue/compiler-ssr@3.4.26':
+ '@vue/compiler-ssr@3.4.34':
+ dependencies:
+ '@vue/compiler-dom': 3.4.34
+ '@vue/shared': 3.4.34
+
+ '@vue/compiler-vue2@2.7.16':
dependencies:
- '@vue/compiler-dom': 3.4.26
- '@vue/shared': 3.4.26
+ de-indent: 1.0.2
+ he: 1.2.0
'@vue/devtools-api@6.6.1': {}
- '@vue/language-core@2.0.16(typescript@5.4.5)':
+ '@vue/language-core@2.0.16(typescript@5.5.4)':
dependencies:
'@volar/language-core': 2.2.0
- '@vue/compiler-dom': 3.4.25
- '@vue/shared': 3.4.25
+ '@vue/compiler-dom': 3.4.31
+ '@vue/shared': 3.4.31
computeds: 0.0.1
minimatch: 9.0.4
path-browserify: 1.0.1
vue-template-compiler: 2.7.14
optionalDependencies:
- typescript: 5.4.5
+ typescript: 5.5.4
+
+ '@vue/language-core@2.0.29(typescript@5.5.4)':
+ dependencies:
+ '@volar/language-core': 2.4.0-alpha.18
+ '@vue/compiler-dom': 3.4.31
+ '@vue/compiler-vue2': 2.7.16
+ '@vue/shared': 3.4.31
+ computeds: 0.0.1
+ minimatch: 9.0.4
+ muggle-string: 0.4.1
+ path-browserify: 1.0.1
+ optionalDependencies:
+ typescript: 5.5.4
- '@vue/reactivity@3.4.26':
+ '@vue/reactivity@3.4.34':
dependencies:
- '@vue/shared': 3.4.26
+ '@vue/shared': 3.4.34
- '@vue/runtime-core@3.4.26':
+ '@vue/runtime-core@3.4.34':
dependencies:
- '@vue/reactivity': 3.4.26
- '@vue/shared': 3.4.26
+ '@vue/reactivity': 3.4.34
+ '@vue/shared': 3.4.34
- '@vue/runtime-dom@3.4.26':
+ '@vue/runtime-dom@3.4.34':
dependencies:
- '@vue/runtime-core': 3.4.26
- '@vue/shared': 3.4.26
+ '@vue/reactivity': 3.4.34
+ '@vue/runtime-core': 3.4.34
+ '@vue/shared': 3.4.34
csstype: 3.1.3
- '@vue/server-renderer@3.4.26(vue@3.4.26(typescript@5.4.5))':
+ '@vue/server-renderer@3.4.34(vue@3.4.34(typescript@5.5.4))':
dependencies:
- '@vue/compiler-ssr': 3.4.26
- '@vue/shared': 3.4.26
- vue: 3.4.26(typescript@5.4.5)
+ '@vue/compiler-ssr': 3.4.34
+ '@vue/shared': 3.4.34
+ vue: 3.4.34(typescript@5.5.4)
- '@vue/shared@3.4.21': {}
+ '@vue/shared@3.4.29': {}
- '@vue/shared@3.4.25': {}
+ '@vue/shared@3.4.31': {}
- '@vue/shared@3.4.26': {}
+ '@vue/shared@3.4.34': {}
- '@vue/test-utils@2.4.1(@vue/server-renderer@3.4.26(vue@3.4.26(typescript@5.4.5)))(vue@3.4.26(typescript@5.4.5))':
+ '@vue/test-utils@2.4.1(@vue/server-renderer@3.4.34(vue@3.4.34(typescript@5.5.4)))(vue@3.4.34(typescript@5.5.4))':
dependencies:
js-beautify: 1.14.9
- vue: 3.4.26(typescript@5.4.5)
+ vue: 3.4.34(typescript@5.5.4)
vue-component-type-helpers: 1.8.4
optionalDependencies:
- '@vue/server-renderer': 3.4.26(vue@3.4.26(typescript@5.4.5))
+ '@vue/server-renderer': 3.4.34(vue@3.4.34(typescript@5.5.4))
'@webgpu/types@0.1.30': {}
- '@yarnpkg/esbuild-plugin-pnp@3.0.0-rc.15(esbuild@0.20.2)':
+ '@yarnpkg/esbuild-plugin-pnp@3.0.0-rc.15(esbuild@0.19.11)':
dependencies:
- esbuild: 0.20.2
- tslib: 2.6.2
+ esbuild: 0.19.11
+ tslib: 2.6.3
'@yarnpkg/fslib@2.10.3':
dependencies:
@@ -16677,22 +17516,22 @@ snapshots:
mime-types: 2.1.35
negotiator: 0.6.3
- acorn-import-assertions@1.9.0(acorn@8.11.3):
+ acorn-import-assertions@1.9.0(acorn@8.12.1):
dependencies:
- acorn: 8.11.3
+ acorn: 8.12.1
optional: true
- acorn-import-attributes@1.9.5(acorn@8.11.3):
+ acorn-import-attributes@1.9.5(acorn@8.12.1):
dependencies:
- acorn: 8.11.3
+ acorn: 8.12.1
acorn-jsx@5.3.2(acorn@7.4.1):
dependencies:
acorn: 7.4.1
- acorn-jsx@5.3.2(acorn@8.11.3):
+ acorn-jsx@5.3.2(acorn@8.12.1):
dependencies:
- acorn: 8.11.3
+ acorn: 8.12.1
acorn-walk@7.2.0: {}
@@ -16700,7 +17539,7 @@ snapshots:
acorn@7.4.1: {}
- acorn@8.11.3: {}
+ acorn@8.12.1: {}
address@1.2.2: {}
@@ -16714,13 +17553,13 @@ snapshots:
agent-base@6.0.2:
dependencies:
- debug: 4.3.4(supports-color@8.1.1)
+ debug: 4.3.5(supports-color@8.1.1)
transitivePeerDependencies:
- supports-color
agent-base@7.1.0:
dependencies:
- debug: 4.3.4(supports-color@8.1.1)
+ debug: 4.3.5(supports-color@8.1.1)
transitivePeerDependencies:
- supports-color
@@ -16734,7 +17573,7 @@ snapshots:
clean-stack: 5.2.0
indent-string: 5.0.0
- aiscript-vscode@https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/34bf4e1530efcf1efa855bd04e2dab39735e1b02:
+ aiscript-vscode@https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/e1e1b27f2f72cd28a473e004b6da0d8fc0bd40d9:
dependencies:
'@aiscript-dev/aiscript-languageserver': https://github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.6/aiscript-dev-aiscript-languageserver-0.1.6.tgz
vscode-languageclient: 9.0.1
@@ -16743,7 +17582,15 @@ snapshots:
optionalDependencies:
ajv: 8.13.0
- ajv-formats@2.1.1(ajv@8.13.0):
+ ajv-draft-04@1.0.0(ajv@8.17.1):
+ optionalDependencies:
+ ajv: 8.17.1
+
+ ajv-formats@2.1.1(ajv@8.17.1):
+ optionalDependencies:
+ ajv: 8.17.1
+
+ ajv-formats@3.0.1(ajv@8.13.0):
optionalDependencies:
ajv: 8.13.0
@@ -16754,6 +17601,13 @@ snapshots:
json-schema-traverse: 0.4.1
uri-js: 4.4.1
+ ajv@8.12.0:
+ dependencies:
+ fast-deep-equal: 3.1.3
+ json-schema-traverse: 1.0.0
+ require-from-string: 2.0.2
+ uri-js: 4.4.1
+
ajv@8.13.0:
dependencies:
fast-deep-equal: 3.1.3
@@ -16761,6 +17615,13 @@ snapshots:
require-from-string: 2.0.2
uri-js: 4.4.1
+ ajv@8.17.1:
+ dependencies:
+ fast-deep-equal: 3.1.3
+ fast-uri: 3.0.1
+ json-schema-traverse: 1.0.0
+ require-from-string: 2.0.2
+
ansi-colors@4.1.3: {}
ansi-escapes@4.3.2:
@@ -16803,7 +17664,7 @@ snapshots:
archiver-utils@5.0.2:
dependencies:
- glob: 10.3.12
+ glob: 10.3.10
graceful-fs: 4.2.11
is-stream: 2.0.1
lazystream: 1.0.1
@@ -16841,6 +17702,10 @@ snapshots:
dependencies:
deep-equal: 2.2.0
+ aria-query@5.3.0:
+ dependencies:
+ dequal: 2.0.3
+
array-buffer-byte-length@1.0.0:
dependencies:
call-bind: 1.0.2
@@ -16908,7 +17773,7 @@ snapshots:
dependencies:
pvtsutils: 1.3.5
pvutils: 1.1.3
- tslib: 2.6.2
+ tslib: 2.6.3
assert-never@1.2.1: {}
@@ -16926,7 +17791,7 @@ snapshots:
ast-types@0.16.1:
dependencies:
- tslib: 2.6.2
+ tslib: 2.6.3
astral-regex@2.0.0: {}
@@ -16936,6 +17801,8 @@ snapshots:
dependencies:
tslib: 2.6.2
+ async@0.2.10: {}
+
async@3.2.4: {}
asynckit@0.4.0: {}
@@ -16950,12 +17817,12 @@ snapshots:
dependencies:
'@fastify/error': 3.4.0
archy: 1.0.0
- debug: 4.3.4(supports-color@8.1.1)
+ debug: 4.3.5(supports-color@8.1.1)
fastq: 1.17.1
transitivePeerDependencies:
- supports-color
- aws-sdk-client-mock@3.0.1:
+ aws-sdk-client-mock@4.0.1:
dependencies:
'@types/sinon': 10.0.13
sinon: 16.1.3
@@ -16967,13 +17834,13 @@ snapshots:
axios@0.24.0:
dependencies:
- follow-redirects: 1.15.2(debug@4.3.4)
+ follow-redirects: 1.15.2(debug@4.3.5)
transitivePeerDependencies:
- debug
- axios@1.6.2(debug@4.3.4):
+ axios@1.6.2(debug@4.3.5):
dependencies:
- follow-redirects: 1.15.2(debug@4.3.4)
+ follow-redirects: 1.15.2(debug@4.3.5)
form-data: 4.0.0
proxy-from-env: 1.1.0
transitivePeerDependencies:
@@ -16981,9 +17848,9 @@ snapshots:
b4a@1.6.4: {}
- babel-core@7.0.0-bridge.0(@babel/core@7.24.0):
+ babel-core@7.0.0-bridge.0(@babel/core@7.24.7):
dependencies:
- '@babel/core': 7.24.0
+ '@babel/core': 7.24.7
babel-jest@29.7.0(@babel/core@7.23.5):
dependencies:
@@ -17011,31 +17878,31 @@ snapshots:
babel-plugin-jest-hoist@29.6.3:
dependencies:
'@babel/template': 7.24.0
- '@babel/types': 7.24.0
+ '@babel/types': 7.24.7
'@types/babel__core': 7.20.0
'@types/babel__traverse': 7.20.0
- babel-plugin-polyfill-corejs2@0.4.6(@babel/core@7.24.0):
+ babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.24.7):
dependencies:
- '@babel/compat-data': 7.23.5
- '@babel/core': 7.24.0
- '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.24.0)
+ '@babel/compat-data': 7.24.7
+ '@babel/core': 7.24.7
+ '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.7)
semver: 6.3.1
transitivePeerDependencies:
- supports-color
- babel-plugin-polyfill-corejs3@0.8.6(@babel/core@7.24.0):
+ babel-plugin-polyfill-corejs3@0.10.4(@babel/core@7.24.7):
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.24.0)
- core-js-compat: 3.33.3
+ '@babel/core': 7.24.7
+ '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.7)
+ core-js-compat: 3.37.1
transitivePeerDependencies:
- supports-color
- babel-plugin-polyfill-regenerator@0.5.3(@babel/core@7.24.0):
+ babel-plugin-polyfill-regenerator@0.6.2(@babel/core@7.24.7):
dependencies:
- '@babel/core': 7.24.0
- '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.24.0)
+ '@babel/core': 7.24.7
+ '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.7)
transitivePeerDependencies:
- supports-color
@@ -17063,7 +17930,7 @@ snapshots:
babel-walk@3.0.0-canary-5:
dependencies:
- '@babel/types': 7.23.5
+ '@babel/types': 7.24.0
bail@2.0.2: {}
@@ -17115,23 +17982,6 @@ snapshots:
bn.js@4.12.0: {}
- body-parser@1.20.1:
- dependencies:
- bytes: 3.1.2
- content-type: 1.0.5
- debug: 2.6.9
- depd: 2.0.0
- destroy: 1.2.0
- http-errors: 2.0.0
- iconv-lite: 0.4.24
- on-finished: 2.4.1
- qs: 6.11.0
- raw-body: 2.5.1
- type-is: 1.6.18
- unpipe: 1.0.0
- transitivePeerDependencies:
- - supports-color
-
body-parser@1.20.2:
dependencies:
bytes: 3.1.2
@@ -17170,6 +18020,10 @@ snapshots:
dependencies:
fill-range: 7.0.1
+ braces@3.0.3:
+ dependencies:
+ fill-range: 7.1.1
+
broadcast-channel@7.0.0:
dependencies:
'@babel/runtime': 7.23.4
@@ -17179,10 +18033,6 @@ snapshots:
browser-assert@1.2.1: {}
- browserify-zlib@0.1.4:
- dependencies:
- pako: 0.2.9
-
browserslist@4.22.2:
dependencies:
caniuse-lite: 1.0.30001566
@@ -17229,14 +18079,19 @@ snapshots:
node-gyp-build: 4.6.0
optional: true
- bullmq@5.7.8:
+ bufferutil@4.0.8:
+ dependencies:
+ node-gyp-build: 4.6.0
+ optional: true
+
+ bullmq@5.10.4:
dependencies:
cron-parser: 4.8.1
ioredis: 5.4.1
msgpackr: 1.10.1
node-abort-controller: 3.1.1
semver: 7.6.0
- tslib: 2.6.2
+ tslib: 2.6.3
uuid: 9.0.1
transitivePeerDependencies:
- supports-color
@@ -17256,10 +18111,10 @@ snapshots:
cacache@18.0.0:
dependencies:
'@npmcli/fs': 3.1.0
- fs-minipass: 3.0.2
- glob: 10.3.12
- lru-cache: 10.0.2
- minipass: 7.0.4
+ fs-minipass: 3.0.3
+ glob: 10.3.10
+ lru-cache: 10.2.2
+ minipass: 7.1.2
minipass-collect: 1.0.2
minipass-flush: 1.0.5
minipass-pipeline: 1.2.4
@@ -17282,6 +18137,16 @@ snapshots:
normalize-url: 8.0.0
responselike: 3.0.0
+ cacheable-request@12.0.1:
+ dependencies:
+ '@types/http-cache-semantics': 4.0.4
+ get-stream: 9.0.1
+ http-cache-semantics: 4.1.1
+ keyv: 4.5.4
+ mimic-response: 4.0.0
+ normalize-url: 8.0.1
+ responselike: 3.0.0
+
cacheable-request@7.0.2:
dependencies:
clone-response: 1.0.3
@@ -17376,26 +18241,26 @@ snapshots:
dependencies:
is-regex: 1.1.4
- chart.js@4.4.2:
+ chart.js@4.4.3:
dependencies:
'@kurkle/color': 0.3.2
- chartjs-adapter-date-fns@3.0.0(chart.js@4.4.2)(date-fns@2.30.0):
+ chartjs-adapter-date-fns@3.0.0(chart.js@4.4.3)(date-fns@2.30.0):
dependencies:
- chart.js: 4.4.2
+ chart.js: 4.4.3
date-fns: 2.30.0
- chartjs-chart-matrix@2.0.1(chart.js@4.4.2):
+ chartjs-chart-matrix@2.0.1(chart.js@4.4.3):
dependencies:
- chart.js: 4.4.2
+ chart.js: 4.4.3
- chartjs-plugin-gradient@0.6.1(chart.js@4.4.2):
+ chartjs-plugin-gradient@0.6.1(chart.js@4.4.3):
dependencies:
- chart.js: 4.4.2
+ chart.js: 4.4.3
- chartjs-plugin-zoom@2.0.1(chart.js@4.4.2):
+ chartjs-plugin-zoom@2.0.1(chart.js@4.4.3):
dependencies:
- chart.js: 4.4.2
+ chart.js: 4.4.3
hammerjs: 2.0.8
check-error@1.0.3:
@@ -17435,11 +18300,12 @@ snapshots:
optionalDependencies:
fsevents: 2.3.3
- chownr@1.1.4: {}
+ chownr@1.1.4:
+ optional: true
chownr@2.0.0: {}
- chromatic@11.3.0: {}
+ chromatic@11.5.6: {}
ci-info@3.7.1: {}
@@ -17464,8 +18330,6 @@ snapshots:
parse5-htmlparser2-tree-adapter: 6.0.1
yargs: 16.2.0
- cli-spinners@2.7.0: {}
-
cli-spinners@2.9.2: {}
cli-table3@0.6.3:
@@ -17568,7 +18432,7 @@ snapshots:
commondir@1.0.1: {}
- compare-versions@6.1.0: {}
+ compare-versions@6.1.1: {}
compress-commons@6.0.2:
dependencies:
@@ -17617,8 +18481,8 @@ snapshots:
constantinople@4.0.1:
dependencies:
- '@babel/parser': 7.23.9
- '@babel/types': 7.23.5
+ '@babel/parser': 7.24.5
+ '@babel/types': 7.24.0
content-disposition@0.5.4:
dependencies:
@@ -17636,7 +18500,7 @@ snapshots:
cookie@0.6.0: {}
- core-js-compat@3.33.3:
+ core-js-compat@3.37.1:
dependencies:
browserslist: 4.23.0
@@ -17658,13 +18522,13 @@ snapshots:
crc-32: 1.2.2
readable-stream: 4.3.0
- create-jest@29.7.0(@types/node@20.12.7):
+ create-jest@29.7.0(@types/node@20.14.12):
dependencies:
'@jest/types': 29.6.3
chalk: 4.1.2
exit: 0.1.2
graceful-fs: 4.2.11
- jest-config: 29.7.0(@types/node@20.12.7)
+ jest-config: 29.7.0(@types/node@20.14.12)
jest-util: 29.7.0
prompts: 2.4.2
transitivePeerDependencies:
@@ -17677,10 +18541,10 @@ snapshots:
dependencies:
luxon: 3.3.0
- cropperjs@2.0.0-beta.5:
+ cropperjs@2.0.0-rc.1:
dependencies:
- '@cropper/elements': 2.0.0-beta.5
- '@cropper/utils': 2.0.0-beta.5
+ '@cropper/elements': 2.0.0-rc.1
+ '@cropper/utils': 2.0.0-rc.1
cross-env@7.0.3:
dependencies:
@@ -17710,11 +18574,13 @@ snapshots:
shebang-command: 2.0.0
which: 2.0.2
- crypto-random-string@2.0.0: {}
+ crypto-random-string@4.0.0:
+ dependencies:
+ type-fest: 1.4.0
- css-declaration-sorter@7.2.0(postcss@8.4.38):
+ css-declaration-sorter@7.2.0(postcss@8.4.40):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.40
css-select@5.1.0:
dependencies:
@@ -17740,49 +18606,49 @@ snapshots:
cssesc@3.0.0: {}
- cssnano-preset-default@6.1.2(postcss@8.4.38):
+ cssnano-preset-default@6.1.2(postcss@8.4.40):
dependencies:
browserslist: 4.23.0
- css-declaration-sorter: 7.2.0(postcss@8.4.38)
- cssnano-utils: 4.0.2(postcss@8.4.38)
- postcss: 8.4.38
- postcss-calc: 9.0.1(postcss@8.4.38)
- postcss-colormin: 6.1.0(postcss@8.4.38)
- postcss-convert-values: 6.1.0(postcss@8.4.38)
- postcss-discard-comments: 6.0.2(postcss@8.4.38)
- postcss-discard-duplicates: 6.0.3(postcss@8.4.38)
- postcss-discard-empty: 6.0.3(postcss@8.4.38)
- postcss-discard-overridden: 6.0.2(postcss@8.4.38)
- postcss-merge-longhand: 6.0.5(postcss@8.4.38)
- postcss-merge-rules: 6.1.1(postcss@8.4.38)
- postcss-minify-font-values: 6.1.0(postcss@8.4.38)
- postcss-minify-gradients: 6.0.3(postcss@8.4.38)
- postcss-minify-params: 6.1.0(postcss@8.4.38)
- postcss-minify-selectors: 6.0.4(postcss@8.4.38)
- postcss-normalize-charset: 6.0.2(postcss@8.4.38)
- postcss-normalize-display-values: 6.0.2(postcss@8.4.38)
- postcss-normalize-positions: 6.0.2(postcss@8.4.38)
- postcss-normalize-repeat-style: 6.0.2(postcss@8.4.38)
- postcss-normalize-string: 6.0.2(postcss@8.4.38)
- postcss-normalize-timing-functions: 6.0.2(postcss@8.4.38)
- postcss-normalize-unicode: 6.1.0(postcss@8.4.38)
- postcss-normalize-url: 6.0.2(postcss@8.4.38)
- postcss-normalize-whitespace: 6.0.2(postcss@8.4.38)
- postcss-ordered-values: 6.0.2(postcss@8.4.38)
- postcss-reduce-initial: 6.1.0(postcss@8.4.38)
- postcss-reduce-transforms: 6.0.2(postcss@8.4.38)
- postcss-svgo: 6.0.3(postcss@8.4.38)
- postcss-unique-selectors: 6.0.4(postcss@8.4.38)
+ css-declaration-sorter: 7.2.0(postcss@8.4.40)
+ cssnano-utils: 4.0.2(postcss@8.4.40)
+ postcss: 8.4.40
+ postcss-calc: 9.0.1(postcss@8.4.40)
+ postcss-colormin: 6.1.0(postcss@8.4.40)
+ postcss-convert-values: 6.1.0(postcss@8.4.40)
+ postcss-discard-comments: 6.0.2(postcss@8.4.40)
+ postcss-discard-duplicates: 6.0.3(postcss@8.4.40)
+ postcss-discard-empty: 6.0.3(postcss@8.4.40)
+ postcss-discard-overridden: 6.0.2(postcss@8.4.40)
+ postcss-merge-longhand: 6.0.5(postcss@8.4.40)
+ postcss-merge-rules: 6.1.1(postcss@8.4.40)
+ postcss-minify-font-values: 6.1.0(postcss@8.4.40)
+ postcss-minify-gradients: 6.0.3(postcss@8.4.40)
+ postcss-minify-params: 6.1.0(postcss@8.4.40)
+ postcss-minify-selectors: 6.0.4(postcss@8.4.40)
+ postcss-normalize-charset: 6.0.2(postcss@8.4.40)
+ postcss-normalize-display-values: 6.0.2(postcss@8.4.40)
+ postcss-normalize-positions: 6.0.2(postcss@8.4.40)
+ postcss-normalize-repeat-style: 6.0.2(postcss@8.4.40)
+ postcss-normalize-string: 6.0.2(postcss@8.4.40)
+ postcss-normalize-timing-functions: 6.0.2(postcss@8.4.40)
+ postcss-normalize-unicode: 6.1.0(postcss@8.4.40)
+ postcss-normalize-url: 6.0.2(postcss@8.4.40)
+ postcss-normalize-whitespace: 6.0.2(postcss@8.4.40)
+ postcss-ordered-values: 6.0.2(postcss@8.4.40)
+ postcss-reduce-initial: 6.1.0(postcss@8.4.40)
+ postcss-reduce-transforms: 6.0.2(postcss@8.4.40)
+ postcss-svgo: 6.0.3(postcss@8.4.40)
+ postcss-unique-selectors: 6.0.4(postcss@8.4.40)
- cssnano-utils@4.0.2(postcss@8.4.38):
+ cssnano-utils@4.0.2(postcss@8.4.40):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.40
- cssnano@6.1.2(postcss@8.4.38):
+ cssnano@6.1.2(postcss@8.4.40):
dependencies:
- cssnano-preset-default: 6.1.2(postcss@8.4.38)
+ cssnano-preset-default: 6.1.2(postcss@8.4.40)
lilconfig: 3.1.1
- postcss: 8.4.38
+ postcss: 8.4.40
csso@5.0.5:
dependencies:
@@ -17798,52 +18664,7 @@ snapshots:
dependencies:
uniq: 1.0.1
- cypress@13.7.3:
- dependencies:
- '@cypress/request': 3.0.0
- '@cypress/xvfb': 1.2.4(supports-color@8.1.1)
- '@types/sinonjs__fake-timers': 8.1.1
- '@types/sizzle': 2.3.3
- arch: 2.2.0
- blob-util: 2.0.2
- bluebird: 3.7.2
- buffer: 5.7.1
- cachedir: 2.3.0
- chalk: 4.1.2
- check-more-types: 2.24.0
- cli-cursor: 3.1.0
- cli-table3: 0.6.3
- commander: 6.2.1
- common-tags: 1.8.2
- dayjs: 1.11.10
- debug: 4.3.4(supports-color@8.1.1)
- enquirer: 2.3.6
- eventemitter2: 6.4.7
- execa: 4.1.0
- executable: 4.1.1
- extract-zip: 2.0.1(supports-color@8.1.1)
- figures: 3.2.0
- fs-extra: 9.1.0
- getos: 3.2.1
- is-ci: 3.0.1
- is-installed-globally: 0.4.0
- lazy-ass: 1.6.0
- listr2: 3.14.0(enquirer@2.3.6)
- lodash: 4.17.21
- log-symbols: 4.1.0
- minimist: 1.2.8
- ospath: 1.2.2
- pretty-bytes: 5.6.0
- process: 0.11.10
- proxy-from-env: 1.0.0
- request-progress: 3.0.0
- semver: 7.6.0
- supports-color: 8.1.1
- tmp: 0.2.3
- untildify: 4.0.0
- yauzl: 2.10.0
-
- cypress@13.8.1:
+ cypress@13.13.1:
dependencies:
'@cypress/request': 3.0.0
'@cypress/xvfb': 1.2.4(supports-color@8.1.1)
@@ -17861,7 +18682,7 @@ snapshots:
commander: 6.2.1
common-tags: 1.8.2
dayjs: 1.11.10
- debug: 4.3.4(supports-color@8.1.1)
+ debug: 4.3.5(supports-color@8.1.1)
enquirer: 2.3.6
eventemitter2: 6.4.7
execa: 4.1.0
@@ -17925,7 +18746,7 @@ snapshots:
optionalDependencies:
supports-color: 5.5.0
- debug@4.3.4(supports-color@8.1.1):
+ debug@4.3.5(supports-color@8.1.1):
dependencies:
ms: 2.1.2
optionalDependencies:
@@ -18018,17 +18839,6 @@ snapshots:
defu@6.1.4: {}
- del@6.1.1:
- dependencies:
- globby: 11.1.0
- graceful-fs: 4.2.11
- is-glob: 4.0.3
- is-path-cwd: 2.2.0
- is-path-inside: 3.0.3
- p-map: 4.0.0
- rimraf: 3.0.2
- slash: 3.0.0
-
delayed-stream@1.0.0: {}
delegates@1.0.0:
@@ -18044,9 +18854,6 @@ snapshots:
detect-indent@6.1.0: {}
- detect-libc@2.0.2:
- optional: true
-
detect-libc@2.0.3: {}
detect-newline@3.1.0: {}
@@ -18058,7 +18865,7 @@ snapshots:
detect-port@1.5.1:
dependencies:
address: 1.2.2
- debug: 4.3.4(supports-color@8.1.1)
+ debug: 4.3.5(supports-color@8.1.1)
transitivePeerDependencies:
- supports-color
@@ -18072,6 +18879,8 @@ snapshots:
diff@5.1.0: {}
+ diff@5.2.0: {}
+
dijkstrajs@1.0.2: {}
dir-glob@3.0.1:
@@ -18118,13 +18927,6 @@ snapshots:
duplexer@0.1.2: {}
- duplexify@3.7.1:
- dependencies:
- end-of-stream: 1.4.4
- inherits: 2.0.4
- readable-stream: 2.3.7
- stream-shift: 1.0.1
-
eastasianwidth@0.2.0: {}
ecc-jsbn@0.1.2:
@@ -18145,7 +18947,7 @@ snapshots:
ee-first@1.1.1: {}
- ejs@3.1.9:
+ ejs@3.1.10:
dependencies:
jake: 10.8.5
@@ -18244,7 +19046,7 @@ snapshots:
isarray: 2.0.5
stop-iteration-iterator: 1.0.0
- es-module-lexer@0.9.3: {}
+ es-module-lexer@1.5.4: {}
es-set-tostringtag@2.0.1:
dependencies:
@@ -18272,10 +19074,10 @@ snapshots:
esbuild-plugin-alias@0.2.1: {}
- esbuild-register@3.5.0(esbuild@0.20.2):
+ esbuild-register@3.5.0(esbuild@0.19.11):
dependencies:
- debug: 4.3.4(supports-color@8.1.1)
- esbuild: 0.20.2
+ debug: 4.3.5(supports-color@8.1.1)
+ esbuild: 0.19.11
transitivePeerDependencies:
- supports-color
@@ -18330,31 +19132,58 @@ snapshots:
'@esbuild/win32-ia32': 0.19.11
'@esbuild/win32-x64': 0.19.11
- esbuild@0.20.2:
+ esbuild@0.21.5:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.21.5
+ '@esbuild/android-arm': 0.21.5
+ '@esbuild/android-arm64': 0.21.5
+ '@esbuild/android-x64': 0.21.5
+ '@esbuild/darwin-arm64': 0.21.5
+ '@esbuild/darwin-x64': 0.21.5
+ '@esbuild/freebsd-arm64': 0.21.5
+ '@esbuild/freebsd-x64': 0.21.5
+ '@esbuild/linux-arm': 0.21.5
+ '@esbuild/linux-arm64': 0.21.5
+ '@esbuild/linux-ia32': 0.21.5
+ '@esbuild/linux-loong64': 0.21.5
+ '@esbuild/linux-mips64el': 0.21.5
+ '@esbuild/linux-ppc64': 0.21.5
+ '@esbuild/linux-riscv64': 0.21.5
+ '@esbuild/linux-s390x': 0.21.5
+ '@esbuild/linux-x64': 0.21.5
+ '@esbuild/netbsd-x64': 0.21.5
+ '@esbuild/openbsd-x64': 0.21.5
+ '@esbuild/sunos-x64': 0.21.5
+ '@esbuild/win32-arm64': 0.21.5
+ '@esbuild/win32-ia32': 0.21.5
+ '@esbuild/win32-x64': 0.21.5
+
+ esbuild@0.23.0:
optionalDependencies:
- '@esbuild/aix-ppc64': 0.20.2
- '@esbuild/android-arm': 0.20.2
- '@esbuild/android-arm64': 0.20.2
- '@esbuild/android-x64': 0.20.2
- '@esbuild/darwin-arm64': 0.20.2
- '@esbuild/darwin-x64': 0.20.2
- '@esbuild/freebsd-arm64': 0.20.2
- '@esbuild/freebsd-x64': 0.20.2
- '@esbuild/linux-arm': 0.20.2
- '@esbuild/linux-arm64': 0.20.2
- '@esbuild/linux-ia32': 0.20.2
- '@esbuild/linux-loong64': 0.20.2
- '@esbuild/linux-mips64el': 0.20.2
- '@esbuild/linux-ppc64': 0.20.2
- '@esbuild/linux-riscv64': 0.20.2
- '@esbuild/linux-s390x': 0.20.2
- '@esbuild/linux-x64': 0.20.2
- '@esbuild/netbsd-x64': 0.20.2
- '@esbuild/openbsd-x64': 0.20.2
- '@esbuild/sunos-x64': 0.20.2
- '@esbuild/win32-arm64': 0.20.2
- '@esbuild/win32-ia32': 0.20.2
- '@esbuild/win32-x64': 0.20.2
+ '@esbuild/aix-ppc64': 0.23.0
+ '@esbuild/android-arm': 0.23.0
+ '@esbuild/android-arm64': 0.23.0
+ '@esbuild/android-x64': 0.23.0
+ '@esbuild/darwin-arm64': 0.23.0
+ '@esbuild/darwin-x64': 0.23.0
+ '@esbuild/freebsd-arm64': 0.23.0
+ '@esbuild/freebsd-x64': 0.23.0
+ '@esbuild/linux-arm': 0.23.0
+ '@esbuild/linux-arm64': 0.23.0
+ '@esbuild/linux-ia32': 0.23.0
+ '@esbuild/linux-loong64': 0.23.0
+ '@esbuild/linux-mips64el': 0.23.0
+ '@esbuild/linux-ppc64': 0.23.0
+ '@esbuild/linux-riscv64': 0.23.0
+ '@esbuild/linux-s390x': 0.23.0
+ '@esbuild/linux-x64': 0.23.0
+ '@esbuild/netbsd-x64': 0.23.0
+ '@esbuild/openbsd-arm64': 0.23.0
+ '@esbuild/openbsd-x64': 0.23.0
+ '@esbuild/sunos-x64': 0.23.0
+ '@esbuild/win32-arm64': 0.23.0
+ '@esbuild/win32-ia32': 0.23.0
+ '@esbuild/win32-x64': 0.23.0
escalade@3.1.1: {}
@@ -18397,37 +19226,17 @@ snapshots:
transitivePeerDependencies:
- supports-color
- eslint-module-utils@2.8.0(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint@8.53.0):
- dependencies:
- debug: 3.2.7(supports-color@8.1.1)
- optionalDependencies:
- '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.3.3)
- eslint: 8.53.0
- eslint-import-resolver-node: 0.3.9
- transitivePeerDependencies:
- - supports-color
-
- eslint-module-utils@2.8.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0):
+ eslint-module-utils@2.8.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint@9.8.0):
dependencies:
debug: 3.2.7(supports-color@8.1.1)
optionalDependencies:
- '@typescript-eslint/parser': 7.1.0(eslint@8.57.0)(typescript@5.3.3)
- eslint: 8.57.0
+ '@typescript-eslint/parser': 7.17.0(eslint@9.8.0)(typescript@5.5.4)
+ eslint: 9.8.0
eslint-import-resolver-node: 0.3.9
transitivePeerDependencies:
- supports-color
- eslint-module-utils@2.8.0(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0):
- dependencies:
- debug: 3.2.7(supports-color@8.1.1)
- optionalDependencies:
- '@typescript-eslint/parser': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
- eslint: 8.57.0
- eslint-import-resolver-node: 0.3.9
- transitivePeerDependencies:
- - supports-color
-
- eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0):
+ eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.5.4))(eslint@9.8.0):
dependencies:
array-includes: 3.1.7
array.prototype.findlastindex: 1.2.3
@@ -18435,9 +19244,9 @@ snapshots:
array.prototype.flatmap: 1.3.2
debug: 3.2.7(supports-color@8.1.1)
doctrine: 2.1.0
- eslint: 8.53.0
+ eslint: 9.8.0
eslint-import-resolver-node: 0.3.9
- eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint@8.53.0)
+ eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint@9.8.0)
hasown: 2.0.0
is-core-module: 2.13.1
is-glob: 4.0.3
@@ -18448,76 +19257,22 @@ snapshots:
semver: 6.3.1
tsconfig-paths: 3.15.0
optionalDependencies:
- '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.3.3)
+ '@typescript-eslint/parser': 7.17.0(eslint@9.8.0)(typescript@5.5.4)
transitivePeerDependencies:
- eslint-import-resolver-typescript
- eslint-import-resolver-webpack
- supports-color
- eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0):
+ eslint-plugin-vue@9.27.0(eslint@9.8.0):
dependencies:
- array-includes: 3.1.7
- array.prototype.findlastindex: 1.2.3
- array.prototype.flat: 1.3.2
- array.prototype.flatmap: 1.3.2
- debug: 3.2.7(supports-color@8.1.1)
- doctrine: 2.1.0
- eslint: 8.57.0
- eslint-import-resolver-node: 0.3.9
- eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0)
- hasown: 2.0.0
- is-core-module: 2.13.1
- is-glob: 4.0.3
- minimatch: 3.1.2
- object.fromentries: 2.0.7
- object.groupby: 1.0.1
- object.values: 1.1.7
- semver: 6.3.1
- tsconfig-paths: 3.15.0
- optionalDependencies:
- '@typescript-eslint/parser': 7.1.0(eslint@8.57.0)(typescript@5.3.3)
- transitivePeerDependencies:
- - eslint-import-resolver-typescript
- - eslint-import-resolver-webpack
- - supports-color
-
- eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0):
- dependencies:
- array-includes: 3.1.7
- array.prototype.findlastindex: 1.2.3
- array.prototype.flat: 1.3.2
- array.prototype.flatmap: 1.3.2
- debug: 3.2.7(supports-color@8.1.1)
- doctrine: 2.1.0
- eslint: 8.57.0
- eslint-import-resolver-node: 0.3.9
- eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0)
- hasown: 2.0.0
- is-core-module: 2.13.1
- is-glob: 4.0.3
- minimatch: 3.1.2
- object.fromentries: 2.0.7
- object.groupby: 1.0.1
- object.values: 1.1.7
- semver: 6.3.1
- tsconfig-paths: 3.15.0
- optionalDependencies:
- '@typescript-eslint/parser': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
- transitivePeerDependencies:
- - eslint-import-resolver-typescript
- - eslint-import-resolver-webpack
- - supports-color
-
- eslint-plugin-vue@9.25.0(eslint@8.57.0):
- dependencies:
- '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
- eslint: 8.57.0
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.8.0)
+ eslint: 9.8.0
globals: 13.24.0
natural-compare: 1.4.0
nth-check: 2.1.1
- postcss-selector-parser: 6.0.15
+ postcss-selector-parser: 6.0.16
semver: 7.6.0
- vue-eslint-parser: 9.4.2(eslint@8.57.0)
+ vue-eslint-parser: 9.4.3(eslint@9.8.0)
xml-name-validator: 4.0.0
transitivePeerDependencies:
- supports-color
@@ -18529,98 +19284,64 @@ snapshots:
esrecurse: 4.3.0
estraverse: 5.3.0
+ eslint-scope@8.0.2:
+ dependencies:
+ esrecurse: 4.3.0
+ estraverse: 5.3.0
+
eslint-visitor-keys@3.4.3: {}
- eslint@8.53.0:
+ eslint-visitor-keys@4.0.0: {}
+
+ eslint@9.8.0:
dependencies:
- '@eslint-community/eslint-utils': 4.4.0(eslint@8.53.0)
- '@eslint-community/regexpp': 4.6.2
- '@eslint/eslintrc': 2.1.4
- '@eslint/js': 8.53.0
- '@humanwhocodes/config-array': 0.11.13
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.8.0)
+ '@eslint-community/regexpp': 4.11.0
+ '@eslint/config-array': 0.17.1
+ '@eslint/eslintrc': 3.1.0
+ '@eslint/js': 9.8.0
'@humanwhocodes/module-importer': 1.0.1
+ '@humanwhocodes/retry': 0.3.0
'@nodelib/fs.walk': 1.2.8
- '@ungap/structured-clone': 1.2.0
ajv: 6.12.6
chalk: 4.1.2
cross-spawn: 7.0.3
- debug: 4.3.4(supports-color@8.1.1)
- doctrine: 3.0.0
+ debug: 4.3.5(supports-color@8.1.1)
escape-string-regexp: 4.0.0
- eslint-scope: 7.2.2
- eslint-visitor-keys: 3.4.3
- espree: 9.6.1
- esquery: 1.4.2
+ eslint-scope: 8.0.2
+ eslint-visitor-keys: 4.0.0
+ espree: 10.1.0
+ esquery: 1.6.0
esutils: 2.0.3
fast-deep-equal: 3.1.3
- file-entry-cache: 6.0.1
+ file-entry-cache: 8.0.0
find-up: 5.0.0
glob-parent: 6.0.2
- globals: 13.19.0
- graphemer: 1.4.0
- ignore: 5.2.4
+ ignore: 5.3.1
imurmurhash: 0.1.4
is-glob: 4.0.3
is-path-inside: 3.0.3
- js-yaml: 4.1.0
json-stable-stringify-without-jsonify: 1.0.1
levn: 0.4.1
lodash.merge: 4.6.2
minimatch: 3.1.2
natural-compare: 1.4.0
- optionator: 0.9.3
+ optionator: 0.9.4
strip-ansi: 6.0.1
text-table: 0.2.0
transitivePeerDependencies:
- supports-color
- eslint@8.57.0:
+ espree@10.1.0:
dependencies:
- '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
- '@eslint-community/regexpp': 4.6.2
- '@eslint/eslintrc': 2.1.4
- '@eslint/js': 8.57.0
- '@humanwhocodes/config-array': 0.11.14
- '@humanwhocodes/module-importer': 1.0.1
- '@nodelib/fs.walk': 1.2.8
- '@ungap/structured-clone': 1.2.0
- ajv: 6.12.6
- chalk: 4.1.2
- cross-spawn: 7.0.3
- debug: 4.3.4(supports-color@8.1.1)
- doctrine: 3.0.0
- escape-string-regexp: 4.0.0
- eslint-scope: 7.2.2
- eslint-visitor-keys: 3.4.3
- espree: 9.6.1
- esquery: 1.4.2
- esutils: 2.0.3
- fast-deep-equal: 3.1.3
- file-entry-cache: 6.0.1
- find-up: 5.0.0
- glob-parent: 6.0.2
- globals: 13.19.0
- graphemer: 1.4.0
- ignore: 5.2.4
- imurmurhash: 0.1.4
- is-glob: 4.0.3
- is-path-inside: 3.0.3
- js-yaml: 4.1.0
- json-stable-stringify-without-jsonify: 1.0.1
- levn: 0.4.1
- lodash.merge: 4.6.2
- minimatch: 3.1.2
- natural-compare: 1.4.0
- optionator: 0.9.3
- strip-ansi: 6.0.1
- text-table: 0.2.0
- transitivePeerDependencies:
- - supports-color
+ acorn: 8.12.1
+ acorn-jsx: 5.3.2(acorn@8.12.1)
+ eslint-visitor-keys: 4.0.0
espree@9.6.1:
dependencies:
- acorn: 8.11.3
- acorn-jsx: 5.3.2(acorn@8.11.3)
+ acorn: 8.12.1
+ acorn-jsx: 5.3.2(acorn@8.12.1)
eslint-visitor-keys: 3.4.3
esprima@4.0.1: {}
@@ -18629,6 +19350,10 @@ snapshots:
dependencies:
estraverse: 5.3.0
+ esquery@1.6.0:
+ dependencies:
+ estraverse: 5.3.0
+
esrecurse@4.3.0:
dependencies:
estraverse: 5.3.0
@@ -18706,7 +19431,7 @@ snapshots:
human-signals: 3.0.1
is-stream: 3.0.0
merge-stream: 2.0.0
- npm-run-path: 5.1.0
+ npm-run-path: 5.3.0
onetime: 6.0.0
signal-exit: 3.0.7
strip-final-newline: 3.0.0
@@ -18723,6 +19448,21 @@ snapshots:
signal-exit: 4.1.0
strip-final-newline: 3.0.0
+ execa@9.3.0:
+ dependencies:
+ '@sindresorhus/merge-streams': 4.0.0
+ cross-spawn: 7.0.3
+ figures: 6.1.0
+ get-stream: 9.0.1
+ human-signals: 7.0.0
+ is-plain-obj: 4.1.0
+ is-stream: 4.0.1
+ npm-run-path: 5.3.0
+ pretty-ms: 9.0.0
+ signal-exit: 4.1.0
+ strip-final-newline: 4.0.0
+ yoctocolors: 2.0.2
+
executable@4.1.1:
dependencies:
pify: 2.3.0
@@ -18739,42 +19479,6 @@ snapshots:
exponential-backoff@3.1.1: {}
- express@4.18.2:
- dependencies:
- accepts: 1.3.8
- array-flatten: 1.1.1
- body-parser: 1.20.1
- content-disposition: 0.5.4
- content-type: 1.0.5
- cookie: 0.5.0
- cookie-signature: 1.0.6
- debug: 2.6.9
- depd: 2.0.0
- encodeurl: 1.0.2
- escape-html: 1.0.3
- etag: 1.8.1
- finalhandler: 1.2.0
- fresh: 0.5.2
- http-errors: 2.0.0
- merge-descriptors: 1.0.1
- methods: 1.1.2
- on-finished: 2.4.1
- parseurl: 1.3.3
- path-to-regexp: 0.1.7
- proxy-addr: 2.0.7
- qs: 6.11.0
- range-parser: 1.2.1
- safe-buffer: 5.2.1
- send: 0.18.0
- serve-static: 1.15.0
- setprototypeof: 1.2.0
- statuses: 2.0.1
- type-is: 1.6.18
- utils-merge: 1.0.1
- vary: 1.1.2
- transitivePeerDependencies:
- - supports-color
-
express@4.19.2:
dependencies:
accepts: 1.3.8
@@ -18824,7 +19528,7 @@ snapshots:
extract-zip@2.0.1(supports-color@8.1.1):
dependencies:
- debug: 4.3.4(supports-color@8.1.1)
+ debug: 4.3.5(supports-color@8.1.1)
get-stream: 5.2.0
yauzl: 2.10.0
optionalDependencies:
@@ -18848,15 +19552,15 @@ snapshots:
'@nodelib/fs.walk': 1.2.8
glob-parent: 5.1.2
merge2: 1.4.1
- micromatch: 4.0.5
+ micromatch: 4.0.7
fast-json-stable-stringify@2.1.0: {}
fast-json-stringify@5.8.0:
dependencies:
'@fastify/deepmerge': 1.3.0
- ajv: 8.13.0
- ajv-formats: 2.1.1(ajv@8.13.0)
+ ajv: 8.17.1
+ ajv-formats: 2.1.1(ajv@8.17.1)
fast-deep-equal: 3.1.3
fast-uri: 2.2.0
rfdc: 1.3.0
@@ -18873,6 +19577,8 @@ snapshots:
fast-uri@2.2.0: {}
+ fast-uri@3.0.1: {}
+
fast-xml-parser@4.2.5:
dependencies:
strnum: 1.0.5
@@ -18885,7 +19591,7 @@ snapshots:
raw-body: 2.5.2
secure-json-parse: 2.7.0
- fastify@4.26.2:
+ fastify@4.28.1:
dependencies:
'@fastify/ajv-compiler': 3.5.0
'@fastify/error': 3.4.0
@@ -18896,20 +19602,16 @@ snapshots:
fast-json-stringify: 5.8.0
find-my-way: 8.2.0
light-my-request: 5.11.0
- pino: 8.17.0
+ pino: 9.2.0
process-warning: 3.0.0
proxy-addr: 2.0.7
rfdc: 1.3.0
secure-json-parse: 2.7.0
semver: 7.6.0
- toad-cache: 3.3.0
+ toad-cache: 3.7.0
transitivePeerDependencies:
- supports-color
- fastq@1.15.0:
- dependencies:
- reusify: 1.0.4
-
fastq@1.17.1:
dependencies:
reusify: 1.0.4
@@ -18918,6 +19620,10 @@ snapshots:
dependencies:
bser: 2.1.1
+ fd-package-json@1.2.0:
+ dependencies:
+ walk-up-path: 3.0.1
+
fd-slicer@1.1.0:
dependencies:
pend: 1.2.0
@@ -18937,9 +19643,13 @@ snapshots:
dependencies:
escape-string-regexp: 1.0.5
- file-entry-cache@6.0.1:
+ figures@6.1.0:
+ dependencies:
+ is-unicode-supported: 2.0.0
+
+ file-entry-cache@8.0.0:
dependencies:
- flat-cache: 3.0.4
+ flat-cache: 4.0.1
file-system-cache@2.3.0:
dependencies:
@@ -18952,11 +19662,11 @@ snapshots:
strtok3: 7.0.0
token-types: 5.0.1
- file-type@19.0.0:
+ file-type@19.3.0:
dependencies:
- readable-web-to-node-stream: 3.0.2
- strtok3: 7.0.0
- token-types: 5.0.1
+ strtok3: 8.0.1
+ token-types: 6.0.0
+ uint8array-extras: 1.4.0
filelist@1.0.4:
dependencies:
@@ -18974,6 +19684,10 @@ snapshots:
dependencies:
to-regex-range: 5.0.1
+ fill-range@7.1.1:
+ dependencies:
+ to-regex-range: 5.0.1
+
finalhandler@1.2.0:
dependencies:
debug: 2.6.9
@@ -19033,23 +19747,23 @@ snapshots:
ps-list: 8.1.1
taskkill: 5.0.0
- flat-cache@3.0.4:
+ flat-cache@4.0.1:
dependencies:
- flatted: 3.2.7
- rimraf: 3.0.2
+ flatted: 3.3.1
+ keyv: 4.5.4
- flatted@3.2.7: {}
+ flatted@3.3.1: {}
flow-parser@0.202.0: {}
- fluent-ffmpeg@2.1.2:
+ fluent-ffmpeg@2.1.3:
dependencies:
- async: 3.2.4
+ async: 0.2.10
which: 1.3.1
- follow-redirects@1.15.2(debug@4.3.4):
+ follow-redirects@1.15.2(debug@4.3.5):
optionalDependencies:
- debug: 4.3.4(supports-color@8.1.1)
+ debug: 4.3.5(supports-color@8.1.1)
for-each@0.3.3:
dependencies:
@@ -19072,12 +19786,6 @@ snapshots:
combined-stream: 1.0.8
mime-types: 2.1.35
- form-data@3.0.1:
- dependencies:
- asynckit: 0.4.0
- combined-stream: 1.0.8
- mime-types: 2.1.35
-
form-data@4.0.0:
dependencies:
asynckit: 0.4.0
@@ -19094,8 +19802,6 @@ snapshots:
from@0.1.7: {}
- fs-constants@1.0.0: {}
-
fs-extra@11.1.1:
dependencies:
graceful-fs: 4.2.11
@@ -19130,9 +19836,9 @@ snapshots:
dependencies:
minipass: 3.3.6
- fs-minipass@3.0.2:
+ fs-minipass@3.0.3:
dependencies:
- minipass: 5.0.0
+ minipass: 7.1.2
fs.realpath@1.0.0: {}
@@ -19176,8 +19882,6 @@ snapshots:
has-proto: 1.0.1
has-symbols: 1.0.3
- get-npm-tarball-url@2.0.3: {}
-
get-package-type@0.1.0: {}
get-pixels-frame-info-update@3.3.2:
@@ -19204,6 +19908,11 @@ snapshots:
get-stream@8.0.1: {}
+ get-stream@9.0.1:
+ dependencies:
+ '@sec-ant/readable-stream': 0.4.1
+ is-stream: 4.0.1
+
get-symbol-description@1.0.0:
dependencies:
call-bind: 1.0.2
@@ -19262,13 +19971,23 @@ snapshots:
minipass: 7.0.4
path-scurry: 1.10.1
- glob@10.3.12:
+ glob@10.4.2:
dependencies:
foreground-child: 3.1.1
- jackspeak: 2.3.6
- minimatch: 9.0.3
- minipass: 7.0.4
- path-scurry: 1.10.2
+ jackspeak: 3.4.0
+ minimatch: 9.0.4
+ minipass: 7.1.2
+ package-json-from-dist: 1.0.0
+ path-scurry: 1.11.1
+
+ glob@11.0.0:
+ dependencies:
+ foreground-child: 3.1.1
+ jackspeak: 4.0.1
+ minimatch: 10.0.1
+ minipass: 7.1.2
+ package-json-from-dist: 1.0.0
+ path-scurry: 2.0.0
glob@7.2.3:
dependencies:
@@ -19293,14 +20012,14 @@ snapshots:
globals@11.12.0: {}
- globals@13.19.0:
- dependencies:
- type-fest: 0.20.2
-
globals@13.24.0:
dependencies:
type-fest: 0.20.2
+ globals@14.0.0: {}
+
+ globals@15.8.0: {}
+
globalthis@1.0.3:
dependencies:
define-properties: 1.2.0
@@ -19314,6 +20033,15 @@ snapshots:
merge2: 1.4.1
slash: 3.0.0
+ globby@14.0.1:
+ dependencies:
+ '@sindresorhus/merge-streams': 2.3.0
+ fast-glob: 3.3.2
+ ignore: 5.3.1
+ path-type: 5.0.0
+ slash: 5.1.0
+ unicorn-magic: 0.1.0
+
google-protobuf@3.21.2:
optional: true
@@ -19349,19 +20077,19 @@ snapshots:
p-cancelable: 3.0.0
responselike: 3.0.0
- got@14.2.1:
+ got@14.4.2:
dependencies:
- '@sindresorhus/is': 6.1.0
+ '@sindresorhus/is': 7.0.0
'@szmarczak/http-timer': 5.0.1
cacheable-lookup: 7.0.0
- cacheable-request: 10.2.14
+ cacheable-request: 12.0.1
decompress-response: 6.0.0
form-data-encoder: 4.0.2
- get-stream: 8.0.1
http2-wrapper: 2.2.1
lowercase-keys: 3.0.0
p-cancelable: 4.0.1
responselike: 3.0.0
+ type-fest: 4.20.1
graceful-fs@4.2.11: {}
@@ -19371,15 +20099,6 @@ snapshots:
graphql@16.8.1: {}
- gunzip-maybe@1.4.2:
- dependencies:
- browserify-zlib: 0.1.4
- is-deflate: 1.0.0
- is-gzip: 1.0.0
- peek-stream: 1.1.3
- pumpify: 1.5.1
- through2: 2.0.5
-
hammerjs@2.0.8: {}
handlebars@4.7.7:
@@ -19501,10 +20220,10 @@ snapshots:
http-link-header@1.1.3: {}
- http-proxy-agent@7.0.0:
+ http-proxy-agent@7.0.2:
dependencies:
agent-base: 7.1.0
- debug: 4.3.4(supports-color@8.1.1)
+ debug: 4.3.5(supports-color@8.1.1)
transitivePeerDependencies:
- supports-color
@@ -19543,14 +20262,28 @@ snapshots:
https-proxy-agent@5.0.1:
dependencies:
agent-base: 6.0.2
- debug: 4.3.4(supports-color@8.1.1)
+ debug: 4.3.5(supports-color@8.1.1)
transitivePeerDependencies:
- supports-color
https-proxy-agent@7.0.2:
dependencies:
agent-base: 7.1.0
- debug: 4.3.4(supports-color@8.1.1)
+ debug: 4.3.4(supports-color@5.5.0)
+ transitivePeerDependencies:
+ - supports-color
+
+ https-proxy-agent@7.0.4:
+ dependencies:
+ agent-base: 7.1.0
+ debug: 4.3.5(supports-color@8.1.1)
+ transitivePeerDependencies:
+ - supports-color
+
+ https-proxy-agent@7.0.5:
+ dependencies:
+ agent-base: 7.1.0
+ debug: 4.3.5(supports-color@8.1.1)
transitivePeerDependencies:
- supports-color
@@ -19562,6 +20295,8 @@ snapshots:
human-signals@5.0.0: {}
+ human-signals@7.0.0: {}
+
iconv-lite@0.4.24:
dependencies:
safer-buffer: 2.1.2
@@ -19576,9 +20311,9 @@ snapshots:
ignore-by-default@1.0.1: {}
- ignore-walk@6.0.4:
+ ignore-walk@6.0.5:
dependencies:
- minimatch: 9.0.3
+ minimatch: 9.0.4
ignore@5.2.4: {}
@@ -19591,20 +20326,20 @@ snapshots:
parent-module: 1.0.1
resolve-from: 4.0.0
- import-in-the-middle@1.4.2:
+ import-in-the-middle@1.10.0:
dependencies:
- acorn: 8.11.3
- acorn-import-assertions: 1.9.0(acorn@8.11.3)
+ acorn: 8.12.1
+ acorn-import-attributes: 1.9.5(acorn@8.12.1)
cjs-module-lexer: 1.2.2
module-details-from-path: 1.0.3
- optional: true
- import-in-the-middle@1.7.4:
+ import-in-the-middle@1.7.1:
dependencies:
- acorn: 8.11.3
- acorn-import-attributes: 1.9.5(acorn@8.11.3)
+ acorn: 8.12.1
+ acorn-import-assertions: 1.9.0(acorn@8.12.1)
cjs-module-lexer: 1.2.2
module-details-from-path: 1.0.3
+ optional: true
import-lazy@4.0.0: {}
@@ -19646,7 +20381,7 @@ snapshots:
dependencies:
'@ioredis/commands': 1.2.0
cluster-key-slot: 1.1.2
- debug: 4.3.4(supports-color@8.1.1)
+ debug: 4.3.4(supports-color@5.5.0)
denque: 2.1.0
lodash.defaults: 4.2.0
lodash.isarguments: 3.1.0
@@ -19658,15 +20393,14 @@ snapshots:
iota-array@1.0.0: {}
- ip-address@7.1.0:
+ ip-address@9.0.5:
dependencies:
jsbn: 1.1.0
- sprintf-js: 1.1.2
+ sprintf-js: 1.1.3
- ip-cidr@3.1.0:
+ ip-cidr@4.0.1:
dependencies:
- ip-address: 7.1.0
- jsbn: 1.1.0
+ ip-address: 9.0.5
ip-regex@4.3.0: {}
@@ -19724,8 +20458,6 @@ snapshots:
dependencies:
has-tostringtag: 1.0.0
- is-deflate@1.0.0: {}
-
is-docker@2.2.1: {}
is-expression@4.0.0:
@@ -19749,8 +20481,6 @@ snapshots:
dependencies:
is-extglob: 2.1.1
- is-gzip@1.0.0: {}
-
is-installed-globally@0.4.0:
dependencies:
global-dirs: 3.0.1
@@ -19781,8 +20511,6 @@ snapshots:
is-number@7.0.0: {}
- is-path-cwd@2.2.0: {}
-
is-path-inside@3.0.3: {}
is-plain-obj@1.1.0: {}
@@ -19816,11 +20544,13 @@ snapshots:
is-stream@3.0.0: {}
+ is-stream@4.0.1: {}
+
is-string@1.0.7:
dependencies:
has-tostringtag: 1.0.0
- is-svg@5.0.0:
+ is-svg@5.0.1:
dependencies:
fast-xml-parser: 4.2.5
@@ -19840,6 +20570,8 @@ snapshots:
is-unicode-supported@0.1.0: {}
+ is-unicode-supported@2.0.0: {}
+
is-weakmap@2.0.1: {}
is-weakref@1.0.2:
@@ -19873,8 +20605,8 @@ snapshots:
istanbul-lib-instrument@5.2.1:
dependencies:
- '@babel/core': 7.24.0
- '@babel/parser': 7.24.0
+ '@babel/core': 7.24.7
+ '@babel/parser': 7.24.7
'@istanbuljs/schema': 0.1.3
istanbul-lib-coverage: 3.2.2
semver: 6.3.1
@@ -19883,8 +20615,8 @@ snapshots:
istanbul-lib-instrument@6.0.0:
dependencies:
- '@babel/core': 7.24.0
- '@babel/parser': 7.24.0
+ '@babel/core': 7.24.7
+ '@babel/parser': 7.24.7
'@istanbuljs/schema': 0.1.3
istanbul-lib-coverage: 3.2.2
semver: 7.6.0
@@ -19899,12 +20631,20 @@ snapshots:
istanbul-lib-source-maps@4.0.1:
dependencies:
- debug: 4.3.4(supports-color@8.1.1)
+ debug: 4.3.5(supports-color@8.1.1)
istanbul-lib-coverage: 3.2.2
source-map: 0.6.1
transitivePeerDependencies:
- supports-color
+ istanbul-lib-source-maps@5.0.4:
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.25
+ debug: 4.3.5(supports-color@8.1.1)
+ istanbul-lib-coverage: 3.2.2
+ transitivePeerDependencies:
+ - supports-color
+
istanbul-reports@3.1.6:
dependencies:
html-escaper: 2.0.2
@@ -19918,6 +20658,18 @@ snapshots:
optionalDependencies:
'@pkgjs/parseargs': 0.11.0
+ jackspeak@3.4.0:
+ dependencies:
+ '@isaacs/cliui': 8.0.2
+ optionalDependencies:
+ '@pkgjs/parseargs': 0.11.0
+
+ jackspeak@4.0.1:
+ dependencies:
+ '@isaacs/cliui': 8.0.2
+ optionalDependencies:
+ '@pkgjs/parseargs': 0.11.0
+
jake@10.8.5:
dependencies:
async: 3.2.4
@@ -19937,7 +20689,7 @@ snapshots:
'@jest/expect': 29.7.0
'@jest/test-result': 29.7.0
'@jest/types': 29.6.3
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
chalk: 4.1.2
co: 4.6.0
dedent: 1.3.0
@@ -19957,16 +20709,16 @@ snapshots:
- babel-plugin-macros
- supports-color
- jest-cli@29.7.0(@types/node@20.12.7):
+ jest-cli@29.7.0(@types/node@20.14.12):
dependencies:
'@jest/core': 29.7.0
'@jest/test-result': 29.7.0
'@jest/types': 29.6.3
chalk: 4.1.2
- create-jest: 29.7.0(@types/node@20.12.7)
+ create-jest: 29.7.0(@types/node@20.14.12)
exit: 0.1.2
import-local: 3.1.0
- jest-config: 29.7.0(@types/node@20.12.7)
+ jest-config: 29.7.0(@types/node@20.14.12)
jest-util: 29.7.0
jest-validate: 29.7.0
yargs: 17.7.2
@@ -19976,7 +20728,7 @@ snapshots:
- supports-color
- ts-node
- jest-config@29.7.0(@types/node@20.12.7):
+ jest-config@29.7.0(@types/node@20.14.12):
dependencies:
'@babel/core': 7.23.5
'@jest/test-sequencer': 29.7.0
@@ -19995,13 +20747,13 @@ snapshots:
jest-runner: 29.7.0
jest-util: 29.7.0
jest-validate: 29.7.0
- micromatch: 4.0.5
+ micromatch: 4.0.7
parse-json: 5.2.0
pretty-format: 29.7.0
slash: 3.0.0
strip-json-comments: 3.1.1
optionalDependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
transitivePeerDependencies:
- babel-plugin-macros
- supports-color
@@ -20030,7 +20782,7 @@ snapshots:
'@jest/environment': 29.7.0
'@jest/fake-timers': 29.7.0
'@jest/types': 29.6.3
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
jest-mock: 29.7.0
jest-util: 29.7.0
@@ -20047,14 +20799,14 @@ snapshots:
dependencies:
'@jest/types': 29.6.3
'@types/graceful-fs': 4.1.6
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
anymatch: 3.1.3
fb-watchman: 2.0.2
graceful-fs: 4.2.11
jest-regex-util: 29.6.3
jest-util: 29.7.0
jest-worker: 29.7.0
- micromatch: 4.0.5
+ micromatch: 4.0.7
walker: 1.0.8
optionalDependencies:
fsevents: 2.3.3
@@ -20078,7 +20830,7 @@ snapshots:
'@types/stack-utils': 2.0.1
chalk: 4.1.2
graceful-fs: 4.2.11
- micromatch: 4.0.5
+ micromatch: 4.0.7
pretty-format: 29.7.0
slash: 3.0.0
stack-utils: 2.0.6
@@ -20086,7 +20838,7 @@ snapshots:
jest-mock@29.7.0:
dependencies:
'@jest/types': 29.6.3
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
jest-util: 29.7.0
jest-pnp-resolver@1.2.3(jest-resolve@29.7.0):
@@ -20121,7 +20873,7 @@ snapshots:
'@jest/test-result': 29.7.0
'@jest/transform': 29.7.0
'@jest/types': 29.6.3
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
chalk: 4.1.2
emittery: 0.13.1
graceful-fs: 4.2.11
@@ -20149,7 +20901,7 @@ snapshots:
'@jest/test-result': 29.7.0
'@jest/transform': 29.7.0
'@jest/types': 29.6.3
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
chalk: 4.1.2
cjs-module-lexer: 1.2.2
collect-v8-coverage: 1.0.1
@@ -20195,7 +20947,7 @@ snapshots:
jest-util@29.7.0:
dependencies:
'@jest/types': 29.6.3
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
chalk: 4.1.2
ci-info: 3.7.1
graceful-fs: 4.2.11
@@ -20214,7 +20966,7 @@ snapshots:
dependencies:
'@jest/test-result': 29.7.0
'@jest/types': 29.6.3
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
ansi-escapes: 4.3.2
chalk: 4.1.2
emittery: 0.13.1
@@ -20228,17 +20980,17 @@ snapshots:
jest-worker@29.7.0:
dependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
jest-util: 29.7.0
merge-stream: 2.0.0
supports-color: 8.1.1
- jest@29.7.0(@types/node@20.12.7):
+ jest@29.7.0(@types/node@20.14.12):
dependencies:
'@jest/core': 29.7.0
'@jest/types': 29.6.3
import-local: 3.1.0
- jest-cli: 29.7.0(@types/node@20.12.7)
+ jest-cli: 29.7.0(@types/node@20.14.12)
transitivePeerDependencies:
- '@types/node'
- babel-plugin-macros
@@ -20268,6 +21020,8 @@ snapshots:
js-tokens@4.0.0: {}
+ js-tokens@9.0.0: {}
+
js-yaml@3.14.1:
dependencies:
argparse: 1.0.10
@@ -20283,60 +21037,89 @@ snapshots:
jschardet@3.0.0: {}
- jscodeshift@0.15.1(@babel/preset-env@7.23.5(@babel/core@7.24.0)):
+ jscodeshift@0.15.1(@babel/preset-env@7.24.7(@babel/core@7.24.7)):
dependencies:
- '@babel/core': 7.24.0
- '@babel/parser': 7.24.0
- '@babel/plugin-transform-class-properties': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.24.0)
- '@babel/plugin-transform-nullish-coalescing-operator': 7.23.4(@babel/core@7.24.0)
- '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.24.0)
- '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.24.0)
- '@babel/preset-flow': 7.23.3(@babel/core@7.24.0)
- '@babel/preset-typescript': 7.23.3(@babel/core@7.24.0)
- '@babel/register': 7.22.15(@babel/core@7.24.0)
- babel-core: 7.0.0-bridge.0(@babel/core@7.24.0)
+ '@babel/core': 7.24.7
+ '@babel/parser': 7.24.7
+ '@babel/plugin-transform-class-properties': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-modules-commonjs': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-nullish-coalescing-operator': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-optional-chaining': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-private-methods': 7.24.7(@babel/core@7.24.7)
+ '@babel/preset-flow': 7.23.3(@babel/core@7.24.7)
+ '@babel/preset-typescript': 7.23.3(@babel/core@7.24.7)
+ '@babel/register': 7.22.15(@babel/core@7.24.7)
+ babel-core: 7.0.0-bridge.0(@babel/core@7.24.7)
chalk: 4.1.2
flow-parser: 0.202.0
graceful-fs: 4.2.11
- micromatch: 4.0.5
+ micromatch: 4.0.7
neo-async: 2.6.2
node-dir: 0.1.17
- recast: 0.23.4
+ recast: 0.23.6
temp: 0.8.4
write-file-atomic: 2.4.3
optionalDependencies:
- '@babel/preset-env': 7.23.5(@babel/core@7.24.0)
+ '@babel/preset-env': 7.24.7(@babel/core@7.24.7)
transitivePeerDependencies:
- supports-color
- jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3):
+ jsdom@24.1.1(bufferutil@4.0.7)(utf-8-validate@6.0.3):
dependencies:
cssstyle: 4.0.1
data-urls: 5.0.0
decimal.js: 10.4.3
form-data: 4.0.0
html-encoding-sniffer: 4.0.0
- http-proxy-agent: 7.0.0
- https-proxy-agent: 7.0.2
+ http-proxy-agent: 7.0.2
+ https-proxy-agent: 7.0.5
is-potential-custom-element-name: 1.0.1
- nwsapi: 2.2.9
+ nwsapi: 2.2.12
parse5: 7.1.2
- rrweb-cssom: 0.6.0
+ rrweb-cssom: 0.7.1
+ saxes: 6.0.0
+ symbol-tree: 3.2.4
+ tough-cookie: 4.1.4
+ w3c-xmlserializer: 5.0.0
+ webidl-conversions: 7.0.0
+ whatwg-encoding: 3.1.1
+ whatwg-mimetype: 4.0.0
+ whatwg-url: 14.0.0
+ ws: 8.18.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
+ xml-name-validator: 5.0.0
+ transitivePeerDependencies:
+ - bufferutil
+ - supports-color
+ - utf-8-validate
+
+ jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4):
+ dependencies:
+ cssstyle: 4.0.1
+ data-urls: 5.0.0
+ decimal.js: 10.4.3
+ form-data: 4.0.0
+ html-encoding-sniffer: 4.0.0
+ http-proxy-agent: 7.0.2
+ https-proxy-agent: 7.0.5
+ is-potential-custom-element-name: 1.0.1
+ nwsapi: 2.2.12
+ parse5: 7.1.2
+ rrweb-cssom: 0.7.1
saxes: 6.0.0
symbol-tree: 3.2.4
- tough-cookie: 4.1.3
+ tough-cookie: 4.1.4
w3c-xmlserializer: 5.0.0
webidl-conversions: 7.0.0
whatwg-encoding: 3.1.1
whatwg-mimetype: 4.0.0
whatwg-url: 14.0.0
- ws: 8.17.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
+ ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
xml-name-validator: 5.0.0
transitivePeerDependencies:
- bufferutil
- supports-color
- utf-8-validate
+ optional: true
jsesc@0.5.0: {}
@@ -20385,9 +21168,9 @@ snapshots:
optionalDependencies:
graceful-fs: 4.2.11
- jsonld@8.3.2(web-streams-polyfill@3.2.1):
+ jsonld@8.3.2(web-streams-polyfill@4.0.0):
dependencies:
- '@digitalbazaar/http-client': 3.4.1(web-streams-polyfill@3.2.1)
+ '@digitalbazaar/http-client': 3.4.1(web-streams-polyfill@4.0.0)
canonicalize: 1.0.8
lru-cache: 6.0.0
rdf-canonize: 3.4.0
@@ -20412,8 +21195,6 @@ snapshots:
jsrsasign@11.1.0: {}
- jssha@3.3.1: {}
-
jstransformer@1.0.0:
dependencies:
is-promise: 2.2.2
@@ -20440,13 +21221,13 @@ snapshots:
kleur@3.0.3: {}
- ky-universal@0.11.0(ky@0.33.3)(web-streams-polyfill@3.2.1):
+ ky-universal@0.11.0(ky@0.33.3)(web-streams-polyfill@4.0.0):
dependencies:
abort-controller: 3.0.0
ky: 0.33.3
node-fetch: 3.3.2
optionalDependencies:
- web-streams-polyfill: 3.2.1
+ web-streams-polyfill: 4.0.0
ky@0.33.3: {}
@@ -20492,7 +21273,10 @@ snapshots:
optionalDependencies:
enquirer: 2.3.6
- local-pkg@0.4.3: {}
+ local-pkg@0.5.0:
+ dependencies:
+ mlly: 1.5.0
+ pkg-types: 1.0.3
locate-path@3.0.0:
dependencies:
@@ -20515,8 +21299,6 @@ snapshots:
lodash.isarguments@3.1.0: {}
- lodash.isequal@4.5.0: {}
-
lodash.memoize@4.1.2: {}
lodash.merge@4.6.2: {}
@@ -20561,6 +21343,8 @@ snapshots:
lru-cache@10.2.2: {}
+ lru-cache@11.0.0: {}
+
lru-cache@4.1.5:
dependencies:
pseudomap: 1.0.2
@@ -20588,9 +21372,11 @@ snapshots:
dependencies:
'@jridgewell/sourcemap-codec': 1.4.15
- magic-string@0.30.7:
+ magicast@0.3.4:
dependencies:
- '@jridgewell/sourcemap-codec': 1.4.15
+ '@babel/parser': 7.24.5
+ '@babel/types': 7.24.0
+ source-map-js: 1.2.0
mailcheck@1.1.1: {}
@@ -20613,7 +21399,7 @@ snapshots:
cacache: 18.0.0
http-cache-semantics: 4.1.1
is-lambda: 1.0.1
- minipass: 7.0.4
+ minipass: 7.1.2
minipass-fetch: 3.0.3
minipass-flush: 1.0.5
minipass-pipeline: 1.2.4
@@ -20637,7 +21423,7 @@ snapshots:
markdown-table@3.0.3: {}
- markdown-to-jsx@7.3.2(react@18.3.1):
+ markdown-to-jsx@7.4.7(react@18.3.1):
dependencies:
react: 18.3.1
@@ -20750,7 +21536,7 @@ snapshots:
media-typer@0.3.0: {}
- meilisearch@0.38.0(encoding@0.1.13):
+ meilisearch@0.41.0(encoding@0.1.13):
dependencies:
cross-fetch: 3.1.6(encoding@0.1.13)
transitivePeerDependencies:
@@ -20963,7 +21749,7 @@ snapshots:
micromark@4.0.0:
dependencies:
'@types/debug': 4.1.12
- debug: 4.3.4(supports-color@8.1.1)
+ debug: 4.3.5(supports-color@8.1.1)
decode-named-character-reference: 1.0.2
devlop: 1.1.0
micromark-core-commonmark: 2.0.0
@@ -20982,9 +21768,9 @@ snapshots:
transitivePeerDependencies:
- supports-color
- micromatch@4.0.5:
+ micromatch@4.0.7:
dependencies:
- braces: 3.0.2
+ braces: 3.0.3
picomatch: 2.3.1
mime-db@1.52.0: {}
@@ -21011,6 +21797,10 @@ snapshots:
minimalistic-assert@1.0.1: {}
+ minimatch@10.0.1:
+ dependencies:
+ brace-expansion: 2.0.1
+
minimatch@3.0.8:
dependencies:
brace-expansion: 1.1.11
@@ -21081,6 +21871,8 @@ snapshots:
minipass@7.0.4: {}
+ minipass@7.1.2: {}
+
minizlib@1.3.3:
dependencies:
minipass: 2.9.0
@@ -21091,8 +21883,6 @@ snapshots:
minipass: 3.3.6
yallist: 4.0.0
- mkdirp-classic@0.5.3: {}
-
mkdirp@0.5.6:
dependencies:
minimist: 1.2.8
@@ -21103,7 +21893,7 @@ snapshots:
mlly@1.5.0:
dependencies:
- acorn: 8.11.3
+ acorn: 8.12.1
pathe: 1.1.2
pkg-types: 1.0.3
ufo: 1.3.2
@@ -21142,18 +21932,18 @@ snapshots:
optionalDependencies:
msgpackr-extract: 3.0.2
- msw-storybook-addon@2.0.1(msw@2.2.14(typescript@5.4.5)):
+ msw-storybook-addon@2.0.3(msw@2.3.4(typescript@5.5.4)):
dependencies:
is-node-process: 1.2.0
- msw: 2.2.14(typescript@5.4.5)
+ msw: 2.3.4(typescript@5.5.4)
- msw@2.2.14(typescript@5.4.5):
+ msw@2.3.4(typescript@5.5.4):
dependencies:
'@bundled-es-modules/cookie': 2.0.0
'@bundled-es-modules/statuses': 1.0.1
+ '@bundled-es-modules/tough-cookie': 0.1.6
'@inquirer/confirm': 3.1.6
- '@mswjs/cookies': 1.1.0
- '@mswjs/interceptors': 0.26.15
+ '@mswjs/interceptors': 0.29.1
'@open-draft/until': 2.1.0
'@types/cookie': 0.6.0
'@types/statuses': 2.0.4
@@ -21164,10 +21954,10 @@ snapshots:
outvariant: 1.4.2
path-to-regexp: 6.2.1
strict-event-emitter: 0.5.1
- type-fest: 4.9.0
+ type-fest: 4.20.1
yargs: 17.7.2
optionalDependencies:
- typescript: 5.4.5
+ typescript: 5.5.4
muggle-string@0.4.1: {}
@@ -21193,7 +21983,7 @@ snapshots:
object-assign: 4.1.1
thenify-all: 1.6.0
- nan@2.18.0: {}
+ nan@2.20.0: {}
nanoid@3.3.7: {}
@@ -21271,7 +22061,7 @@ snapshots:
node-fetch-native@1.0.2: {}
- node-fetch@2.6.11(encoding@0.1.13):
+ node-fetch@2.6.13(encoding@0.1.13):
dependencies:
whatwg-url: 5.0.0
optionalDependencies:
@@ -21295,11 +22085,11 @@ snapshots:
node-gyp-build@4.6.0:
optional: true
- node-gyp@10.0.1:
+ node-gyp@10.1.0:
dependencies:
env-paths: 2.2.1
exponential-backoff: 3.1.1
- glob: 10.3.12
+ glob: 10.3.10
graceful-fs: 4.2.11
make-fetch-happen: 13.0.0
nopt: 7.2.0
@@ -21314,7 +22104,7 @@ snapshots:
node-releases@2.0.14: {}
- nodemailer@6.9.13: {}
+ nodemailer@6.9.14: {}
nodemon@3.0.2:
dependencies:
@@ -21329,14 +22119,14 @@ snapshots:
touch: 3.1.0
undefsafe: 2.0.5
- nodemon@3.1.0:
+ nodemon@3.1.4:
dependencies:
chokidar: 3.5.3
debug: 4.3.4(supports-color@5.5.0)
ignore-by-default: 1.0.1
minimatch: 3.1.2
pstree.remy: 1.1.8
- semver: 7.5.4
+ semver: 7.6.0
simple-update-notifier: 2.0.0
supports-color: 5.5.0
touch: 3.1.0
@@ -21381,6 +22171,8 @@ snapshots:
normalize-url@8.0.0: {}
+ normalize-url@8.0.1: {}
+
npm-run-path@2.0.2:
dependencies:
path-key: 2.0.1
@@ -21393,6 +22185,10 @@ snapshots:
dependencies:
path-key: 4.0.0
+ npm-run-path@5.3.0:
+ dependencies:
+ path-key: 4.0.0
+
npmlog@5.0.1:
dependencies:
are-we-there-yet: 2.0.0
@@ -21410,7 +22206,7 @@ snapshots:
dependencies:
boolbase: 1.0.0
- nwsapi@2.2.9: {}
+ nwsapi@2.2.12: {}
oauth-sign@0.9.0: {}
@@ -21508,30 +22304,30 @@ snapshots:
undici: 5.28.2
yargs-parser: 21.1.1
- opentelemetry-instrumentation-fetch-node@1.2.0:
+ opentelemetry-instrumentation-fetch-node@1.2.3(@opentelemetry/api@1.9.0):
dependencies:
- '@opentelemetry/api': 1.8.0
- '@opentelemetry/instrumentation': 0.43.0(@opentelemetry/api@1.8.0)
- '@opentelemetry/semantic-conventions': 1.24.1
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/instrumentation': 0.46.0(@opentelemetry/api@1.9.0)
+ '@opentelemetry/semantic-conventions': 1.25.1
transitivePeerDependencies:
- supports-color
optional: true
- optionator@0.9.3:
+ optionator@0.9.4:
dependencies:
- '@aashutoshrathi/word-wrap': 1.2.6
deep-is: 0.1.4
fast-levenshtein: 2.0.6
levn: 0.4.1
prelude-ls: 1.2.1
type-check: 0.4.0
+ word-wrap: 1.2.5
ora@5.4.1:
dependencies:
bl: 4.1.0
chalk: 4.1.2
cli-cursor: 3.1.0
- cli-spinners: 2.7.0
+ cli-spinners: 2.9.2
is-interactive: 1.0.0
is-unicode-supported: 0.1.0
log-symbols: 4.1.0
@@ -21546,9 +22342,9 @@ snapshots:
ospath@1.2.2: {}
- otpauth@9.2.3:
+ otpauth@9.3.1:
dependencies:
- jssha: 3.3.1
+ '@noble/hashes': 1.4.0
outvariant@1.4.2: {}
@@ -21568,7 +22364,7 @@ snapshots:
dependencies:
yocto-queue: 0.1.0
- p-limit@4.0.0:
+ p-limit@5.0.0:
dependencies:
yocto-queue: 1.0.0
@@ -21599,7 +22395,7 @@ snapshots:
p-try@2.2.0: {}
- pako@0.2.9: {}
+ package-json-from-dist@1.0.0: {}
parent-module@1.0.1:
dependencies:
@@ -21611,11 +22407,13 @@ snapshots:
parse-json@5.2.0:
dependencies:
- '@babel/code-frame': 7.23.5
+ '@babel/code-frame': 7.24.7
error-ex: 1.3.2
json-parse-even-better-errors: 2.3.1
lines-and-columns: 1.2.4
+ parse-ms@4.0.0: {}
+
parse-srcset@1.0.2: {}
parse5-htmlparser2-tree-adapter@6.0.1:
@@ -21658,10 +22456,15 @@ snapshots:
lru-cache: 10.0.2
minipass: 7.0.4
- path-scurry@1.10.2:
+ path-scurry@1.11.1:
dependencies:
lru-cache: 10.2.2
- minipass: 7.0.4
+ minipass: 7.1.2
+
+ path-scurry@2.0.0:
+ dependencies:
+ lru-cache: 11.0.0
+ minipass: 7.1.2
path-to-regexp@0.1.7: {}
@@ -21675,6 +22478,8 @@ snapshots:
path-type@4.0.0: {}
+ path-type@5.0.0: {}
+
pathe@1.1.2: {}
pathval@1.1.1: {}
@@ -21685,11 +22490,7 @@ snapshots:
peek-readable@5.0.0: {}
- peek-stream@1.1.3:
- dependencies:
- buffer-from: 1.1.2
- duplexify: 3.7.1
- through2: 2.0.5
+ peek-readable@5.1.3: {}
pend@1.2.0: {}
@@ -21704,11 +22505,9 @@ snapshots:
pg-numeric@1.0.2: {}
- pg-pool@3.6.2(pg@8.11.5):
+ pg-pool@3.6.2(pg@8.12.0):
dependencies:
- pg: 8.11.5
-
- pg-protocol@1.6.0: {}
+ pg: 8.12.0
pg-protocol@1.6.1: {}
@@ -21730,10 +22529,10 @@ snapshots:
postgres-interval: 3.0.0
postgres-range: 1.1.3
- pg@8.11.5:
+ pg@8.12.0:
dependencies:
pg-connection-string: 2.6.4
- pg-pool: 3.6.2(pg@8.11.5)
+ pg-pool: 3.6.2(pg@8.12.0)
pg-protocol: 1.6.1
pg-types: 2.2.0
pgpass: 1.0.5
@@ -21744,10 +22543,12 @@ snapshots:
dependencies:
split2: 4.1.0
- photoswipe@5.4.3: {}
+ photoswipe@5.4.4: {}
picocolors@1.0.0: {}
+ picocolors@1.0.1: {}
+
picomatch@2.3.1: {}
pid-port@1.0.0:
@@ -21758,26 +22559,26 @@ snapshots:
pify@4.0.1: {}
- pino-abstract-transport@1.1.0:
+ pino-abstract-transport@1.2.0:
dependencies:
readable-stream: 4.3.0
split2: 4.1.0
- pino-std-serializers@6.1.0: {}
+ pino-std-serializers@7.0.0: {}
- pino@8.17.0:
+ pino@9.2.0:
dependencies:
atomic-sleep: 1.0.0
fast-redact: 3.1.2
on-exit-leak-free: 2.1.0
- pino-abstract-transport: 1.1.0
- pino-std-serializers: 6.1.0
- process-warning: 2.2.0
+ pino-abstract-transport: 1.2.0
+ pino-std-serializers: 7.0.0
+ process-warning: 3.0.0
quick-format-unescaped: 4.0.4
real-require: 0.2.0
safe-stable-stringify: 2.4.2
- sonic-boom: 3.7.0
- thread-stream: 2.3.0
+ sonic-boom: 4.0.1
+ thread-stream: 3.1.0
pirates@4.0.5: {}
@@ -21823,140 +22624,140 @@ snapshots:
dependencies:
'@babel/runtime': 7.23.4
- postcss-calc@9.0.1(postcss@8.4.38):
+ postcss-calc@9.0.1(postcss@8.4.40):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.40
postcss-selector-parser: 6.0.15
postcss-value-parser: 4.2.0
- postcss-colormin@6.1.0(postcss@8.4.38):
+ postcss-colormin@6.1.0(postcss@8.4.40):
dependencies:
browserslist: 4.23.0
caniuse-api: 3.0.0
colord: 2.9.3
- postcss: 8.4.38
+ postcss: 8.4.40
postcss-value-parser: 4.2.0
- postcss-convert-values@6.1.0(postcss@8.4.38):
+ postcss-convert-values@6.1.0(postcss@8.4.40):
dependencies:
browserslist: 4.23.0
- postcss: 8.4.38
+ postcss: 8.4.40
postcss-value-parser: 4.2.0
- postcss-discard-comments@6.0.2(postcss@8.4.38):
+ postcss-discard-comments@6.0.2(postcss@8.4.40):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.40
- postcss-discard-duplicates@6.0.3(postcss@8.4.38):
+ postcss-discard-duplicates@6.0.3(postcss@8.4.40):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.40
- postcss-discard-empty@6.0.3(postcss@8.4.38):
+ postcss-discard-empty@6.0.3(postcss@8.4.40):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.40
- postcss-discard-overridden@6.0.2(postcss@8.4.38):
+ postcss-discard-overridden@6.0.2(postcss@8.4.40):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.40
- postcss-merge-longhand@6.0.5(postcss@8.4.38):
+ postcss-merge-longhand@6.0.5(postcss@8.4.40):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.40
postcss-value-parser: 4.2.0
- stylehacks: 6.1.1(postcss@8.4.38)
+ stylehacks: 6.1.1(postcss@8.4.40)
- postcss-merge-rules@6.1.1(postcss@8.4.38):
+ postcss-merge-rules@6.1.1(postcss@8.4.40):
dependencies:
browserslist: 4.23.0
caniuse-api: 3.0.0
- cssnano-utils: 4.0.2(postcss@8.4.38)
- postcss: 8.4.38
+ cssnano-utils: 4.0.2(postcss@8.4.40)
+ postcss: 8.4.40
postcss-selector-parser: 6.0.16
- postcss-minify-font-values@6.1.0(postcss@8.4.38):
+ postcss-minify-font-values@6.1.0(postcss@8.4.40):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.40
postcss-value-parser: 4.2.0
- postcss-minify-gradients@6.0.3(postcss@8.4.38):
+ postcss-minify-gradients@6.0.3(postcss@8.4.40):
dependencies:
colord: 2.9.3
- cssnano-utils: 4.0.2(postcss@8.4.38)
- postcss: 8.4.38
+ cssnano-utils: 4.0.2(postcss@8.4.40)
+ postcss: 8.4.40
postcss-value-parser: 4.2.0
- postcss-minify-params@6.1.0(postcss@8.4.38):
+ postcss-minify-params@6.1.0(postcss@8.4.40):
dependencies:
browserslist: 4.23.0
- cssnano-utils: 4.0.2(postcss@8.4.38)
- postcss: 8.4.38
+ cssnano-utils: 4.0.2(postcss@8.4.40)
+ postcss: 8.4.40
postcss-value-parser: 4.2.0
- postcss-minify-selectors@6.0.4(postcss@8.4.38):
+ postcss-minify-selectors@6.0.4(postcss@8.4.40):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.40
postcss-selector-parser: 6.0.16
- postcss-normalize-charset@6.0.2(postcss@8.4.38):
+ postcss-normalize-charset@6.0.2(postcss@8.4.40):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.40
- postcss-normalize-display-values@6.0.2(postcss@8.4.38):
+ postcss-normalize-display-values@6.0.2(postcss@8.4.40):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.40
postcss-value-parser: 4.2.0
- postcss-normalize-positions@6.0.2(postcss@8.4.38):
+ postcss-normalize-positions@6.0.2(postcss@8.4.40):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.40
postcss-value-parser: 4.2.0
- postcss-normalize-repeat-style@6.0.2(postcss@8.4.38):
+ postcss-normalize-repeat-style@6.0.2(postcss@8.4.40):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.40
postcss-value-parser: 4.2.0
- postcss-normalize-string@6.0.2(postcss@8.4.38):
+ postcss-normalize-string@6.0.2(postcss@8.4.40):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.40
postcss-value-parser: 4.2.0
- postcss-normalize-timing-functions@6.0.2(postcss@8.4.38):
+ postcss-normalize-timing-functions@6.0.2(postcss@8.4.40):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.40
postcss-value-parser: 4.2.0
- postcss-normalize-unicode@6.1.0(postcss@8.4.38):
+ postcss-normalize-unicode@6.1.0(postcss@8.4.40):
dependencies:
browserslist: 4.23.0
- postcss: 8.4.38
+ postcss: 8.4.40
postcss-value-parser: 4.2.0
- postcss-normalize-url@6.0.2(postcss@8.4.38):
+ postcss-normalize-url@6.0.2(postcss@8.4.40):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.40
postcss-value-parser: 4.2.0
- postcss-normalize-whitespace@6.0.2(postcss@8.4.38):
+ postcss-normalize-whitespace@6.0.2(postcss@8.4.40):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.40
postcss-value-parser: 4.2.0
- postcss-ordered-values@6.0.2(postcss@8.4.38):
+ postcss-ordered-values@6.0.2(postcss@8.4.40):
dependencies:
- cssnano-utils: 4.0.2(postcss@8.4.38)
- postcss: 8.4.38
+ cssnano-utils: 4.0.2(postcss@8.4.40)
+ postcss: 8.4.40
postcss-value-parser: 4.2.0
- postcss-reduce-initial@6.1.0(postcss@8.4.38):
+ postcss-reduce-initial@6.1.0(postcss@8.4.40):
dependencies:
browserslist: 4.23.0
caniuse-api: 3.0.0
- postcss: 8.4.38
+ postcss: 8.4.40
- postcss-reduce-transforms@6.0.2(postcss@8.4.38):
+ postcss-reduce-transforms@6.0.2(postcss@8.4.40):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.40
postcss-value-parser: 4.2.0
postcss-selector-parser@6.0.15:
@@ -21969,15 +22770,15 @@ snapshots:
cssesc: 3.0.0
util-deprecate: 1.0.2
- postcss-svgo@6.0.3(postcss@8.4.38):
+ postcss-svgo@6.0.3(postcss@8.4.40):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.40
postcss-value-parser: 4.2.0
svgo: 3.2.0
- postcss-unique-selectors@6.0.4(postcss@8.4.38):
+ postcss-unique-selectors@6.0.4(postcss@8.4.40):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.40
postcss-selector-parser: 6.0.16
postcss-value-parser@4.2.0: {}
@@ -21988,6 +22789,12 @@ snapshots:
picocolors: 1.0.0
source-map-js: 1.2.0
+ postcss@8.4.40:
+ dependencies:
+ nanoid: 3.3.7
+ picocolors: 1.0.1
+ source-map-js: 1.2.0
+
postgres-array@2.0.0: {}
postgres-array@3.0.2: {}
@@ -22012,7 +22819,7 @@ snapshots:
prelude-ls@1.2.1: {}
- prettier@3.2.5: {}
+ prettier@3.3.3: {}
pretty-bytes@5.6.0: {}
@@ -22030,6 +22837,10 @@ snapshots:
pretty-hrtime@1.0.3: {}
+ pretty-ms@9.0.0:
+ dependencies:
+ parse-ms: 4.0.0
+
private-ip@2.3.3:
dependencies:
ip-regex: 4.3.0
@@ -22115,19 +22926,21 @@ snapshots:
js-stringify: 1.0.2
pug-runtime: 3.0.1
- pug-code-gen@3.0.2:
+ pug-code-gen@3.0.3:
dependencies:
constantinople: 4.0.1
doctypes: 1.1.0
js-stringify: 1.0.2
pug-attrs: 3.0.0
- pug-error: 2.0.0
+ pug-error: 2.1.0
pug-runtime: 3.0.1
void-elements: 3.1.0
with: 7.0.2
pug-error@2.0.0: {}
+ pug-error@2.1.0: {}
+
pug-filters@4.0.0:
dependencies:
constantinople: 4.0.1
@@ -22165,9 +22978,9 @@ snapshots:
pug-walk@2.0.0: {}
- pug@3.0.2:
+ pug@3.0.3:
dependencies:
- pug-code-gen: 3.0.2
+ pug-code-gen: 3.0.3
pug-filters: 4.0.0
pug-lexer: 5.0.1
pug-linker: 4.0.0
@@ -22176,29 +22989,18 @@ snapshots:
pug-runtime: 3.0.1
pug-strip-comments: 2.0.0
- pump@2.0.1:
- dependencies:
- end-of-stream: 1.4.4
- once: 1.4.0
-
pump@3.0.0:
dependencies:
end-of-stream: 1.4.4
once: 1.4.0
- pumpify@1.5.1:
- dependencies:
- duplexify: 3.7.1
- inherits: 2.0.4
- pump: 2.0.1
-
punycode@2.3.1: {}
pure-rand@6.0.0: {}
pvtsutils@1.3.5:
dependencies:
- tslib: 2.6.2
+ tslib: 2.6.3
pvutils@1.1.3: {}
@@ -22247,13 +23049,6 @@ snapshots:
ratelimiter@3.4.1: {}
- raw-body@2.5.1:
- dependencies:
- bytes: 3.1.2
- http-errors: 2.0.0
- iconv-lite: 0.4.24
- unpipe: 1.0.0
-
raw-body@2.5.2:
dependencies:
bytes: 3.1.2
@@ -22265,11 +23060,11 @@ snapshots:
dependencies:
setimmediate: 1.0.5
- re2@1.20.10:
+ re2@1.21.3:
dependencies:
install-artifact-from-github: 1.3.5
- nan: 2.18.0
- node-gyp: 10.0.1
+ nan: 2.20.0
+ node-gyp: 10.1.0
transitivePeerDependencies:
- supports-color
@@ -22278,15 +23073,15 @@ snapshots:
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- react-docgen-typescript@2.2.2(typescript@5.4.5):
+ react-docgen-typescript@2.2.2(typescript@5.5.4):
dependencies:
- typescript: 5.4.5
+ typescript: 5.5.4
react-docgen@7.0.1:
dependencies:
- '@babel/core': 7.24.0
- '@babel/traverse': 7.24.0
- '@babel/types': 7.24.0
+ '@babel/core': 7.24.7
+ '@babel/traverse': 7.24.7
+ '@babel/types': 7.24.7
'@types/babel__core': 7.20.0
'@types/babel__traverse': 7.20.0
'@types/doctrine': 0.0.9
@@ -22380,21 +23175,13 @@ snapshots:
real-require@0.2.0: {}
- recast@0.23.4:
- dependencies:
- assert: 2.1.0
- ast-types: 0.16.1
- esprima: 4.0.1
- source-map: 0.6.1
- tslib: 2.6.2
-
recast@0.23.6:
dependencies:
ast-types: 0.16.1
esprima: 4.0.1
source-map: 0.6.1
tiny-invariant: 1.3.3
- tslib: 2.6.2
+ tslib: 2.6.3
reconnecting-websocket@4.4.0: {}
@@ -22532,7 +23319,7 @@ snapshots:
require-in-the-middle@7.3.0:
dependencies:
- debug: 4.3.4(supports-color@8.1.1)
+ debug: 4.3.5(supports-color@8.1.1)
module-details-from-path: 1.0.3
resolve: 1.22.8
transitivePeerDependencies:
@@ -22556,11 +23343,6 @@ snapshots:
resolve.exports@2.0.0: {}
- resolve@1.19.0:
- dependencies:
- is-core-module: 2.13.1
- path-parse: 1.0.7
-
resolve@1.22.8:
dependencies:
is-core-module: 2.13.1
@@ -22600,31 +23382,34 @@ snapshots:
rimraf@3.0.2:
dependencies:
glob: 7.2.3
+ optional: true
- rollup@4.17.2:
+ rollup@4.19.1:
dependencies:
'@types/estree': 1.0.5
optionalDependencies:
- '@rollup/rollup-android-arm-eabi': 4.17.2
- '@rollup/rollup-android-arm64': 4.17.2
- '@rollup/rollup-darwin-arm64': 4.17.2
- '@rollup/rollup-darwin-x64': 4.17.2
- '@rollup/rollup-linux-arm-gnueabihf': 4.17.2
- '@rollup/rollup-linux-arm-musleabihf': 4.17.2
- '@rollup/rollup-linux-arm64-gnu': 4.17.2
- '@rollup/rollup-linux-arm64-musl': 4.17.2
- '@rollup/rollup-linux-powerpc64le-gnu': 4.17.2
- '@rollup/rollup-linux-riscv64-gnu': 4.17.2
- '@rollup/rollup-linux-s390x-gnu': 4.17.2
- '@rollup/rollup-linux-x64-gnu': 4.17.2
- '@rollup/rollup-linux-x64-musl': 4.17.2
- '@rollup/rollup-win32-arm64-msvc': 4.17.2
- '@rollup/rollup-win32-ia32-msvc': 4.17.2
- '@rollup/rollup-win32-x64-msvc': 4.17.2
+ '@rollup/rollup-android-arm-eabi': 4.19.1
+ '@rollup/rollup-android-arm64': 4.19.1
+ '@rollup/rollup-darwin-arm64': 4.19.1
+ '@rollup/rollup-darwin-x64': 4.19.1
+ '@rollup/rollup-linux-arm-gnueabihf': 4.19.1
+ '@rollup/rollup-linux-arm-musleabihf': 4.19.1
+ '@rollup/rollup-linux-arm64-gnu': 4.19.1
+ '@rollup/rollup-linux-arm64-musl': 4.19.1
+ '@rollup/rollup-linux-powerpc64le-gnu': 4.19.1
+ '@rollup/rollup-linux-riscv64-gnu': 4.19.1
+ '@rollup/rollup-linux-s390x-gnu': 4.19.1
+ '@rollup/rollup-linux-x64-gnu': 4.19.1
+ '@rollup/rollup-linux-x64-musl': 4.19.1
+ '@rollup/rollup-win32-arm64-msvc': 4.19.1
+ '@rollup/rollup-win32-ia32-msvc': 4.19.1
+ '@rollup/rollup-win32-x64-msvc': 4.19.1
fsevents: 2.3.3
rrweb-cssom@0.6.0: {}
+ rrweb-cssom@0.7.1: {}
+
rss-parser@3.13.0:
dependencies:
entities: 2.2.0
@@ -22672,7 +23457,7 @@ snapshots:
parse-srcset: 1.0.2
postcss: 8.4.38
- sass@1.76.0:
+ sass@1.77.8:
dependencies:
chokidar: 3.5.3
immutable: 4.2.2
@@ -22754,14 +23539,14 @@ snapshots:
dependencies:
kind-of: 6.0.3
- sharp@0.33.3:
+ sharp@0.33.4:
dependencies:
color: 4.2.3
detect-libc: 2.0.3
semver: 7.6.0
optionalDependencies:
- '@img/sharp-darwin-arm64': 0.33.3
- '@img/sharp-darwin-x64': 0.33.3
+ '@img/sharp-darwin-arm64': 0.33.4
+ '@img/sharp-darwin-x64': 0.33.4
'@img/sharp-libvips-darwin-arm64': 1.0.2
'@img/sharp-libvips-darwin-x64': 1.0.2
'@img/sharp-libvips-linux-arm': 1.0.2
@@ -22770,15 +23555,15 @@ snapshots:
'@img/sharp-libvips-linux-x64': 1.0.2
'@img/sharp-libvips-linuxmusl-arm64': 1.0.2
'@img/sharp-libvips-linuxmusl-x64': 1.0.2
- '@img/sharp-linux-arm': 0.33.3
- '@img/sharp-linux-arm64': 0.33.3
- '@img/sharp-linux-s390x': 0.33.3
- '@img/sharp-linux-x64': 0.33.3
- '@img/sharp-linuxmusl-arm64': 0.33.3
- '@img/sharp-linuxmusl-x64': 0.33.3
- '@img/sharp-wasm32': 0.33.3
- '@img/sharp-win32-ia32': 0.33.3
- '@img/sharp-win32-x64': 0.33.3
+ '@img/sharp-linux-arm': 0.33.4
+ '@img/sharp-linux-arm64': 0.33.4
+ '@img/sharp-linux-s390x': 0.33.4
+ '@img/sharp-linux-x64': 0.33.4
+ '@img/sharp-linuxmusl-arm64': 0.33.4
+ '@img/sharp-linuxmusl-x64': 0.33.4
+ '@img/sharp-wasm32': 0.33.4
+ '@img/sharp-win32-ia32': 0.33.4
+ '@img/sharp-win32-x64': 0.33.4
shebang-command@1.2.0:
dependencies:
@@ -22792,9 +23577,10 @@ snapshots:
shebang-regex@3.0.0: {}
- shiki@1.4.0:
+ shiki@1.12.0:
dependencies:
- '@shikijs/core': 1.4.0
+ '@shikijs/core': 1.12.0
+ '@types/hast': 3.0.4
shimmer@1.2.1: {}
@@ -22810,11 +23596,11 @@ snapshots:
signal-exit@4.1.0: {}
- simple-oauth2@5.0.0:
+ simple-oauth2@5.1.0:
dependencies:
- '@hapi/hoek': 10.0.1
+ '@hapi/hoek': 11.0.4
'@hapi/wreck': 18.0.1
- debug: 4.3.4(supports-color@8.1.1)
+ debug: 4.3.5(supports-color@8.1.1)
joi: 17.11.0
transitivePeerDependencies:
- supports-color
@@ -22895,6 +23681,8 @@ snapshots:
slash@3.0.0: {}
+ slash@5.1.0: {}
+
slice-ansi@3.0.0:
dependencies:
ansi-styles: 4.3.0
@@ -22912,7 +23700,7 @@ snapshots:
socks-proxy-agent@8.0.2:
dependencies:
agent-base: 7.1.0
- debug: 4.3.4(supports-color@8.1.1)
+ debug: 4.3.5(supports-color@8.1.1)
socks: 2.7.1
transitivePeerDependencies:
- supports-color
@@ -22922,7 +23710,7 @@ snapshots:
ip: 2.0.1
smart-buffer: 4.2.0
- sonic-boom@3.7.0:
+ sonic-boom@4.0.1:
dependencies:
atomic-sleep: 1.0.0
@@ -22978,7 +23766,7 @@ snapshots:
sprintf-js@1.0.3: {}
- sprintf-js@1.1.2: {}
+ sprintf-js@1.1.3: {}
sshpk@1.17.0:
dependencies:
@@ -23004,16 +23792,16 @@ snapshots:
standard-as-callback@2.1.0: {}
- start-server-and-test@2.0.3:
+ start-server-and-test@2.0.4:
dependencies:
arg: 5.0.2
bluebird: 3.7.2
check-more-types: 2.24.0
- debug: 4.3.4(supports-color@8.1.1)
+ debug: 4.3.5(supports-color@8.1.1)
execa: 5.1.1
lazy-ass: 1.6.0
ps-tree: 1.2.0
- wait-on: 7.2.0(debug@4.3.4)
+ wait-on: 7.2.0(debug@4.3.5)
transitivePeerDependencies:
- supports-color
@@ -23027,28 +23815,52 @@ snapshots:
store2@2.14.2: {}
- storybook-addon-misskey-theme@https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/components@8.0.9(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/core-events@8.0.9)(@storybook/manager-api@8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/preview-api@8.0.9)(@storybook/theming@8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/types@8.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
+ storybook-addon-misskey-theme@https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(3rvqj7p7l43ansgshs3zbslm7u):
dependencies:
- '@storybook/blocks': 8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@storybook/components': 8.0.9(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@storybook/core-events': 8.0.9
- '@storybook/manager-api': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@storybook/preview-api': 8.0.9
- '@storybook/theming': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@storybook/types': 8.0.9
+ '@storybook/blocks': 8.2.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@storybook/components': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@storybook/core-events': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@storybook/manager-api': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@storybook/preview-api': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@storybook/theming': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
+ '@storybook/types': 8.2.6(storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4))
optionalDependencies:
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- storybook@8.0.9(@babel/preset-env@7.23.5(@babel/core@7.24.0))(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3):
+ storybook@8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(utf-8-validate@6.0.4):
dependencies:
- '@storybook/cli': 8.0.9(@babel/preset-env@7.23.5(@babel/core@7.24.0))(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3)
+ '@babel/core': 7.24.7
+ '@babel/types': 7.24.7
+ '@storybook/codemod': 8.2.6(bufferutil@4.0.8)(utf-8-validate@6.0.4)
+ '@storybook/core': 8.2.6(bufferutil@4.0.8)(utf-8-validate@6.0.4)
+ '@types/semver': 7.5.8
+ '@yarnpkg/fslib': 2.10.3
+ '@yarnpkg/libzip': 2.3.0
+ chalk: 4.1.2
+ commander: 6.2.1
+ cross-spawn: 7.0.3
+ detect-indent: 6.1.0
+ envinfo: 7.8.1
+ execa: 5.1.1
+ fd-package-json: 1.2.0
+ find-up: 5.0.0
+ fs-extra: 11.1.1
+ giget: 1.1.2
+ globby: 14.0.1
+ jscodeshift: 0.15.1(@babel/preset-env@7.24.7(@babel/core@7.24.7))
+ leven: 3.1.0
+ ora: 5.4.1
+ prettier: 3.3.3
+ prompts: 2.4.2
+ semver: 7.6.0
+ strip-json-comments: 3.1.1
+ tempy: 3.1.0
+ tiny-invariant: 1.3.3
+ ts-dedent: 2.2.0
transitivePeerDependencies:
- '@babel/preset-env'
- bufferutil
- - encoding
- - react
- - react-dom
- supports-color
- utf-8-validate
@@ -23067,8 +23879,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- stream-shift@1.0.1: {}
-
stream-wormhole@1.1.0: {}
streamsearch@1.1.0: {}
@@ -23151,6 +23961,8 @@ snapshots:
strip-final-newline@3.0.0: {}
+ strip-final-newline@4.0.0: {}
+
strip-indent@3.0.0:
dependencies:
min-indent: 1.0.1
@@ -23161,9 +23973,9 @@ snapshots:
strip-json-comments@3.1.1: {}
- strip-literal@1.3.0:
+ strip-literal@2.1.0:
dependencies:
- acorn: 8.11.3
+ js-tokens: 9.0.0
strip-outer@2.0.0: {}
@@ -23174,10 +23986,15 @@ snapshots:
'@tokenizer/token': 0.3.0
peek-readable: 5.0.0
- stylehacks@6.1.1(postcss@8.4.38):
+ strtok3@8.0.1:
+ dependencies:
+ '@tokenizer/token': 0.3.0
+ peek-readable: 5.1.3
+
+ stylehacks@6.1.1(postcss@8.4.40):
dependencies:
browserslist: 4.23.0
- postcss: 8.4.38
+ postcss: 8.4.40
postcss-selector-parser: 6.0.16
supports-color@5.5.0:
@@ -23213,22 +24030,7 @@ snapshots:
symbol-tree@3.2.4: {}
- systeminformation@5.22.7: {}
-
- tar-fs@2.1.1:
- dependencies:
- chownr: 1.1.4
- mkdirp-classic: 0.5.3
- pump: 3.0.0
- tar-stream: 2.2.0
-
- tar-stream@2.2.0:
- dependencies:
- bl: 4.1.0
- end-of-stream: 1.4.4
- fs-constants: 1.0.0
- inherits: 2.0.4
- readable-stream: 3.6.0
+ systeminformation@5.22.11: {}
tar-stream@3.1.6:
dependencies:
@@ -23264,24 +24066,23 @@ snapshots:
dependencies:
memoizerific: 1.11.3
- temp-dir@2.0.0: {}
+ temp-dir@3.0.0: {}
temp@0.8.4:
dependencies:
rimraf: 2.6.3
- tempy@1.0.1:
+ tempy@3.1.0:
dependencies:
- del: 6.1.1
- is-stream: 2.0.1
- temp-dir: 2.0.0
- type-fest: 0.16.0
- unique-string: 2.0.0
+ is-stream: 3.0.0
+ temp-dir: 3.0.0
+ type-fest: 2.19.0
+ unique-string: 3.0.0
- terser@5.30.3:
+ terser@5.31.3:
dependencies:
- '@jridgewell/source-map': 0.3.5
- acorn: 8.11.3
+ '@jridgewell/source-map': 0.3.6
+ acorn: 8.12.1
commander: 2.20.3
source-map-support: 0.5.21
@@ -23303,27 +24104,20 @@ snapshots:
dependencies:
any-promise: 1.3.0
- thread-stream@2.3.0:
+ thread-stream@3.1.0:
dependencies:
real-require: 0.2.0
- three@0.164.1: {}
+ three@0.167.0: {}
- throttle-debounce@5.0.0: {}
+ throttle-debounce@5.0.2: {}
throttleit@1.0.0: {}
- through2@2.0.5:
- dependencies:
- readable-stream: 2.3.7
- xtend: 4.0.2
-
through@2.3.4: {}
through@2.3.8: {}
- tiny-invariant@1.3.1: {}
-
tiny-invariant@1.3.3: {}
tiny-lru@10.0.1: {}
@@ -23332,7 +24126,7 @@ snapshots:
tinycolor2@1.6.0: {}
- tinypool@0.7.0: {}
+ tinypool@0.8.4: {}
tinyspy@2.2.0: {}
@@ -23348,12 +24142,8 @@ snapshots:
dependencies:
is-number: 7.0.0
- toad-cache@3.3.0: {}
-
toad-cache@3.7.0: {}
- tocbot@4.21.1: {}
-
toidentifier@1.0.1: {}
token-stream@1.0.0: {}
@@ -23363,6 +24153,11 @@ snapshots:
'@tokenizer/token': 0.3.0
ieee754: 1.2.1
+ token-types@6.0.0:
+ dependencies:
+ '@tokenizer/token': 0.3.0
+ ieee754: 1.2.1
+
touch@3.1.0:
dependencies:
nopt: 1.0.10
@@ -23372,7 +24167,7 @@ snapshots:
psl: 1.9.0
punycode: 2.3.1
- tough-cookie@4.1.3:
+ tough-cookie@4.1.4:
dependencies:
psl: 1.9.0
punycode: 2.3.1
@@ -23399,9 +24194,9 @@ snapshots:
dependencies:
typescript: 5.3.3
- ts-api-utils@1.3.0(typescript@5.4.5):
+ ts-api-utils@1.3.0(typescript@5.5.4):
dependencies:
- typescript: 5.4.5
+ typescript: 5.5.4
ts-case-convert@2.0.2: {}
@@ -23409,7 +24204,7 @@ snapshots:
ts-map@1.0.3: {}
- tsc-alias@1.8.8:
+ tsc-alias@1.8.10:
dependencies:
chokidar: 3.5.3
commander: 9.5.0
@@ -23431,9 +24226,9 @@ snapshots:
minimist: 1.2.8
strip-bom: 3.0.0
- tsd@0.30.7:
+ tsd@0.31.1:
dependencies:
- '@tsd/typescript': 5.3.3
+ '@tsd/typescript': 5.4.5
eslint-formatter-pretty: 4.1.0
globby: 11.1.0
jest-diff: 29.7.0
@@ -23445,6 +24240,8 @@ snapshots:
tslib@2.6.2: {}
+ tslib@2.6.3: {}
+
tsx@4.4.0:
dependencies:
esbuild: 0.18.20
@@ -23464,8 +24261,6 @@ snapshots:
type-detect@4.0.8: {}
- type-fest@0.16.0: {}
-
type-fest@0.18.1: {}
type-fest@0.20.2: {}
@@ -23476,9 +24271,11 @@ snapshots:
type-fest@0.8.1: {}
+ type-fest@1.4.0: {}
+
type-fest@2.19.0: {}
- type-fest@4.9.0: {}
+ type-fest@4.20.1: {}
type-is@1.6.18:
dependencies:
@@ -23514,7 +24311,7 @@ snapshots:
typedarray@0.0.6: {}
- typeorm@0.3.20(ioredis@5.4.1)(pg@8.11.5):
+ typeorm@0.3.20(ioredis@5.4.1)(pg@8.12.0):
dependencies:
'@sqltools/formatter': 1.2.5
app-root-path: 3.1.0
@@ -23522,7 +24319,7 @@ snapshots:
chalk: 4.1.2
cli-highlight: 2.1.11
dayjs: 1.11.10
- debug: 4.3.4(supports-color@8.1.1)
+ debug: 4.3.4(supports-color@5.5.0)
dotenv: 16.0.3
glob: 10.3.10
mkdirp: 2.1.6
@@ -23533,7 +24330,7 @@ snapshots:
yargs: 17.7.2
optionalDependencies:
ioredis: 5.4.1
- pg: 8.11.5
+ pg: 8.12.0
transitivePeerDependencies:
- supports-color
@@ -23541,7 +24338,7 @@ snapshots:
typescript@5.4.2: {}
- typescript@5.4.5: {}
+ typescript@5.5.4: {}
ufo@1.3.2: {}
@@ -23554,6 +24351,8 @@ snapshots:
dependencies:
'@lukeed/csprng': 1.0.1
+ uint8array-extras@1.4.0: {}
+
ulid@2.3.0: {}
unbox-primitive@1.0.2:
@@ -23582,6 +24381,8 @@ snapshots:
unicode-property-aliases-ecmascript@2.1.0: {}
+ unicorn-magic@0.1.0: {}
+
unified@11.0.4:
dependencies:
'@types/unist': 3.0.2
@@ -23602,9 +24403,9 @@ snapshots:
dependencies:
imurmurhash: 0.1.4
- unique-string@2.0.0:
+ unique-string@3.0.0:
dependencies:
- crypto-random-string: 2.0.0
+ crypto-random-string: 4.0.0
unist-util-is@6.0.0:
dependencies:
@@ -23637,7 +24438,7 @@ snapshots:
unplugin@1.4.0:
dependencies:
- acorn: 8.11.3
+ acorn: 8.12.1
chokidar: 3.5.3
webpack-sources: 3.2.3
webpack-virtual-modules: 0.5.0
@@ -23670,6 +24471,11 @@ snapshots:
node-gyp-build: 4.6.0
optional: true
+ utf-8-validate@6.0.4:
+ dependencies:
+ node-gyp-build: 4.6.0
+ optional: true
+
util-deprecate@1.0.2: {}
util@0.12.5:
@@ -23682,20 +24488,22 @@ snapshots:
utils-merge@1.0.1: {}
+ uuid@10.0.0: {}
+
uuid@3.4.0: {}
uuid@8.3.2: {}
uuid@9.0.1: {}
- v-code-diff@1.11.0(vue@3.4.26(typescript@5.4.5)):
+ v-code-diff@1.12.0(vue@3.4.34(typescript@5.5.4)):
dependencies:
diff: 5.1.0
diff-match-patch: 1.0.5
highlight.js: 11.9.0
- vue: 3.4.26(typescript@5.4.5)
- vue-demi: 0.14.7(vue@3.4.26(typescript@5.4.5))
- vue-i18n: 9.13.1(vue@3.4.26(typescript@5.4.5))
+ vue: 3.4.34(typescript@5.5.4)
+ vue-demi: 0.14.7(vue@3.4.34(typescript@5.5.4))
+ vue-i18n: 9.13.1(vue@3.4.34(typescript@5.5.4))
v8-to-istanbul@9.2.0:
dependencies:
@@ -23708,8 +24516,6 @@ snapshots:
spdx-correct: 3.1.1
spdx-expression-parse: 3.0.1
- validator@13.9.0: {}
-
vary@1.1.2: {}
verror@1.10.0:
@@ -23729,14 +24535,13 @@ snapshots:
unist-util-stringify-position: 4.0.0
vfile-message: 4.0.2
- vite-node@0.34.6(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3):
+ vite-node@1.6.0(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3):
dependencies:
cac: 6.7.14
- debug: 4.3.4(supports-color@8.1.1)
- mlly: 1.5.0
+ debug: 4.3.5(supports-color@8.1.1)
pathe: 1.1.2
picocolors: 1.0.0
- vite: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3)
+ vite: 5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3)
transitivePeerDependencies:
- '@types/node'
- less
@@ -23749,53 +24554,50 @@ snapshots:
vite-plugin-turbosnap@1.0.3: {}
- vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3):
+ vite@5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3):
dependencies:
- esbuild: 0.20.2
- postcss: 8.4.38
- rollup: 4.17.2
+ esbuild: 0.21.5
+ postcss: 8.4.40
+ rollup: 4.19.1
optionalDependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.14.12
fsevents: 2.3.3
- sass: 1.76.0
- terser: 5.30.3
+ sass: 1.77.8
+ terser: 5.31.3
- vitest-fetch-mock@0.2.2(encoding@0.1.13)(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)):
+ vitest-fetch-mock@0.2.2(encoding@0.1.13)(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.8)(terser@5.31.3)):
dependencies:
cross-fetch: 3.1.6(encoding@0.1.13)
- vitest: 0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)
+ vitest: 1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.8)(terser@5.31.3)
transitivePeerDependencies:
- encoding
- vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3):
+ vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.8)(terser@5.31.3):
dependencies:
- '@types/chai': 4.3.11
- '@types/chai-subset': 1.3.5
- '@types/node': 20.12.7
- '@vitest/expect': 0.34.6
- '@vitest/runner': 0.34.6
- '@vitest/snapshot': 0.34.6
- '@vitest/spy': 0.34.6
- '@vitest/utils': 0.34.6
- acorn: 8.11.3
+ '@vitest/expect': 1.6.0
+ '@vitest/runner': 1.6.0
+ '@vitest/snapshot': 1.6.0
+ '@vitest/spy': 1.6.0
+ '@vitest/utils': 1.6.0
acorn-walk: 8.3.2
- cac: 6.7.14
chai: 4.3.10
- debug: 4.3.4(supports-color@8.1.1)
- local-pkg: 0.4.3
- magic-string: 0.30.7
+ debug: 4.3.4(supports-color@5.5.0)
+ execa: 8.0.1
+ local-pkg: 0.5.0
+ magic-string: 0.30.10
pathe: 1.1.2
picocolors: 1.0.0
std-env: 3.7.0
- strip-literal: 1.3.0
+ strip-literal: 2.1.0
tinybench: 2.6.0
- tinypool: 0.7.0
- vite: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3)
- vite-node: 0.34.6(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3)
+ tinypool: 0.8.4
+ vite: 5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3)
+ vite-node: 1.6.0(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3)
why-is-node-running: 2.2.2
optionalDependencies:
+ '@types/node': 20.14.12
happy-dom: 10.0.3
- jsdom: 24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
+ jsdom: 24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)
transitivePeerDependencies:
- less
- lightningcss
@@ -23828,98 +24630,100 @@ snapshots:
dependencies:
vscode-languageserver-protocol: 3.17.5
- vue-component-meta@2.0.16(typescript@5.4.5):
+ vscode-uri@3.0.8: {}
+
+ vue-component-meta@2.0.16(typescript@5.5.4):
dependencies:
'@volar/typescript': 2.2.0
- '@vue/language-core': 2.0.16(typescript@5.4.5)
+ '@vue/language-core': 2.0.16(typescript@5.5.4)
path-browserify: 1.0.1
vue-component-type-helpers: 2.0.16
optionalDependencies:
- typescript: 5.4.5
+ typescript: 5.5.4
vue-component-type-helpers@1.8.4: {}
vue-component-type-helpers@2.0.16: {}
- vue-component-type-helpers@2.0.19: {}
+ vue-component-type-helpers@2.0.29: {}
- vue-demi@0.14.7(vue@3.4.26(typescript@5.4.5)):
+ vue-demi@0.14.7(vue@3.4.34(typescript@5.5.4)):
dependencies:
- vue: 3.4.26(typescript@5.4.5)
+ vue: 3.4.34(typescript@5.5.4)
- vue-docgen-api@4.75.1(vue@3.4.26(typescript@5.4.5)):
+ vue-docgen-api@4.75.1(vue@3.4.34(typescript@5.5.4)):
dependencies:
- '@babel/parser': 7.24.0
- '@babel/types': 7.24.0
- '@vue/compiler-dom': 3.4.21
- '@vue/compiler-sfc': 3.4.26
+ '@babel/parser': 7.24.7
+ '@babel/types': 7.24.7
+ '@vue/compiler-dom': 3.4.29
+ '@vue/compiler-sfc': 3.4.34
ast-types: 0.16.1
hash-sum: 2.0.0
lru-cache: 8.0.4
- pug: 3.0.2
- recast: 0.23.4
+ pug: 3.0.3
+ recast: 0.23.6
ts-map: 1.0.3
- vue: 3.4.26(typescript@5.4.5)
- vue-inbrowser-compiler-independent-utils: 4.71.1(vue@3.4.26(typescript@5.4.5))
+ vue: 3.4.34(typescript@5.5.4)
+ vue-inbrowser-compiler-independent-utils: 4.71.1(vue@3.4.34(typescript@5.5.4))
- vue-eslint-parser@9.4.2(eslint@8.57.0):
+ vue-eslint-parser@9.4.3(eslint@9.8.0):
dependencies:
- debug: 4.3.4(supports-color@8.1.1)
- eslint: 8.57.0
+ debug: 4.3.4(supports-color@5.5.0)
+ eslint: 9.8.0
eslint-scope: 7.2.2
eslint-visitor-keys: 3.4.3
espree: 9.6.1
esquery: 1.4.2
lodash: 4.17.21
- semver: 7.5.4
+ semver: 7.6.0
transitivePeerDependencies:
- supports-color
- vue-i18n@9.13.1(vue@3.4.26(typescript@5.4.5)):
+ vue-i18n@9.13.1(vue@3.4.34(typescript@5.5.4)):
dependencies:
'@intlify/core-base': 9.13.1
'@intlify/shared': 9.13.1
'@vue/devtools-api': 6.6.1
- vue: 3.4.26(typescript@5.4.5)
+ vue: 3.4.34(typescript@5.5.4)
- vue-inbrowser-compiler-independent-utils@4.71.1(vue@3.4.26(typescript@5.4.5)):
+ vue-inbrowser-compiler-independent-utils@4.71.1(vue@3.4.34(typescript@5.5.4)):
dependencies:
- vue: 3.4.26(typescript@5.4.5)
+ vue: 3.4.34(typescript@5.5.4)
vue-template-compiler@2.7.14:
dependencies:
de-indent: 1.0.2
he: 1.2.0
- vue-tsc@2.0.16(typescript@5.4.5):
+ vue-tsc@2.0.29(typescript@5.5.4):
dependencies:
- '@volar/typescript': 2.2.0
- '@vue/language-core': 2.0.16(typescript@5.4.5)
+ '@volar/typescript': 2.4.0-alpha.18
+ '@vue/language-core': 2.0.29(typescript@5.5.4)
semver: 7.6.0
- typescript: 5.4.5
+ typescript: 5.5.4
- vue@3.4.26(typescript@5.4.5):
+ vue@3.4.34(typescript@5.5.4):
dependencies:
- '@vue/compiler-dom': 3.4.26
- '@vue/compiler-sfc': 3.4.26
- '@vue/runtime-dom': 3.4.26
- '@vue/server-renderer': 3.4.26(vue@3.4.26(typescript@5.4.5))
- '@vue/shared': 3.4.26
+ '@vue/compiler-dom': 3.4.34
+ '@vue/compiler-sfc': 3.4.34
+ '@vue/runtime-dom': 3.4.34
+ '@vue/server-renderer': 3.4.34(vue@3.4.34(typescript@5.5.4))
+ '@vue/shared': 3.4.34
optionalDependencies:
- typescript: 5.4.5
+ typescript: 5.5.4
- vuedraggable@4.1.0(vue@3.4.26(typescript@5.4.5)):
+ vuedraggable@4.1.0(vue@3.4.34(typescript@5.5.4)):
dependencies:
sortablejs: 1.14.0
- vue: 3.4.26(typescript@5.4.5)
+ vue: 3.4.34(typescript@5.5.4)
w3c-xmlserializer@5.0.0:
dependencies:
xml-name-validator: 5.0.0
- wait-on@7.2.0(debug@4.3.4):
+ wait-on@7.2.0(debug@4.3.5):
dependencies:
- axios: 1.6.2(debug@4.3.4)
+ axios: 1.6.2(debug@4.3.5)
joi: 17.11.0
lodash: 4.17.21
minimist: 1.2.8
@@ -23927,6 +24731,8 @@ snapshots:
transitivePeerDependencies:
- debug
+ walk-up-path@3.0.1: {}
+
walker@1.0.8:
dependencies:
makeerror: 1.0.12
@@ -23952,6 +24758,9 @@ snapshots:
web-streams-polyfill@3.2.1: {}
+ web-streams-polyfill@4.0.0:
+ optional: true
+
webidl-conversions@3.0.1: {}
webidl-conversions@7.0.0: {}
@@ -24031,11 +24840,13 @@ snapshots:
with@7.0.2:
dependencies:
- '@babel/parser': 7.23.9
- '@babel/types': 7.23.5
+ '@babel/parser': 7.24.5
+ '@babel/types': 7.24.0
assert-never: 1.2.1
babel-walk: 3.0.0-canary-5
+ word-wrap@1.2.5: {}
+
wordwrap@1.0.0: {}
wrap-ansi@6.2.0:
@@ -24069,11 +24880,16 @@ snapshots:
imurmurhash: 0.1.4
signal-exit: 3.0.7
- ws@8.17.0(bufferutil@4.0.7)(utf-8-validate@6.0.3):
+ ws@8.18.0(bufferutil@4.0.7)(utf-8-validate@6.0.3):
optionalDependencies:
bufferutil: 4.0.7
utf-8-validate: 6.0.3
+ ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4):
+ optionalDependencies:
+ bufferutil: 4.0.8
+ utf-8-validate: 6.0.4
+
xev@3.0.2: {}
xml-js@1.6.11:
@@ -24157,13 +24973,7 @@ snapshots:
yocto-queue@1.0.0: {}
- z-schema@5.0.5:
- dependencies:
- lodash.get: 4.4.2
- lodash.isequal: 4.5.0
- validator: 13.9.0
- optionalDependencies:
- commander: 9.5.0
+ yoctocolors@2.0.2: {}
zip-stream@6.0.1:
dependencies:
diff --git a/scripts/build-assets.mjs b/scripts/build-assets.mjs
index b5aa5eb4ab..2b275e12d6 100644
--- a/scripts/build-assets.mjs
+++ b/scripts/build-assets.mjs
@@ -13,7 +13,7 @@ import * as terser from 'terser';
import { build as buildLocales } from '../locales/index.js';
import generateDTS from '../locales/generateDTS.js';
-import meta from '../package.json' assert { type: "json" };
+import meta from '../package.json' with { type: "json" };
import buildTarball from './tarball.mjs';
const configDir = fileURLToPath(new URL('../.config', import.meta.url));
diff --git a/scripts/changelog-checker/.eslintrc.cjs b/scripts/changelog-checker/.eslintrc.cjs
deleted file mode 100644
index 6acf8b3e6e..0000000000
--- a/scripts/changelog-checker/.eslintrc.cjs
+++ /dev/null
@@ -1,9 +0,0 @@
-module.exports = {
- parserOptions: {
- tsconfigRootDir: __dirname,
- project: ['./tsconfig.json'],
- },
- extends: [
- '../../packages/shared/.eslintrc.js',
- ],
-};
diff --git a/scripts/changelog-checker/eslint.config.js b/scripts/changelog-checker/eslint.config.js
new file mode 100644
index 0000000000..813e96981a
--- /dev/null
+++ b/scripts/changelog-checker/eslint.config.js
@@ -0,0 +1,17 @@
+import tsParser from '@typescript-eslint/parser';
+import sharedConfig from '../../packages/shared/eslint.config.js';
+
+export default [
+ ...sharedConfig,
+ {
+ files: ['src/**/*.ts', 'src/**/*.tsx'],
+ languageOptions: {
+ parserOptions: {
+ parser: tsParser,
+ project: ['./tsconfig.json'],
+ sourceType: 'module',
+ tsconfigRootDir: import.meta.dirname,
+ },
+ },
+ },
+];
diff --git a/scripts/tarball.mjs b/scripts/tarball.mjs
index b1862ad289..e9d8900aca 100644
--- a/scripts/tarball.mjs
+++ b/scripts/tarball.mjs
@@ -10,7 +10,7 @@ import { fileURLToPath } from 'node:url';
import glob from 'fast-glob';
import walk from 'ignore-walk';
import Pack from 'tar/lib/pack.js';
-import meta from '../package.json' assert { type: "json" };
+import meta from '../package.json' with { type: "json" };
const cwd = fileURLToPath(new URL('..', import.meta.url));
const ignore = [