Compare commits

..

20 commits

Author SHA1 Message Date
Kagami Sascha Rosylight 0b0a416566 Merge remote-tracking branch 'origin/develop' into misskey-js 2023-03-25 07:58:26 +01:00
Kagami Sascha Rosylight 9044fa5d1a
Merge branch 'develop' into misskey-js 2023-03-19 10:26:30 +01:00
Kagami Sascha Rosylight 3bb343e2fc
Merge branch 'develop' into misskey-js 2023-03-17 11:11:21 +01:00
Kagami Sascha Rosylight f2fd8bfac1 Update Dockerfile 2023-03-16 23:05:48 +01:00
Kagami Sascha Rosylight 1602ad843a Update pnpm-lock.yaml 2023-03-16 22:42:46 +01:00
Kagami Sascha Rosylight e68236bd84 Update package.json 2023-03-16 22:35:52 +01:00
Kagami Sascha Rosylight 447b6f9e5f upgrade @types/node 2023-03-16 22:30:12 +01:00
Kagami Sascha Rosylight 746bc322b7 types too 2023-03-16 22:24:59 +01:00
Kagami Sascha Rosylight a6aee82fcf upgrade jest 2023-03-16 22:23:52 +01:00
Kagami Sascha Rosylight 6095b33ab2 fix vite build 2023-03-16 22:13:42 +01:00
Kagami Sascha Rosylight 5ac094e51b fix lint errors 2023-03-16 21:38:20 +01:00
Kagami Sascha Rosylight bdf013d547 Update pnpm-lock.yaml 2023-03-16 21:35:58 +01:00
Kagami Sascha Rosylight 96a2dda153 Update package.json 2023-03-16 21:32:16 +01:00
Kagami Sascha Rosylight d69d2c8e8d Update test-misskey-js.yml 2023-03-16 21:24:22 +01:00
Kagami Sascha Rosylight 8736bb42f2 Update test-misskey-js.yml 2023-03-16 21:22:39 +01:00
Kagami Sascha Rosylight effd78dc98 skip pnpm/action-setup? 2023-03-16 21:18:32 +01:00
Kagami Sascha Rosylight 634ce0fa49 Update misskey-js.api.md 2023-03-16 21:18:08 +01:00
Kagami Sascha Rosylight 6e6a5222cd enable corepack first 2023-03-16 21:14:55 +01:00
Kagami Sascha Rosylight ce5a9630ca update workflows 2023-03-16 21:13:21 +01:00
Kagami Sascha Rosylight d123722616 chore: integrate misskey-js as a workspace item 2023-03-16 21:07:16 +01:00
2591 changed files with 65731 additions and 247455 deletions

View file

@ -1,224 +0,0 @@
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Misskey configuration
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# ┌────────────────────────┐
#───┘ Initial Setup Password └─────────────────────────────────────────────────────
# Password to initiate setting up admin account.
# It will not be used after the initial setup is complete.
#
# Be sure to change this when you set up Misskey via the Internet.
#
# The provider of the service who sets up Misskey on behalf of the customer should
# set this value to something unique when generating the Misskey config file,
# and provide it to the customer.
setupPassword: example_password_please_change_this_or_you_will_get_hacked
# ┌─────┐
#───┘ URL └─────────────────────────────────────────────────────
# Final accessible URL seen by a user.
url: 'http://misskey.local'
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
# URL SETTINGS AFTER THAT!
# ┌───────────────────────┐
#───┘ Port and TLS settings └───────────────────────────────────
#
# Misskey requires a reverse proxy to support HTTPS connections.
#
# +----- https://example.tld/ ------------+
# +------+ |+-------------+ +----------------+|
# | User | ---> || Proxy (443) | ---> | Misskey (3000) ||
# +------+ |+-------------+ +----------------+|
# +---------------------------------------+
#
# You need to set up a reverse proxy. (e.g. nginx)
# An encrypted connection with HTTPS is highly recommended
# because tokens may be transferred in GET requests.
# The port that your Misskey server should listen on.
port: 61812
# ┌──────────────────────────┐
#───┘ PostgreSQL configuration └────────────────────────────────
db:
host: db
port: 5432
# Database name
db: misskey
# Auth
user: postgres
pass: postgres
# Whether disable Caching queries
#disableCache: true
# Extra Connection options
#extra:
# ssl: true
dbReplications: false
# You can configure any number of replicas here
#dbSlaves:
# -
# host:
# port:
# db:
# user:
# pass:
# -
# host:
# port:
# db:
# user:
# pass:
# ┌─────────────────────┐
#───┘ Redis configuration └─────────────────────────────────────
redis:
host: redis
port: 6379
#family: 0 # 0=Both, 4=IPv4, 6=IPv6
#pass: example-pass
#prefix: example-prefix
#db: 1
#redisForPubsub:
# host: redis
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #db: 1
#redisForJobQueue:
# host: redis
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #db: 1
#redisForTimelines:
# host: redis
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #db: 1
#redisForReactions:
# host: redis
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #db: 1
# ┌───────────────────────────┐
#───┘ MeiliSearch configuration └─────────────────────────────
#meilisearch:
# host: meilisearch
# port: 7700
# apiKey: ''
# ssl: true
# index: ''
# ┌───────────────┐
#───┘ ID generation └───────────────────────────────────────────
# You can select the ID generation method.
# You don't usually need to change this setting, but you can
# change it according to your preferences.
# Available methods:
# aid ... Short, Millisecond accuracy
# aidx ... Millisecond accuracy
# meid ... Similar to ObjectID, Millisecond accuracy
# ulid ... Millisecond accuracy
# objectid ... This is left for backward compatibility
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
# ID SETTINGS AFTER THAT!
id: 'aidx'
# ┌────────────────┐
#───┘ Error tracking └──────────────────────────────────────────
# Sentry is available for error tracking.
# See the Sentry documentation for more details on options.
#sentryForBackend:
# enableNodeProfiling: true
# options:
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
#sentryForFrontend:
# options:
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
# ┌─────────────────────┐
#───┘ Other configuration └─────────────────────────────────────
# Whether disable HSTS
#disableHsts: true
# Number of worker processes
#clusterLimit: 1
# Job concurrency per worker
# deliverJobConcurrency: 128
# inboxJobConcurrency: 16
# Job rate limiter
# deliverJobPerSec: 128
# inboxJobPerSec: 32
# Job attempts
# deliverJobMaxAttempts: 12
# inboxJobMaxAttempts: 8
# IP address family used for outgoing request (ipv4, ipv6 or dual)
#outgoingAddressFamily: ipv4
# Proxy for HTTP/HTTPS
#proxy: http://127.0.0.1:3128
proxyBypassHosts:
- api.deepl.com
- api-free.deepl.com
- www.recaptcha.net
- hcaptcha.com
- challenges.cloudflare.com
# Proxy for SMTP/SMTPS
#proxySmtp: http://127.0.0.1:3128 # use HTTP/1.1 CONNECT
#proxySmtp: socks4://127.0.0.1:1080 # use SOCKS4
#proxySmtp: socks5://127.0.0.1:1080 # use SOCKS5
# Media Proxy
#mediaProxy: https://example.com/proxy
# Proxy remote files (default: true)
proxyRemoteFiles: true
# Sign to ActivityPub GET request (default: true)
signToActivityPubGet: true
allowedPrivateNetworks: [
'127.0.0.1/32'
]
# Upload or download file size limits (bytes)
#maxFileSize: 262144000

View file

@ -1,11 +1,4 @@
# misskey settings
# MISSKEY_URL=https://example.tld/
# db settings # db settings
POSTGRES_PASSWORD=example-misskey-pass POSTGRES_PASSWORD=example-misskey-pass
# DATABASE_PASSWORD=${POSTGRES_PASSWORD}
POSTGRES_USER=example-misskey-user POSTGRES_USER=example-misskey-user
# DATABASE_USER=${POSTGRES_USER}
POSTGRES_DB=misskey POSTGRES_DB=misskey
# DATABASE_DB=${POSTGRES_DB}
DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}"

View file

@ -6,7 +6,6 @@
#───┘ URL └───────────────────────────────────────────────────── #───┘ URL └─────────────────────────────────────────────────────
# Final accessible URL seen by a user. # Final accessible URL seen by a user.
# You can set url from an environment variable instead.
url: https://example.tld/ url: https://example.tld/
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE # ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
@ -39,11 +38,9 @@ db:
port: 5432 port: 5432
# Database name # Database name
# You can set db from an environment variable instead.
db: misskey db: misskey
# Auth # Auth
# You can set user and pass from environment variables instead.
user: example-misskey-user user: example-misskey-user
pass: example-misskey-pass pass: example-misskey-pass
@ -54,23 +51,6 @@ db:
#extra: #extra:
# ssl: true # ssl: true
dbReplications: false
# You can configure any number of replicas here
#dbSlaves:
# -
# host:
# port:
# db:
# user:
# pass:
# -
# host:
# port:
# db:
# user:
# pass:
# ┌─────────────────────┐ # ┌─────────────────────┐
#───┘ Redis configuration └───────────────────────────────────── #───┘ Redis configuration └─────────────────────────────────────
@ -82,51 +62,15 @@ redis:
#prefix: example-prefix #prefix: example-prefix
#db: 1 #db: 1
#redisForPubsub: # ┌─────────────────────────────┐
# host: redis #───┘ Elasticsearch configuration └─────────────────────────────
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #db: 1
#redisForJobQueue: #elasticsearch:
# host: redis # host: localhost
# port: 6379 # port: 9200
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6 # ssl: false
# #pass: example-pass # user:
# #prefix: example-prefix # pass:
# #db: 1
#redisForTimelines:
# host: redis
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #db: 1
#redisForReactions:
# host: redis
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #db: 1
# ┌───────────────────────────┐
#───┘ MeiliSearch configuration └─────────────────────────────
# You can set scope to local (default value) or global
# (include notes from remote).
#meilisearch:
# host: meilisearch
# port: 7700
# apiKey: ''
# ssl: true
# index: ''
# scope: local
# ┌───────────────┐ # ┌───────────────┐
#───┘ ID generation └─────────────────────────────────────────── #───┘ ID generation └───────────────────────────────────────────
@ -137,7 +81,6 @@ redis:
# Available methods: # Available methods:
# aid ... Short, Millisecond accuracy # aid ... Short, Millisecond accuracy
# aidx ... Millisecond accuracy
# meid ... Similar to ObjectID, Millisecond accuracy # meid ... Similar to ObjectID, Millisecond accuracy
# ulid ... Millisecond accuracy # ulid ... Millisecond accuracy
# objectid ... This is left for backward compatibility # objectid ... This is left for backward compatibility
@ -145,22 +88,7 @@ redis:
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE # ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
# ID SETTINGS AFTER THAT! # ID SETTINGS AFTER THAT!
id: 'aidx' id: 'aid'
# ┌────────────────┐
#───┘ Error tracking └──────────────────────────────────────────
# Sentry is available for error tracking.
# See the Sentry documentation for more details on options.
#sentryForBackend:
# enableNodeProfiling: true
# options:
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
#sentryForFrontend:
# options:
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
# ┌─────────────────────┐ # ┌─────────────────────┐
#───┘ Other configuration └───────────────────────────────────── #───┘ Other configuration └─────────────────────────────────────
@ -177,7 +105,7 @@ id: 'aidx'
# Job rate limiter # Job rate limiter
# deliverJobPerSec: 128 # deliverJobPerSec: 128
# inboxJobPerSec: 32 # inboxJobPerSec: 16
# Job attempts # Job attempts
# deliverJobMaxAttempts: 12 # deliverJobMaxAttempts: 12
@ -204,15 +132,12 @@ proxyBypassHosts:
# Media Proxy # Media Proxy
#mediaProxy: https://example.com/proxy #mediaProxy: https://example.com/proxy
# Proxy remote files (default: true) # Proxy remote files (default: false)
proxyRemoteFiles: true #proxyRemoteFiles: true
# Sign to ActivityPub GET request (default: true) # Sign to ActivityPub GET request (default: true)
signToActivityPubGet: true signToActivityPubGet: true
# For security reasons, uploading attachments from the intranet is prohibited,
# but exceptions can be made from the following settings. Default value is "undefined".
# Read changelog to learn more (Improvements of 12.90.0 (2021/09/04)).
#allowedPrivateNetworks: [ #allowedPrivateNetworks: [
# '127.0.0.1/32' # '127.0.0.1/32'
#] #]

View file

@ -2,77 +2,6 @@
# Misskey configuration # Misskey configuration
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# ┌──────────────────────────────┐
#───┘ a boring but important thing └────────────────────────────
#
# First of all, let me tell you a story that may possibly be
# boring to you and possibly important to you.
#
# Misskey is licensed under the AGPLv3 license. This license is
# known to be often misunderstood. Please read the following
# instructions carefully and select the appropriate option so
# that you do not negligently cause a license violation.
#
# --------
# Option 1: If you host Misskey AS-IS (without any changes to
# the source code. forks are not included).
#
# Step 1: Congratulations! You don't need to do anything.
# --------
# Option 2: If you have made changes to the source code (forks
# are included) and publish a Git repository of source
# code. There should be no access restrictions on
# this repository. Strictly speaking, it doesn't have
# to be a Git repository, but you'll probably use Git!
#
# Step 1: Build and run the Misskey server first.
# Step 2: Open <https://your.misskey.example/admin/settings> in
# your browser with the administrator account.
# Step 3: Enter the URL of your Git repository in the
# "Repository URL" field.
# --------
# Option 3: If neither of the above applies to you.
# (In this case, the source code should be published
# on the Misskey interface. IT IS NOT ENOUGH TO
# DISCLOSE THE SOURCE CODE WHEN A USER REQUESTS IT BY
# E-MAIL OR OTHER MEANS. If you are not satisfied
# with this, it is recommended that you read the
# license again carefully. Anyway, enabling this
# option will automatically generate and publish a
# tarball at build time, protecting you from
# inadvertent license violations. (There is no legal
# guarantee, of course.) The tarball will generated
# from the root directory of your codebase. So it is
# also recommended to check <built/tarball> directory
# once after building and before activating the server
# to avoid ACCIDENTAL LEAKING OF SENSITIVE INFORMATION.
# To prevent certain files from being included in the
# tarball, add a glob pattern after line 15 in
# <scripts/tarball.mjs>. DO NOT FORGET TO BUILD AFTER
# ENABLING THIS OPTION!)
#
# Step 1: Uncomment the following line.
#
# publishTarballInsteadOfProvideRepositoryUrl: true
# ┌────────────────────────┐
#───┘ Initial Setup Password └─────────────────────────────────────────────────────
# Password to initiate setting up admin account.
# It will not be used after the initial setup is complete.
#
# Be sure to change this when you set up Misskey via the Internet.
#
# The provider of the service who sets up Misskey on behalf of the customer should
# set this value to something unique when generating the Misskey config file,
# and provide it to the customer.
#
# setupPassword: example_password_please_change_this_or_you_will_get_hacked
# ┌─────┐ # ┌─────┐
#───┘ URL └───────────────────────────────────────────────────── #───┘ URL └─────────────────────────────────────────────────────
@ -101,10 +30,6 @@ url: https://example.tld/
# The port that your Misskey server should listen on. # The port that your Misskey server should listen on.
port: 3000 port: 3000
# You can also use UNIX domain socket.
# socket: /path/to/misskey.sock
# chmodSocket: '777'
# ┌──────────────────────────┐ # ┌──────────────────────────┐
#───┘ PostgreSQL configuration └──────────────────────────────── #───┘ PostgreSQL configuration └────────────────────────────────
@ -126,23 +51,6 @@ db:
#extra: #extra:
# ssl: true # ssl: true
dbReplications: false
# You can configure any number of replicas here
#dbSlaves:
# -
# host:
# port:
# db:
# user:
# pass:
# -
# host:
# port:
# db:
# user:
# pass:
# ┌─────────────────────┐ # ┌─────────────────────┐
#───┘ Redis configuration └───────────────────────────────────── #───┘ Redis configuration └─────────────────────────────────────
@ -153,62 +61,16 @@ redis:
#pass: example-pass #pass: example-pass
#prefix: example-prefix #prefix: example-prefix
#db: 1 #db: 1
# You can specify more ioredis options...
#username: example-username
#redisForPubsub: # ┌─────────────────────────────┐
#───┘ Elasticsearch configuration └─────────────────────────────
#elasticsearch:
# host: localhost # host: localhost
# port: 6379 # port: 9200
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6 # ssl: false
# #pass: example-pass # user:
# #prefix: example-prefix # pass:
# #db: 1
# # You can specify more ioredis options...
# #username: example-username
#redisForJobQueue:
# host: localhost
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #db: 1
# # You can specify more ioredis options...
# #username: example-username
#redisForTimelines:
# host: localhost
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #db: 1
# # You can specify more ioredis options...
# #username: example-username
#redisForReactions:
# host: localhost
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #db: 1
# # You can specify more ioredis options...
# #username: example-username
# ┌───────────────────────────┐
#───┘ MeiliSearch configuration └─────────────────────────────
# You can set scope to local (default value) or global
# (include notes from remote).
#meilisearch:
# host: localhost
# port: 7700
# apiKey: ''
# ssl: true
# index: ''
# scope: local
# ┌───────────────┐ # ┌───────────────┐
#───┘ ID generation └─────────────────────────────────────────── #───┘ ID generation └───────────────────────────────────────────
@ -219,7 +81,6 @@ redis:
# Available methods: # Available methods:
# aid ... Short, Millisecond accuracy # aid ... Short, Millisecond accuracy
# aidx ... Millisecond accuracy
# meid ... Similar to ObjectID, Millisecond accuracy # meid ... Similar to ObjectID, Millisecond accuracy
# ulid ... Millisecond accuracy # ulid ... Millisecond accuracy
# objectid ... This is left for backward compatibility # objectid ... This is left for backward compatibility
@ -227,22 +88,7 @@ redis:
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE # ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
# ID SETTINGS AFTER THAT! # ID SETTINGS AFTER THAT!
id: 'aidx' id: 'aid'
# ┌────────────────┐
#───┘ Error tracking └──────────────────────────────────────────
# Sentry is available for error tracking.
# See the Sentry documentation for more details on options.
#sentryForBackend:
# enableNodeProfiling: true
# options:
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
#sentryForFrontend:
# options:
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
# ┌─────────────────────┐ # ┌─────────────────────┐
#───┘ Other configuration └───────────────────────────────────── #───┘ Other configuration └─────────────────────────────────────
@ -254,23 +100,16 @@ id: 'aidx'
#clusterLimit: 1 #clusterLimit: 1
# Job concurrency per worker # Job concurrency per worker
#deliverJobConcurrency: 128 # deliverJobConcurrency: 128
#inboxJobConcurrency: 16 # inboxJobConcurrency: 16
#relationshipJobConcurrency: 16
# What's relationshipJob?:
# Follow, unfollow, block and unblock(ings) while following-imports, etc. or account migrations.
# Job rate limiter # Job rate limiter
#deliverJobPerSec: 128 # deliverJobPerSec: 128
#inboxJobPerSec: 32 # inboxJobPerSec: 16
#relationshipJobPerSec: 64
# Job attempts # Job attempts
#deliverJobMaxAttempts: 12 # deliverJobMaxAttempts: 12
#inboxJobMaxAttempts: 8 # inboxJobMaxAttempts: 8
# Local address used for outgoing requests
#outgoingAddress: 127.0.0.1
# IP address family used for outgoing request (ipv4, ipv6 or dual) # IP address family used for outgoing request (ipv4, ipv6 or dual)
#outgoingAddressFamily: ipv4 #outgoingAddressFamily: ipv4
@ -296,9 +135,9 @@ proxyBypassHosts:
# * Perform image compression (on a different server resource than the main process) # * Perform image compression (on a different server resource than the main process)
#mediaProxy: https://example.com/proxy #mediaProxy: https://example.com/proxy
# Proxy remote files (default: true) # Proxy remote files (default: false)
# Proxy remote files by this instance or mediaProxy to prevent remote files from running in remote domains. # Proxy remote files by this instance or mediaProxy to prevent remote files from running in remote domains.
proxyRemoteFiles: true #proxyRemoteFiles: true
# Movie Thumbnail Generation URL # Movie Thumbnail Generation URL
# There is no reference implementation. # There is no reference implementation.
@ -309,15 +148,9 @@ proxyRemoteFiles: true
# Sign to ActivityPub GET request (default: true) # Sign to ActivityPub GET request (default: true)
signToActivityPubGet: true signToActivityPubGet: true
# For security reasons, uploading attachments from the intranet is prohibited,
# but exceptions can be made from the following settings. Default value is "undefined".
# Read changelog to learn more (Improvements of 12.90.0 (2021/09/04)).
#allowedPrivateNetworks: [ #allowedPrivateNetworks: [
# '127.0.0.1/32' # '127.0.0.1/32'
#] #]
# Upload or download file size limits (bytes) # Upload or download file size limits (bytes)
#maxFileSize: 262144000 #maxFileSize: 262144000
# PID File of master process
#pidFile: /tmp/misskey.pid

View file

@ -1,22 +1,20 @@
{ {
"name": "Misskey", "name": "Misskey",
"dockerComposeFile": "compose.yml", "dockerComposeFile": "docker-compose.yml",
"service": "app", "service": "app",
"workspaceFolder": "/workspace", "workspaceFolder": "/workspace",
"features": { "features": {
"ghcr.io/devcontainers/features/node:1": { "ghcr.io/devcontainers-contrib/features/pnpm:2": {}
"version": "20.16.0"
},
"ghcr.io/devcontainers-contrib/features/corepack:1": {}
}, },
"forwardPorts": [3000], "forwardPorts": [3000],
"postCreateCommand": "/bin/bash .devcontainer/init.sh", "postCreateCommand": "sudo chmod 755 .devcontainer/init.sh && .devcontainer/init.sh",
"customizations": { "customizations": {
"vscode": { "vscode": {
"extensions": [ "extensions": [
"editorconfig.editorconfig", "editorconfig.editorconfig",
"dbaeumer.vscode-eslint", "dbaeumer.vscode-eslint",
"Vue.volar", "Vue.volar",
"Vue.vscode-typescript-vue-plugin",
"Orta.vscode-jest", "Orta.vscode-jest",
"dbaeumer.vscode-eslint", "dbaeumer.vscode-eslint",
"mrmlnc.vscode-json5" "mrmlnc.vscode-json5"

View file

@ -51,23 +51,6 @@ db:
#extra: #extra:
# ssl: true # ssl: true
dbReplications: false
# You can configure any number of replicas here
#dbSlaves:
# -
# host:
# port:
# db:
# user:
# pass:
# -
# host:
# port:
# db:
# user:
# pass:
# ┌─────────────────────┐ # ┌─────────────────────┐
#───┘ Redis configuration └───────────────────────────────────── #───┘ Redis configuration └─────────────────────────────────────
@ -79,47 +62,15 @@ redis:
#prefix: example-prefix #prefix: example-prefix
#db: 1 #db: 1
#redisForPubsub: # ┌─────────────────────────────┐
# host: redis #───┘ Elasticsearch configuration └─────────────────────────────
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #db: 1
#redisForJobQueue: #elasticsearch:
# host: redis # host: localhost
# port: 6379 # port: 9200
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6 # ssl: false
# #pass: example-pass # user:
# #prefix: example-prefix # pass:
# #db: 1
#redisForTimelines:
# host: redis
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #db: 1
#redisForReactions:
# host: redis
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #db: 1
# ┌───────────────────────────┐
#───┘ MeiliSearch configuration └─────────────────────────────
#meilisearch:
# host: meilisearch
# port: 7700
# apiKey: ''
# ssl: true
# index: ''
# ┌───────────────┐ # ┌───────────────┐
#───┘ ID generation └─────────────────────────────────────────── #───┘ ID generation └───────────────────────────────────────────
@ -130,7 +81,6 @@ redis:
# Available methods: # Available methods:
# aid ... Short, Millisecond accuracy # aid ... Short, Millisecond accuracy
# aidx ... Millisecond accuracy
# meid ... Similar to ObjectID, Millisecond accuracy # meid ... Similar to ObjectID, Millisecond accuracy
# ulid ... Millisecond accuracy # ulid ... Millisecond accuracy
# objectid ... This is left for backward compatibility # objectid ... This is left for backward compatibility
@ -138,22 +88,7 @@ redis:
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE # ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
# ID SETTINGS AFTER THAT! # ID SETTINGS AFTER THAT!
id: 'aidx' id: 'aid'
# ┌────────────────┐
#───┘ Error tracking └──────────────────────────────────────────
# Sentry is available for error tracking.
# See the Sentry documentation for more details on options.
#sentryForBackend:
# enableNodeProfiling: true
# options:
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
#sentryForFrontend:
# options:
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
# ┌─────────────────────┐ # ┌─────────────────────┐
#───┘ Other configuration └───────────────────────────────────── #───┘ Other configuration └─────────────────────────────────────
@ -170,7 +105,7 @@ id: 'aidx'
# Job rate limiter # Job rate limiter
# deliverJobPerSec: 128 # deliverJobPerSec: 128
# inboxJobPerSec: 32 # inboxJobPerSec: 16
# Job attempts # Job attempts
# deliverJobMaxAttempts: 12 # deliverJobMaxAttempts: 12
@ -197,8 +132,8 @@ proxyBypassHosts:
# Media Proxy # Media Proxy
#mediaProxy: https://example.com/proxy #mediaProxy: https://example.com/proxy
# Proxy remote files (default: true) # Proxy remote files (default: false)
proxyRemoteFiles: true #proxyRemoteFiles: true
# Sign to ActivityPub GET request (default: true) # Sign to ActivityPub GET request (default: true)
signToActivityPubGet: true signToActivityPubGet: true

View file

@ -1,12 +1,13 @@
version: '3.8'
services: services:
app: app:
build: build:
context: . context: .
dockerfile: Dockerfile dockerfile: Dockerfile
volumes: volumes:
- ../:/workspace:cached - ../:/workspace:cached
- node_modules:/workspace/node_modules
command: sleep infinity command: sleep infinity
@ -45,7 +46,6 @@ services:
volumes: volumes:
postgres-data: postgres-data:
redis-data: redis-data:
node_modules:
networks: networks:
internal_network: internal_network:

View file

@ -2,16 +2,10 @@
set -xe set -xe
sudo chown node node_modules sudo chown -R node /workspace
sudo apt-get update
sudo apt-get -y install libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libnss3 libxss1 libasound2 libxtst6 xauth xvfb
git config --global --add safe.directory /workspace
git submodule update --init git submodule update --init
corepack install
corepack enable
pnpm config set store-dir /home/node/.local/share/pnpm/store pnpm config set store-dir /home/node/.local/share/pnpm/store
pnpm install --frozen-lockfile pnpm install --frozen-lockfile
cp .devcontainer/devcontainer.yml .config/default.yml cp .devcontainer/devcontainer.yml .config/default.yml
pnpm build pnpm build
pnpm migrate pnpm migrate
pnpm exec cypress install

View file

@ -7,11 +7,13 @@ Dockerfile
build/ build/
built/ built/
db/ db/
.devcontainer/compose.yml docker-compose.yml
elasticsearch/
node_modules/ node_modules/
packages/*/node_modules packages/*/node_modules
redis/ redis/
files/ files/
misskey-assets/
fluent-emojis/ fluent-emojis/
.pnp.* .pnp.*
@ -27,4 +29,4 @@ fluent-emojis/
.idea/ .idea/
packages/*/.vscode/ packages/*/.vscode/
packages/backend/test/compose.yml packages/backend/test/docker-compose.yml

View file

@ -6,10 +6,6 @@ indent_size = 2
charset = utf-8 charset = utf-8
insert_final_newline = true insert_final_newline = true
end_of_line = lf end_of_line = lf
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml}] [*.{yml,yaml}]
indent_style = space indent_style = space

3
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1,3 @@
# These are supported funding model platforms
patreon: syuilo

43
.github/ISSUE_TEMPLATE/01_bug-report.md vendored Normal file
View file

@ -0,0 +1,43 @@
---
name: 🐛 Bug Report
about: Create a report to help us improve
title: ''
labels: ⚠bug?
assignees: ''
---
<!--
Thanks for reporting!
First, in order to avoid duplicate Issues, please search to see if the problem you found has already been reported.
Also, If you are NOT owner/admin of server, PLEASE DONT REPORT SERVER SPECIFIC ISSUES TO HERE! (e.g. feature XXX is not working in misskey.example) Please try with another misskey servers, and if your issue is only reproducible with specific server, contact your server's owner/admin first.
-->
## 💡 Summary
<!-- Tell us what the bug is -->
## 🥰 Expected Behavior
<!--- Tell us what should happen -->
## 🤬 Actual Behavior
<!--
Tell us what happens instead of the expected behavior.
Please include errors from the developer console and/or server log files if you have access to them.
-->
## 📝 Steps to Reproduce
1.
2.
3.
## 📌 Environment
<!-- Tell us where on the platform it happens -->
Misskey version:
Your OS:
Your browser:

View file

@ -1,97 +0,0 @@
name: 🐛 Bug Report
description: Create a report to help us improve
labels: ["⚠bug?"]
body:
- type: markdown
attributes:
value: |
Thanks for reporting!
First, in order to avoid duplicate Issues, please search to see if the problem you found has already been reported.
Also, If you are NOT owner/admin of server, PLEASE DONT REPORT SERVER SPECIFIC ISSUES TO HERE! (e.g. feature XXX is not working in misskey.example) Please try with another misskey servers, and if your issue is only reproducible with specific server, contact your server's owner/admin first.
- type: textarea
attributes:
label: 💡 Summary
description: Tell us what the bug is
validations:
required: true
- type: textarea
attributes:
label: 🥰 Expected Behavior
description: Tell us what should happen
validations:
required: true
- type: textarea
attributes:
label: 🤬 Actual Behavior
description: |
Tell us what happens instead of the expected behavior.
Please include errors from the developer console and/or server log files if you have access to them.
validations:
required: true
- type: textarea
attributes:
label: 📝 Steps to Reproduce
placeholder: |
1.
2.
3.
validations:
required: false
- type: textarea
attributes:
label: 💻 Frontend Environment
description: |
Tell us where on the platform it happens
DO NOT WRITE "latest". Please provide the specific version.
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.example.com
* Misskey: 2024.x.x
value: |
* Model and OS of the device(s):
* Browser:
* Server URL:
* Misskey:
render: markdown
validations:
required: false
- type: textarea
attributes:
label: 🛰 Backend Environment (for server admin)
description: |
Tell us where on the platform it happens
DO NOT WRITE "latest". Please provide the specific version.
If you are using a managed service, put that after the version.
Examples:
* Installation Method or Hosting Service: docker compose, k8s/docker, systemd, "Misskey install shell script", development environment
* Misskey: 2024.x.x
* Node: 20.x.x
* PostgreSQL: 15.x.x
* Redis: 7.x.x
* OS and Architecture: Ubuntu 24.04.2 LTS aarch64
value: |
* Installation Method or Hosting Service:
* Misskey:
* Node:
* PostgreSQL:
* Redis:
* OS and Architecture:
render: markdown
validations:
required: false
- type: checkboxes
attributes:
label: Do you want to address this bug yourself?
options:
- label: Yes, I will patch the bug myself and send a pull request

View file

@ -0,0 +1,12 @@
---
name: ✨ Feature Request
about: Suggest an idea for this project
title: ''
labels: ✨Feature
assignees: ''
---
## Summary
<!-- Tell us what the suggestion is -->

View file

@ -1,22 +0,0 @@
name: ✨ Feature Request
description: Suggest an idea for this project
labels: ["✨Feature"]
body:
- type: textarea
attributes:
label: Summary
description: Tell us what the suggestion is
validations:
required: true
- type: textarea
attributes:
label: Purpose
description: Describe the specific problem or need you think this feature will solve, and who it will help.
validations:
required: true
- type: checkboxes
attributes:
label: Do you want to implement this feature yourself?
options:
- label: Yes, I will implement this by myself and send a pull request

View file

@ -1,8 +1,7 @@
contact_links: contact_links:
- name: 👪 Misskey Forum
url: https://forum.misskey.io/
about: Ask questions and share knowledge
- name: 💬 Misskey official Discord - name: 💬 Misskey official Discord
url: https://discord.gg/Wp8gVStHW3 url: https://discord.gg/Wp8gVStHW3
about: Chat freely about Misskey 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

View file

@ -9,40 +9,24 @@ updates:
directory: "/" directory: "/"
schedule: schedule:
interval: daily interval: daily
open-pull-requests-limit: 100 open-pull-requests-limit: 0
# Add only the root, not each workspace item
# https://github.com/dependabot/dependabot-core/issues/4993#issuecomment-1289133027
- package-ecosystem: npm - package-ecosystem: npm
directory: "/" directory: "/"
schedule: schedule:
interval: daily interval: daily
open-pull-requests-limit: 10 open-pull-requests-limit: 0
# List dependencies required to be updated together, sharing the same version numbers. - package-ecosystem: npm
# Those who simply have the common owner (e.g. @fastify) don't need to be listed. directory: "/packages/backend"
groups: schedule:
aws-sdk: interval: daily
patterns: open-pull-requests-limit: 0
- "@aws-sdk/*" - package-ecosystem: npm
bull-board: directory: "/packages/frontend"
patterns: schedule:
- "@bull-board/*" interval: daily
nestjs: open-pull-requests-limit: 0
patterns: - package-ecosystem: npm
- "@nestjs/*" directory: "/packages/sw"
slacc: schedule:
patterns: interval: daily
- "slacc-*" open-pull-requests-limit: 0
storybook:
patterns:
- "storybook*"
- "@storybook/*"
swc-core:
patterns:
- "@swc/core*"
typescript-eslint:
patterns:
- "@typescript-eslint/*"
tensorflow:
patterns:
- "@tensorflow/*"

40
.github/labeler.yml vendored
View file

@ -1,34 +1,12 @@
'packages/backend': '⚙Server':
- any: - packages/backend/**/*
- changed-files:
- any-glob-to-any-file: ['packages/backend/**/*']
'packages/backend:test': '🖥Client':
- any: - packages/frontend/**/*
- changed-files:
- any-glob-to-any-file: ['packages/backend/test/**/*', 'packages/backend/test-federation/**/*']
'packages/frontend': '🧪Test':
- any: - cypress/**/*
- changed-files: - packages/backend/test/**/*
- any-glob-to-any-file: ['packages/frontend/**/*']
'packages/frontend:test': '‼️ wrong locales':
- any: - any: ['locales/*.yml', '!locales/ja-JP.yml']
- changed-files:
- any-glob-to-any-file: ['cypress/**/*']
'packages/sw':
- any:
- changed-files:
- any-glob-to-any-file: ['packages/sw/**/*']
'packages/misskey-js':
- any:
- changed-files:
- any-glob-to-any-file: ['packages/misskey-js/**/*']
'packages/misskey-js:test':
- any:
- changed-files:
- any-glob-to-any-file: ['packages/misskey-js/test/**/*', 'packages/misskey-js/test-d/**/*']

View file

@ -1,7 +1,5 @@
url: 'http://misskey.local' url: 'http://misskey.local'
setupPassword: example_password_please_change_this_or_you_will_get_hacked
# ローカルでテストするときにポートを被らないようにするためデフォルトのものとは変える(以下同じ) # ローカルでテストするときにポートを被らないようにするためデフォルトのものとは変える(以下同じ)
port: 61812 port: 61812
@ -14,4 +12,4 @@ db:
redis: redis:
host: 127.0.0.1 host: 127.0.0.1
port: 56312 port: 56312
id: aidx id: aid

View file

@ -19,6 +19,5 @@ https://github.com/misskey-dev/misskey/blob/develop/CONTRIBUTING.md
## Checklist ## Checklist
- [ ] Read the [contribution guide](https://github.com/misskey-dev/misskey/blob/develop/CONTRIBUTING.md) - [ ] Read the [contribution guide](https://github.com/misskey-dev/misskey/blob/develop/CONTRIBUTING.md)
- [ ] Test working in a local environment - [ ] Test working in a local environment
- [ ] (If needed) Add story of storybook
- [ ] (If needed) Update CHANGELOG.md - [ ] (If needed) Update CHANGELOG.md
- [ ] (If possible) Add tests - [ ] (If possible) Add tests

10
.github/reviewer-lottery.yml vendored Normal file
View file

@ -0,0 +1,10 @@
groups:
- name: devs
reviewers: 2
internal_reviewers: 1
usernames:
- syuilo
- acid-chicken
- EbiseLutica
- rinsuki
- tamaina

View file

@ -1,14 +1,7 @@
name: API report (misskey.js) name: API report
on: [push, pull_request]
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: jobs:
report: report:
@ -16,14 +9,14 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4.1.1 uses: actions/checkout@v3.3.0
- run: corepack enable - run: corepack enable
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v4.0.4 uses: actions/setup-node@v3.6.0
with: with:
node-version-file: '.node-version' node-version: 18.x
cache: 'pnpm' cache: 'pnpm'
- name: Install dependencies - name: Install dependencies

View file

@ -1,43 +0,0 @@
name: Check the description in CHANGELOG.md
on:
pull_request:
branches:
- master
- develop
jobs:
check-changelog:
runs-on: ubuntu-latest
steps:
- name: Checkout head
uses: actions/checkout@v4.1.1
- name: Setup Node.js
uses: actions/setup-node@v4.0.4
with:
node-version-file: '.node-version'
- name: Checkout base
run: |
mkdir _base
cp -r .git _base/.git
cd _base
git fetch --depth 1 origin ${{ github.base_ref }}
git checkout origin/${{ github.base_ref }} CHANGELOG.md
- name: Copy to Checker directory for CHANGELOG-base.md
run: cp _base/CHANGELOG.md scripts/changelog-checker/CHANGELOG-base.md
- name: Copy to Checker directory for CHANGELOG-head.md
run: cp CHANGELOG.md scripts/changelog-checker/CHANGELOG-head.md
- name: diff
continue-on-error: true
run: diff -u CHANGELOG-base.md CHANGELOG-head.md
working-directory: scripts/changelog-checker
- name: Setup Checker
run: npm install
working-directory: scripts/changelog-checker
- name: Run Checker
run: npm run run
working-directory: scripts/changelog-checker

View file

@ -1,139 +0,0 @@
name: Check Misskey JS autogen
on:
pull_request_target:
branches:
- master
- develop
- improve-misskey-js-autogen-check
paths:
- packages/backend/**
jobs:
# pull_request_target safety: permissions: read-all, and there are no secrets used in this job
generate-misskey-js:
runs-on: ubuntu-latest
permissions:
contents: read
if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }}
steps:
- name: checkout
uses: actions/checkout@v4.1.1
with:
submodules: true
persist-credentials: false
ref: refs/pull/${{ github.event.pull_request.number }}/merge
- name: setup pnpm
uses: pnpm/action-setup@v4
- name: setup node
id: setup-node
uses: actions/setup-node@v4.0.4
with:
node-version-file: '.node-version'
cache: pnpm
- name: install dependencies
run: pnpm i --frozen-lockfile
# generate api.json
- name: Copy Config
run: cp .config/example.yml .config/default.yml
- name: Build
run: pnpm build
- name: Generate API JSON
run: pnpm --filter backend generate-api-json
# build misskey js
- name: Build misskey-js
run: |-
cp packages/backend/built/api.json packages/misskey-js/generator/api.json
pnpm run --filter misskey-js-type-generator generate
# packages/misskey-js/generator/built/autogen
- name: Upload Generated
uses: actions/upload-artifact@v4
with:
name: generated-misskey-js
path: packages/misskey-js/generator/built/autogen
# pull_request_target safety: permissions: read-all, and no user codes are executed
get-actual-misskey-js:
runs-on: ubuntu-latest
permissions:
contents: read
if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }}
steps:
- name: checkout
uses: actions/checkout@v4.1.1
with:
submodules: true
persist-credentials: false
ref: refs/pull/${{ github.event.pull_request.number }}/merge
- name: Upload From Merged
uses: actions/upload-artifact@v4
with:
name: actual-misskey-js
path: packages/misskey-js/src/autogen
# pull_request_target safety: nothing is cloned from repository
comment-misskey-js-autogen:
runs-on: ubuntu-latest
needs: [generate-misskey-js, get-actual-misskey-js]
permissions:
pull-requests: write
steps:
- name: download generated-misskey-js
uses: actions/download-artifact@v4
with:
name: generated-misskey-js
path: misskey-js-generated
- name: download actual-misskey-js
uses: actions/download-artifact@v4
with:
name: actual-misskey-js
path: misskey-js-actual
- name: check misskey-js changes
id: check-changes
run: |
diff -r -u --label=generated --label=on-tree ./misskey-js-generated ./misskey-js-actual > misskey-js.diff || true
if [ -s misskey-js.diff ]; then
echo "changes=true" >> $GITHUB_OUTPUT
else
echo "changes=false" >> $GITHUB_OUTPUT
fi
- name: Print full diff
run: cat ./misskey-js.diff
- name: send message
if: steps.check-changes.outputs.changes == 'true'
uses: thollander/actions-comment-pull-request@v2
with:
comment_tag: check-misskey-js-autogen
message: |-
Thank you for sending us a great Pull Request! 👍
Please regenerate misskey-js type definitions! 🙏
example:
```sh
pnpm run build-misskey-js-with-types
```
- name: send message
if: steps.check-changes.outputs.changes == 'false'
uses: thollander/actions-comment-pull-request@v2
with:
comment_tag: check-misskey-js-autogen
mode: delete
message: "Thank you!"
create_if_not_exists: false
- name: Make failure if changes are detected
if: steps.check-changes.outputs.changes == 'true'
run: exit 1

View file

@ -1,29 +0,0 @@
name: Check Misskey JS version
on:
push:
branches: [ develop ]
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 のバージョンが一致しているかを確認する
name: Check version
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4.1.1
- name: Check version
run: |
if [ "$(jq -r '.version' package.json)" != "$(jq -r '.version' packages/misskey-js/package.json)" ]; then
echo "Version mismatch!"
exit 1
fi

View file

@ -1,79 +0,0 @@
name: Check SPDX-License-Identifier
on:
push:
branches:
- master
- develop
pull_request:
jobs:
check-spdx-license-id:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4.1.1
- name: Check
run: |
counter=0
search() {
local directory="$1"
find "$directory" -type f \
'(' \
-name "*.cjs" -and -not -name '*.config.cjs' -o \
-name "*.html" -o \
-name "*.js" -and -not -name '*.config.js' -o \
-name "*.mjs" -and -not -name '*.config.mjs' -o \
-name "*.scss" -o \
-name "*.ts" -and -not -name '*.config.ts' -o \
-name "*.vue" \
')' -and \
-not -name '*eslint*'
}
check() {
local file="$1"
if ! (
grep -q "SPDX-FileCopyrightText: syuilo and misskey-project" "$file" ||
grep -q "SPDX-License-Identifier: AGPL-3.0-only" "$file"
); then
echo "Missing: $file"
((counter++))
fi
}
directories=(
"cypress/e2e"
"packages/backend/migration"
"packages/backend/src"
"packages/backend/test"
"packages/frontend-shared/@types"
"packages/frontend-shared/js"
"packages/frontend/.storybook"
"packages/frontend/@types"
"packages/frontend/lib"
"packages/frontend/public"
"packages/frontend/src"
"packages/frontend/test"
"packages/frontend-embed/@types"
"packages/frontend-embed/src"
"packages/misskey-bubble-game/src"
"packages/misskey-reversi/src"
"packages/sw/src"
"scripts"
)
for directory in "${directories[@]}"; do
for file in $(search $directory); do
check "$file"
done
done
if [ $counter -gt 0 ]; then
echo "SPDX-License-Identifier is missing in $counter files."
exit 1
else
echo "SPDX-License-Identifier is certainly described in all target files!"
exit 0
fi

View file

@ -10,7 +10,7 @@ jobs:
check_copyright_year: check_copyright_year:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4.1.1 - uses: actions/checkout@v3.2.0
- run: | - run: |
if [ "$(grep Copyright COPYING | sed -e 's/.*2014-\([0-9]*\) .*/\1/g')" -ne "$(date +%Y)" ]; then if [ "$(grep Copyright COPYING | sed -e 's/.*2014-\([0-9]*\) .*/\1/g')" -ne "$(date +%Y)" ]; then
echo "Please change copyright year!" echo "Please change copyright year!"

View file

@ -1,84 +0,0 @@
name: deploy-test-environment
on:
issue_comment:
types: [created]
workflow_dispatch:
inputs:
repository:
description: 'Repository to deploy (optional, use the repository where this workflow is stored by default)'
required: false
default: ''
branch_or_hash:
description: 'Branch or Commit hash to deploy (optional, use the branch where this workflow is stored by default)'
required: false
default: ''
wait_time:
description: 'Time to wait in seconds (optional, 1800 seconds by default)'
required: false
default: ''
jobs:
get-pr-ref:
runs-on: ubuntu-latest
if: github.event_name == 'issue_comment' && github.event.issue.pull_request && startsWith(github.event.comment.body, '/preview')
outputs:
is-allowed-user: ${{ steps.check-allowed-users.outputs.is-allowed-user }}
pr-ref: ${{ steps.get-ref.outputs.pr-ref }}
wait_time: ${{ steps.get-wait-time.outputs.wait_time }}
steps:
- name: Checkout
uses: actions/checkout@v4.1.1
- name: Check allowed users
id: check-allowed-users
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ORG_ID: ${{ github.repository_owner_id }}
COMMENT_AUTHOR: ${{ github.event.comment.user.login }}
run: |
MEMBERSHIP_STATUS=$(curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/organizations/$ORG_ID/public_members/$COMMENT_AUTHOR" \
-o /dev/null -w '%{http_code}\n' -s)
if [ "$MEMBERSHIP_STATUS" -eq 204 ]; then
echo "is-allowed-user=true" > $GITHUB_OUTPUT
else
echo "is-allowed-user=false" > $GITHUB_OUTPUT
fi
- name: Get PR ref
id: get-ref
run: |
PR_REF="refs/pull/${{ github.event.issue.number }}/head"
echo "pr-ref=$PR_REF" >> $GITHUB_OUTPUT
- name: Extract wait time
id: get-wait-time
env:
COMMENT_BODY: ${{ github.event.comment.body }}
run: |
WAIT_TIME=$(echo "$COMMENT_BODY" | grep -oP '(?<=/preview\s)\d+' || echo "1800")
echo "wait_time=$WAIT_TIME" > $GITHUB_OUTPUT
deploy-test-environment-pr-comment:
needs: get-pr-ref
if: needs.get-pr-ref.outputs.is-allowed-user == 'true'
uses: joinmisskey/misskey-tga/.github/workflows/deploy-test-environment.yml@main
with:
repository: ${{ github.repository }}
branch_or_hash: ${{ needs.get-pr-ref.outputs.pr-ref }}
wait_time: ${{ needs.get-pr-ref.outputs.wait_time }}
secrets:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
deploy-test-environment-wd:
if: github.event_name == 'workflow_dispatch'
uses: joinmisskey/misskey-tga/.github/workflows/deploy-test-environment.yml@main
with:
repository: ${{ inputs.repository || github.repository }}
branch_or_hash: ${{ inputs.branch_or_hash || github.ref_name }}
wait_time: ${{ inputs.wait_time || '1800' }}
secrets:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}

View file

@ -6,83 +6,38 @@ on:
- develop - develop
workflow_dispatch: workflow_dispatch:
env:
REGISTRY_IMAGE: misskey/misskey
jobs: jobs:
# see https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners push_to_registry:
build: name: Push Docker image to Docker Hub
name: Build
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
platform:
- linux/amd64
- linux/arm64
if: github.repository == 'misskey-dev/misskey' if: github.repository == 'misskey-dev/misskey'
steps: steps:
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Check out the repo - name: Check out the repo
uses: actions/checkout@v4.1.1 uses: actions/checkout@v3.3.0
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 id: buildx
uses: docker/setup-buildx-action@v2.3.0
with:
platforms: linux/amd64,linux/arm64
- name: Docker meta
id: meta
uses: docker/metadata-action@v4
with:
images: misskey/misskey
- name: Log in to Docker Hub - name: Log in to Docker Hub
uses: docker/login-action@v3 uses: docker/login-action@v2
with: with:
username: ${{ secrets.DOCKER_USERNAME }} username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }} password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push by digest - name: Build and Push to Docker Hub
id: build uses: docker/build-push-action@v4
uses: docker/build-push-action@v6
with: with:
builder: ${{ steps.buildx.outputs.name }}
context: . context: .
push: true push: true
platforms: ${{ matrix.platform }} platforms: ${{ steps.buildx.outputs.platforms }}
provenance: false provenance: false
tags: misskey/misskey:develop
labels: develop labels: develop
cache-from: type=gha cache-from: type=gha
cache-to: type=gha,mode=max cache-to: type=gha,mode=max
outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
merge:
runs-on: ubuntu-latest
needs:
- build
steps:
- name: Download digests
uses: actions/download-artifact@v4
with:
path: /tmp/digests
pattern: digests-*
merge-multiple: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Create manifest list and push
working-directory: /tmp/digests
run: |
docker buildx imagetools create --tag ${{ env.REGISTRY_IMAGE }}:develop \
$(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *)
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:develop

View file

@ -5,101 +5,45 @@ on:
types: [published] types: [published]
workflow_dispatch: workflow_dispatch:
env:
REGISTRY_IMAGE: misskey/misskey
TAGS: |
type=edge
type=ref,event=pr
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
jobs: jobs:
# see https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners push_to_registry:
build: name: Push Docker image to Docker Hub
name: Build
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
platform:
- linux/amd64
- linux/arm64
steps: steps:
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Check out the repo - name: Check out the repo
uses: actions/checkout@v4.1.1 uses: actions/checkout@v3.3.0
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 id: buildx
uses: docker/setup-buildx-action@v2.3.0
with:
platforms: linux/amd64,linux/arm64
- name: Docker meta - name: Docker meta
id: meta id: meta
uses: docker/metadata-action@v5 uses: docker/metadata-action@v4
with: with:
images: ${{ env.REGISTRY_IMAGE }} images: misskey/misskey
tags: ${{ env.TAGS }} tags: |
type=edge
type=ref,event=pr
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
- name: Log in to Docker Hub - name: Log in to Docker Hub
uses: docker/login-action@v3 uses: docker/login-action@v2
with: with:
username: ${{ secrets.DOCKER_USERNAME }} username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }} password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push to Docker Hub - name: Build and Push to Docker Hub
id: build uses: docker/build-push-action@v4
uses: docker/build-push-action@v6
with: with:
builder: ${{ steps.buildx.outputs.name }}
context: . context: .
push: true push: true
platforms: ${{ matrix.platform }} platforms: ${{ steps.buildx.outputs.platforms }}
provenance: false provenance: false
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha cache-from: type=gha
cache-to: type=gha,mode=max cache-to: type=gha,mode=max
outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
merge:
runs-on: ubuntu-latest
needs:
- build
steps:
- name: Download digests
uses: actions/download-artifact@v4
with:
path: /tmp/digests
pattern: digests-*
merge-multiple: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY_IMAGE }}
tags: ${{ env.TAGS }}
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Create manifest list and push
working-directory: /tmp/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *)
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta.outputs.version }}

View file

@ -13,16 +13,14 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
DOCKER_CONTENT_TRUST: 1 DOCKER_CONTENT_TRUST: 1
DOCKLE_VERSION: 0.4.14
steps: steps:
- uses: actions/checkout@v4.1.1 - uses: actions/checkout@v3.2.0
- name: Download and install dockle v${{ env.DOCKLE_VERSION }} - run: |
run: | curl -L -o dockle.deb "https://github.com/goodwithtech/dockle/releases/download/v0.4.10/dockle_0.4.10_Linux-64bit.deb"
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 sudo dpkg -i dockle.deb
- run: | - run: |
cp .config/docker_example.env .config/docker.env cp .config/docker_example.env .config/docker.env
cp ./compose_example.yml ./compose.yml cp ./docker-compose.yml.example ./docker-compose.yml
- run: | - run: |
docker compose up -d web docker compose up -d web
docker tag "$(docker compose images web | awk 'OFS=":" {print $4}' | tail -n +2)" misskey-web:latest docker tag "$(docker compose images web | awk 'OFS=":" {print $4}' | tail -n +2)" misskey-web:latest

View file

@ -1,69 +0,0 @@
# this name is used in report-api-diff.yml so be careful when change name
name: Get api.json from Misskey
on:
pull_request:
branches:
- master
- develop
paths:
- packages/backend/**
- .github/workflows/get-api-diff.yml
jobs:
get-from-misskey:
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
matrix:
node-version: [20.16.0]
api-json-name: [api-base.json, api-head.json]
include:
- api-json-name: api-base.json
ref: ${{ github.base_ref }}
- api-json-name: api-head.json
ref: refs/pull/${{ github.event.number }}/merge
steps:
- uses: actions/checkout@v4.1.1
with:
ref: ${{ matrix.ref }}
submodules: true
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.0.4
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- run: corepack enable
- run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml
run: git diff --exit-code pnpm-lock.yaml
- name: Copy Configure
run: cp .config/example.yml .config/default.yml
- name: Build
run: pnpm build
- name: Generate API JSON
run: pnpm --filter backend generate-api-json
- name: Copy API.json
run: cp packages/backend/built/api.json ${{ matrix.api-json-name }}
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: api-artifact-${{ matrix.api-json-name }}
path: ${{ matrix.api-json-name }}
save-pr-number:
runs-on: ubuntu-latest
steps:
- name: Save PR number
env:
PR_NUMBER: ${{ github.event.number }}
run: |
echo "$PR_NUMBER" > ./pr_number
- uses: actions/upload-artifact@v4
with:
name: api-artifact-pr-number
path: pr_number

View file

@ -11,6 +11,6 @@ jobs:
pull-requests: write pull-requests: write
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/labeler@v5 - uses: actions/labeler@v4
with: with:
repo-token: "${{ secrets.GITHUB_TOKEN }}" repo-token: "${{ secrets.GITHUB_TOKEN }}"

View file

@ -5,41 +5,23 @@ on:
branches: branches:
- master - master
- develop - develop
paths:
- packages/backend/**
- packages/frontend/**
- packages/frontend-shared/**
- packages/frontend-embed/**
- packages/sw/**
- packages/misskey-js/**
- packages/misskey-bubble-game/**
- packages/misskey-reversi/**
- packages/shared/eslint.config.js
- .github/workflows/lint.yml
pull_request: pull_request:
paths:
- packages/backend/**
- packages/frontend/**
- packages/frontend-shared/**
- packages/frontend-embed/**
- packages/sw/**
- packages/misskey-js/**
- packages/misskey-bubble-game/**
- packages/misskey-reversi/**
- packages/shared/eslint.config.js
- .github/workflows/lint.yml
jobs: jobs:
pnpm_install: pnpm_install:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4.1.1 - uses: actions/checkout@v3.3.0
with: with:
fetch-depth: 0 fetch-depth: 0
submodules: true submodules: true
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v2
- uses: actions/setup-node@v4.0.4
with: with:
node-version-file: '.node-version' version: 7
run_install: false
- uses: actions/setup-node@v3.6.0
with:
node-version: 18.x
cache: 'pnpm' cache: 'pnpm'
- run: corepack enable - run: corepack enable
- run: pnpm i --frozen-lockfile - run: pnpm i --frozen-lockfile
@ -53,34 +35,24 @@ jobs:
workspace: workspace:
- backend - backend
- frontend - frontend
- frontend-shared
- frontend-embed
- sw - sw
- misskey-js - misskey-js
- misskey-bubble-game
- misskey-reversi
env:
eslint-cache-version: v1
eslint-cache-path: ${{ github.workspace }}/node_modules/.cache/eslint-${{ matrix.workspace }}
steps: steps:
- uses: actions/checkout@v4.1.1 - uses: actions/checkout@v3.3.0
with: with:
fetch-depth: 0 fetch-depth: 0
submodules: true submodules: true
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v2
- uses: actions/setup-node@v4.0.4
with: with:
node-version-file: '.node-version' version: 7
run_install: false
- uses: actions/setup-node@v3.6.0
with:
node-version: 18.x
cache: 'pnpm' cache: 'pnpm'
- run: corepack enable - run: corepack enable
- run: pnpm i --frozen-lockfile - run: pnpm i --frozen-lockfile
- name: Restore eslint cache - run: pnpm --filter ${{ matrix.workspace }} run eslint
uses: actions/cache@v4.1.0
with:
path: ${{ env.eslint-cache-path }}
key: eslint-${{ env.eslint-cache-version }}-${{ matrix.workspace }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ github.ref_name }}-${{ github.sha }}
restore-keys: eslint-${{ env.eslint-cache-version }}-${{ matrix.workspace }}-${{ hashFiles('**/pnpm-lock.yaml') }}-
- run: pnpm --filter ${{ matrix.workspace }} run eslint --cache --cache-location ${{ env.eslint-cache-path }} --cache-strategy content
typecheck: typecheck:
needs: [pnpm_install] needs: [pnpm_install]
@ -90,22 +62,20 @@ jobs:
matrix: matrix:
workspace: workspace:
- backend - backend
- sw
- misskey-js - misskey-js
steps: steps:
- uses: actions/checkout@v4.1.1 - uses: actions/checkout@v3.3.0
with: with:
fetch-depth: 0 fetch-depth: 0
submodules: true submodules: true
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v2
- uses: actions/setup-node@v4.0.4
with: with:
node-version-file: '.node-version' version: 7
run_install: false
- uses: actions/setup-node@v3.6.0
with:
node-version: 18.x
cache: 'pnpm' cache: 'pnpm'
- run: corepack enable - run: corepack enable
- run: pnpm i --frozen-lockfile - run: pnpm i --frozen-lockfile
- run: pnpm --filter misskey-js run build
if: ${{ matrix.workspace == 'backend' || matrix.workspace == 'sw' }}
- run: pnpm --filter misskey-reversi run build
if: ${{ matrix.workspace == 'backend' }}
- run: pnpm --filter ${{ matrix.workspace }} run typecheck - run: pnpm --filter ${{ matrix.workspace }} run typecheck

View file

@ -1,28 +0,0 @@
name: Lint
on:
push:
paths:
- locales/**
- .github/workflows/locale.yml
pull_request:
paths:
- locales/**
- .github/workflows/locale.yml
jobs:
locale_verify:
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4.1.1
with:
fetch-depth: 0
submodules: true
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4.0.4
with:
node-version-file: '.node-version'
cache: 'pnpm'
- run: corepack enable
- run: pnpm i --frozen-lockfile
- run: cd locales && node verify.js

View file

@ -17,13 +17,13 @@ jobs:
# See app.yml for an example app manifest # See app.yml for an example app manifest
- name: Generate token - name: Generate token
id: generate_token id: generate_token
uses: tibdex/github-app-token@v2 uses: tibdex/github-app-token@v1
with: with:
app_id: ${{ secrets.DEPLOYBOT_APP_ID }} app_id: ${{ secrets.DEPLOYBOT_APP_ID }}
private_key: ${{ secrets.DEPLOYBOT_PRIVATE_KEY }} private_key: ${{ secrets.DEPLOYBOT_PRIVATE_KEY }}
- name: Slash Command Dispatch - name: Slash Command Dispatch
uses: peter-evans/slash-command-dispatch@v4 uses: peter-evans/slash-command-dispatch@v1
env: env:
TOKEN: ${{ steps.generate_token.outputs.token }} TOKEN: ${{ steps.generate_token.outputs.token }}
with: with:

View file

@ -1,42 +0,0 @@
name: On Release Created (Publish misskey-js)
on:
release:
types: [created]
workflow_dispatch:
jobs:
publish-misskey-js:
name: Publish misskey-js
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
strategy:
matrix:
node-version: [20.16.0]
steps:
- uses: actions/checkout@v4.1.1
with:
submodules: true
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.0.4
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
registry-url: 'https://registry.npmjs.org'
- name: Publish package
run: |
corepack enable
pnpm i --frozen-lockfile
pnpm build
pnpm --filter misskey-js publish --access public --no-git-checks --provenance
env:
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
NPM_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}

View file

@ -13,7 +13,7 @@ jobs:
github.event.client_payload.slash_command.sha != '' && github.event.client_payload.slash_command.sha != '' &&
contains(github.event.client_payload.pull_request.head.sha, github.event.client_payload.slash_command.sha) contains(github.event.client_payload.pull_request.head.sha, github.event.client_payload.slash_command.sha)
steps: steps:
- uses: actions/github-script@v7.0.1 - uses: actions/github-script@v6.3.3
id: check-id id: check-id
env: env:
number: ${{ github.event.client_payload.pull_request.number }} number: ${{ github.event.client_payload.pull_request.number }}
@ -37,7 +37,7 @@ jobs:
return check[0].id; return check[0].id;
- uses: actions/github-script@v7.0.1 - uses: actions/github-script@v6.3.3
env: env:
check_id: ${{ steps.check-id.outputs.result }} check_id: ${{ steps.check-id.outputs.result }}
details_url: ${{ github.server_url }}/${{ github.repository }}/runs/${{ github.run_id }} details_url: ${{ github.server_url }}/${{ github.repository }}/runs/${{ github.run_id }}
@ -53,7 +53,7 @@ jobs:
# Check out merge commit # Check out merge commit
- name: Fork based /deploy checkout - name: Fork based /deploy checkout
uses: actions/checkout@v4.1.1 uses: actions/checkout@v3.3.0
with: with:
ref: 'refs/pull/${{ github.event.client_payload.pull_request.number }}/merge' ref: 'refs/pull/${{ github.event.client_payload.pull_request.number }}/merge'
@ -72,7 +72,7 @@ jobs:
timeout: 15m timeout: 15m
# Update check run called "integration-fork" # Update check run called "integration-fork"
- uses: actions/github-script@v7.0.1 - uses: actions/github-script@v6.3.3
id: update-check-run id: update-check-run
if: ${{ always() }} if: ${{ always() }}
env: env:

View file

@ -10,7 +10,7 @@ jobs:
destroy-preview-environment: destroy-preview-environment:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/github-script@v7.0.1 - uses: actions/github-script@v6.3.3
id: check-conclusion id: check-conclusion
env: env:
number: ${{ github.event.number }} number: ${{ github.event.number }}

View file

@ -1,48 +0,0 @@
name: "Release Manager: sync changelog with PR"
on:
push:
branches:
- develop
paths:
- 'CHANGELOG.md'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
permissions:
contents: write
issues: write
pull-requests: write
jobs:
edit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# headが$GITHUB_REF_NAME, baseが$STABLE_BRANCHかつopenのPRを1つ取得
- name: Get PR
run: |
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
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
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:
PR_NUMBER: ${{ steps.get_pr.outputs.pr_number }}
CHANGELOG: ${{ steps.changelog.outputs.changelog }}

View file

@ -1,135 +0,0 @@
name: "Release Manager [Dispatch]"
on:
workflow_dispatch:
inputs:
## Specify the type of the next release.
#version_increment_type:
# type: choice
# description: 'VERSION INCREMENT TYPE'
# default: 'patch'
# required: false
# options:
# - 'major'
# - 'minor'
# - 'patch'
merge:
type: boolean
description: 'MERGE RELEASE BRANCH TO MAIN'
default: false
start-rc:
type: boolean
description: 'Start Release Candidate'
default: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
permissions:
contents: write
issues: write
pull-requests: write
jobs:
get-pr:
runs-on: ubuntu-latest
outputs:
pr_number: ${{ steps.get_pr.outputs.pr_number }}
steps:
- uses: actions/checkout@v4
# headが$GITHUB_REF_NAME, baseが$STABLE_BRANCHかつopenのPRを1つ取得
- name: Get PRs
run: |
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@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`
changes_template: |
## Unreleased
### General
-
### Client
-
### Server
-
use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }}
indent: ${{ vars.INDENT }}
secrets:
RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }}
RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
create-prerelease:
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 }}
draft_prerelease_channel: alpha
ready_start_prerelease_channel: beta
prerelease_channel: ${{ inputs.start-rc && 'rc' || '' }}
secrets:
RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }}
RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
create-target:
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.
#
# Misskey calender versioning (yyyy.MM.patch) example
version_increment_script: |
const now = new Date();
const year = now.toLocaleDateString('en-US', { year: 'numeric', timeZone: 'Asia/Tokyo' });
const month = now.toLocaleDateString('en-US', { month: 'numeric', timeZone: 'Asia/Tokyo' });
const [major, minor, _patch] = process.env.CURRENT_VERSION.split('.');
const patch = Number(_patch.split('-')[0]);
if (Number.isNaN(patch)) {
console.error('Invalid patch version', year, month, process.env.CURRENT_VERSION, major, minor, _patch);
throw new Error('Invalid patch version');
}
if (year !== major || month !== minor) {
return `${year}.${month}.0`;
} else {
return `${major}.${minor}.${patch + 1}`;
}
##Semver example
#version_increment_script: |
# const [major, minor, patch] = process.env.CURRENT_VERSION.split('.');
# if ("${{ inputs.version_increment_type }}" === "major") {
# return `${Number(major) + 1}.0.0`;
# } else if ("${{ inputs.version_increment_type }}" === "minor") {
# return `${major}.${Number(minor) + 1}.0`;
# } else {
# return `${major}.${minor}.${Number(patch) + 1}`;
# }
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 }}
draft_prerelease_channel: alpha
secrets:
RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }}
RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}

View file

@ -1,46 +0,0 @@
name: "Release Manager: release RC when ready for review"
on:
pull_request:
types: [ready_for_review]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
permissions:
contents: write
issues: write
pull-requests: write
jobs:
check:
runs-on: ubuntu-latest
outputs:
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,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@v2
needs: check
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 }}
draft_prerelease_channel: alpha
ready_start_prerelease_channel: beta
secrets:
RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }}
RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}

View file

@ -1,104 +0,0 @@
name: Report API Diff
on:
workflow_run:
types: [completed]
workflows:
- Get api.json from Misskey # get-api-diff.yml
jobs:
compare-diff:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
permissions:
pull-requests: write
# api-artifact
steps:
- name: Download artifact
uses: actions/github-script@v7.0.1
with:
script: |
const fs = require('fs');
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
let matchArtifacts = allArtifacts.data.artifacts.filter((artifact) => {
return artifact.name.startsWith("api-artifact-") || artifact.name == "api-artifact"
});
await Promise.all(matchArtifacts.map(async (artifact) => {
let download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: artifact.id,
archive_format: 'zip',
});
await fs.promises.writeFile(`${process.env.GITHUB_WORKSPACE}/${artifact.name}.zip`, Buffer.from(download.data));
}));
- name: Extract all artifacts
run: |
find . -mindepth 1 -maxdepth 1 -type f -name '*.zip' -exec unzip {} -d artifacts ';'
ls -la
- name: Load PR Number
id: load-pr-num
run: echo "pr-number=$(cat artifacts/pr_number)" >> "$GITHUB_OUTPUT"
- name: Output base
run: cat ./artifacts/api-base.json
- name: Output head
run: cat ./artifacts/api-head.json
- name: Arrange json files
run: |
jq '.' ./artifacts/api-base.json > ./api-base.json
jq '.' ./artifacts/api-head.json > ./api-head.json
- name: Get diff of 2 files
run: diff -u --label=base --label=head ./api-base.json ./api-head.json | cat > api.json.diff
- name: Get full diff
run: diff --label=base --label=head --new-line-format='+%L' --old-line-format='-%L' --unchanged-line-format=' %L' ./api-base.json ./api-head.json | cat > api-full.json.diff
- name: Echo full diff
run: cat ./api-full.json.diff
- name: Upload full diff to Artifact
uses: actions/upload-artifact@v4
with:
name: api-artifact
path: |
api-full.json.diff
api-base.json
api-head.json
- id: out-diff
name: Build diff Comment
run: |
HEADER="このPRによるapi.jsonの差分"
FOOTER="[Get diff files from Workflow Page](https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID})"
DIFF_BYTES="$(stat ./api.json.diff -c '%s' | tr -d '\n')"
echo "$HEADER" > ./output.md
if (( "$DIFF_BYTES" <= 1 )); then
echo '差分はありません。' >> ./output.md
else
echo '<details>' >> ./output.md
echo '<summary>差分はこちら</summary>' >> ./output.md
echo >> ./output.md
echo '```diff' >> ./output.md
cat ./api.json.diff >> ./output.md
echo '```' >> ./output.md
echo '</details>' >> .output.md
fi
echo "$FOOTER" >> ./output.md
- uses: thollander/actions-comment-pull-request@v2
with:
pr_number: ${{ steps.load-pr-num.outputs.pr-number }}
comment_tag: show_diff
filePath: ./output.md
- name: Tell error to PR
uses: thollander/actions-comment-pull-request@v2
if: failure() && steps.load-pr-num.outputs.pr-number
with:
pr_number: ${{ steps.load-pr-num.outputs.pr-number }}
comment_tag: show_diff_error
message: |
api.jsonの差分作成中にエラーが発生しました。詳細は[Workflowのログ](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})を確認してください。

13
.github/workflows/reviewer_lottery.yml vendored Normal file
View file

@ -0,0 +1,13 @@
name: "Reviewer lottery"
on:
pull_request_target:
types: [opened, ready_for_review, reopened]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: uesteibar/reviewer-lottery@v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}

View file

@ -1,116 +0,0 @@
name: Storybook
on:
push:
branches:
- master
- develop
- dev/storybook8 # for testing
pull_request_target:
branches-ignore:
# Since pull requests targets master mostly is the "develop" branch.
# Storybook CI is checked on the "push" event of "develop" branch so it would cause a duplicate build.
# This is a waste of chromatic build quota, so we don't run storybook CI on pull requests targets master.
- master
jobs:
build:
runs-on: ubuntu-latest
env:
NODE_OPTIONS: "--max_old_space_size=7168"
steps:
- uses: actions/checkout@v4.1.1
if: github.event_name != 'pull_request_target'
with:
fetch-depth: 0
submodules: true
- uses: actions/checkout@v4.1.1
if: github.event_name == 'pull_request_target'
with:
fetch-depth: 0
submodules: true
ref: "refs/pull/${{ github.event.number }}/merge"
- name: Checkout actual HEAD
if: github.event_name == 'pull_request_target'
id: rev
run: |
echo "base=$(git rev-list --parents -n1 HEAD | cut -d" " -f2)" >> $GITHUB_OUTPUT
git checkout $(git rev-list --parents -n1 HEAD | cut -d" " -f3)
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Use Node.js 20.x
uses: actions/setup-node@v4.0.4
with:
node-version-file: '.node-version'
cache: 'pnpm'
- run: corepack enable
- run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml
run: git diff --exit-code pnpm-lock.yaml
- name: Build misskey-js
run: pnpm --filter misskey-js build
- name: Build storybook
run: pnpm --filter frontend build-storybook
- name: Publish to Chromatic
if: github.event_name != 'pull_request_target' && github.ref == 'refs/heads/master'
run: pnpm --filter frontend chromatic --exit-once-uploaded -d storybook-static
env:
CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
- name: Publish to Chromatic
if: github.event_name != 'pull_request_target' && github.ref != 'refs/heads/master'
id: chromatic_push
run: |
DIFF="${{ github.event.before }} HEAD"
if [ "$DIFF" = "0000000000000000000000000000000000000000 HEAD" ]; then
DIFF="HEAD"
fi
CHROMATIC_PARAMETER="$(node packages/frontend/.storybook/changes.js $(git diff-tree --no-commit-id --name-only -r $(echo "$DIFF") | xargs))"
if [ "$CHROMATIC_PARAMETER" = " --skip" ]; then
echo "skip=true" >> $GITHUB_OUTPUT
fi
if pnpm --filter frontend chromatic -d storybook-static $(echo "$CHROMATIC_PARAMETER"); then
echo "success=true" >> $GITHUB_OUTPUT
else
echo "success=false" >> $GITHUB_OUTPUT
fi
env:
CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
- name: Publish to Chromatic
if: github.event_name == 'pull_request_target'
id: chromatic_pull_request
run: |
DIFF="${{ steps.rev.outputs.base }} HEAD"
if [ "$DIFF" = "0000000000000000000000000000000000000000 HEAD" ]; then
DIFF="HEAD"
fi
CHROMATIC_PARAMETER="$(node packages/frontend/.storybook/changes.js $(git diff-tree --no-commit-id --name-only -r $(echo "$DIFF") | xargs))"
if [ "$CHROMATIC_PARAMETER" = " --skip" ]; then
echo "skip=true" >> $GITHUB_OUTPUT
fi
BRANCH="${{ github.event.pull_request.head.user.login }}:$HEAD_REF"
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")
env:
HEAD_REF: ${{ github.event.pull_request.head.ref }}
CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
- name: Notify that Chromatic detects changes
uses: actions/github-script@v7.0.1
if: github.event_name != 'pull_request_target' && steps.chromatic_push.outputs.success == 'false'
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
github.rest.repos.createCommitComment({
owner: context.repo.owner,
repo: context.repo.repo,
commit_sha: context.sha,
body: 'Chromatic detects changes. Please [review the changes on Chromatic](https://www.chromatic.com/builds?appId=6428f7d7b962f0b79f97d6e4).'
})
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: storybook
path: packages/frontend/storybook-static

View file

@ -5,48 +5,40 @@ on:
branches: branches:
- master - master
- develop - develop
paths:
- packages/backend/**
# for permissions
- packages/misskey-js/**
- .github/workflows/test-backend.yml
pull_request: pull_request:
paths:
- packages/backend/**
# for permissions
- packages/misskey-js/**
- .github/workflows/test-backend.yml
jobs: jobs:
unit: jest:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
node-version: [20.16.0] node-version: [18.x]
services: services:
postgres: postgres:
image: postgres:15 image: postgres:13
ports: ports:
- 54312:5432 - 54312:5432
env: env:
POSTGRES_DB: test-misskey POSTGRES_DB: test-misskey
POSTGRES_HOST_AUTH_METHOD: trust POSTGRES_HOST_AUTH_METHOD: trust
redis: redis:
image: redis:7 image: redis:6
ports: ports:
- 56312:6379 - 56312:6379
steps: steps:
- uses: actions/checkout@v4.1.1 - uses: actions/checkout@v3.3.0
with: with:
submodules: true submodules: true
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v2
- name: Install FFmpeg with:
uses: FedericoCarboni/setup-ffmpeg@v3 version: 7
run_install: false
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.0.4 uses: actions/setup-node@v3.6.0
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: 'pnpm' cache: 'pnpm'
@ -59,56 +51,9 @@ jobs:
- name: Build - name: Build
run: pnpm build run: pnpm build
- name: Test - name: Test
run: pnpm --filter backend test-and-coverage run: pnpm jest-and-coverage
- name: Upload to Codecov - name: Upload Coverage
uses: codecov/codecov-action@v4 uses: codecov/codecov-action@v3
with: with:
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}
files: ./packages/backend/coverage/coverage-final.json files: ./packages/backend/coverage/coverage-final.json
e2e:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20.16.0]
services:
postgres:
image: postgres:15
ports:
- 54312:5432
env:
POSTGRES_DB: test-misskey
POSTGRES_HOST_AUTH_METHOD: trust
redis:
image: redis:7
ports:
- 56312:6379
steps:
- uses: actions/checkout@v4.1.1
with:
submodules: true
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.0.4
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- run: corepack enable
- run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml
run: git diff --exit-code pnpm-lock.yaml
- name: Copy Configure
run: cp .github/misskey/test.yml .config
- name: Build
run: pnpm build
- name: Test
run: pnpm --filter backend test-and-coverage:e2e
- name: Upload to Codecov
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./packages/backend/coverage/coverage-final.json

View file

@ -1,59 +0,0 @@
name: Test (federation)
on:
push:
branches:
- master
- develop
paths:
- packages/backend/**
- packages/misskey-js/**
- .github/workflows/test-federation.yml
pull_request:
paths:
- packages/backend/**
- packages/misskey-js/**
- .github/workflows/test-federation.yml
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20.16.0]
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Install FFmpeg
uses: FedericoCarboni/setup-ffmpeg@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.0.3
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- name: Build Misskey
run: |
corepack enable && corepack prepare
pnpm i --frozen-lockfile
pnpm build
- name: Setup
run: |
cd packages/backend/test-federation
bash ./setup.sh
sudo chmod 644 ./certificates/*.test.key
- name: Start servers
# https://github.com/docker/compose/issues/1294#issuecomment-374847206
run: |
cd packages/backend/test-federation
docker compose up -d --scale tester=0
- name: Test
run: |
cd packages/backend/test-federation
docker compose run --no-deps tester
- name: Stop servers
run: |
cd packages/backend/test-federation
docker compose down

View file

@ -5,37 +5,27 @@ on:
branches: branches:
- master - master
- develop - develop
paths:
- packages/frontend/**
# for permissions
- packages/misskey-js/**
# for e2e
- packages/backend/**
- .github/workflows/test-frontend.yml
pull_request: pull_request:
paths:
- packages/frontend/**
# for permissions
- packages/misskey-js/**
# for e2e
- packages/backend/**
- .github/workflows/test-frontend.yml
jobs: jobs:
vitest: vitest:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
node-version: [20.16.0] node-version: [18.x]
steps: steps:
- uses: actions/checkout@v4.1.1 - uses: actions/checkout@v3.3.0
with: with:
submodules: true submodules: true
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v2
with:
version: 7
run_install: false
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.0.4 uses: actions/setup-node@v3.6.0
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: 'pnpm' cache: 'pnpm'
@ -50,7 +40,7 @@ jobs:
- name: Test - name: Test
run: pnpm --filter frontend test-and-coverage run: pnpm --filter frontend test-and-coverage
- name: Upload Coverage - name: Upload Coverage
uses: codecov/codecov-action@v4 uses: codecov/codecov-action@v3
with: with:
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}
files: ./packages/frontend/coverage/coverage-final.json files: ./packages/frontend/coverage/coverage-final.json
@ -61,24 +51,24 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
node-version: [20.16.0] node-version: [18.x]
browser: [chrome] browser: [chrome]
services: services:
postgres: postgres:
image: postgres:15 image: postgres:13
ports: ports:
- 54312:5432 - 54312:5432
env: env:
POSTGRES_DB: test-misskey POSTGRES_DB: test-misskey
POSTGRES_HOST_AUTH_METHOD: trust POSTGRES_HOST_AUTH_METHOD: trust
redis: redis:
image: redis:7 image: redis:6
ports: ports:
- 56312:6379 - 56312:6379
steps: steps:
- uses: actions/checkout@v4.1.1 - uses: actions/checkout@v3.3.0
with: with:
submodules: true submodules: true
# https://github.com/cypress-io/cypress-docker-images/issues/150 # https://github.com/cypress-io/cypress-docker-images/issues/150
@ -88,9 +78,12 @@ jobs:
#- uses: browser-actions/setup-firefox@latest #- uses: browser-actions/setup-firefox@latest
# if: ${{ matrix.browser == 'firefox' }} # if: ${{ matrix.browser == 'firefox' }}
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v2
with:
version: 7
run_install: false
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.0.4 uses: actions/setup-node@v3.6.0
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: 'pnpm' cache: 'pnpm'
@ -108,20 +101,19 @@ jobs:
- name: Cypress install - name: Cypress install
run: pnpm exec cypress install run: pnpm exec cypress install
- name: Cypress run - name: Cypress run
uses: cypress-io/github-action@v6 uses: cypress-io/github-action@v5
timeout-minutes: 15
with: with:
install: false install: false
start: pnpm start:test start: pnpm start:test
wait-on: 'http://localhost:61812' wait-on: 'http://localhost:61812'
headed: true headless: false
browser: ${{ matrix.browser }} browser: ${{ matrix.browser }}
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v2
if: failure() if: failure()
with: with:
name: ${{ matrix.browser }}-cypress-screenshots name: ${{ matrix.browser }}-cypress-screenshots
path: cypress/screenshots path: cypress/screenshots
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v2
if: always() if: always()
with: with:
name: ${{ matrix.browser }}-cypress-videos name: ${{ matrix.browser }}-cypress-videos

View file

@ -6,14 +6,9 @@ name: Test (misskey.js)
on: on:
push: push:
branches: [ develop ] branches: [ develop ]
paths:
- packages/misskey-js/**
- .github/workflows/test-misskey-js.yml
pull_request: pull_request:
branches: [ develop ] branches: [ develop ]
paths:
- packages/misskey-js/**
- .github/workflows/test-misskey-js.yml
jobs: jobs:
test: test:
@ -21,17 +16,17 @@ jobs:
strategy: strategy:
matrix: matrix:
node-version: [20.16.0] node-version: [18.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/ # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4.1.1 uses: actions/checkout@v3.3.0
- run: corepack enable - run: corepack enable
- name: Setup Node.js ${{ matrix.node-version }} - name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.0.4 uses: actions/setup-node@v3.6.0
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: 'pnpm' cache: 'pnpm'
@ -51,7 +46,7 @@ jobs:
CI: true CI: true
- name: Upload Coverage - name: Upload Coverage
uses: codecov/codecov-action@v4 uses: codecov/codecov-action@v3
with: with:
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}
files: ./packages/misskey-js/coverage/coverage-final.json files: ./packages/misskey-js/coverage/coverage-final.json

View file

@ -1,39 +0,0 @@
name: Test (production install and build)
on:
push:
branches:
- master
- develop
pull_request:
env:
NODE_ENV: production
jobs:
production:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20.16.0]
steps:
- uses: actions/checkout@v4.1.1
with:
submodules: true
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.0.4
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- run: corepack enable
- run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml
run: git diff --exit-code pnpm-lock.yaml
- name: Copy Configure
run: cp .github/misskey/test.yml .config/default.yml
- name: Build
run: pnpm build

View file

@ -1,45 +0,0 @@
name: Test (backend)
on:
push:
branches:
- master
- 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.16.0]
steps:
- uses: actions/checkout@v4.1.1
with:
submodules: true
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.0.4
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- name: Install Redocly CLI
run: npm i -g @redocly/cli
- run: corepack enable
- run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml
run: git diff --exit-code pnpm-lock.yaml
- name: Copy Configure
run: cp .config/example.yml .config/default.yml
- name: Build and generate
run: pnpm build && pnpm --filter backend generate-api-json
- name: Validation
run: npx @redocly/cli lint --extends=minimal ./packages/backend/built/api.json

19
.gitignore vendored
View file

@ -35,21 +35,16 @@ coverage
!/.config/example.yml !/.config/example.yml
!/.config/docker_example.yml !/.config/docker_example.yml
!/.config/docker_example.env !/.config/docker_example.env
!/.config/cypress-devcontainer.yml
docker-compose.yml docker-compose.yml
./compose.yml !/.devcontainer/docker-compose.yml
.devcontainer/compose.yml
!/.devcontainer/compose.yml
# misskey # misskey
/build /build
built built
built-test
js-built
/data /data
/.cache-loader /.cache-loader
/db /db
/meili_data /elasticsearch
npm-debug.log npm-debug.log
*.pem *.pem
run.bat run.bat
@ -61,13 +56,6 @@ api-docs.json
/files /files
ormconfig.json ormconfig.json
temp temp
/packages/frontend/src/**/*.stories.ts
tsdoc-metadata.json
misskey-assets
# Vite temporary files
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
# blender backups # blender backups
*.blend1 *.blend1
@ -75,6 +63,3 @@ vite.config.ts.timestamp-*
*.blend3 *.blend3
*.blend4 *.blend4
*.blend5 *.blend5
# VSCode addon
.favorites.json

3
.gitmodules vendored
View file

@ -1,3 +1,6 @@
[submodule "misskey-assets"]
path = misskey-assets
url = https://github.com/misskey-dev/assets.git
[submodule "fluent-emojis"] [submodule "fluent-emojis"]
path = fluent-emojis path = fluent-emojis
url = https://github.com/misskey-dev/emojis.git url = https://github.com/misskey-dev/emojis.git

View file

@ -1 +1 @@
20.16.0 v18.13.0

1
.npmrc
View file

@ -1 +0,0 @@
engine-strict = true

View file

@ -3,7 +3,9 @@
"editorconfig.editorconfig", "editorconfig.editorconfig",
"dbaeumer.vscode-eslint", "dbaeumer.vscode-eslint",
"Vue.volar", "Vue.volar",
"Vue.vscode-typescript-vue-plugin",
"Orta.vscode-jest", "Orta.vscode-jest",
"dbaeumer.vscode-eslint",
"mrmlnc.vscode-json5" "mrmlnc.vscode-json5"
] ]
} }

23
.vscode/settings.json vendored
View file

@ -1,15 +1,10 @@
{ {
"search.exclude": { "search.exclude": {
"**/node_modules": true "**/node_modules": true
}, },
"typescript.tsdk": "node_modules/typescript/lib", "typescript.tsdk": "node_modules/typescript/lib",
"files.associations": { "files.associations": {
"*.test.ts": "typescript" "*.test.ts": "typescript"
}, },
"jest.jestCommandLine": "pnpm run jest", "jest.autoRun": "off"
"jest.runMode": "on-demand", }
"editor.codeActionsOnSave": {
"source.fixAll": "explicit"
},
"editor.formatOnSave": false
}

File diff suppressed because it is too large Load diff

View file

@ -2,131 +2,45 @@
## Our Pledge ## Our Pledge
We as members, contributors, and leaders pledge to make participation in our In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards ## Our Standards
Examples of behavior that contributes to a positive environment for our Examples of behavior that contributes to creating a positive environment include:
community include:
* Demonstrating empathy and kindness toward other people * Using welcoming and inclusive language
* Being respectful of differing opinions, viewpoints, and experiences * Being respectful of differing viewpoints and experiences
* Giving and gracefully accepting constructive feedback * Gracefully accepting constructive criticism
* Accepting responsibility and apologizing to those affected by our mistakes, * Focusing on what is best for the community
and learning from the experience * Showing empathy towards other community members
* Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include: Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery, and sexual attention or advances of * The use of sexualized language or imagery and unwelcome sexual attention or advances
any kind * Trolling, insulting/derogatory comments, and personal or political attacks
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment * Public or private harassment
* Publishing others' private information, such as a physical or email address, * Publishing others' private information, such as a physical or electronic address, without explicit permission
without their explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities ## Our Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope ## Scope
This Code of Conduct applies within all community spaces, and also applies when This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement ## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at syuilotan@yahoo.co.jp. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
reported to the community leaders responsible for enforcement at
<syuilotan@yahoo.co.jp>.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution ## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by [homepage]: http://contributor-covenant.org
[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. [version]: http://contributor-covenant.org/version/1/4/
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

View file

@ -1,7 +1,7 @@
# Contribution guide # 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. 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.** > 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.\ > 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. > 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.
@ -15,33 +15,18 @@ Before creating an issue, please check the following:
- To avoid duplication, please search for similar issues before creating a new issue. - To avoid duplication, please search for similar issues before creating a new issue.
- Do not use Issues to ask questions or troubleshooting. - Do not use Issues to ask questions or troubleshooting.
- Issues should only be used to feature requests, suggestions, and bug tracking. - 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). - Please ask questions or troubleshooting in ~~the [Misskey Forum](https://forum.misskey.io/)~~ [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. > Do not close issues that are about to be resolved. It should remain open until a commit that actually resolves it is merged.
### Recommended discussing before implementation ## 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. 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. 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. 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 Committer to assign you). 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.
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 ## Well-known branches
- **`master`** branch is tracking the latest release and used for production purposes. - **`master`** branch is tracking the latest release and used for production purposes.
@ -52,45 +37,25 @@ The Committers may:
## Creating a PR ## Creating a PR
Thank you for your PR! Before creating a PR, please check the following: 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. - 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 - `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. - 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. - 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. - 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. - 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. - 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. - 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. - If this PR includes UI changes, please attach a screenshot in the text.
Thanks for your cooperation 🤗 Thanks for your cooperation 🤗
### Additional things for ActivityPub payload changes
*This section is specific to misskey-dev implementation. Other fork or implementation may take different way. A significant difference is that non-"misskey-dev" extension is not described in the misskey-hub's document.*
If PR includes changes to ActivityPub payload, please reflect it in [misskey-hub's document](https://github.com/misskey-dev/misskey-hub-next/blob/master/content/ns.md) by sending PR.
The name of purporsed extension property (referred as "extended property" in later) to ActivityPub shall be prefixed by `_misskey_`. (i.e. `_misskey_quote`)
The extended property in `packages/backend/src/core/activitypub/type.ts` **must** be declared as optional because ActivityPub payloads that comes from older Misskey or other implementation may not contain it.
The extended property must be included in the context definition. Context is defined in `packages/backend/src/core/activitypub/misc/contexts.ts`.
The key shall be same as the name of extended property, and the value shall be same as "short IRI".
"Short IRI" is defined in misskey-hub's document, but usually takes form of `misskey:<name of extended property>`. (i.e. `misskey:_misskey_quote`)
One should not add property that has defined before by other implementation, or add custom variant value to "well-known" property.
## Reviewers guide ## Reviewers guide
Be willing to comment on the good points and not just the things you want fixed 💯 Be willing to comment on the good points and not just the things you want fixed 💯
読んでおくといいやつ
- https://blog.lacolaco.net/posts/1e2cf439b3c2/
- https://konifar-zatsu.hatenadiary.jp/entry/2024/11/05/192421
### Review perspective ### Review perspective
- Scope - Scope
- Are the goals of the PR clear? - Are the goals of the PR clear?
- Is the granularity of the PR appropriate? - Is the granularity of the PR appropriate?
- Security - Security
- Does merging this PR create a vulnerability? - Does merging this PR create a vulnerability?
- Performance - Performance
@ -112,7 +77,7 @@ An actual domain will be assigned so you can test the federation.
## Release ## Release
### Release Instructions ### Release Instructions
1. Commit version changes in the `develop` branch ([package.json](package.json)) 1. Commit version changes in the `develop` branch ([package.json](https://github.com/misskey-dev/misskey/blob/develop/package.json))
2. Create a release PR. 2. Create a release PR.
- Into `master` from `develop` branch. - Into `master` from `develop` branch.
- The title must be in the format `Release: x.y.z`. - The title must be in the format `Release: x.y.z`.
@ -123,7 +88,7 @@ An actual domain will be assigned so you can test the federation.
- The target branch must be `master` - The target branch must be `master`
- The tag name must be the version - The tag name must be the version
> [!NOTE] > **Note**
> Why this instruction is necessary: > Why this instruction is necessary:
> - To perform final QA checks > - To perform final QA checks
> - To distribute responsibility > - To distribute responsibility
@ -136,30 +101,26 @@ You can improve our translations with your Crowdin account.
Your changes in Crowdin are automatically submitted as a PR (with the title "New Crowdin translations") to the repository. Your changes in Crowdin are automatically submitted as a PR (with the title "New Crowdin translations") to the repository.
The owner [@syuilo](https://github.com/syuilo) merges the PR into the develop branch before the next release. The owner [@syuilo](https://github.com/syuilo) merges the PR into the develop branch before the next release.
If your language is not listed in Crowdin, please open an issue. We will add it to Crowdin. If your language is not listed in Crowdin, please open an issue.
For newly added languages, once the translation progress per language exceeds 70%, it will be officially introduced into Misskey and made available to users.
![Crowdin](https://d322cqt584bo4o.cloudfront.net/misskey/localized.svg) ![Crowdin](https://d322cqt584bo4o.cloudfront.net/misskey/localized.svg)
## Development ## Development
### Setup During development, it is useful to use the
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. ```
pnpm dev
```
There are a few ways to proceed. command.
#### Use system-wide software - Server-side source files and automatically builds them if they are modified. Automatically start the server process(es).
You could install them in system-wide (such as from package manager). - Vite HMR (just the `vite` command) is available. The behavior may be different from production.
- Service Worker is watched by esbuild.
#### 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.
### Dev Container
Instead of running `pnpm` locally, you can use Dev Container to set up your development environment. 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. 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. **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. It will run the following command automatically inside the container.
@ -171,81 +132,38 @@ pnpm build
pnpm migrate pnpm migrate
``` ```
After finishing the migration, you can proceed. After finishing the migration, run the `pnpm dev` command to start the development server.
### Start developing ``` bash
During development, it is useful to use the
```
pnpm dev pnpm dev
``` ```
command.
- Server-side source files and automatically builds them if they are modified. Automatically start the server process(es).
- Vite HMR (just the `vite` command) is available. The behavior may be different from production.
- Service Worker is watched by esbuild.
- The front end can be viewed by accessing `http://localhost:5173`.
- The backend listens on the port configured with `port` in .config/default.yml.
If you have not changed it from the default, it will be "http://localhost:3000".
If "port" in .config/default.yml is set to something other than 3000, you need to change the proxy settings in packages/frontend/vite.config.local-dev.ts.
### `MK_DEV_PREFER=backend pnpm dev`
pnpm dev has another mode with `MK_DEV_PREFER=backend`.
```
MK_DEV_PREFER=backend pnpm dev
```
- This mode is closer to the production environment than the default mode.
- Vite runs behind the backend (the backend will proxy Vite at /vite).
- You can see Misskey by accessing `http://localhost:3000` (Replace `3000` with the port configured with `port` in .config/default.yml).
- To change the port of Vite, specify with `VITE_PORT` environment variable.
- HMR may not work in some environments such as Windows.
## Testing ## Testing
You can run non-backend tests by executing following commands: - Test codes are located in [`/packages/backend/test`](/packages/backend/test).
```sh
pnpm --filter frontend test ### Run test
pnpm --filter misskey-js test Create a config file.
``` ```
Backend tests require manual preparation of servers. See the next section for more on this.
### Backend
There are three types of test codes for the backend:
- Unit tests: [`/packages/backend/test/unit`](/packages/backend/test/unit)
- Single-server E2E tests: [`/packages/backend/test/e2e`](/packages/backend/test/e2e)
- Multiple-server E2E tests: [`/packages/backend/test-federation`](/packages/backend/test-federation)
#### Running Unit Tests or Single-server E2E Tests
1. Create a config file:
```sh
cp .github/misskey/test.yml .config/ cp .github/misskey/test.yml .config/
``` ```
Prepare DB/Redis for testing.
2. Start DB and Redis servers for testing:
```sh
docker compose -f packages/backend/test/compose.yml up
``` ```
Instead, you can prepare an empty (data can be erased) DB and edit `.config/test.yml` appropriately. docker compose -f packages/backend/test/docker-compose.yml up
3. Run all tests:
```sh
pnpm --filter backend test # unit tests
pnpm --filter backend test:e2e # single-server E2E tests
``` ```
If you want to run a specific test, run as a following command: Alternatively, prepare an empty (data can be erased) DB and edit `.config/test.yml`.
```sh
pnpm --filter backend test -- packages/backend/test/unit/activitypub.ts Run all test.
pnpm --filter backend test:e2e -- packages/backend/test/e2e/nodeinfo.ts ```
pnpm test
``` ```
#### Running Multiple-server E2E Tests #### Run specify test
See [`/packages/backend/test-federation/README.md`](/packages/backend/test-federation/README.md). ```
pnpm jest -- foo.ts
```
## Environment Variable ### e2e tests
TODO
- `MISSKEY_CONFIG_YML`: Specify the file path of config.yml instead of default.yml (e.g. `2nd.yml`).
- `MISSKEY_WEBFINGER_USE_HTTP`: If it's set true, WebFinger requests will be http instead of https, useful for testing federation between servers in localhost. NEVER USE IN PRODUCTION.
## Continuous integration ## Continuous integration
Misskey uses GitHub Actions for executing automated tests. Misskey uses GitHub Actions for executing automated tests.
@ -264,7 +182,7 @@ niraxは、Misskeyで使用しているオリジナルのフロントエンド
### ルート定義 ### ルート定義
ルート定義は、以下の形式のオブジェクトの配列です。 ルート定義は、以下の形式のオブジェクトの配列です。
```ts ``` ts
{ {
name?: string; name?: string;
path: string; path: string;
@ -277,7 +195,7 @@ niraxは、Misskeyで使用しているオリジナルのフロントエンド
} }
``` ```
> [!WARNING] > **Warning**
> 現状、ルートは定義された順に評価されます。 > 現状、ルートは定義された順に評価されます。
> たとえば、`/foo/:id`ルート定義の次に`/foo/bar`ルート定義がされていた場合、後者がマッチすることはありません。 > たとえば、`/foo/:id`ルート定義の次に`/foo/bar`ルート定義がされていた場合、後者がマッチすることはありません。
@ -285,196 +203,7 @@ niraxは、Misskeyで使用しているオリジナルのフロントエンド
vue-routerとの最大の違いは、niraxは複数のルーターが存在することを許可している点です。 vue-routerとの最大の違いは、niraxは複数のルーターが存在することを許可している点です。
これにより、アプリ内ウィンドウでブラウザとは個別にルーティングすることなどが可能になります。 これにより、アプリ内ウィンドウでブラウザとは個別にルーティングすることなどが可能になります。
## Storybook
Misskey uses [Storybook](https://storybook.js.org/) for UI development.
### Setup & Run
#### Setup
```bash
pnpm --filter misskey-js build
```
#### Run
```bash
pnpm --filter frontend storybook-dev
```
### Usage
When you create a new component (in this example, `MyComponent.vue`), the story file (`MyComponent.stories.ts`) will be automatically generated by the `.storybook/generate.js` script.
You can override the default story by creating a impl story file (`MyComponent.stories.impl.ts`).
```ts
/* eslint-disable @typescript-eslint/explicit-function-return-type */
import { StoryObj } from '@storybook/vue3';
import MyComponent from './MyComponent.vue';
export const Default = {
render(args) {
return {
components: {
MyComponent,
},
setup() {
return {
args,
};
},
computed: {
props() {
return {
...this.args,
};
},
},
template: '<MyComponent v-bind="props" />',
};
},
args: {
foo: 'bar',
},
parameters: {
layout: 'centered',
},
} 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.
```ts
import MyComponent from './MyComponent.vue';
void MyComponent;
```
You can override the component meta by creating a meta story file (`MyComponent.stories.meta.ts`).
```ts
export const argTypes = {
scale: {
control: {
type: 'range',
min: 1,
max: 4,
},
},
};
```
Also, you can use msw to mock API requests in the storybook. Creating a `MyComponent.stories.msw.ts` file to define the mock handlers.
```ts
import { HttpResponse, http } from 'msw';
export const handlers = [
http.post('/api/notes/timeline', ({ request }) => {
return HttpResponse.json([]);
}),
];
```
Don't forget to re-run the `.storybook/generate.js` script after adding, editing, or removing the above files.
## Nest
### Nest Service Circular dependency / Nestでサービスの循環参照でエラーが起きた場合
#### forwardRef
まずは簡単に`forwardRef`を試してみる
```typescript
export class FooService {
constructor(
@Inject(forwardRef(() => BarService))
private barService: BarService
) {
}
}
```
#### OnModuleInit
できなければ`OnModuleInit`を使う
```typescript
import { Injectable, OnModuleInit } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core';
import { BarService } from '@/core/BarService';
@Injectable()
export class FooService implements OnModuleInit {
private barService: BarService // constructorから移動してくる
constructor(
private moduleRef: ModuleRef,
) {
}
async onModuleInit() {
this.barService = this.moduleRef.get(BarService.name);
}
public async niceMethod() {
return await this.barService.incredibleMethod({ hoge: 'fuga' });
}
}
```
##### Service Unit Test
テストで`onModuleInit`を呼び出す必要がある
```typescript
// import ...
describe('test', () => {
let app: TestingModule;
let fooService: FooService; // for test case
let barService: BarService; // for test case
beforeEach(async () => {
app = await Test.createTestingModule({
imports: ...,
providers: [
FooService,
{ // mockする (mockは必須ではないかもしれない)
provide: BarService,
useFactory: () => ({
incredibleMethod: jest.fn(),
}),
},
{ // Provideにする
provide: BarService.name,
useExisting: BarService,
},
],
})
.useMocker(...
.compile();
fooService = app.get<FooService>(FooService);
barService = app.get<BarService>(BarService) as jest.Mocked<BarService>;
// onModuleInitを実行する
await fooService.onModuleInit();
});
test('nice', () => {
await fooService.niceMethod();
expect(barService.incredibleMethod).toHaveBeenCalled();
expect(barService.incredibleMethod.mock.lastCall![0])
.toEqual({ hoge: 'fuga' });
});
})
```
## Notes ## Notes
### Misskeyのドメイン固有の概念は`Mi`をprefixする
例えばGoogleが自社サービスをMap、Earth、DriveではなくGoogle Map、Google Earth、Google Driveのように命名するのと同じ
コード上でMisskeyのドメイン固有の概念には`Mi`をprefixすることで、他のドメインの同様の概念と区別できるほか、名前の衝突を防ぐ。
ただし、文脈上Misskeyのものを指すことが明らかであり、名前の衝突の恐れがない場合は、一時的なローカル変数に限って`Mi`を省略してもよい。
### How to resolve conflictions occurred at pnpm-lock.yaml? ### How to resolve conflictions occurred at pnpm-lock.yaml?
Just execute `pnpm` to fix it. Just execute `pnpm` to fix it.
@ -571,13 +300,13 @@ pnpm dlx typeorm migration:generate -d ormconfig.js -o <migration name>
- 作成されたスクリプトは不必要な変更を含むため除去してください - 作成されたスクリプトは不必要な変更を含むため除去してください
### JSON SchemaのobjectでanyOfを使うとき ### JSON SchemaのobjectでanyOfを使うとき
JSON Schemaで、objectに対してanyOfを使う場合、anyOfの中でpropertiesを定義しないこと。 JSON Schemaで、objectに対してanyOfを使う場合、anyOfの中でpropertiesを定義しないこと。
バリデーションが効かないため。SchemaTypeもそのように作られており、objectのanyOf内のpropertiesは捨てられます バリデーションが効かないため。SchemaTypeもそのように作られており、objectのanyOf内のpropertiesは捨てられます
https://github.com/misskey-dev/misskey/pull/10082 https://github.com/misskey-dev/misskey/pull/10082
テキストhogeおよびfugaについて、片方を必須としつつ両方の指定もありうる場合: テキストhogeおよびfugaについて、片方を必須としつつ両方の指定もありうる場合:
```ts ```
export const paramDef = { export const paramDef = {
type: 'object', type: 'object',
properties: { properties: {
@ -604,27 +333,3 @@ marginはそのコンポーネントを使う側が設定する
## その他 ## その他
### HTMLのクラス名で follow という単語は使わない ### HTMLのクラス名で follow という単語は使わない
広告ブロッカーで誤ってブロックされる 広告ブロッカーで誤ってブロックされる
### indexというファイル名を使うな
ESMではディレクトリインポートは廃止されているのと、ディレクトリインポートせずともファイル名が index だと何故か一部のライブラリ?でディレクトリインポートだと見做されてエラーになる
## CSS Recipe
### Lighten CSS vars
``` css
color: hsl(from var(--MI_THEME-accent) h s calc(l + 10));
```
### Darken CSS vars
``` css
color: hsl(from var(--MI_THEME-accent) h s calc(l - 10));
```
### Add alpha to CSS vars
``` css
color: color(from var(--MI_THEME-accent) srgb r g b / 0.5);
```

View file

@ -1,5 +1,5 @@
Unless otherwise stated this repository is Unless otherwise stated this repository is
Copyright © 2014-2024 syuilo and contributors Copyright © 2014-2023 syuilo and contributers
And is distributed under The GNU Affero General Public License Version 3, you should have received a copy of the license file as LICENSE. And is distributed under The GNU Affero General Public License Version 3, you should have received a copy of the license file as LICENSE.

View file

@ -1,6 +1,6 @@
# syntax = docker/dockerfile:1.4 # syntax = docker/dockerfile:1.4
ARG NODE_VERSION=20.16.0-bullseye ARG NODE_VERSION=18.13.0-bullseye
# build assets & compile TypeScript # build assets & compile TypeScript
@ -21,21 +21,17 @@ WORKDIR /misskey
COPY --link ["pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "./"] COPY --link ["pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "./"]
COPY --link ["scripts", "./scripts"] COPY --link ["scripts", "./scripts"]
COPY --link ["packages/backend/package.json", "./packages/backend/"] COPY --link ["packages/backend/package.json", "./packages/backend/"]
COPY --link ["packages/frontend-shared/package.json", "./packages/frontend-shared/"]
COPY --link ["packages/frontend/package.json", "./packages/frontend/"] COPY --link ["packages/frontend/package.json", "./packages/frontend/"]
COPY --link ["packages/frontend-embed/package.json", "./packages/frontend-embed/"]
COPY --link ["packages/sw/package.json", "./packages/sw/"] COPY --link ["packages/sw/package.json", "./packages/sw/"]
COPY --link ["packages/misskey-js/package.json", "./packages/misskey-js/"] COPY --link ["packages/misskey-js/package.json", "./packages/misskey-js/"]
COPY --link ["packages/misskey-reversi/package.json", "./packages/misskey-reversi/"]
COPY --link ["packages/misskey-bubble-game/package.json", "./packages/misskey-bubble-game/"]
ARG NODE_ENV=production
RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \ RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \
pnpm i --frozen-lockfile --aggregate-output pnpm i --frozen-lockfile --aggregate-output
COPY --link . ./ COPY --link . ./
ARG NODE_ENV=production
RUN git submodule update --init RUN git submodule update --init
RUN pnpm build RUN pnpm build
RUN rm -rf .git/ RUN rm -rf .git/
@ -55,11 +51,6 @@ WORKDIR /misskey
COPY --link ["pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "./"] COPY --link ["pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "./"]
COPY --link ["scripts", "./scripts"] COPY --link ["scripts", "./scripts"]
COPY --link ["packages/backend/package.json", "./packages/backend/"] COPY --link ["packages/backend/package.json", "./packages/backend/"]
COPY --link ["packages/misskey-js/package.json", "./packages/misskey-js/"]
COPY --link ["packages/misskey-reversi/package.json", "./packages/misskey-reversi/"]
COPY --link ["packages/misskey-bubble-game/package.json", "./packages/misskey-bubble-game/"]
ARG NODE_ENV=production
RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \ RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \
pnpm i --frozen-lockfile --aggregate-output pnpm i --frozen-lockfile --aggregate-output
@ -71,37 +62,25 @@ ARG GID="991"
RUN apt-get update \ RUN apt-get update \
&& apt-get install -y --no-install-recommends \ && apt-get install -y --no-install-recommends \
ffmpeg tini curl libjemalloc-dev libjemalloc2 \ ffmpeg tini curl \
&& ln -s /usr/lib/$(uname -m)-linux-gnu/libjemalloc.so.2 /usr/local/lib/libjemalloc.so \
&& corepack enable \ && corepack enable \
&& groupadd -g "${GID}" misskey \ && groupadd -g "${GID}" misskey \
&& useradd -l -u "${UID}" -g "${GID}" -m -d /misskey misskey \ && useradd -l -u "${UID}" -g "${GID}" -m -d /misskey misskey \
&& find / -type d -path /sys -prune -o -type d -path /proc -prune -o -type f -perm /u+s -ignore_readdir_race -exec chmod u-s {} \; \ && find / -type d -path /proc -prune -o -type f -perm /u+s -ignore_readdir_race -exec chmod u-s {} \; \
&& find / -type d -path /sys -prune -o -type d -path /proc -prune -o -type f -perm /g+s -ignore_readdir_race -exec chmod g-s {} \; \ && find / -type d -path /proc -prune -o -type f -perm /g+s -ignore_readdir_race -exec chmod g-s {} \; \
&& apt-get clean \ && apt-get clean \
&& rm -rf /var/lib/apt/lists && rm -rf /var/lib/apt/lists
USER misskey USER misskey
WORKDIR /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/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/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
COPY --chown=misskey:misskey --from=target-builder /misskey/packages/misskey-reversi/node_modules ./packages/misskey-reversi/node_modules
COPY --chown=misskey:misskey --from=target-builder /misskey/packages/misskey-bubble-game/node_modules ./packages/misskey-bubble-game/node_modules
COPY --chown=misskey:misskey --from=native-builder /misskey/built ./built COPY --chown=misskey:misskey --from=native-builder /misskey/built ./built
COPY --chown=misskey:misskey --from=native-builder /misskey/packages/misskey-js/built ./packages/misskey-js/built
COPY --chown=misskey:misskey --from=native-builder /misskey/packages/misskey-reversi/built ./packages/misskey-reversi/built
COPY --chown=misskey:misskey --from=native-builder /misskey/packages/misskey-bubble-game/built ./packages/misskey-bubble-game/built
COPY --chown=misskey:misskey --from=native-builder /misskey/packages/backend/built ./packages/backend/built COPY --chown=misskey:misskey --from=native-builder /misskey/packages/backend/built ./packages/backend/built
COPY --chown=misskey:misskey --from=native-builder /misskey/fluent-emojis /misskey/fluent-emojis COPY --chown=misskey:misskey --from=native-builder /misskey/fluent-emojis /misskey/fluent-emojis
COPY --chown=misskey:misskey . ./ COPY --chown=misskey:misskey . ./
ENV LD_PRELOAD=/usr/local/lib/libjemalloc.so
ENV NODE_ENV=production ENV NODE_ENV=production
HEALTHCHECK --interval=5s --retries=20 CMD ["/bin/bash", "/misskey/healthcheck.sh"] HEALTHCHECK --interval=5s --retries=20 CMD ["/bin/bash", "/misskey/healthcheck.sh"]
ENTRYPOINT ["/usr/bin/tini", "--"] ENTRYPOINT ["/usr/bin/tini", "--"]

View file

@ -1,18 +1,16 @@
<div align="center"> <div align="center">
<a href="https://misskey-hub.net"> <a href="https://misskey-hub.net">
<img src="./assets/title_float.svg" alt="Misskey logo" style="border-radius:50%" width="300"/> <img src="./assets/title_float.svg" alt="Misskey logo" style="border-radius:50%" width="400"/>
</a> </a>
**🌎 **Misskey** is an open source, federated social media platform that's free forever! 🚀** **🌎 **[Misskey](https://misskey-hub.net/)** is an open source, decentralized social media platform that's free forever! 🚀**
[Learn more](https://misskey-hub.net/)
--- ---
<a href="https://misskey-hub.net/servers/"> <a href="https://misskey-hub.net/instances.html">
<img src="https://custom-icon-badges.herokuapp.com/badge/find_an-instance-acea31?logoColor=acea31&style=for-the-badge&logo=misskey&labelColor=363B40" alt="find an instance"/></a> <img src="https://custom-icon-badges.herokuapp.com/badge/find_an-instance-acea31?logoColor=acea31&style=for-the-badge&logo=misskey&labelColor=363B40" alt="find an instance"/></a>
<a href="https://misskey-hub.net/docs/for-admin/install/guides/"> <a href="https://misskey-hub.net/docs/install.html">
<img src="https://custom-icon-badges.herokuapp.com/badge/create_an-instance-FBD53C?logoColor=FBD53C&style=for-the-badge&logo=server&labelColor=363B40" alt="create an instance"/></a> <img src="https://custom-icon-badges.herokuapp.com/badge/create_an-instance-FBD53C?logoColor=FBD53C&style=for-the-badge&logo=server&labelColor=363B40" alt="create an instance"/></a>
<a href="./CONTRIBUTING.md"> <a href="./CONTRIBUTING.md">
@ -23,27 +21,39 @@
<a href="https://www.patreon.com/syuilo"> <a href="https://www.patreon.com/syuilo">
<img src="https://custom-icon-badges.herokuapp.com/badge/become_a-patron-F96854?logoColor=F96854&style=for-the-badge&logo=patreon&labelColor=363B40" alt="become a patron"/></a> <img src="https://custom-icon-badges.herokuapp.com/badge/become_a-patron-F96854?logoColor=F96854&style=for-the-badge&logo=patreon&labelColor=363B40" alt="become a patron"/></a>
---
[![codecov](https://codecov.io/gh/misskey-dev/misskey/branch/develop/graph/badge.svg?token=R6IQZ3QJOL)](https://codecov.io/gh/misskey-dev/misskey)
</div> </div>
## Thanks <div>
<a href="https://sentry.io/"><img src="https://github.com/misskey-dev/misskey/assets/4439005/98576556-222f-467a-94be-e98dbda1d852" height="30" alt="Sentry" /></a> <a href="https://xn--931a.moe/"><img src="https://github.com/misskey-dev/misskey/blob/develop/assets/ai.png?raw=true" align="right" height="320px"/></a>
Thanks to [Sentry](https://sentry.io/) for providing the error tracking platform that helps us catch unexpected errors. ## ✨ Features
- **ActivityPub support**\
Not on Misskey? No problem! Not only can Misskey instances talk to each other, but you can make friends with people on other networks like Mastodon and Pixelfed!
- **Reactions**\
You can add emoji reactions to any post! No longer are you bound by a like button, show everyone exactly how you feel with the tap of a button.
- **Drive**\
With Misskey's built in drive, you get cloud storage right in your social media, where you can upload any files, make folders, and find media from posts you've made!
- **Rich Web UI**\
Misskey has a rich and easy to use Web UI!
It is highly customizable, from changing the layout and adding widgets to making custom themes.
Furthermore, plugins can be created using AiScript, an original programming language.
- And much more...
<a href="https://www.chromatic.com/"><img src="https://user-images.githubusercontent.com/321738/84662277-e3db4f80-af1b-11ea-88f5-91d67a5e59f6.png" height="30" alt="Chromatic" /></a> </div>
Thanks to [Chromatic](https://www.chromatic.com/) for providing the visual testing platform that helps us review UI changes and catch visual regressions. <div style="clear: both;"></div>
<a href="https://about.codecov.io/for/open-source/"><img src="https://about.codecov.io/wp-content/themes/codecov/assets/brand/sentry-cobranding/logos/codecov-by-sentry-logo.svg" height="30" alt="Codecov" /></a> ## Documentation
Thanks to [Codecov](https://about.codecov.io/for/open-source/) for providing the code coverage platform that helps us improve our test coverage. Misskey Documentation can be found at [Misskey Hub](https://misskey-hub.net/), some of the links and graphics above also lead to specific portions of it.
<a href="https://crowdin.com/"><img src="https://user-images.githubusercontent.com/20679825/230709597-1299a011-171a-4294-a91e-355a9b37c672.svg" height="30" alt="Crowdin" /></a> ## Sponsors
<div align="center">
Thanks to [Crowdin](https://crowdin.com/) for providing the localization platform that helps us translate Misskey into many languages. <a class="rss3" title="RSS3" href="https://rss3.io/" target="_blank"><img src="https://rss3.mypinata.cloud/ipfs/QmUG6H3Z7D5P511shn7sB4CPmpjH5uZWu4m5mWX7U3Gqbu" alt="RSS3" height="60"></a>
</div>
<a href="https://hub.docker.com/"><img src="https://user-images.githubusercontent.com/20679825/230148221-f8e73a32-a49b-47c3-9029-9a15c3824f92.png" height="30" alt="Docker" /></a>
Thanks to [Docker](https://hub.docker.com/) for providing the container platform that helps us run Misskey in production.

View file

@ -6,7 +6,6 @@ Also, the later tasks are more indefinite and are subject to change as developme
This is the phase we are at now. We need to make a high-maintenance environment that can withstand future development. This is the phase we are at now. We need to make a high-maintenance environment that can withstand future development.
- ~~Make the number of type errors zero (backend)~~ → Done ✔️ - ~~Make the number of type errors zero (backend)~~ → Done ✔️
- Make the number of type errors zero (frontend)
- Improve CI - Improve CI
- ~~Fix tests~~ → Done ✔️ - ~~Fix tests~~ → Done ✔️
- Fix random test failures - https://github.com/misskey-dev/misskey/issues/7985 and https://github.com/misskey-dev/misskey/issues/7986 - Fix random test failures - https://github.com/misskey-dev/misskey/issues/7985 and https://github.com/misskey-dev/misskey/issues/7986
@ -23,7 +22,7 @@ This is the phase we are at now. We need to make a high-maintenance environment
Once Phase 1 is complete and an environment conducive to the development of a stable system is in place, the implementation of new functions can begin gradually. Once Phase 1 is complete and an environment conducive to the development of a stable system is in place, the implementation of new functions can begin gradually.
- Improve features for moderation - Improve features for moderation
- ~~OAuth2 support https://github.com/misskey-dev/misskey/issues/8262~~ → Done ✔️ - OAuth2 support https://github.com/misskey-dev/misskey/issues/8262
- GraphQL support? - GraphQL support?
## (3) Improve scalability ## (3) Improve scalability

View file

@ -1,6 +1,7 @@
# Reporting Security Issues # Reporting Security Issues
If you discover a security issue in Misskey, please report it by **[this form](https://github.com/misskey-dev/misskey/security/advisories/new)**. If you discover a security issue in Misskey, please report it by sending an
email to [syuilotan@yahoo.co.jp](mailto:syuilotan@yahoo.co.jp).
This will allow us to assess the risk, and make a fix available before we add a This will allow us to assess the risk, and make a fix available before we add a
bug report to the GitHub repository. bug report to the GitHub repository.

View file

@ -23,13 +23,13 @@
</rdf:RDF> </rdf:RDF>
</metadata> </metadata>
<style> <style>
#g8 { #g8 {
animation-name: floating; animation-name: floating;
animation-duration: 3s; animation-duration: 3s;
animation-iteration-count: infinite; animation-iteration-count: infinite;
animation-timing-function: ease-in-out; animation-timing-function: ease-in-out;
} }
@keyframes floating { @keyframes floating {
0% { transform: translate(0, 0px); } 0% { transform: translate(0, 0px); }
50% { transform: translate(0, -5px); } 50% { transform: translate(0, -5px); }

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

View file

@ -72,75 +72,25 @@ db:
#extra: #extra:
# ssl: true # ssl: true
dbReplications: false
# You can configure any number of replicas here
#dbSlaves:
# -
# host:
# port:
# db:
# user:
# pass:
# -
# host:
# port:
# db:
# user:
# pass:
# ┌─────────────────────┐ # ┌─────────────────────┐
#───┘ Redis configuration └───────────────────────────────────── #───┘ Redis configuration └─────────────────────────────────────
redis: redis:
host: localhost host: localhost
port: 6379 port: 6379
#family: 0 # 0=Both, 4=IPv4, 6=IPv6
#pass: example-pass #pass: example-pass
#prefix: example-prefix #prefix: example-prefix
#db: 1 #db: 1
#redisForPubsub: # ┌─────────────────────────────┐
#───┘ Elasticsearch configuration └─────────────────────────────
#elasticsearch:
# host: localhost # host: localhost
# port: 6379 # port: 9200
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6 # ssl: false
# #pass: example-pass # user:
# #prefix: example-prefix # pass:
# #db: 1
#redisForJobQueue:
# host: localhost
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #db: 1
#redisForTimelines:
# host: redis
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #db: 1
#redisForReactions:
# host: redis
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #db: 1
# ┌───────────────────────────┐
#───┘ MeiliSearch configuration └─────────────────────────────
#meilisearch:
# host: localhost
# port: 7700
# apiKey: ''
# ssl: true
# index: ''
# ┌───────────────┐ # ┌───────────────┐
#───┘ ID generation └─────────────────────────────────────────── #───┘ ID generation └───────────────────────────────────────────
@ -151,7 +101,6 @@ redis:
# Available methods: # Available methods:
# aid ... Short, Millisecond accuracy # aid ... Short, Millisecond accuracy
# aidx ... Millisecond accuracy
# meid ... Similar to ObjectID, Millisecond accuracy # meid ... Similar to ObjectID, Millisecond accuracy
# ulid ... Millisecond accuracy # ulid ... Millisecond accuracy
# objectid ... This is left for backward compatibility # objectid ... This is left for backward compatibility
@ -159,23 +108,7 @@ redis:
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE # ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
# ID SETTINGS AFTER THAT! # ID SETTINGS AFTER THAT!
id: "aidx" id: "aid"
# ┌────────────────┐
#───┘ Error tracking └──────────────────────────────────────────
# Sentry is available for error tracking.
# See the Sentry documentation for more details on options.
#sentryForBackend:
# enableNodeProfiling: true
# options:
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
#sentryForFrontend:
# options:
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
# ┌─────────────────────┐ # ┌─────────────────────┐
#───┘ Other configuration └───────────────────────────────────── #───┘ Other configuration └─────────────────────────────────────
@ -191,7 +124,7 @@ id: "aidx"
# Job rate limiter # Job rate limiter
# deliverJobPerSec: 128 # deliverJobPerSec: 128
# inboxJobPerSec: 32 # inboxJobPerSec: 16
# Job attempts # Job attempts
# deliverJobMaxAttempts: 12 # deliverJobMaxAttempts: 12

View file

@ -27,7 +27,7 @@ spec:
ports: ports:
- containerPort: 3000 - containerPort: 3000
- name: postgres - name: postgres
image: postgres:15-alpine image: postgres:14-alpine
env: env:
- name: POSTGRES_USER - name: POSTGRES_USER
value: "example-misskey-user" value: "example-misskey-user"
@ -38,7 +38,7 @@ spec:
ports: ports:
- containerPort: 5432 - containerPort: 5432
- name: redis - name: redis
image: redis:7-alpine image: redis:alpine
ports: ports:
- containerPort: 6379 - containerPort: 6379
volumes: volumes:

View file

@ -1,40 +0,0 @@
# このconfigは、 dockerでMisskey本体を起動せず、 redisとpostgresql などだけを起動します
services:
redis:
restart: always
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- ./redis:/data
healthcheck:
test: "redis-cli ping"
interval: 5s
retries: 20
db:
restart: always
image: postgres:15-alpine
ports:
- "5432:5432"
env_file:
- .config/docker.env
volumes:
- ./db:/var/lib/postgresql/data
healthcheck:
test: "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"
interval: 5s
retries: 20
# meilisearch:
# restart: always
# image: getmeili/meilisearch:v1.3.4
# environment:
# - MEILI_NO_ANALYTICS=true
# - MEILI_ENV=production
# env_file:
# - .config/meilisearch.env
# volumes:
# - ./meili_data:/meili_data

View file

@ -1,8 +1,3 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
describe('Before setup instance', () => { describe('Before setup instance', () => {
beforeEach(() => { beforeEach(() => {
cy.resetState(); cy.resetState();
@ -23,7 +18,6 @@ describe('Before setup instance', () => {
cy.intercept('POST', '/api/admin/accounts/create').as('signup'); cy.intercept('POST', '/api/admin/accounts/create').as('signup');
cy.get('[data-cy-admin-initial-password] input').type('example_password_please_change_this_or_you_will_get_hacked');
cy.get('[data-cy-admin-username] input').type('admin'); cy.get('[data-cy-admin-username] input').type('admin');
cy.get('[data-cy-admin-password] input').type('admin1234'); cy.get('[data-cy-admin-password] input').type('admin1234');
cy.get('[data-cy-admin-ok]').click(); cy.get('[data-cy-admin-ok]').click();
@ -58,12 +52,6 @@ describe('After setup instance', () => {
cy.intercept('POST', '/api/signup').as('signup'); cy.intercept('POST', '/api/signup').as('signup');
cy.get('[data-cy-signup]').click(); cy.get('[data-cy-signup]').click();
cy.get('[data-cy-signup-rules-continue]').should('be.disabled');
cy.get('[data-cy-signup-rules-notes-agree] [data-cy-switch-toggle]').click();
cy.get('[data-cy-modal-dialog-ok]').click();
cy.get('[data-cy-signup-rules-continue]').should('not.be.disabled');
cy.get('[data-cy-signup-rules-continue]').click();
cy.get('[data-cy-signup-submit]').should('be.disabled'); cy.get('[data-cy-signup-submit]').should('be.disabled');
cy.get('[data-cy-signup-username] input').type('alice'); cy.get('[data-cy-signup-username] input').type('alice');
cy.get('[data-cy-signup-submit]').should('be.disabled'); cy.get('[data-cy-signup-submit]').should('be.disabled');
@ -83,12 +71,6 @@ describe('After setup instance', () => {
// ユーザー名が重複している場合の挙動確認 // ユーザー名が重複している場合の挙動確認
cy.get('[data-cy-signup]').click(); cy.get('[data-cy-signup]').click();
cy.get('[data-cy-signup-rules-continue]').should('be.disabled');
cy.get('[data-cy-signup-rules-notes-agree] [data-cy-switch-toggle]').click();
cy.get('[data-cy-modal-dialog-ok]').click();
cy.get('[data-cy-signup-rules-continue]').should('not.be.disabled');
cy.get('[data-cy-signup-rules-continue]').click();
cy.get('[data-cy-signup-username] input').type('alice'); cy.get('[data-cy-signup-username] input').type('alice');
cy.get('[data-cy-signup-password] input').type('alice1234'); cy.get('[data-cy-signup-password] input').type('alice1234');
cy.get('[data-cy-signup-password-retype] input').type('alice1234'); cy.get('[data-cy-signup-password-retype] input').type('alice1234');
@ -120,16 +102,11 @@ describe('After user signup', () => {
it('signin', () => { it('signin', () => {
cy.visitHome(); cy.visitHome();
cy.intercept('POST', '/api/signin-flow').as('signin'); cy.intercept('POST', '/api/signin').as('signin');
cy.get('[data-cy-signin]').click(); cy.get('[data-cy-signin]').click();
cy.get('[data-cy-signin-username] input').type('alice');
cy.get('[data-cy-signin-page-input]').should('be.visible', { timeout: 1000 }); // Enterキーでサインインできるかの確認も兼ねる
// Enterキーで続行できるかの確認も兼ねる
cy.get('[data-cy-signin-username] input').type('alice{enter}');
cy.get('[data-cy-signin-page-password]').should('be.visible', { timeout: 10000 });
// Enterキーで続行できるかの確認も兼ねる
cy.get('[data-cy-signin-password] input').type('alice1234{enter}'); cy.get('[data-cy-signin-password] input').type('alice1234{enter}');
cy.wait('@signin'); cy.wait('@signin');
@ -144,9 +121,8 @@ describe('After user signup', () => {
cy.visitHome(); cy.visitHome();
cy.get('[data-cy-signin]').click(); cy.get('[data-cy-signin]').click();
cy.get('[data-cy-signin-username] input').type('alice');
cy.get('[data-cy-signin-page-input]').should('be.visible', { timeout: 1000 }); cy.get('[data-cy-signin-password] input').type('alice1234{enter}');
cy.get('[data-cy-signin-username] input').type('alice{enter}');
// TODO: cypressにブラウザの言語指定できる機能が実装され次第英語のみテストするようにする // TODO: cypressにブラウザの言語指定できる機能が実装され次第英語のみテストするようにする
cy.contains(/アカウントが凍結されています|This account has been suspended due to/gi); cy.contains(/アカウントが凍結されています|This account has been suspended due to/gi);
@ -173,62 +149,10 @@ describe('After user signed in', () => {
}); });
it('successfully loads', () => { it('successfully loads', () => {
// 表示に時間がかかるのでデフォルト秒数だとタイムアウトする cy.get('[data-cy-open-post-form]').should('be.visible');
cy.get('[data-cy-user-setup-continue]', { timeout: 30000 }).should('be.visible');
}); });
it('account setup wizard', () => {
// 表示に時間がかかるのでデフォルト秒数だとタイムアウトする
cy.get('[data-cy-user-setup-continue]', { timeout: 30000 }).click();
cy.get('[data-cy-user-setup-user-name] input').type('ありす');
cy.get('[data-cy-user-setup-user-description] textarea').type('ほげ');
// TODO: アイコン設定テスト
cy.get('[data-cy-user-setup-continue]').click();
// プライバシー設定
cy.get('[data-cy-user-setup-continue]').click();
// フォローはスキップ
cy.get('[data-cy-user-setup-continue]').click();
// プッシュ通知設定はスキップ
cy.get('[data-cy-user-setup-continue]').click();
cy.get('[data-cy-user-setup-continue]').click();
});
});
describe('After user setup', () => {
beforeEach(() => {
cy.resetState();
// インスタンス初期セットアップ
cy.registerUser('admin', 'pass', true);
// ユーザー作成
cy.registerUser('alice', 'alice1234');
cy.login('alice', 'alice1234');
// アカウント初期設定ウィザード
// 表示に時間がかかるのでデフォルト秒数だとタイムアウトする
cy.get('[data-cy-user-setup] [data-cy-modal-window-close]', { timeout: 30000 }).click();
cy.get('[data-cy-modal-dialog-ok]').click();
});
afterEach(() => {
// テスト終了直前にページ遷移するようなテストケース(例えばアカウント作成)だと、たぶんCypressのバグでブラウザの内容が次のテストケースに引き継がれてしまう(例えばアカウントが作成し終わった段階からテストが始まる)。
// waitを入れることでそれを防止できる
cy.wait(1000);
});
it('note', () => { it('note', () => {
cy.get('[data-cy-open-post-form]').should('be.visible');
cy.get('[data-cy-open-post-form]').click(); cy.get('[data-cy-open-post-form]').click();
cy.get('[data-cy-post-form-text]').type('Hello, Misskey!'); cy.get('[data-cy-post-form-text]').type('Hello, Misskey!');
cy.get('[data-cy-open-post-form-submit]').click(); cy.get('[data-cy-open-post-form-submit]').click();

View file

@ -1,35 +0,0 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
describe('Router transition', () => {
describe('Redirect', () => {
// サーバの初期化。ルートのテストに関しては各describeごとに1度だけ実行で十分だと思う使いまわした方が早い
before(() => {
cy.resetState();
// インスタンス初期セットアップ
cy.registerUser('admin', 'pass', true);
// ユーザー作成
cy.registerUser('alice', 'alice1234');
cy.login('alice', 'alice1234');
// アカウント初期設定ウィザード
// 表示に時間がかかるのでデフォルト秒数だとタイムアウトする
cy.get('[data-cy-user-setup] [data-cy-modal-window-close]', { timeout: 30000 }).click();
cy.wait(500);
cy.get('[data-cy-modal-dialog-ok]').click();
});
it('redirect to user profile', () => {
// テストのためだけに用意されたリダイレクト用ルートに飛ぶ
cy.visit('/redirect-test');
// プロフィールページのURLであることを確認する
cy.url().should('include', '/@alice')
});
});
});

View file

@ -1,9 +1,3 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
/* flaky
describe('After user signed in', () => { describe('After user signed in', () => {
beforeEach(() => { beforeEach(() => {
cy.resetState(); cy.resetState();
@ -16,10 +10,6 @@ describe('After user signed in', () => {
cy.registerUser('alice', 'alice1234'); cy.registerUser('alice', 'alice1234');
cy.login('alice', 'alice1234'); cy.login('alice', 'alice1234');
// アカウント初期設定ウィザード
cy.get('[data-cy-user-setup] [data-cy-modal-window-close]').click();
cy.get('[data-cy-modal-dialog-ok]').click();
}); });
afterEach(() => { afterEach(() => {
@ -29,26 +19,26 @@ describe('After user signed in', () => {
}); });
it('widget edit toggle is visible', () => { it('widget edit toggle is visible', () => {
cy.get('[data-cy-widget-edit]').should('be.visible'); cy.get('.mk-widget-edit').should('be.visible');
}); });
it('widget select should be visible in edit mode', () => { it('widget select should be visible in edit mode', () => {
cy.get('[data-cy-widget-edit]').click(); cy.get('.mk-widget-edit').click();
cy.get('[data-cy-widget-select]').should('be.visible'); cy.get('.mk-widget-select').should('be.visible');
}); });
it('first widget should be removed', () => { it('first widget should be removed', () => {
cy.get('[data-cy-widget-edit]').click(); cy.get('.mk-widget-edit').click();
cy.get('[data-cy-customize-container]:first-child [data-cy-customize-container-remove]._button').click(); cy.get('[data-cy-customize-container]:first-child [data-cy-customize-container-remove]._button').click();
cy.get('[data-cy-customize-container]').should('have.length', 2); cy.get('[data-cy-customize-container]').should('have.length', 2);
}); });
function buildWidgetTest(widgetName) { function buildWidgetTest(widgetName) {
it(`${widgetName} widget should get added`, () => { it(`${widgetName} widget should get added`, () => {
cy.get('[data-cy-widget-edit]').click(); cy.get('.mk-widget-edit').click();
cy.get('[data-cy-widget-select] select').select(widgetName, { force: true }); cy.get('.mk-widget-select select').select(widgetName, { force: true });
cy.get('[data-cy-bg]._modalBg[data-cy-transparent]').click({ multiple: true, force: true }); cy.get('[data-cy-bg]._modalBg[data-cy-transparent]').click({ multiple: true, force: true });
cy.get('[data-cy-widget-add]').click({ force: true }); cy.get('.mk-widget-add').click({ force: true });
cy.get(`[data-cy-mkw-${widgetName}]`).should('exist'); cy.get(`[data-cy-mkw-${widgetName}]`).should('exist');
}); });
} }
@ -73,4 +63,3 @@ describe('After user signed in', () => {
buildWidgetTest('aiscript'); buildWidgetTest('aiscript');
buildWidgetTest('aichan'); buildWidgetTest('aichan');
}); });
*/

View file

@ -30,13 +30,9 @@ Cypress.Commands.add('visitHome', () => {
}) })
Cypress.Commands.add('resetState', () => { Cypress.Commands.add('resetState', () => {
// iframe.contentWindow.indexedDB.deleteDatabase() がchromeのバグで使用できないため、indexedDBを無効化している。 cy.window(win => {
// see https://github.com/misskey-dev/misskey/issues/13605#issuecomment-2053652123
/*
cy.window().then(win => {
win.indexedDB.deleteDatabase('keyval-store'); win.indexedDB.deleteDatabase('keyval-store');
}); });
*/
cy.request('POST', '/api/reset-db', {}).as('reset'); cy.request('POST', '/api/reset-db', {}).as('reset');
cy.get('@reset').its('status').should('equal', 204); cy.get('@reset').its('status').should('equal', 204);
cy.reload(true); cy.reload(true);
@ -48,19 +44,16 @@ Cypress.Commands.add('registerUser', (username, password, isAdmin = false) => {
cy.request('POST', route, { cy.request('POST', route, {
username: username, username: username,
password: password, password: password,
...(isAdmin ? { setupPassword: 'example_password_please_change_this_or_you_will_get_hacked' } : {}),
}).its('body').as(username); }).its('body').as(username);
}); });
Cypress.Commands.add('login', (username, password) => { Cypress.Commands.add('login', (username, password) => {
cy.visitHome(); cy.visitHome();
cy.intercept('POST', '/api/signin-flow').as('signin'); cy.intercept('POST', '/api/signin').as('signin');
cy.get('[data-cy-signin]').click(); cy.get('[data-cy-signin]').click();
cy.get('[data-cy-signin-page-input]').should('be.visible', { timeout: 1000 }); cy.get('[data-cy-signin-username] input').type(username);
cy.get('[data-cy-signin-username] input').type(`${username}{enter}`);
cy.get('[data-cy-signin-page-password]').should('be.visible', { timeout: 10000 });
cy.get('[data-cy-signin-password] input').type(`${password}{enter}`); cy.get('[data-cy-signin-password] input').type(`${password}{enter}`);
cy.wait('@signin').as('signedIn'); cy.wait('@signin').as('signedIn');

View file

@ -21,8 +21,6 @@ import './commands'
Cypress.on('uncaught:exception', (err, runnable) => { Cypress.on('uncaught:exception', (err, runnable) => {
if ([ if ([
'The source image cannot be decoded',
// Chrome // Chrome
'ResizeObserver loop limit exceeded', 'ResizeObserver loop limit exceeded',

View file

@ -1,19 +0,0 @@
declare global {
namespace Cypress {
interface Chainable {
login(username: string, password: string): Chainable<void>;
registerUser(
username: string,
password: string,
isAdmin?: boolean
): Chainable<void>;
resetState(): Chainable<void>;
visitHome(): Chainable<void>;
}
}
}
export {}

View file

@ -1,8 +0,0 @@
{
"compilerOptions": {
"lib": ["dom", "es5"],
"target": "es5",
"types": ["cypress", "node"]
},
"include": ["./**/*.ts"]
}

View file

@ -1,3 +1,5 @@
version: "3"
services: services:
web: web:
build: . build: .
@ -5,8 +7,7 @@ services:
links: links:
- db - db
- redis - redis
# - mcaptcha # - es
# - meilisearch
depends_on: depends_on:
db: db:
condition: service_healthy condition: service_healthy
@ -17,8 +18,6 @@ services:
networks: networks:
- internal_network - internal_network
- external_network - external_network
# env_file:
# - .config/docker.env
volumes: volumes:
- ./files:/misskey/files - ./files:/misskey/files
- ./.config:/misskey/.config:ro - ./.config:/misskey/.config:ro
@ -49,48 +48,16 @@ services:
interval: 5s interval: 5s
retries: 20 retries: 20
# mcaptcha: # es:
# restart: always # restart: always
# image: mcaptcha/mcaptcha:latest # image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.4.2
# networks:
# internal_network:
# external_network:
# aliases:
# - localhost
# ports:
# - 7493:7493
# env_file:
# - .config/docker.env
# environment: # environment:
# PORT: 7493 # - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
# MCAPTCHA_redis_URL: "redis://mcaptcha_redis/" # - "TAKE_FILE_OWNERSHIP=111"
# depends_on:
# db:
# condition: service_healthy
# mcaptcha_redis:
# condition: service_healthy
#
# mcaptcha_redis:
# image: mcaptcha/cache:latest
# networks:
# - internal_network
# healthcheck:
# test: "redis-cli ping"
# interval: 5s
# retries: 20
# meilisearch:
# restart: always
# image: getmeili/meilisearch:v1.3.4
# environment:
# - MEILI_NO_ANALYTICS=true
# - MEILI_ENV=production
# env_file:
# - .config/meilisearch.env
# networks: # networks:
# - internal_network # - internal_network
# volumes: # volumes:
# - ./meili_data:/meili_data # - ./elasticsearch:/usr/share/elasticsearch/data
networks: networks:
internal_network: internal_network:

25
docs/DONATORS.md Normal file
View file

@ -0,0 +1,25 @@
DONATORS
========
The list of people who have sent donation for Misskey.
(In random order, honorific titles are omitted.)
* らふぁ
* 俺様
* なぎうり
* スルメ https://surume.tk/
* 藍
* 音船 https://otofune.me/
* aqz https://misskey.xyz/aqz
* kotodu "虚無創作中"
* Maya Minatsuki
* Knzk https://knzk.me/@Knzk
* ねじりわさび https://knzk.me/@y
* NCLS https://knzk.me/@imncls]
* こじま @skoji@sandbox.skoji.jp
:heart: Thanks for donating, guys!
---
If your name is missing, please contact us!

65
gulpfile.js Normal file
View file

@ -0,0 +1,65 @@
/**
* Gulp tasks
*/
const fs = require('fs');
const gulp = require('gulp');
const replace = require('gulp-replace');
const terser = require('gulp-terser');
const cssnano = require('gulp-cssnano');
const locales = require('./locales');
const meta = require('./package.json');
gulp.task('copy:backend:views', () =>
gulp.src('./packages/backend/src/server/web/views/**/*').pipe(gulp.dest('./packages/backend/built/server/web/views'))
);
gulp.task('copy:frontend:fonts', () =>
gulp.src('./packages/frontend/node_modules/three/examples/fonts/**/*').pipe(gulp.dest('./built/_frontend_dist_/fonts/'))
);
gulp.task('copy:frontend:tabler-icons', () =>
gulp.src('./packages/frontend/node_modules/@tabler/icons-webfont/**/*').pipe(gulp.dest('./built/_frontend_dist_/tabler-icons/'))
);
gulp.task('copy:frontend:locales', cb => {
fs.mkdirSync('./built/_frontend_dist_/locales', { recursive: true });
const v = { '_version_': meta.version };
for (const [lang, locale] of Object.entries(locales)) {
fs.writeFileSync(`./built/_frontend_dist_/locales/${lang}.${meta.version}.json`, JSON.stringify({ ...locale, ...v }), 'utf-8');
}
cb();
});
gulp.task('build:backend:script', () => {
return gulp.src(['./packages/backend/src/server/web/boot.js', './packages/backend/src/server/web/bios.js', './packages/backend/src/server/web/cli.js'])
.pipe(replace('LANGS', JSON.stringify(Object.keys(locales))))
.pipe(terser({
toplevel: true
}))
.pipe(gulp.dest('./packages/backend/built/server/web/'));
});
gulp.task('build:backend:style', () => {
return gulp.src(['./packages/backend/src/server/web/style.css', './packages/backend/src/server/web/bios.css', './packages/backend/src/server/web/cli.css'])
.pipe(cssnano({
zindex: false
}))
.pipe(gulp.dest('./packages/backend/built/server/web/'));
});
gulp.task('build', gulp.parallel(
'copy:frontend:locales', 'copy:backend:views', 'build:backend:script', 'build:backend:style', 'copy:frontend:fonts', 'copy:frontend:tabler-icons'
));
gulp.task('default', gulp.task('build'));
gulp.task('watch', () => {
gulp.watch([
'./packages/*/src/**/*',
], { ignoreInitial: false }, gulp.task('build'));
});

View file

@ -1,7 +1,4 @@
#!/bin/bash #!/bin/bash
# SPDX-FileCopyrightText: syuilo and misskey-project
# SPDX-License-Identifier: AGPL-3.0-only
PORT=$(grep '^port:' /misskey/.config/default.yml | awk 'NR==1{print $2; exit}') PORT=$(grep '^port:' /misskey/.config/default.yml | awk 'NR==1{print $2; exit}')
curl -Sfso/dev/null "http://localhost:${PORT}/healthz" curl -s -S -o /dev/null "http://localhost:${PORT}"

View file

@ -1,54 +0,0 @@
/*
* 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 { abuseUserReport } from '../packages/frontend/.storybook/fakes.js';
import { commonHandlers } from '../packages/frontend/.storybook/mocks.js';
import MkAbuseReport from './MkAbuseReport.vue';
export const Default = {
render(args) {
return {
components: {
MkAbuseReport,
},
setup() {
return {
args,
};
},
computed: {
props() {
return {
...this.args,
};
},
events() {
return {
resolved: action('resolved'),
};
},
},
template: '<MkAbuseReport v-bind="props" v-on="events" />',
};
},
args: {
report: abuseUserReport(),
},
parameters: {
layout: 'fullscreen',
msw: {
handlers: [
...commonHandlers,
http.post('/api/admin/resolve-abuse-user-report', async ({ request }) => {
action('POST /api/admin/resolve-abuse-user-report')(await request.json());
return HttpResponse.json({});
}),
],
},
},
} satisfies StoryObj<typeof MkAbuseReport>;

View file

@ -1,41 +0,0 @@
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<div :class="[$style.root]">
<div :inert="disabled" :class="[{ [$style.disabled]: disabled }]">
<slot></slot>
</div>
<div v-if="disabled" :class="[$style.cover]"></div>
</div>
</template>
<script lang="ts" setup>
defineProps<{
disabled?: boolean;
}>();
</script>
<style lang="scss" module>
.root {
position: relative;
}
.disabled {
opacity: 0.7;
}
.cover {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
cursor: not-allowed;
--color: color(from var(--MI_THEME-error) srgb r g b / 0.25);
background-size: auto auto;
background-image: repeating-linear-gradient(135deg, transparent, transparent 10px, var(--color) 4px, var(--color) 14px);
}
</style>

View file

@ -1 +0,0 @@
使われなくなったけど消すのは勿体ない(将来使えるかもしれない)コードを入れておくとこ

View file

@ -2,7 +2,6 @@
_lang_: "العربية" _lang_: "العربية"
headlineMisskey: "شبكة مرتبطة بالملاحظات" headlineMisskey: "شبكة مرتبطة بالملاحظات"
introMisskey: "اهلا بك! ميسكي هو منصة تدوين مصغر لا مركزية ومفتوحة المصدر.\nيمكنك مشاركة \"ملاحظات\" عن ما يجري حولك، وإخبار الجميع عن نفسك 📡\nتسمح لك \"الانفعالات\" بتعبير عن شعورك حول ملاحظات الآخرين 👍\nاكتشف عالمًا جديدًا 🚀" introMisskey: "اهلا بك! ميسكي هو منصة تدوين مصغر لا مركزية ومفتوحة المصدر.\nيمكنك مشاركة \"ملاحظات\" عن ما يجري حولك، وإخبار الجميع عن نفسك 📡\nتسمح لك \"الانفعالات\" بتعبير عن شعورك حول ملاحظات الآخرين 👍\nاكتشف عالمًا جديدًا 🚀"
poweredByMisskeyDescription: "{name} هو إحدى الخِدمات التي تستخدم المنصة مفتوحة المصدر <b>ميسكي</b> (يشار إليه كمثيل ميسكي)"
monthAndDay: "{day}/{month}" monthAndDay: "{day}/{month}"
search: "البحث" search: "البحث"
notifications: "الإشعارات" notifications: "الإشعارات"
@ -20,7 +19,6 @@ noNotes: "لم يُعثر على أية ملاحظات"
noNotifications: "ليس هناك أية اشعارات" noNotifications: "ليس هناك أية اشعارات"
instance: "مثيل الخادم" instance: "مثيل الخادم"
settings: "الاعدادات" settings: "الاعدادات"
notificationSettings: "إعدادات الإشعارات"
basicSettings: "الاعدادات الأساسية" basicSettings: "الاعدادات الأساسية"
otherSettings: "إعدادات أخرى" otherSettings: "إعدادات أخرى"
openInWindow: "افتح في نافذة جديدة" openInWindow: "افتح في نافذة جديدة"
@ -41,23 +39,16 @@ unfavorite: "إزالة من المفضلة"
favorited: "أُضيف إلى المفضلة." favorited: "أُضيف إلى المفضلة."
alreadyFavorited: "تمت إضافته بالفعل إلى المفضلة." alreadyFavorited: "تمت إضافته بالفعل إلى المفضلة."
cantFavorite: "تعذرت الإضافة إلى المفضلة." cantFavorite: "تعذرت الإضافة إلى المفضلة."
pin: "ثبتها على الصفحة الشخصية" pin: "دبّسها على الصفحة الشخصية"
unpin: "فكها من ملفك الشخصي" unpin: "ألغ تدبيسها من ملفك الشخصي"
copyContent: "انسخ المحتوى" copyContent: "انسخ المحتوى"
copyLink: "انسخ الرابط" copyLink: "انسخ الرابط"
delete: "حذف" delete: "حذف"
deleteAndEdit: "إزالة وإعادة الصياغة" deleteAndEdit: "إزالة وإعادة الصياغة"
deleteAndEditConfirm: "أمتأكد من حذف الملاحظة؟ ستفقد كل مشاركاتها، والتفاعلات، والردود عليها." deleteAndEditConfirm: "أمتأكد من حذف الملاحظة؟ ستفقد كل مشاركاتها، والتفاعلات، والردود عليها."
addToList: "أضفه إلى قائمة" addToList: "أضفه إلى قائمة"
addToAntenna: "أضف إلى هوائي"
sendMessage: "أرسل رسالة" sendMessage: "أرسل رسالة"
copyRSS: "انسخ رابط RSS"
copyUsername: "انسخ اسم المستخدم" copyUsername: "انسخ اسم المستخدم"
copyUserId: "انسخ معرف المستخدم"
copyNoteId: "انسخ معرف الملاحظة"
copyFileId: "انسخ معرّف الملف"
copyFolderId: "انسخ معرّف المجلد"
copyProfileUrl: "انسخ رابط الملف الشخصي"
searchUser: "ابحث عن مستخدمين" searchUser: "ابحث عن مستخدمين"
reply: "رد" reply: "رد"
loadMore: "عرض المزيد" loadMore: "عرض المزيد"
@ -110,27 +101,23 @@ renoted: "أُعيد نشره"
cantRenote: "لا يمكن إعادة نشر الملاحظة" cantRenote: "لا يمكن إعادة نشر الملاحظة"
cantReRenote: "لا يمكنك إعادة نشر ملاحظة معاد نشرها" cantReRenote: "لا يمكنك إعادة نشر ملاحظة معاد نشرها"
quote: "اقتبس" quote: "اقتبس"
inChannelRenote: "إعادة نشر في قناة" pinnedNote: "ملاحظة مدبسة"
inChannelQuote: "اقتباس في قناة" pinned: "دبّسها على الصفحة الشخصية"
pinnedNote: "ملاحظة مثبتة"
pinned: "ثبتها على الصفحة الشخصية"
you: "أنت" you: "أنت"
clickToShow: "اضغط للعرض" clickToShow: "اضغط للعرض"
sensitive: "محتوى حساس" sensitive: "محتوى حساس"
add: "إضافة" add: "إضافة"
reaction: "التفاعلات" reaction: "التفاعلات"
reactions: "التفاعلات" reactions: "التفاعلات"
reactionSetting: "التفاعلات المراد عرضها في منتقي التفاعلات."
reactionSettingDescription2: "اسحب لترتيب ، انقر للحذف ، استخدم \"+\" للإضافة." reactionSettingDescription2: "اسحب لترتيب ، انقر للحذف ، استخدم \"+\" للإضافة."
rememberNoteVisibility: "تذكر إعدادت مدى رؤية الملاحظات" rememberNoteVisibility: "تذكر إعدادت مدى رؤية الملاحظات"
attachCancel: "أزل المرفق" attachCancel: "أزل المرفق"
deleteFile: "حُذف الملف"
markAsSensitive: "علّمه كمحتوى حساس" markAsSensitive: "علّمه كمحتوى حساس"
unmarkAsSensitive: "ألغ تعيينه كمحتوى حساس" unmarkAsSensitive: "ألغ تعيينه كمحتوى حساس"
enterFileName: "ادخل اسم الملف" enterFileName: "ادخل اسم الملف"
mute: "اكتم" mute: "اكتم"
unmute: "إلغاء الكتم" unmute: "إلغاء الكتم"
renoteMute: "اكتم إعادة النشر"
renoteUnmute: "ارفع الكتم عن إعادة النشر"
block: "احجب" block: "احجب"
unblock: "إلغاء الحجب" unblock: "إلغاء الحجب"
suspend: "علِق" suspend: "علِق"
@ -140,10 +127,7 @@ unblockConfirm: "أمتأكد من إلغاء حجب هذا الحساب؟"
suspendConfirm: "أمتأكد من تعليق الحساب؟" suspendConfirm: "أمتأكد من تعليق الحساب؟"
unsuspendConfirm: "أمتأكد من إلغاء تعليق؟" unsuspendConfirm: "أمتأكد من إلغاء تعليق؟"
selectList: "اختر قائمة" selectList: "اختر قائمة"
editList: "عدّل القائمة"
selectChannel: "اختر قناة"
selectAntenna: "اختر هوائيًا" selectAntenna: "اختر هوائيًا"
editAntenna: "عدّل الهوائي"
selectWidget: "اختر ودجة" selectWidget: "اختر ودجة"
editWidgets: "عدّل الودجات" editWidgets: "عدّل الودجات"
editWidgetsExit: "تم" editWidgetsExit: "تم"
@ -155,7 +139,6 @@ emojiUrl: "رابط الإيموجي"
addEmoji: "إضافة إيموجي" addEmoji: "إضافة إيموجي"
settingGuide: "الإعدادات المستحسنة" settingGuide: "الإعدادات المستحسنة"
cacheRemoteFiles: "خزن مؤقتا الملفات البعيدة" cacheRemoteFiles: "خزن مؤقتا الملفات البعيدة"
cacheRemoteFilesDescription: "إذا عُطل هذا الإعداد، ستُحمل الملفات من المثيل البعيد، هذا سيقلل من المساحة المستغلة على القرص لكن سيزيد حجم تدفق البيانات وهذا لأن الصور المصغرة لن تولّد."
flagAsBot: "علّمه كحساب آلي" flagAsBot: "علّمه كحساب آلي"
flagAsBotDescription: "فعّل هذا الخيار إذا كان هذا الحساب يُدار عبر برمجية. إذا فُعل فسيكون بمثابة علامة للمطورين الآخرين لتجنب سلاسل لا متناهية من التفاعل بين حسابات الآلية وضبط أنظمة ميسكي للتعامل مع هذا الحساب كآلي." flagAsBotDescription: "فعّل هذا الخيار إذا كان هذا الحساب يُدار عبر برمجية. إذا فُعل فسيكون بمثابة علامة للمطورين الآخرين لتجنب سلاسل لا متناهية من التفاعل بين حسابات الآلية وضبط أنظمة ميسكي للتعامل مع هذا الحساب كآلي."
flagAsCat: "علّم هذا الحساب كحساب قط" flagAsCat: "علّم هذا الحساب كحساب قط"
@ -214,7 +197,7 @@ blockedUsers: "الحسابات المحجوبة"
noUsers: "ليس هناك مستخدمون" noUsers: "ليس هناك مستخدمون"
editProfile: "تعديل الملف التعريفي" editProfile: "تعديل الملف التعريفي"
noteDeleteConfirm: "هل تريد حذف هذه الملاحظة؟" noteDeleteConfirm: "هل تريد حذف هذه الملاحظة؟"
pinLimitExceeded: "لا يمكنك تثبيت الملاحظات بعد الآن." pinLimitExceeded: "لا يمكنك تدبيس الملاحظات بعد الآن."
intro: "لقد انتهت عملية تنصيب Misskey. الرجاء إنشاء حساب إداري." intro: "لقد انتهت عملية تنصيب Misskey. الرجاء إنشاء حساب إداري."
done: "تمّ" done: "تمّ"
processing: "المعالجة جارية" processing: "المعالجة جارية"
@ -267,16 +250,12 @@ noMoreHistory: "لا يوجد المزيد من التاريخ"
startMessaging: "ابدأ محادثة" startMessaging: "ابدأ محادثة"
nUsersRead: "قرأه {n}" nUsersRead: "قرأه {n}"
agreeTo: "اوافق على {0}" agreeTo: "اوافق على {0}"
agree: "أقبل" tos: "شروط الخدمة"
agreeBelow: "أقبل ما يلي"
basicNotesBeforeCreateAccount: "ملاحظات مهمة"
termsOfService: "شروط الخدمة"
start: "البداية" start: "البداية"
home: "الرئيسي" home: "الرئيسي"
remoteUserCaution: "هذه المعلومات قد لا تكون مكتملة بما أن المستخدم من مثيل بعيد." remoteUserCaution: "هذه المعلومات قد لا تكون مكتملة بما أن المستخدم من مثيل بعيد."
activity: "النشاط" activity: "النشاط"
images: "صور" images: "الصور"
image: "صور"
birthday: "تاريخ الميلاد" birthday: "تاريخ الميلاد"
yearsOld: "{age} سنة" yearsOld: "{age} سنة"
registeredDate: "انضم في" registeredDate: "انضم في"
@ -313,7 +292,7 @@ copyUrl: "انسخ الرابط"
rename: "إعادة التسمية" rename: "إعادة التسمية"
avatar: "الصورة الرمزية" avatar: "الصورة الرمزية"
banner: "الصورة الرأسية" banner: "الصورة الرأسية"
displayOfSensitiveMedia: "عرض المحتوى الحساس" nsfw: "محتوى حساس"
whenServerDisconnected: "عند فقدان الاتصال بالخادم" whenServerDisconnected: "عند فقدان الاتصال بالخادم"
disconnectedFromServer: "قُطِع الإتصال بالخادم" disconnectedFromServer: "قُطِع الإتصال بالخادم"
reload: "انعش" reload: "انعش"
@ -348,21 +327,20 @@ invite: "دعوة"
driveCapacityPerLocalAccount: "حصة التخزين لكل مستخدم محلي" driveCapacityPerLocalAccount: "حصة التخزين لكل مستخدم محلي"
driveCapacityPerRemoteAccount: "حصة التخزين لكل مستخدم بعيد" driveCapacityPerRemoteAccount: "حصة التخزين لكل مستخدم بعيد"
inMb: "بالميغابايت" inMb: "بالميغابايت"
iconUrl: "رابط الأيقونة"
bannerUrl: "رابط صورة اللافتة" bannerUrl: "رابط صورة اللافتة"
backgroundImageUrl: "رابط صورة الخلفية" backgroundImageUrl: "رابط صورة الخلفية"
basicInfo: "المعلومات الأساسية " basicInfo: "المعلومات الأساسية "
pinnedUsers: "المستخدمون المثبتون" pinnedUsers: "المستخدمون المدبسون"
pinnedUsersDescription: "قائمة المستخدمين المثبتين في لسان \"استكشف\" ، اجعل كل اسم مستخدم في سطر لوحده." pinnedUsersDescription: "قائمة المستخدمين المدبسين في لسان \"استكشف\" ، اجعل كل اسم مستخدم في سطر لوحده."
pinnedPages: "الصفحات المثبتة" pinnedPages: "الصفحات المدبسة"
pinnedPagesDescription: "أدخل مسار الصفحات التي تريد تثبيتها في أعلى هذا الموقع، اجعل كل مسار في سطر لوحده." pinnedPagesDescription: "أدخل مسار الصفحات التي تريد تدبيسها في أعلى هذا الموقع، اجعل كل مسار في سطر لوحده."
pinnedClipId: "معرّف المشبك المثبت" pinnedClipId: "معرّف المشبك المدبس"
pinnedNotes: "ملاحظة مثبتة" pinnedNotes: "ملاحظة مدبسة"
hcaptcha: "hCaptcha" hcaptcha: "hCaptcha"
enableHcaptcha: "فعّل hCaptcha" enableHcaptcha: "فعّل hCaptcha"
hcaptchaSiteKey: "مفتاح الموقع" hcaptchaSiteKey: "مفتاح الموقع"
hcaptchaSecretKey: "المفتاح السري" hcaptchaSecretKey: "المفتاح السري"
mcaptchaSiteKey: "مفتاح الموقع"
mcaptchaSecretKey: "المفتاح السري"
recaptcha: "reCAPTCHA" recaptcha: "reCAPTCHA"
enableRecaptcha: "تمكين reCAPTCHA" enableRecaptcha: "تمكين reCAPTCHA"
recaptchaSiteKey: "مفتاح الموقع" recaptchaSiteKey: "مفتاح الموقع"
@ -379,7 +357,6 @@ antennaExcludeKeywords: "الكلمات المفتاحية المستثناة"
antennaKeywordsDescription: "افصل بينهم بمسافة لاستخدام معامل \"و\" أو بسطر لاستخدام معامل \"أو\"" antennaKeywordsDescription: "افصل بينهم بمسافة لاستخدام معامل \"و\" أو بسطر لاستخدام معامل \"أو\""
notifyAntenna: "نبهني بصول ملاحظات جديدة" notifyAntenna: "نبهني بصول ملاحظات جديدة"
withFileAntenna: "ملاحظات تحوي ملفات فقط" withFileAntenna: "ملاحظات تحوي ملفات فقط"
enableServiceworker: "فعّل إرسال الإشعارات للمتصفح"
antennaUsersDescription: "اكتب اسم مستخدم لكل سطر" antennaUsersDescription: "اكتب اسم مستخدم لكل سطر"
caseSensitive: "حساسية حالة الأحرف" caseSensitive: "حساسية حالة الأحرف"
withReplies: "بالردود" withReplies: "بالردود"
@ -402,15 +379,11 @@ about: "عن"
aboutMisskey: "عن Misskey" aboutMisskey: "عن Misskey"
administrator: "المدير" administrator: "المدير"
token: "الرمز المميز" token: "الرمز المميز"
2fa: "الاستيثاق بعاملَيْن"
totp: "تطبيق استيثاق"
moderator: "مشرِف" moderator: "مشرِف"
moderation: "الإشراف" moderation: "الإشراف"
nUsersMentioned: "{n} مستخدمين أُشير إليهم" nUsersMentioned: "{n} مستخدمين أُشير إليهم"
securityKeyAndPasskey: "الأمن ومفاتيح الأمان"
securityKey: "مفتاح الأمان" securityKey: "مفتاح الأمان"
lastUsed: "آخر استخدام" lastUsed: "آخر استخدام"
lastUsedAt: "آخر استخدام: {t}"
unregister: "إلغاء التسجيل" unregister: "إلغاء التسجيل"
passwordLessLogin: "لِج مِن دون كلمة سرية" passwordLessLogin: "لِج مِن دون كلمة سرية"
resetPassword: "أعد تعيين كلمتك السرية" resetPassword: "أعد تعيين كلمتك السرية"
@ -420,6 +393,7 @@ share: "شارِك"
notFound: "غير موجود" notFound: "غير موجود"
notFoundDescription: "تعذر العثور على صفحة يقود إليها هذا الرابط." notFoundDescription: "تعذر العثور على صفحة يقود إليها هذا الرابط."
uploadFolder: "المجلد الافتراضي للرفع" uploadFolder: "المجلد الافتراضي للرفع"
cacheClear: "مسح ذاكرة التخزين المؤقت"
markAsReadAllNotifications: "وضع جميع الإشعارات كأنها مقروءة" markAsReadAllNotifications: "وضع جميع الإشعارات كأنها مقروءة"
markAsReadAllUnreadNotes: "علّم جميع الملاحظات كمقروءة" markAsReadAllUnreadNotes: "علّم جميع الملاحظات كمقروءة"
markAsReadAllTalkMessages: "علّم جميع الرسائل كمقروءة" markAsReadAllTalkMessages: "علّم جميع الرسائل كمقروءة"
@ -460,8 +434,6 @@ or: "أو"
language: "اللغة" language: "اللغة"
uiLanguage: "لغة واجهة المستخدم" uiLanguage: "لغة واجهة المستخدم"
aboutX: "عن {x}" aboutX: "عن {x}"
emojiStyle: "نمط الوجوه التعبيرية"
showNoteActionsOnlyHover: "أظهر الإجراءات عند التمرير فوق الملاحظة"
noHistory: "السجل فارغ" noHistory: "السجل فارغ"
signinHistory: "تاريخ تسجيل الدخول" signinHistory: "تاريخ تسجيل الدخول"
doing: "انتظر لحظة" doing: "انتظر لحظة"
@ -472,7 +444,6 @@ createAccount: "أنشئ حسابًا"
existingAccount: "الحسابات الموجودة" existingAccount: "الحسابات الموجودة"
regenerate: "أعِد التوليد" regenerate: "أعِد التوليد"
fontSize: "حجم الخط" fontSize: "حجم الخط"
limitTo: "سقفهُ لـ{x}"
noFollowRequests: "ليس لديك طلبات متابعة معلقة" noFollowRequests: "ليس لديك طلبات متابعة معلقة"
openImageInNewTab: "إفتح الصورة بصفحة جديدة" openImageInNewTab: "إفتح الصورة بصفحة جديدة"
dashboard: "لوحة التحكم" dashboard: "لوحة التحكم"
@ -494,16 +465,13 @@ objectStoragePrefix: "البادئة"
objectStoragePrefixDesc: "ستُحفظ الملفات في مجلدات تحوي اسماءها هذه البادئة." objectStoragePrefixDesc: "ستُحفظ الملفات في مجلدات تحوي اسماءها هذه البادئة."
objectStorageEndpoint: "نقطة النهاية" objectStorageEndpoint: "نقطة النهاية"
objectStorageRegion: "المنطقة" objectStorageRegion: "المنطقة"
objectStorageRegionDesc: "حدد منطقة مثل \"xx-east-1\". إذا كانت خدمتك لا تميز بين المناطق استخدم \"us-east-1\" أو اتركها فارغة إذا كنت تستخدم متغيرات البيئة أو ملفات ضبط AWS."
objectStorageUseSSL: "استخدم SSL" objectStorageUseSSL: "استخدم SSL"
objectStorageUseSSLDesc: "عطل هذا الخيار إذا لم ترد استخدام API عبر HTTPS" objectStorageUseSSLDesc: "عطل هذا الخيار إذا لم ترد استخدام API عبر HTTPS"
objectStorageUseProxy: "اتصل عبر وكيل" objectStorageUseProxy: "اتصل عبر وكيل"
objectStorageUseProxyDesc: "عطل هذا الخيار إذا لم ترد استخدام API عبر وكيل" objectStorageUseProxyDesc: "عطل هذا الخيار إذا لم ترد استخدام API عبر وكيل"
objectStorageSetPublicRead: "عينها ك\"علنية\" عند الرفع"
serverLogs: "سجلات الخادم" serverLogs: "سجلات الخادم"
deleteAll: "حذف الكل" deleteAll: "حذف الكل"
showFixedPostForm: "أظهر نموذج الكتابة في أعلى الصفحة" showFixedPostForm: "أظهر نموذج الكتابة في أعلى الصفحة"
showFixedPostFormInChannel: "أظهر نموذج الكتابة في أعلى الخط الزمني (قنوات)"
newNoteRecived: "هناك ملاحظات جديدة" newNoteRecived: "هناك ملاحظات جديدة"
sounds: "الرنات" sounds: "الرنات"
sound: "الرنات" sound: "الرنات"
@ -538,12 +506,9 @@ userSuspended: "عُلق هذا المستخدم."
userSilenced: "كُتم هذا المستخدم." userSilenced: "كُتم هذا المستخدم."
yourAccountSuspendedTitle: "هذا الحساب معلق" yourAccountSuspendedTitle: "هذا الحساب معلق"
yourAccountSuspendedDescription: "عُلق الحساب بسبب انتهاك شروط خدمة المثيل و ما شابه. إذا أردت معرفة التفصيل تواصل مع مدير المثيل. رجاءً لا تنشئ حساب جديد." yourAccountSuspendedDescription: "عُلق الحساب بسبب انتهاك شروط خدمة المثيل و ما شابه. إذا أردت معرفة التفصيل تواصل مع مدير المثيل. رجاءً لا تنشئ حساب جديد."
accountDeleted: "حُذف الحساب"
accountDeletedDescription: "حُذف هذا الحساب."
menu: "القائمة" menu: "القائمة"
divider: "فاصل" divider: "فاصل"
addItem: "إضافة عنصر" addItem: "إضافة عنصر"
rearrange: "أعد الترتيب"
relays: "المُرَحلات" relays: "المُرَحلات"
addRelay: "إضافة مُرحّل" addRelay: "إضافة مُرحّل"
inboxUrl: "رابط صندوق الوارد" inboxUrl: "رابط صندوق الوارد"
@ -566,8 +531,6 @@ author: "الكاتب"
leaveConfirm: "لديك تغييرات غير محفوظة. أتريد المتابعة دون حفظها؟" leaveConfirm: "لديك تغييرات غير محفوظة. أتريد المتابعة دون حفظها؟"
manage: "إدارة " manage: "إدارة "
plugins: "الإضافات" plugins: "الإضافات"
preferencesBackups: "النُسخ الاحتياطية للإعدادات"
useBlurEffectForModal: "استخدم تأثير الطمس في المشروط"
useFullReactionPicker: "استخدم الحجم الكامل لمنتقي التفاعلات" useFullReactionPicker: "استخدم الحجم الكامل لمنتقي التفاعلات"
width: "العرض" width: "العرض"
height: "الإرتفاع" height: "الإرتفاع"
@ -626,7 +589,10 @@ abuseReported: "أُرسل البلاغ، شكرًا لك"
reporter: "المُبلّغ" reporter: "المُبلّغ"
reporteeOrigin: "أصل البلاغ" reporteeOrigin: "أصل البلاغ"
reporterOrigin: "أصل المُبلّغ" reporterOrigin: "أصل المُبلّغ"
forwardReport: "وجّه البلاغ إلى المثيل البعيد"
forwardReportIsAnonymous: "في المثيل البعيد سيظهر المبلّغ كحساب مجهول."
send: "أرسل" send: "أرسل"
abuseMarkAsResolved: "علّم البلاغ كمحلول"
openInNewTab: "افتح في لسان جديد" openInNewTab: "افتح في لسان جديد"
defaultNavigationBehaviour: "سلوك الملاحة الافتراضي" defaultNavigationBehaviour: "سلوك الملاحة الافتراضي"
editTheseSettingsMayBreakAccount: "تعديل هذه الإعدادات قد يسبب عطبًا لحسابك" editTheseSettingsMayBreakAccount: "تعديل هذه الإعدادات قد يسبب عطبًا لحسابك"
@ -640,9 +606,7 @@ clip: "مِشبك"
createNew: "أنشِئ جديد" createNew: "أنشِئ جديد"
optional: "اختياري" optional: "اختياري"
createNewClip: "أنشئ مِشبكَا جديدًا" createNewClip: "أنشئ مِشبكَا جديدًا"
confirmToUnclipAlreadyClippedNote: "هذه الملاحظة تنتمي للمشبك {name} سلفًا، أتريد حذفها منه⸮"
public: "علني" public: "علني"
private: "خاص"
i18nInfo: "يترجم متطوعون ميسكي إلى عدة لغات، يمكنك المساعدة عبر {link}" i18nInfo: "يترجم متطوعون ميسكي إلى عدة لغات، يمكنك المساعدة عبر {link}"
manageAccessTokens: "إدارة رموز الوصول" manageAccessTokens: "إدارة رموز الوصول"
accountInfo: "معلومات الحساب" accountInfo: "معلومات الحساب"
@ -663,7 +627,6 @@ driveFilesCount: "عدد الملفات في قرص التخزين"
driveUsage: "المستغل من قرص التخزين" driveUsage: "المستغل من قرص التخزين"
noCrawle: "ارفض فهرسة زاحف الويب" noCrawle: "ارفض فهرسة زاحف الويب"
noCrawleDescription: "يطلب من محركات البحث ألّا يُفهرسوا ملفك الشخصي وملاحظات وصفحاتك وما شابه." noCrawleDescription: "يطلب من محركات البحث ألّا يُفهرسوا ملفك الشخصي وملاحظات وصفحاتك وما شابه."
lockedAccountInfo: "ستكون هذه الملاحظة مرئية للجميع مالم تحدد مرئتيها إلى \"للمتابعين فقط\""
alwaysMarkSensitive: "علّم افتراضيًا جميع ملاحظاتي كذات محتوى حساس" alwaysMarkSensitive: "علّم افتراضيًا جميع ملاحظاتي كذات محتوى حساس"
loadRawImages: "حمّل الصور الأصلية بدلًا من المصغرات" loadRawImages: "حمّل الصور الأصلية بدلًا من المصغرات"
disableShowingAnimatedImages: "لا تشغّل الصور المتحركة" disableShowingAnimatedImages: "لا تشغّل الصور المتحركة"
@ -677,13 +640,10 @@ contact: "التواصل"
useSystemFont: "استخدم الخط الافتراضية للنظام" useSystemFont: "استخدم الخط الافتراضية للنظام"
clips: "مشابك" clips: "مشابك"
experimentalFeatures: "ميّزات اختبارية" experimentalFeatures: "ميّزات اختبارية"
experimental: "اختباري"
developer: "المطور" developer: "المطور"
makeExplorable: "أظهر الحساب في صفحة \"استكشاف\"" makeExplorable: "أظهر الحساب في صفحة \"استكشاف\""
makeExplorableDescription: "بتعطيل هذا الخيار لن يظهر حسابك في صفحة \"استكشاف\"" makeExplorableDescription: "بتعطيل هذا الخيار لن يظهر حسابك في صفحة \"استكشاف\""
showGapBetweenNotesInTimeline: "أظهر فجوات بين المشاركات في الخيط الزمني" showGapBetweenNotesInTimeline: "أظهر فجوات بين المشاركات في الخيط الزمني"
left: "يسار"
center: "وسط"
wide: "عريض" wide: "عريض"
narrow: "رفيع" narrow: "رفيع"
reloadToApplySetting: "سيُطبق هذا الإعداد بعد إعادة تحميل الصفحة، أتريد إعادة تحميلها الآن؟" reloadToApplySetting: "سيُطبق هذا الإعداد بعد إعادة تحميل الصفحة، أتريد إعادة تحميلها الآن؟"
@ -701,7 +661,6 @@ accentColor: "طابع لوني"
textColor: "لون النص" textColor: "لون النص"
saveAs: "احفظ كـ..." saveAs: "احفظ كـ..."
advanced: "متقدم" advanced: "متقدم"
advancedSettings: "إعدادات متقدمة"
value: "القيمة" value: "القيمة"
createdAt: "أُنشئ في" createdAt: "أُنشئ في"
updatedAt: "حُدّث في" updatedAt: "حُدّث في"
@ -721,7 +680,6 @@ editCode: "حرر الشفرة"
apply: "تطبيق" apply: "تطبيق"
receiveAnnouncementFromInstance: "استلم إشعارات من هذا المثيل" receiveAnnouncementFromInstance: "استلم إشعارات من هذا المثيل"
emailNotification: "إشعارات البريد الكتروني" emailNotification: "إشعارات البريد الكتروني"
publish: "علني"
inChannelSearch: "ابحث عن قناة" inChannelSearch: "ابحث عن قناة"
useReactionPickerForContextMenu: "افتح منتقي التفاعلات عند النقر بالزر الأيمن" useReactionPickerForContextMenu: "افتح منتقي التفاعلات عند النقر بالزر الأيمن"
typingUsers: "{users} يكتب(ون)..." typingUsers: "{users} يكتب(ون)..."
@ -734,7 +692,7 @@ unlikeConfirm: "أتريد إلغاء إعجابك؟"
fullView: "ملء الشاشة" fullView: "ملء الشاشة"
quitFullView: "اخرج من وضع ملء للشاشة" quitFullView: "اخرج من وضع ملء للشاشة"
addDescription: "أضف وصفًا" addDescription: "أضف وصفًا"
userPagePinTip: "لعرض ملاحظة هنا اختر \"ثبتها على الصفحة الشخصية\" من قائمة تلك الملاحظة." userPagePinTip: "لعرض ملاحظة هنا اختر \"دبسها على الصفحة الشخصية\" من قائمة تلك الملاحظة."
notSpecifiedMentionWarning: "في الملاحظة ذكر لمستخدمين لن يستلموها." notSpecifiedMentionWarning: "في الملاحظة ذكر لمستخدمين لن يستلموها."
info: "عن" info: "عن"
userInfo: "معلومات المستخدم" userInfo: "معلومات المستخدم"
@ -761,14 +719,12 @@ noMaintainerInformationWarning: "لم تُضبط معلومات المدير"
noBotProtectionWarning: "لم تضبط الحماية من الحسابات الآلية" noBotProtectionWarning: "لم تضبط الحماية من الحسابات الآلية"
configure: "اضبط" configure: "اضبط"
postToGallery: "انشر في المعرض" postToGallery: "انشر في المعرض"
postToHashtag: "انشر بهذا الوسم"
gallery: "المعرض" gallery: "المعرض"
recentPosts: "المشاركات الحديثة" recentPosts: "المشاركات الحديثة"
popularPosts: "المشاركات المتداولة" popularPosts: "المشاركات المتداولة"
shareWithNote: "شاركه في ملاحظة" shareWithNote: "شاركه في ملاحظة"
ads: "الإعلانات" ads: "الإعلانات"
expiration: "ينتهي استطلاع الرأي في" expiration: "ينتهي استطلاع الرأي في"
startingperiod: "ابدأ"
memo: "تذكير" memo: "تذكير"
priority: "الأولوية" priority: "الأولوية"
high: "عالية" high: "عالية"
@ -794,18 +750,13 @@ translate: "ترجم"
translatedFrom: "تُرجم من {x}" translatedFrom: "تُرجم من {x}"
accountDeletionInProgress: "حذف الحساب جارٍ" accountDeletionInProgress: "حذف الحساب جارٍ"
usernameInfo: "الاسم الذي يميزك عن بافي مستخدمي هذا الخادم، يمكنك استخدام الحروف اللاتينية (a~z, A~Z) والأرقام (0~9) والشرطة السفلية (_). لا يمكنك تغييره بعد تسجيله." usernameInfo: "الاسم الذي يميزك عن بافي مستخدمي هذا الخادم، يمكنك استخدام الحروف اللاتينية (a~z, A~Z) والأرقام (0~9) والشرطة السفلية (_). لا يمكنك تغييره بعد تسجيله."
devMode: "وضع المُطوّر"
keepCw: "أبقِ على تحذيرات المحتوى" keepCw: "أبقِ على تحذيرات المحتوى"
pubSub: "حسابات Pub/Sub"
lastCommunication: "آخر تواصل" lastCommunication: "آخر تواصل"
resolved: "عولج" resolved: "عولج"
unresolved: "لم يعالج" unresolved: "لم يعالج"
breakFollow: "إلغاء الاشتراك" breakFollow: "إلغاء الاشتراك"
breakFollowConfirm: "أمتأكد من إزالة المتابِع ؟"
itsOn: "مفعّل" itsOn: "مفعّل"
itsOff: "معطّل" itsOff: "معطّل"
on: "مفعل"
off: "معطل"
emailRequiredForSignup: "عنوان البريد الإلكتروني إلزامي للتسجيل" emailRequiredForSignup: "عنوان البريد الإلكتروني إلزامي للتسجيل"
unread: "غير مقروءة" unread: "غير مقروءة"
filter: "رشّح" filter: "رشّح"
@ -816,7 +767,8 @@ makeReactionsPublicDescription: "هذا سيجعل قائمة تفاعلاتك
classic: "تقليدي" classic: "تقليدي"
muteThread: "اكتم النقاش" muteThread: "اكتم النقاش"
unmuteThread: "ارفع الكتم عن النقاش" unmuteThread: "ارفع الكتم عن النقاش"
continueThread: "اعرض بقية النقاش" ffVisibility: "مرئية المتابِعين/المتابَعين"
ffVisibilityDescription: "يسمح لك بتحديد من يمكنهم رؤية متابِعيك ومتابَعيك."
deleteAccountConfirm: "سيحذف حسابك نهائيًا، أتريد المتابعة؟" deleteAccountConfirm: "سيحذف حسابك نهائيًا، أتريد المتابعة؟"
incorrectPassword: "كلمة السر خاطئة." incorrectPassword: "كلمة السر خاطئة."
voteConfirm: "متيقِّن من تصويتك لـ {choice}؟" voteConfirm: "متيقِّن من تصويتك لـ {choice}؟"
@ -838,282 +790,23 @@ tenMinutes: "10 دقائق"
oneHour: "ساعة" oneHour: "ساعة"
oneDay: "يوم" oneDay: "يوم"
oneWeek: "أسبوع" oneWeek: "أسبوع"
oneMonth: "شهر"
failedToFetchAccountInformation: "تعذر جلب معلومات الحساب" failedToFetchAccountInformation: "تعذر جلب معلومات الحساب"
cropImage: "اقتصاص الصورة"
cropImageAsk: "أتريد اقتصاص هذه الصورة"
cropYes: "اقتص"
cropNo: "استخدمها كما هي"
file: "الملفات" file: "الملفات"
recentNHours: "آخر {n} ساعة"
recentNDays: "آخر {n} أيام"
noEmailServerWarning: "خادم البريد غير مضبوط."
thereIsUnresolvedAbuseReportWarning: "توجد بلاغات غير معالجة."
recommended: "مقترح"
check: "التحقق"
driveCapOverrideLabel: "غيّر حجم قرص التخزين لهذا المستخدم"
driveCapOverrideCaption: "أعد الحجم إلى القيمة الافتراضية بإدخال 0 أو أقل."
requireAdminForView: "لاستعراض هذه الصفحة وجب عليك الولوج كمدير."
isSystemAccount: "حساب أنشأه النظام ويُدار من قِبله."
typeToConfirm: "أدخل {x} للتأكيد"
deleteAccount: "احذف الحساب"
document: "التوثيق"
numberOfPageCache: "عدد الصفحات المخزنة مؤقتًا"
numberOfPageCacheDescription: "رفع الرقم سيسحن تجربة المستخدم لكن سيرفع استهلاك الذاكرة."
logoutConfirm: "أتريد الخروج؟"
lastActiveDate: "آخر استخدام"
statusbar: "شريط الحالة"
pleaseSelect: "حدد خيارًا"
reverse: "اقلب" reverse: "اقلب"
colored: "ملوّن" colored: "ملوّن"
refreshInterval: "مهلة التحديث"
label: "التسمية" label: "التسمية"
type: "نوع"
speed: "سرعة"
slow: "بطيء"
fast: "سريع"
sensitiveMediaDetection: "التعرف على المحتوى الحساس"
localOnly: "المحلي فقط" localOnly: "المحلي فقط"
remoteOnly: "بُعدي فقط"
failedToUpload: "فشل الرفع"
cannotUploadBecauseInappropriate: "تعذر رفع الملف لوجود محتوى حساس فيه."
cannotUploadBecauseNoFreeSpace: "تعذر رفع الملف لنقص مساحة التخزين."
cannotUploadBecauseExceedsFileSizeLimit: "تعذر رفع الملف بسبب تجاوز حجمه للحد المسموح"
beta: "بيتا"
enableAutoSensitive: "تعيين تلقائي كمحتوى حساس NSFW"
enableAutoSensitiveDescription: "عند الاستطاعة يسمح باكتشاف المحتوى حساس NSFW تلقائيًا في الوسائط باستخدام تعلم الآلة ووسمها تبعًا لذلك. قد يكون هذا الخيار مفعلا من جهة الخادم وسيعمل حتى وان عُطل."
activeEmailValidationDescription: "يتحقق من صحة عنوان البريد الإلكتروني بشكل أكثر حزمًا وذلك عبر تحديد ما إذا كان عنوان بريد إلكتروني مؤقت وإمكانية التواصل معه. إذا لم يحدد هذا الخيار فسيتحقق من نسق عنوان البريد الإلكتروني."
navbar: "شريط التنقل"
shuffle: "خلط"
account: "الحسابات" account: "الحسابات"
move: "أنقل"
pushNotification: "إرسال الإشعارات"
subscribePushNotification: "فعّل إرسال الإشعارات"
unsubscribePushNotification: "عطل إرسال الإشعارات"
pushNotificationAlreadySubscribed: "إرسال الإشعارات مفعل سلفًا"
pushNotificationNotSupported: "متصفحك لا يدعم إرسال الإشعارات أو المثيل لا يدعمها."
sendPushNotificationReadMessage: "احذف الإشعارات فور قراءتها"
sendPushNotificationReadMessageCaption: "هذا قد يزيد من معدل استهلاك الطاقة لجهازك."
windowMaximize: "املأ الشاشة"
windowRestore: "استرجاع"
caption: "التعليق التوضيحي"
loggedInAsBot: "والج كآلي"
tools: "أدوات"
cannotLoad: "تعذر التحميل" cannotLoad: "تعذر التحميل"
numberOfProfileView: "مشاهدات الملف الشخصي"
like: "أعجبني" like: "أعجبني"
unlike: "ألغِ الإعجاب"
numberOfLikes: "الإعجابات"
show: "المظهر" show: "المظهر"
neverShow: "لا تظهره مجددًا"
remindMeLater: "ربما لاحقا"
didYouLikeMisskey: "هل أعجبك ميسكي؟"
pleaseDonate: "يستخدم {host} البرمجية الحرة ميسكي. نتمنى أن تتبرعوا للمشروع مما سيسمح لنا متابعة تطويره!"
roles: "الأدوار"
role: "الدور"
noRole: "لم يُعثر على دور"
normalUser: "مستخدم عادي"
undefined: "غير معرّف"
assign: "أسند"
unassign: "ألغ الإسناد"
color: "اللون" color: "اللون"
manageCustomEmojis: "إدارة الإيموجي المخصصة"
youCannotCreateAnymore: "وصلت لسقف الإنشاء."
cannotPerformTemporary: "غير متاح مؤقتاً"
invalidParamError: "معاملات غير صالحة"
permissionDeniedError: "رُفضة العملية"
preset: "إعدادات مسبقة"
selectFromPresets: "اختر من الإعدادات المسبقة"
achievements: "الإنجازات"
gotInvalidResponseError: "استجابة غير متوقعة من الخادم"
gotInvalidResponseErrorDescription: "يتعذر الوصول إلى الخادم أوأنه يُصان، رجاءً حاول لاحقًا."
thisPostMayBeAnnoying: "هذا قد يزعج الآخرين."
thisPostMayBeAnnoyingHome: "أنشر في الخط الزمني الرئيس"
thisPostMayBeAnnoyingCancel: "ألغِ"
internalServerError: "خطأ داخلي في الخادم"
internalServerErrorDescription: "واجه الخادم خطأ غي متوقع."
copyErrorInfo: "انسخ تفاصيل الخطأ"
joinThisServer: "سجل في هذا المثيل"
exploreOtherServers: "اعثر على مثيل آخر"
disableFederationOk: "عطّل"
invitationRequiredToRegister: "هذا المثيل للمدعوين فقط. لتسجيل فيه تحتاج رمزًا صالحًا."
postToTheChannel: "انشر في قناة"
cannotBeChangedLater: "لا يمكن تغييره لاحقًا."
reactionAcceptance: "قبول التفاعلات"
rolesAssignedToMe: "الأدوار المسندة إلي"
resetPasswordConfirm: "هل تريد إعادة تعيين كلمة السر؟"
license: "الرخصة"
unfavoriteConfirm: "أتريد إزالتها من المفضلة؟"
reactionsDisplaySize: "حجم التفاعلات"
limitWidthOfReaction: "تصغير حجم التفاعلات"
noteIdOrUrl: "معرف الملاحظة أو رابطها"
video: "فيديو"
videos: "فيديوهات"
dataSaver: "موفر البيانات"
accountMigration: "ترحيل الحساب"
accountMoved: "نقل هذا المستخدم حسابه:"
accountMovedShort: "رُحل هذا الحساب."
operationForbidden: "عملية ممنوعة"
forceShowAds: "أظهر الإعلانات التجارية دائما"
reactionsList: "التفاعلات"
renotesList: "إعادات النشر"
notificationDisplay: "إشعارات"
leftTop: "أعلى اليسار"
rightTop: "أعلى اليمين"
leftBottom: "أسفل اليسار"
rightBottom: "أسفل اليمين"
stackAxis: "اتجاه التكديس"
vertical: "عمودي"
horizontal: "جانبي"
position: "الموضع"
serverRules: "قوانين الخادم"
pleaseConfirmBelowBeforeSignup: "رجاءً وافق على ما يلي قبل التسجيل."
pleaseAgreeAllToContinue: "للمتابعة وافق على الحقول أعلاه."
continue: "متابعة"
preservedUsernames: "أسماء المستخدمين المحجوزة"
preservedUsernamesDescription: "قائمة بأسماء المستخدمين المحجوزة كلٌ في سطر. لن يُقبل التسجيل بهذه الأسماء وستبقى محصورة على التسجيل اليدوي بواسطة المديرين. لن يتأثر المستخدمون الذين يملكون هذه الأسماء سلفًا."
createNoteFromTheFile: "أنشئ ملاحظة من هذا الملف"
archive: "الأرشيف"
channelArchiveConfirmTitle: "أتريد أرشفت {name}؟"
channelArchiveConfirmDescription: "لن يمكنك نشر ملاحظات في القناة المأرشفة ولن تظهر في قائمة القنوات ولا في نتائج البحث."
thisChannelArchived: "أُرشفت هذه القناة."
displayOfNote: "عرض الملاحظة"
initialAccountSetting: "إعداد الملف الشخصي"
youFollowing: "متابَع"
preventAiLearning: "منع استخدام البيانات في تعليم الآلة"
options: "خيارات"
specifyUser: "مستخدم محدد"
failedToPreviewUrl: "تتعذر المعاينة"
update: "حدِّث"
rolesThatCanBeUsedThisEmojiAsReaction: "الأدوار التي يُسمح لأصحابها استخدام هذا اإيموجي في اللتفاعل"
rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "إذا لم تحدد دورًا يمكن للجميع استخدام هذا الإيموجي في التفاعل."
rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "يجب أن تكون الأدوار علنية."
cancelReactionConfirm: "أتريد حذف تفاعلك؟"
changeReactionConfirm: "أتريد تعديل تفاعلك؟"
later: "لاحقاً"
goToMisskey: "لميسكي"
additionalEmojiDictionary: "قواميس إيموجي إضافية"
installed: "مُثبت"
enableServerMachineStats: "نشر إحصائيات عتاد الخادم"
turnOffToImprovePerformance: "تفعيله قد يزيد الأداء."
createInviteCode: "ولِّد دعوة"
inviteCodeCreated: "ولِّدت دعوة"
inviteLimitExceeded: "وصلتَ لحد عدد الدعوات المسموح لك توليدها."
createLimitRemaining: "حد عدد الدعوات: {limit} دعوة"
expirationDate: "تاريخ انتهاء الصلاحية"
noExpirationDate: "لا نهاية لصلاحيتها"
inviteCodeUsedAt: "اُستخدم رمز الدعوة في"
registeredUserUsingInviteCode: "اِستخدم رمز الدعوة"
unused: "غير مستعمَل"
expired: "منتهية صلاحيته"
icon: "الصورة الرمزية"
replies: "رد"
renotes: "أعد النشر"
sourceCode: "الشفرة المصدرية"
flip: "اقلب"
lastNDays: "آخر {n} أيام"
surrender: "ألغِ"
_delivery:
stop: "مُعلّق"
_initialAccountSetting:
accountCreated: "نجح إنشاء حسابك!"
letsStartAccountSetup: "إذا كنت جديدًا لنعدّ حسابك الشخصي."
letsFillYourProfile: "أولًا لنعد ملفك الشخصي."
profileSetting: "إعدادات الملف الشخصي"
privacySetting: "إعدادات الخصوصية"
theseSettingsCanEditLater: "يمكنك تغيير هذه الإعدادات لاحقًا."
skipAreYouSure: "أتريد تخطي إعداد الملف الشخصي؟"
laterAreYouSure: "أتريد إعداد الملف الشخصي لاحقًا؟"
_serverRules:
description: "مجموعة من القواعد لعرضها عند التسجيل، من المستحسن كتابة ملخصٍ للشروط الخدمة."
_accountMigration:
moveFrom: "انقل حسابًا آخر لهذا الحساب"
moveFromLabel: "الحساب الأصلي #{n}"
moveTo: "انقل هذا الحساب لحساب آخر"
moveToLabel: "الحساب الوجهة:"
moveCannotBeUndone: "لا يمكن التراجع عن نقل الحساب."
movedTo: "الحساب الوجهة:"
_achievements:
_types:
_notes1:
description: "انشر ملاحظتك الأولى"
flavor: "تمتع باستخدام ميسكي!"
_notes10:
title: "بعض الملاحظات"
description: "انشر 10 ملاحظات"
_notes100:
title: "كثير من الملاحظات"
description: "انشر 100 ملاحظة"
_notes500:
description: "انشر 500 ملاحظة"
_notes1000:
title: "جبل ملاحظات"
description: "انشر 1000 ملاحظة"
_notes5000:
description: "انشر 5000 ملاحظة"
_notes10000:
description: "انشر 10000 ملاحظة"
_notes20000:
title: "أريد...ملاحظات...أكثر"
description: "انشر 20000 ملاحظة"
_notes30000:
title: "ملاحظات وملاحظات وملاحظات"
description: "انشر 30000 ملاحظة"
_notes40000:
title: "مصنع ملاحظات"
description: "انشر 40000 ملاحظة"
_notes50000:
title: "كوكب ملاحظات"
description: "انشر 50000 ملاحظة"
_notes60000:
title: "نجم ملاحظات"
description: "انشر 60000 ملاحظة"
_notes70000:
title: "ثقب أسود للملاحظات"
description: "انشر 70000 ملاحظة"
_notes80000:
title: "مجرة ملاحظات"
description: "انشر 80000 ملاحظة"
_notes90000:
title: "كوْن ملاحظات"
description: "انشر 90000 ملاحظة"
_notes100000:
title: "كل ملاحظاتك لنا"
description: "انشر 100000 ملاحظة"
flavor: "حقًا لديك الكثير من القصص"
_login3:
title: "مبتدأ I"
_noteFavorited1:
description: "فضًِل ملاحظتك الأولى"
_myNoteFavorited1:
title: "ساعٍ للنجوم"
description: "أعجب شخص آخر بإحدى ملاحظاتك"
_profileFilled:
title: "مستعد"
description: "أعدّ حسابك"
_markedAsCat:
title: "أنا قط"
_role: _role:
new: "دور جديد"
edit: "حرر الأدوار"
name: "اسم الدور"
description: "وصف الدور"
permission: "أذونات الدور"
assignTarget: "نوع الإسناد"
condition: "الشرط"
options: "خيارات"
policies: "السياسة العامة"
priority: "الأولوية" priority: "الأولوية"
_priority: _priority:
low: "منخفضة" low: "منخفضة"
middle: "متوسط" middle: "متوسط"
high: "عالية" high: "عالية"
_options:
canManageCustomEmojis: "إدارة الإيموجي المخصصة"
pinMax: "حد عدد الملاحظات المثبتة"
_condition:
isLocal: "مستخدم محلي"
isRemote: "مستخدم بعيد"
_emailUnavailable: _emailUnavailable:
used: "هذا البريد الإلكتروني مستخدم" used: "هذا البريد الإلكتروني مستخدم"
format: "صيغة البريد الإلكتروني غير صالحة" format: "صيغة البريد الإلكتروني غير صالحة"
@ -1156,10 +849,6 @@ _plugin:
install: "ثبّت إضافات" install: "ثبّت إضافات"
installWarn: "رجاءً لا تثبت إضافات غير موثوقة." installWarn: "رجاءً لا تثبت إضافات غير موثوقة."
manage: "إدارة الإضافات" manage: "إدارة الإضافات"
viewSource: "اظهر المصدر"
_preferencesBackups:
createdAt: "تم إنشاؤه: {date} {time}"
updatedAt: "آخر تحديث: {date} {time}"
_registry: _registry:
scope: "الحيّز" scope: "الحيّز"
key: "مفتاح" key: "مفتاح"
@ -1175,6 +864,10 @@ _aboutMisskey:
donate: "تبرع لميسكي" donate: "تبرع لميسكي"
morePatrons: "نحن نقدر الدعم الذي قدمه العديد من الأشخاص الذين لم نذكرهم. شكرًا لكم 🥰" morePatrons: "نحن نقدر الدعم الذي قدمه العديد من الأشخاص الذين لم نذكرهم. شكرًا لكم 🥰"
patrons: "الداعمون" patrons: "الداعمون"
_nsfw:
respect: "اخف الوسائط ذات المحتوى الحساس"
ignore: "اعرض الوسائط ذات المحتوى الحساس"
force: "اخف كل الوسائط"
_instanceTicker: _instanceTicker:
none: "لا تظهره بتاتًا" none: "لا تظهره بتاتًا"
remote: "أظهر للمستخدمين البِعاد" remote: "أظهر للمستخدمين البِعاد"
@ -1200,6 +893,11 @@ _wordMute:
muteWords: "الكلمات المحظورة" muteWords: "الكلمات المحظورة"
muteWordsDescription: "افصل بينهم بمسافة لاستخدام معامل \"و\" أو بسطر لاستخدام معامل \"أو\"." muteWordsDescription: "افصل بينهم بمسافة لاستخدام معامل \"و\" أو بسطر لاستخدام معامل \"أو\"."
muteWordsDescription2: "احصر الكلمات المفتاحية بين بين شرطتين مائلتين لاستخدامها كتعابير نمطية" muteWordsDescription2: "احصر الكلمات المفتاحية بين بين شرطتين مائلتين لاستخدامها كتعابير نمطية"
softDescription: "اخف الملاحظات التي تستوف الشروط من الخيط الزمني."
hardDescription: "اخف الملاحظات التي تستوف الشروط من الخيط الزمني.بالإضافة إلى أن هذه الملاحظات ستبقى مخفية حتى وإن تغيرت الشروط."
soft: "لينة"
hard: "قاسية"
mutedNotes: "الملاحظات المكتومة"
_instanceMute: _instanceMute:
instanceMuteDescription: "هذه سيحجب كل ملاحظات الخوادم المحجوبة ومشاركاتها والردود على تلك الملاحظات حتى وإن كانت من خادم غير محجوب." instanceMuteDescription: "هذه سيحجب كل ملاحظات الخوادم المحجوبة ومشاركاتها والردود على تلك الملاحظات حتى وإن كانت من خادم غير محجوب."
instanceMuteDescription2: "مدخلة لكل سطر" instanceMuteDescription2: "مدخلة لكل سطر"
@ -1252,12 +950,17 @@ _theme:
buttonBg: "خلفية الأزرار" buttonBg: "خلفية الأزرار"
buttonHoverBg: "خلفية الأزرار (عند التمرير فوقها)" buttonHoverBg: "خلفية الأزرار (عند التمرير فوقها)"
inputBorder: "حواف حقل الإدخال" inputBorder: "حواف حقل الإدخال"
listItemHoverBg: "خلفية عناصر القائمة (عند التمرير فوقها)"
driveFolderBg: "خلفية مجلد قرص التخزين" driveFolderBg: "خلفية مجلد قرص التخزين"
messageBg: "خلفية المحادثة" messageBg: "خلفية المحادثة"
_sfx: _sfx:
note: "الملاحظات" note: "الملاحظات"
noteMy: "ملاحظتي" noteMy: "ملاحظتي"
notification: "الإشعارات" notification: "الإشعارات"
chat: "المحادثة"
chatBg: "المحادثة (الخلفية)"
antenna: "الهوائيات"
channel: "إشعارات القنات"
_ago: _ago:
future: "المستقبَل" future: "المستقبَل"
justNow: "اللحظة" justNow: "اللحظة"
@ -1274,6 +977,29 @@ _time:
minute: "د" minute: "د"
hour: "سا" hour: "سا"
day: "ي" day: "ي"
_tutorial:
title: "كيف تستخدم Misskey"
step1_1: "مرحبًا!"
step1_2: "تدعى هذه الصفحة 'الخيط الزمني' وهي تحوي ملاحظات الأشخاص الذي تتابعهم مرتبة حسب تاريخ نشرها."
step1_3: "خيطك الزمني فارغ حاليًا بما أنك لا تتابع أي شخص ولم تنشر أي ملاحظة."
step2_1: "لننهي إعداد ملفك الشخصي قبل كتابة ملاحظة أو متابعة أشخاص."
step2_2: "أعطاء معلومات عن شخصيتك يمنح من له نفس إهتماماتك فرصة متابعتك والتفاعل مع ملاحظاتك."
step3_1: "هل أنهيت إعداد حسابك؟"
step3_2: "إذا تاليًا لتنشر ملاحظة. أنقر على أيقونة القلم في أعلى الشاشة"
step3_3: "املأ النموذج وانقر الزرّ الموجود في أعلى اليمين للإرسال."
step3_4: "ليس لديك ما تقوله؟ إذا اكتب \"بدأتُ استخدم ميسكي\"."
step4_1: "هل نشرت ملاحظتك الأولى؟"
step4_2: "مرحى! يمكنك الآن رؤية ملاحظتك في الخيط الزمني."
step5_1: "والآن، لنجعل الخيط الزمني أكثر حيوية وذلك بمتابعة بعض المستخدمين."
step5_2: "تعرض صفحة {features} الملاحظات المتداولة في هذا المثيل ويتيح لك {Explore} العثور على المستخدمين الرائدين. اعثر على الأشخاص الذين يثيرون إهتمامك وتابعهم!"
step5_3: "لمتابعة مستخدمين ادخل ملفهم الشخصي بالنقر على صورتهم الشخصية ثم اضغط زر 'تابع'."
step5_4: "إذا كان لدى المستخدم رمز قفل بجوار اسمه ، وجب عليك انتظاره ليقبل طلب المتابعة يدويًا."
step6_1: "الآن ستتمكن من رؤية ملاحظات المستخدمين المتابَعين في الخيط الزمني."
step6_2: "يمكنك التفاعل بسرعة مع الملاحظات عن طريق إضافة \"تفاعل\"."
step6_3: "لإضافة تفاعل لملاحظة ، انقر فوق علامة \"+\" أسفل للملاحظة واختر الإيموجي المطلوب."
step7_1: "مبارك ! أنهيت الدورة التعليمية الأساسية لاستخدام ميسكي."
step7_2: "إذا أردت معرفة المزيد عن ميسكي زر {help}."
step7_3: "حظًا سعيدًا واستمتع بوقتك مع ميسكي! 🚀"
_2fa: _2fa:
alreadyRegistered: "سجلت سلفًا جهازًا للاستيثاق بعاملين." alreadyRegistered: "سجلت سلفًا جهازًا للاستيثاق بعاملين."
step1: "أولًا ثبّت تطبيق استيثاق على جهازك (مثل {a} و{b})." step1: "أولًا ثبّت تطبيق استيثاق على جهازك (مثل {a} و{b})."
@ -1351,7 +1077,6 @@ _widgets:
onlineUsers: "المتّصلون" onlineUsers: "المتّصلون"
jobQueue: "قائمة الانتظار" jobQueue: "قائمة الانتظار"
serverMetric: "إحصائيات الخادم" serverMetric: "إحصائيات الخادم"
userList: "قائمة المستخدمين"
_userList: _userList:
chooseList: "اختر قائمة" chooseList: "اختر قائمة"
_cw: _cw:
@ -1415,8 +1140,6 @@ _profile:
changeBanner: "غيّر اللافتة" changeBanner: "غيّر اللافتة"
_exportOrImport: _exportOrImport:
allNotes: "كل الملاحظات" allNotes: "كل الملاحظات"
favoritedNotes: " الملاحظات المفضلة"
clips: "مِشبك"
followingList: "المتابَعون" followingList: "المتابَعون"
muteList: "المستخدمون المكتومون" muteList: "المستخدمون المكتومون"
blockingList: "المستخدمون المحجوبون" blockingList: "المستخدمون المحجوبون"
@ -1435,8 +1158,6 @@ _charts:
notesTotal: "إجمالي الملاحظات" notesTotal: "إجمالي الملاحظات"
filesIncDec: "تباين عدد الملفات" filesIncDec: "تباين عدد الملفات"
filesTotal: "العدد الإجمالي للملفات" filesTotal: "العدد الإجمالي للملفات"
storageUsageIncDec: "التباين في استغلال مساحة التخزين"
storageUsageTotal: "اجمالي مساحة التخزين المستغلة"
_instanceCharts: _instanceCharts:
requests: "الطلبات" requests: "الطلبات"
users: "تباين عدد المستخدمين" users: "تباين عدد المستخدمين"
@ -1482,7 +1203,7 @@ _pages:
url: "رابط الصفحة" url: "رابط الصفحة"
summary: "ملخص الصفحة" summary: "ملخص الصفحة"
alignCenter: "توسيط العناصر" alignCenter: "توسيط العناصر"
hideTitleWhenPinned: "اخف عنوان الصفحة عند تثبيتها في ملف الشخصي" hideTitleWhenPinned: "اخف عنوان الصفحة عند تدبيسها في ملف الشخصي"
font: "الخط" font: "الخط"
fontSerif: "Serif" fontSerif: "Serif"
fontSansSerif: "Sans Serif" fontSansSerif: "Sans Serif"
@ -1497,7 +1218,7 @@ _pages:
text: "نص" text: "نص"
textarea: "حقل نصي" textarea: "حقل نصي"
section: "قسم" section: "قسم"
image: "صور" image: "الصور"
button: "زرّ" button: "زرّ"
note: "ملاحظة مضمّنة" note: "ملاحظة مضمّنة"
_note: _note:
@ -1512,76 +1233,48 @@ _notification:
fileUploaded: "نجح رفع الملف" fileUploaded: "نجح رفع الملف"
youGotMention: "{name} أشار إليك" youGotMention: "{name} أشار إليك"
youGotReply: "ردّ عليك {name}" youGotReply: "ردّ عليك {name}"
youGotQuote: "اقتبس {name} منشورك" youGotQuote: "اقتبس منك {name}"
youRenoted: "أعاد {name} نشر منشورك" youRenoted: "إعادت نشر من {name}"
youWereFollowed: "يتابعك" youWereFollowed: "يتابعك"
youReceivedFollowRequest: "تلقيتَ طلب متابعة" youReceivedFollowRequest: "تلقيتَ طلب متابعة"
yourFollowRequestAccepted: "قُبل طلب المتابعة" yourFollowRequestAccepted: "قُبل طلب المتابعة"
pollEnded: "انتهى الاستطلاع" pollEnded: "ظهرت نتائج الاستطلاع"
unreadAntennaNote: "هوائي {name}" unreadAntennaNote: "هوائي {name}"
_types: _types:
all: "الكل" all: "الكل"
follow: "متابِعون جدد" follow: "متابِعون جدد"
mention: "الإشارات" mention: "الإشارات"
reply: "الردود" reply: "الردود"
renote: "أعاد النشر" renote: "أعد النشر"
quote: "الاقتباسات" quote: "الاقتباسات"
reaction: "التفاعل" reaction: "التفاعلات"
receiveFollowRequest: "طلبات المتابعة" receiveFollowRequest: "طلبات المتابعة المتلقاة"
followRequestAccepted: "طلبات المتابعة المقبولة" followRequestAccepted: "طلبات المتابعة المقبولة"
login: "لِج"
app: "إشعارات التطبيقات المرتبطة" app: "إشعارات التطبيقات المرتبطة"
_actions: _actions:
followBack: "تابعك بالمثل" followBack: "تابعك بالمثل"
reply: "رد" reply: "رد"
renote: "أعد النشر" renote: "أعد النشر"
_deck: _deck:
alwaysShowMainColumn: "أظهر العمود الأساسي دائمًا" alwaysShowMainColumn: "أظهر العمود الرئيسي دائمًا"
columnAlign: "محاذاة الأعمدة" columnAlign: "حاذِ الأعمدة"
addColumn: "إضافة عمود" addColumn: "أضف عمودًا"
swapLeft: "التحريك إلى اليسار" swapLeft: "حرّك لليسار"
swapRight: "التحريك إلى اليمين" swapRight: "حرّك لليمين"
swapUp: "التحريك إلى الأعلى" swapUp: "حرّك لأعلى"
swapDown: "التحريك إلى الأسفل" swapDown: "حرّك لأسفل"
profile: "حسابي الشخصي" profile: "الملف الشخصي"
newProfile: "ملف تعريفي جديد"
deleteProfile: "حذف الملف التعريفي"
_columns: _columns:
main: "الرئيسية" main: "الرئيسي"
widgets: "التطبيقات المُصغّرة" widgets: "الودجات"
notifications: "الإشعارات" notifications: "الإشعارات"
tl: "الخط الزمني" tl: "الخيط الزمني"
antenna: "الهوائيات" antenna: "الهوائيات"
list: "القوائم" list: "القوائم"
channel: "القنوات" channel: "القنوات"
mentions: "الإشارات" mentions: "الإشارات"
direct: "مباشرة" direct: "مباشرة"
_webhookSettings: _webhookSettings:
name: "الاسم" name: "الإسم"
active: "مُفعّل" active: "مفعّل"
_events:
reaction: "عند التفاعل"
_abuseReport:
_notificationRecipient:
_recipientType:
mail: "البريد الإلكتروني "
_moderationLogTypes:
suspend: "علِق"
deleteDriveFile: "حُذف الملف"
deleteNote: "حُذفت الملاحظة"
createGlobalAnnouncement: "أُنشئ إعلان عام"
createUserAnnouncement: "أُنشئ إعلان مستخدم"
updateGlobalAnnouncement: "حُدث إعلان عام"
updateUserAnnouncement: "حُدث إعلان مستخدم"
resetPassword: "أعد تعيين كلمتك السرية"
createInvitation: "ولِّد دعوة"
_reversi:
total: "المجموع"
lookingForPlayer: "يبحث عن خصم..."
gameCanceled: "أُلغيت اللعبة."
opponentHasSettingsChanged: "غيَر الخصم إعدادته."
showBoardLabels: "اعرض ترقيم الصفوف والأعمدة على اللوح"
useAvatarAsStone: "حوَل الحجارة إلى صور مستخدمين"
_offlineScreen:
title: "غير متصل - يتعذر الاتصال بالخادم"
header: "يتعذر الاتصال بالخادم"

View file

@ -2,7 +2,6 @@
_lang_: "বাংলা" _lang_: "বাংলা"
headlineMisskey: "নোট ব্যাবহার করে সংযুক্ত নেটওয়ার্ক" headlineMisskey: "নোট ব্যাবহার করে সংযুক্ত নেটওয়ার্ক"
introMisskey: "স্বাগতম! মিসকি একটি ওপেন সোর্স, ডিসেন্ট্রালাইজড মাইক্রোব্লগিং পরিষেবা। \n\"নোট\" তৈরির মাধ্যমে যা ঘটছে তা সবার সাথে শেয়ার করুন 📡\n\"রিঅ্যাকশন\" গুলির মাধ্যমে যেকোনো নোট সম্পর্কে আপনার অনুভূতি ব্যাক্ত করতে পারেন 👍\nএকটি নতুন দুনিয়া ঘুরে দেখুন 🚀\n" introMisskey: "স্বাগতম! মিসকি একটি ওপেন সোর্স, ডিসেন্ট্রালাইজড মাইক্রোব্লগিং পরিষেবা। \n\"নোট\" তৈরির মাধ্যমে যা ঘটছে তা সবার সাথে শেয়ার করুন 📡\n\"রিঅ্যাকশন\" গুলির মাধ্যমে যেকোনো নোট সম্পর্কে আপনার অনুভূতি ব্যাক্ত করতে পারেন 👍\nএকটি নতুন দুনিয়া ঘুরে দেখুন 🚀\n"
poweredByMisskeyDescription: "{name} হল ওপেন সোর্স প্ল্যাটফর্ম <b>Misskey</b>-এর সার্ভারগুলির একটি৷"
monthAndDay: "{day}/{month}" monthAndDay: "{day}/{month}"
search: "খুঁজুন" search: "খুঁজুন"
notifications: "বিজ্ঞপ্তি" notifications: "বিজ্ঞপ্তি"
@ -13,14 +12,12 @@ fetchingAsApObject: "ফেডিভার্স থেকে খবর আন
ok: "ঠিক" ok: "ঠিক"
gotIt: "বুঝেছি" gotIt: "বুঝেছি"
cancel: "বাতিল" cancel: "বাতিল"
noThankYou: "না, ধন্যবাদ"
enterUsername: "ইউজারনেম লিখুন" enterUsername: "ইউজারনেম লিখুন"
renotedBy: "{user} রিনোট করেছেন" renotedBy: "{user} রিনোট করেছেন"
noNotes: "কোন নোট নেই" noNotes: "কোন নোট নেই"
noNotifications: "কোনো বিজ্ঞপ্তি নেই" noNotifications: "কোনো বিজ্ঞপ্তি নেই"
instance: "ইন্সট্যান্স" instance: "ইন্সট্যান্স"
settings: "সেটিংস" settings: "সেটিংস"
notificationSettings: "বিজ্ঞপ্তির সেটিংস"
basicSettings: "সাধারণ সেটিংস" basicSettings: "সাধারণ সেটিংস"
otherSettings: "অন্যান্য সেটিংস" otherSettings: "অন্যান্য সেটিংস"
openInWindow: "নতুন উইন্ডোতে খুলা" openInWindow: "নতুন উইন্ডোতে খুলা"
@ -45,20 +42,12 @@ pin: "পিন করা"
unpin: "পিন সরান" unpin: "পিন সরান"
copyContent: "বিষয়বস্তু কপি করুন" copyContent: "বিষয়বস্তু কপি করুন"
copyLink: "লিঙ্ক কপি করুন" copyLink: "লিঙ্ক কপি করুন"
copyLinkRenote: "রিনোট লিঙ্ক কপি করুন"
delete: "মুছুন" delete: "মুছুন"
deleteAndEdit: "মুছুন এবং সম্পাদনা করুন" deleteAndEdit: "মুছুন এবং সম্পাদনা করুন"
deleteAndEditConfirm: "আপনি কি এই নোটটি মুছে এটি সম্পাদনা করার বিষয়ে নিশ্চিত? আপনি এটির সমস্ত রিঅ্যাকশন, রিনোট এবং জবাব হারাবেন।" deleteAndEditConfirm: "আপনি কি এই নোটটি মুছে এটি সম্পাদনা করার বিষয়ে নিশ্চিত? আপনি এটির সমস্ত রিঅ্যাকশন, রিনোট এবং জবাব হারাবেন।"
addToList: "লিস্ট এ যোগ করুন" addToList: "লিস্ট এ যোগ করুন"
addToAntenna: "অ্যান্টেনা এ যোগ করুন"
sendMessage: "একটি বার্তা পাঠান" sendMessage: "একটি বার্তা পাঠান"
copyRSS: "RSS কপি করুন"
copyUsername: "ব্যবহারকারীর নাম কপি করুন" copyUsername: "ব্যবহারকারীর নাম কপি করুন"
copyUserId: "ব্যবহারকারীর ID কপি করুন"
copyNoteId: "নোটের ID কপি করুন"
copyFileId: "ফাইল ID কপি করুন"
copyFolderId: "ফোল্ডার ID কপি করুন"
copyProfileUrl: "প্রোফাইল URL কপি করুন"
searchUser: "ব্যবহারকারী খুঁজুন..." searchUser: "ব্যবহারকারী খুঁজুন..."
reply: "জবাব" reply: "জবাব"
loadMore: "আরও দেখুন" loadMore: "আরও দেখুন"
@ -111,8 +100,6 @@ renoted: "রিনোট করা হয়েছে"
cantRenote: "এই নোটটি রিনোট করা যাবে না।" cantRenote: "এই নোটটি রিনোট করা যাবে না।"
cantReRenote: "রিনোটকে রিনোট করা যাবে না।" cantReRenote: "রিনোটকে রিনোট করা যাবে না।"
quote: "উদ্ধৃতি" quote: "উদ্ধৃতি"
inChannelRenote: "চ্যানেলে রিনোট"
inChannelQuote: "চ্যানেলে উদ্ধৃতি"
pinnedNote: "পিন করা নোট" pinnedNote: "পিন করা নোট"
pinned: "পিন করা" pinned: "পিন করা"
you: "আপনি" you: "আপনি"
@ -121,10 +108,7 @@ sensitive: "সংবেদনশীল বিষয়বস্তু"
add: "যুক্ত করুন" add: "যুক্ত করুন"
reaction: "প্রতিক্রিয়া" reaction: "প্রতিক্রিয়া"
reactions: "প্রতিক্রিয়া" reactions: "প্রতিক্রিয়া"
emojiPicker: "ইমোজি পিকার" reactionSetting: "রিঅ্যাকশন পিকারে যেসকল প্রতিক্রিয়া দেখানো হবে"
pinnedEmojisForReactionSettingDescription: "রিঅ্যাকশন দেয়ার সময় আপনি ইমোজিটিকে পিন করা এবং প্রদর্শিত হওয়ার জন্য সেট করতে পারেন।"
pinnedEmojisSettingDescription: "ইমোজি ইনপুট দেয়ার সময় আপনি ইমোজিটিকে পিন করা এবং প্রদর্শিত হওয়ার জন্য সেট করতে পারেন।"
emojiPickerDisplay: "পিকার ডিসপ্লে"
reactionSettingDescription2: "পুনরায় সাজাতে টেনে আনুন, মুছতে ক্লিক করুন, যোগ করতে + টিপুন।" reactionSettingDescription2: "পুনরায় সাজাতে টেনে আনুন, মুছতে ক্লিক করুন, যোগ করতে + টিপুন।"
rememberNoteVisibility: "নোটের দৃশ্যমান্যতার সেটিংস মনে রাখুন" rememberNoteVisibility: "নোটের দৃশ্যমান্যতার সেটিংস মনে রাখুন"
attachCancel: "অ্যাটাচমেন্ট সরান " attachCancel: "অ্যাটাচমেন্ট সরান "
@ -268,12 +252,12 @@ noMoreHistory: "আর কোন ইতিহাস নেই"
startMessaging: "চ্যাট শুরু করুন" startMessaging: "চ্যাট শুরু করুন"
nUsersRead: "{n} জন পড়েছেন" nUsersRead: "{n} জন পড়েছেন"
agreeTo: "{0} এর প্রতি আমি সম্মত" agreeTo: "{0} এর প্রতি আমি সম্মত"
tos: "পরিষেবার শর্তাদি"
start: "শুরু করুন" start: "শুরু করুন"
home: "মূল পাতা" home: "মূল পাতা"
remoteUserCaution: "এই ব্যাবহারকারী রিমোট ইন্সট্যান্সের, নিম্নক্ত তথ্য অসম্পূর্ণ হতে পারে।" remoteUserCaution: "এই ব্যাবহারকারী রিমোট ইন্সট্যান্সের, নিম্নক্ত তথ্য অসম্পূর্ণ হতে পারে।"
activity: "কার্যকলাপ" activity: "কার্যকলাপ"
images: "ছবি" images: "ছবি"
image: "ছবি"
birthday: "জন্মদিন" birthday: "জন্মদিন"
yearsOld: "{age} বছর" yearsOld: "{age} বছর"
registeredDate: "যোগদানের তারিখ" registeredDate: "যোগদানের তারিখ"
@ -310,6 +294,7 @@ copyUrl: "URL কপি করুন"
rename: "পুনঃনামকরণ" rename: "পুনঃনামকরণ"
avatar: "প্রোফাইল ছবি" avatar: "প্রোফাইল ছবি"
banner: "ব্যানার" banner: "ব্যানার"
nsfw: "সংবেদনশীল বিষয়বস্তু"
whenServerDisconnected: "সার্ভারের সাথে সংযোগ বিচ্ছিন্ন হয়ে গেলে" whenServerDisconnected: "সার্ভারের সাথে সংযোগ বিচ্ছিন্ন হয়ে গেলে"
disconnectedFromServer: "সার্ভার থেকে সংযোগ বিচ্ছিন্ন হয়েছে" disconnectedFromServer: "সার্ভার থেকে সংযোগ বিচ্ছিন্ন হয়েছে"
reload: "আবার লোড করুন" reload: "আবার লোড করুন"
@ -344,6 +329,7 @@ invite: "আমন্ত্রণ"
driveCapacityPerLocalAccount: "প্রত্যেক স্থানীয় ব্যাবহারকারীর জন্য ড্রাইভের জায়গা" driveCapacityPerLocalAccount: "প্রত্যেক স্থানীয় ব্যাবহারকারীর জন্য ড্রাইভের জায়গা"
driveCapacityPerRemoteAccount: "প্রত্যেক রিমোট ব্যাবহারকারীর জন্য ড্রাইভের জায়গা" driveCapacityPerRemoteAccount: "প্রত্যেক রিমোট ব্যাবহারকারীর জন্য ড্রাইভের জায়গা"
inMb: "মেগাবাইটে লিখুন" inMb: "মেগাবাইটে লিখুন"
iconUrl: "আইকনের URL (ফ্যাভিকন, ইত্যাদি)"
bannerUrl: "ব্যানার ছবির URL" bannerUrl: "ব্যানার ছবির URL"
backgroundImageUrl: "পটভূমির চিত্রের URL" backgroundImageUrl: "পটভূমির চিত্রের URL"
basicInfo: "আপনার ব্যক্তিগত তথ্য" basicInfo: "আপনার ব্যক্তিগত তথ্য"
@ -357,8 +343,6 @@ hcaptcha: "hCaptcha"
enableHcaptcha: "hCaptcha চালু করুন" enableHcaptcha: "hCaptcha চালু করুন"
hcaptchaSiteKey: "সাইট কী" hcaptchaSiteKey: "সাইট কী"
hcaptchaSecretKey: "সিক্রেট কী" hcaptchaSecretKey: "সিক্রেট কী"
mcaptchaSiteKey: "সাইট কী"
mcaptchaSecretKey: "সিক্রেট কী"
recaptcha: "reCAPTCHA" recaptcha: "reCAPTCHA"
enableRecaptcha: "reCAPTCHA চালু করুন" enableRecaptcha: "reCAPTCHA চালু করুন"
recaptchaSiteKey: "সাইট কী" recaptchaSiteKey: "সাইট কী"
@ -411,6 +395,7 @@ share: "শেয়ার"
notFound: "পাওয়া যায়নি" notFound: "পাওয়া যায়নি"
notFoundDescription: "এই URL-এর সাথে সম্পর্কিত কোনো পৃষ্ঠা নেই।" notFoundDescription: "এই URL-এর সাথে সম্পর্কিত কোনো পৃষ্ঠা নেই।"
uploadFolder: "আপলোডের জন্য ডিফল্ট ফোল্ডার" uploadFolder: "আপলোডের জন্য ডিফল্ট ফোল্ডার"
cacheClear: "ক্যাশ পরিষ্কার করুন"
markAsReadAllNotifications: "সমস্ত বিজ্ঞপ্তিগুলি পঠিত হিসাবে চিহ্নিত করুন" markAsReadAllNotifications: "সমস্ত বিজ্ঞপ্তিগুলি পঠিত হিসাবে চিহ্নিত করুন"
markAsReadAllUnreadNotes: "সমস্ত নোটগুলি পঠিত হিসাবে চিহ্নিত করুন" markAsReadAllUnreadNotes: "সমস্ত নোটগুলি পঠিত হিসাবে চিহ্নিত করুন"
markAsReadAllTalkMessages: "সমস্ত মেসেজ পঠিত হিসাবে চিহ্নিত করুন" markAsReadAllTalkMessages: "সমস্ত মেসেজ পঠিত হিসাবে চিহ্নিত করুন"
@ -451,6 +436,7 @@ or: "অথবা"
language: "ভাষা" language: "ভাষা"
uiLanguage: "UI এর ভাষা" uiLanguage: "UI এর ভাষা"
aboutX: "{x} সম্পর্কে" aboutX: "{x} সম্পর্কে"
disableDrawer: "ড্রয়ার মেনু প্রদর্শন করবেন না"
noHistory: "কোনো ইতিহাস নেই" noHistory: "কোনো ইতিহাস নেই"
signinHistory: "প্রবেশ করার ইতিহাস" signinHistory: "প্রবেশ করার ইতিহাস"
doing: "প্রক্রিয়া করছে..." doing: "প্রক্রিয়া করছে..."
@ -624,7 +610,10 @@ abuseReported: "আপনার অভিযোগটি দাখিল কর
reporter: "অভিযোগকারী" reporter: "অভিযোগকারী"
reporteeOrigin: "অভিযোগটির উৎস" reporteeOrigin: "অভিযোগটির উৎস"
reporterOrigin: "অভিযোগকারীর উৎস" reporterOrigin: "অভিযোগকারীর উৎস"
forwardReport: "রিমোট ইন্সত্যান্সে অভিযোগটি পাঠান"
forwardReportIsAnonymous: "আপনার তথ্য রিমোট ইন্সত্যান্সে পাঠানো হবে না এবং একটি বেনামী সিস্টেম অ্যাকাউন্ট হিসাবে প্রদর্শিত হবে।"
send: "পাঠান" send: "পাঠান"
abuseMarkAsResolved: "অভিযোগটিকে সমাধাকৃত হিসাবে চিহ্নিত করুন"
openInNewTab: "নতুন ট্যাবে খুলুন" openInNewTab: "নতুন ট্যাবে খুলুন"
openInSideView: "সাইড ভিউতে খুলুন" openInSideView: "সাইড ভিউতে খুলুন"
defaultNavigationBehaviour: "ডিফল্ট নেভিগেশন" defaultNavigationBehaviour: "ডিফল্ট নেভিগেশন"
@ -640,7 +629,6 @@ createNew: "নতুন"
optional: "প্রয়োজনীয় নয়" optional: "প্রয়োজনীয় নয়"
createNewClip: "নতুন ক্লিপ তৈরি করুন" createNewClip: "নতুন ক্লিপ তৈরি করুন"
public: "সর্বজনীন" public: "সর্বজনীন"
private: "ব্যাক্তিগত"
i18nInfo: "Misskey স্বেচ্ছাসেবকদের দ্বারা বিভিন্ন ভাষায় অনুবাদ করা হচ্ছে। আপনি {link} এ গিয়ে অনুবাদে সহযোগিতা করতে পারেন।" i18nInfo: "Misskey স্বেচ্ছাসেবকদের দ্বারা বিভিন্ন ভাষায় অনুবাদ করা হচ্ছে। আপনি {link} এ গিয়ে অনুবাদে সহযোগিতা করতে পারেন।"
manageAccessTokens: "অ্যাক্সেস টোকেন পরিচালনা করুন" manageAccessTokens: "অ্যাক্সেস টোকেন পরিচালনা করুন"
accountInfo: "অ্যাকাউন্টের তথ্য" accountInfo: "অ্যাকাউন্টের তথ্য"
@ -808,6 +796,8 @@ makeReactionsPublicDescription: "আপনার পূর্ববর্তী
classic: "ক্লাসিক" classic: "ক্লাসিক"
muteThread: "থ্রেড মিউট করুন" muteThread: "থ্রেড মিউট করুন"
unmuteThread: "থ্রেড আনমিউট করুন" unmuteThread: "থ্রেড আনমিউট করুন"
ffVisibility: "অনুসরণ/অনুসরণকারীদের দৃশ্যমান্যতা"
ffVisibilityDescription: "আপনি কাকে অনুসরণ করেন এবং কে আপনাকে অনুসরণ করে, সেটা কারা দেখতে পাবে তা নির্ধারণ করে।"
continueThread: "আরো থ্রেড দেখুন" continueThread: "আরো থ্রেড দেখুন"
deleteAccountConfirm: "আপনার অ্যাকাউন্ট মুছে ফেলা হবে। ঠিক আছে?" deleteAccountConfirm: "আপনার অ্যাকাউন্ট মুছে ফেলা হবে। ঠিক আছে?"
incorrectPassword: "আপনার দেওয়া পাসওয়ার্ডটি ভুল।" incorrectPassword: "আপনার দেওয়া পাসওয়ার্ডটি ভুল।"
@ -846,17 +836,6 @@ account: "অ্যাকাউন্টগুলি"
like: "পছন্দ করা" like: "পছন্দ করা"
show: "প্রদর্শন" show: "প্রদর্শন"
color: "রং" color: "রং"
horizontal: "পাশে"
youFollowing: "অনুসরণ করা হচ্ছে"
icon: "প্রোফাইল ছবি"
replies: "জবাব"
renotes: "রিনোট"
sourceCode: "সোর্স কোড"
flip: "উল্টান"
_delivery:
stop: "স্থগিত করা হয়েছে"
_type:
none: "প্রকাশ করা হচ্ছে"
_role: _role:
priority: "অগ্রাধিকার" priority: "অগ্রাধিকার"
_priority: _priority:
@ -906,7 +885,6 @@ _plugin:
install: "প্লাগইন ইন্সটল করুন" install: "প্লাগইন ইন্সটল করুন"
installWarn: "অবিশ্বস্ত প্লাগইন ইনস্টল করবেন না।" installWarn: "অবিশ্বস্ত প্লাগইন ইনস্টল করবেন না।"
manage: "প্লাগইন ম্যানেজ করুন" manage: "প্লাগইন ম্যানেজ করুন"
viewSource: "উৎস দেখুন"
_registry: _registry:
scope: "স্কোপ" scope: "স্কোপ"
key: "কী" key: "কী"
@ -922,6 +900,10 @@ _aboutMisskey:
donate: "Misskey তে দান করুন" donate: "Misskey তে দান করুন"
morePatrons: "আরও অনেকে আমাদের সাহায্য করছেন। তাদের সবাইকে ধন্যবাদ 🥰" morePatrons: "আরও অনেকে আমাদের সাহায্য করছেন। তাদের সবাইকে ধন্যবাদ 🥰"
patrons: "সমর্থনকারী" patrons: "সমর্থনকারী"
_nsfw:
respect: "স্পর্শকাতর মিডিয়া লুকান"
ignore: "স্পর্শকাতর মিডিয়া লুকাবেন না"
force: "সকল মিডিয়া লুকান"
_instanceTicker: _instanceTicker:
none: "দেখাবেন না" none: "দেখাবেন না"
remote: "রিমোট ব্যাবহারকারীদের জন্য দেখান" remote: "রিমোট ব্যাবহারকারীদের জন্য দেখান"
@ -949,6 +931,11 @@ _wordMute:
muteWords: "নিঃশব্দ করা শব্দগুলি" muteWords: "নিঃশব্দ করা শব্দগুলি"
muteWordsDescription: "স্পেস দিয়ে আলাদা করলে AND শর্ত তৈরি হবে এবং আলাদা লাইনে লিখলে OR শর্ত তৈরি হবে।" muteWordsDescription: "স্পেস দিয়ে আলাদা করলে AND শর্ত তৈরি হবে এবং আলাদা লাইনে লিখলে OR শর্ত তৈরি হবে।"
muteWordsDescription2: "রেগুলার এক্সপ্রেশন ব্যবহার করতে স্ল্যাশ দিয়ে কীওয়ার্ডকে ঘিরে রাখুন।" muteWordsDescription2: "রেগুলার এক্সপ্রেশন ব্যবহার করতে স্ল্যাশ দিয়ে কীওয়ার্ডকে ঘিরে রাখুন।"
softDescription: "টাইমলাইন থেকে নির্দিষ্ট শর্তানুযায়ী নোট লুকিয়ে রাখে।"
hardDescription: "নির্দিষ্ট শর্তানুযায়ী নোটগুলিকে টাইমলাইন থেকে বাদ দেয়। আপনি শর্ত পরিবর্তন করলেও যে নোটগুলি যোগ করা হয়নি সেগুলি বাদ দেওয়া হবে।"
soft: "নমনীয়"
hard: "কঠোর"
mutedNotes: "মিউট করা নোটগুলি"
_instanceMute: _instanceMute:
instanceMuteDescription: "কনফিগার করা ইন্সট্যান্সের সব নোট এবং রিনোট মিউট করুন, মিউট করা ইন্সট্যান্সের ব্যবহারকারীদের উত্তর সহ।" instanceMuteDescription: "কনফিগার করা ইন্সট্যান্সের সব নোট এবং রিনোট মিউট করুন, মিউট করা ইন্সট্যান্সের ব্যবহারকারীদের উত্তর সহ।"
instanceMuteDescription2: "প্রতিটিকে আলাদা লাইনে লিখুন" instanceMuteDescription2: "প্রতিটিকে আলাদা লাইনে লিখুন"
@ -1012,11 +999,15 @@ _theme:
infoFg: "তথ্যের পাঠ্য" infoFg: "তথ্যের পাঠ্য"
infoWarnBg: "ওয়ার্নিং এর পটভূমি" infoWarnBg: "ওয়ার্নিং এর পটভূমি"
infoWarnFg: "ওয়ার্নিং এর পাঠ্য" infoWarnFg: "ওয়ার্নিং এর পাঠ্য"
cwBg: "CW বাটনের পটভূমি"
cwFg: "CW বাটনের পাঠ্য"
cwHoverBg: "CW বাটনের পটভূমি (হভার)"
toastBg: "বিজ্ঞপ্তির পটভূমি" toastBg: "বিজ্ঞপ্তির পটভূমি"
toastFg: "বিজ্ঞপ্তির পাঠ্য" toastFg: "বিজ্ঞপ্তির পাঠ্য"
buttonBg: "বাটনের পটভূমি" buttonBg: "বাটনের পটভূমি"
buttonHoverBg: "বাটনের পটভূমি (হভার)" buttonHoverBg: "বাটনের পটভূমি (হভার)"
inputBorder: "ইনপুট ফিল্ডের বর্ডার" inputBorder: "ইনপুট ফিল্ডের বর্ডার"
listItemHoverBg: "লিস্ট আইটেমের পটভূমি (হোভার)"
driveFolderBg: "ড্রাইভ ফোল্ডারের পটভূমি" driveFolderBg: "ড্রাইভ ফোল্ডারের পটভূমি"
wallpaperOverlay: "ওয়ালপেপার ওভারলে" wallpaperOverlay: "ওয়ালপেপার ওভারলে"
badge: "ব্যাজ" badge: "ব্যাজ"
@ -1028,6 +1019,10 @@ _sfx:
note: "নোটগুলি" note: "নোটগুলি"
noteMy: "নোট (আপনার)" noteMy: "নোট (আপনার)"
notification: "বিজ্ঞপ্তি" notification: "বিজ্ঞপ্তি"
chat: "চ্যাট"
chatBg: "চ্যাট (ব্যাকগ্রাউন্ড)"
antenna: "অ্যান্টেনাগুলি"
channel: "চ্যানেলের বিজ্ঞপ্তি"
_ago: _ago:
future: "ভবিষ্যৎ" future: "ভবিষ্যৎ"
justNow: "এইমাত্র" justNow: "এইমাত্র"
@ -1044,14 +1039,37 @@ _time:
minute: "মিনিট" minute: "মিনিট"
hour: "ঘণ্টা" hour: "ঘণ্টা"
day: "দিন" day: "দিন"
_tutorial:
title: "Misskey কিভাবে ব্যাবহার করবেন"
step1_1: "স্বাগতম!"
step1_2: "এই স্ক্রীনটিকে \"টাইমলাইন\" বলা হয় এবং কালানুক্রমিক ক্রমে আপনার এবং আপনি যাদের \"অনুসরণ করেন\" তাদের \"নোটগুলি\" দেখায়৷"
step1_3: "আপনি আপনার টাইমলাইনে কিছু দেখতে পাবেন না কারণ আপনি এখনও কোনো নোট পোস্ট করেননি এবং আপনি কাউকে অনুসরণ করছেন না৷"
step2_1: "নোট তৈরি করার আগে বা কাউকে অনুসরণ করার আগে প্রথমে আপনার প্রোফাইলটি সম্পূর্ণ করুন।"
step2_2: "আপনি কে তা জানা অনেক লোকের জন্য আপনার নোটগুলি দেখা এবং অনুসরণ করাকে সহজ করে তোলে৷"
step3_1: "আপনি কি সফলভাবে আপনার প্রোফাইল সেট আপ করেছেন?"
step3_2: "এখন, কিছু নোট পোস্ট করার চেষ্টা করুন। পোস্ট ফর্ম খুলতে পেন্সিল চিহ্নযুক্ত বাটনে ক্লিক করুন।"
step3_3: "বিষয়বস্তু লেখার পরে, আপনি ফর্মের উপরের ডানদিকের বাটনে ক্লিক করে পোস্ট করতে পারেন।"
step3_4: "পোস্ট করার মত কিছু মনে পরছে না? \"আমি মিসকি সেট আপ করছি\" বললে কেমন হয়?"
step4_1: "পোস্ট করেছেন?"
step4_2: "সাবাশ! এখন আপনার নোট টাইমলাইনে দেখা যাবে।"
step5_1: "এখন অন্যদেরকে অনুসরণ করে আপনার টাইমলাইনকে প্রাণবন্ত করে তুলুন।"
step5_2: "আপনি {featured}-এ জনপ্রিয় নোটগুলি দেখতে পারেন, যাতে আপনি যে ব্যক্তিকে পছন্দ করেন তাকে বেছে নিতে এবং অনুসরণ করতে পারেন, অথবা {explore}-এ জনপ্রিয় ব্যবহারকারীদের দেখতে পারেন৷"
step5_3: "একজন ব্যবহারকারীকে অনুসরণ করতে, ব্যবহারকারীর আইকনে ক্লিক করুন এবং ব্যবহারকারীর পৃষ্ঠাতে \"অনুসরণ করুন\" বাটনে ক্লিক করুন।"
step5_4: "যদি ব্যবহারকারীর নামের পাশে একটি লক আইকন থাকে তাহলে আপনার অনুসরণের অনুরোধ গ্রহণ করার জন্য তারা কিছু সময় নিতে পারে।"
step6_1: "সবকিছু ঠিক থাকলে আপনি টাইমলাইনে অন্য ব্যবহারকারীদের নোট দেখতে পাবেন।"
step6_2: "আপনি সহজেই আপনার প্রতিক্রিয়া জানাতে অন্য ব্যক্তির নোটে \"রিঅ্যাকশন\" যোগ করতে পারেন।"
step6_3: "একটি রিঅ্যাকশন যোগ করতে, নোটে \"+\" চিহ্নে ক্লিক করুন এবং আপনার পছন্দের রিঅ্যাকশন নির্বাচন করুন।"
step7_1: "অভিনন্দন! আপনি এখন Misskey-র প্রাথমিক টিউটোরিয়ালটি শেষ করেছেন।"
step7_2: "আপনি যদি Misskey সম্পর্কে আরও জানতে চান, তাহলে {help} এ দেখুন।"
step7_3: "এখন Misskey উপভোগ করুন 🚀"
_2fa: _2fa:
alreadyRegistered: "আপনি ইতিমধ্যে একটি 2-ফ্যাক্টর অথেনটিকেশন ডিভাইস নিবন্ধন করেছেন৷" alreadyRegistered: "আপনি ইতিমধ্যে একটি 2-ফ্যাক্টর অথেনটিকেশন ডিভাইস নিবন্ধন করেছেন৷"
step1: "প্রথমে, আপনার ডিভাইসে {a} বা {b} এর মতো একটি অথেনটিকেশন অ্যাপ ইনস্টল করুন৷" step1: "প্রথমে, আপনার ডিভাইসে {a} বা {b} এর মতো একটি অথেনটিকেশন অ্যাপ ইনস্টল করুন৷"
step2: "এরপরে, অ্যাপের সাহায্যে প্রদর্শিত QR কোডটি স্ক্যান করুন।" step2: "এরপরে, অ্যাপের সাহায্যে প্রদর্শিত QR কোডটি স্ক্যান করুন।"
step2Url: "ডেস্কটপ অ্যাপে, নিম্নলিখিত URL লিখুন:"
step3: "অ্যাপে প্রদর্শিত টোকেনটি লিখুন এবং আপনার কাজ শেষ।" step3: "অ্যাপে প্রদর্শিত টোকেনটি লিখুন এবং আপনার কাজ শেষ।"
step4: "আপনাকে এখন থেকে লগ ইন করার সময়, এইভাবে টোকেন লিখতে হবে।" step4: "আপনাকে এখন থেকে লগ ইন করার সময়, এইভাবে টোকেন লিখতে হবে।"
securityKeyInfo: "আপনি একটি হার্ডওয়্যার সিকিউরিটি কী ব্যবহার করে লগ ইন করতে পারেন যা FIDO2 বা ডিভাইসের ফিঙ্গারপ্রিন্ট সেন্সর বা পিন সমর্থন করে৷" securityKeyInfo: "আপনি একটি হার্ডওয়্যার সিকিউরিটি কী ব্যবহার করে লগ ইন করতে পারেন যা FIDO2 বা ডিভাইসের ফিঙ্গারপ্রিন্ট সেন্সর বা পিন সমর্থন করে৷"
renewTOTPCancel: "না, ধন্যবাদ"
_permissions: _permissions:
"read:account": "অ্যাকাউন্টের তথ্য দেখুন" "read:account": "অ্যাকাউন্টের তথ্য দেখুন"
"write:account": "অ্যাকাউন্টের তথ্য সম্পাদন করুন" "write:account": "অ্যাকাউন্টের তথ্য সম্পাদন করুন"
@ -1190,7 +1208,6 @@ _profile:
changeBanner: "ব্যানার পরিবর্তন করুন" changeBanner: "ব্যানার পরিবর্তন করুন"
_exportOrImport: _exportOrImport:
allNotes: "সকল নোট" allNotes: "সকল নোট"
clips: "ক্লিপ"
followingList: "অনুসরণ করা হচ্ছে" followingList: "অনুসরণ করা হচ্ছে"
muteList: "মিউট" muteList: "মিউট"
blockingList: "ব্লক" blockingList: "ব্লক"
@ -1309,7 +1326,6 @@ _notification:
pollEnded: "পোল শেষ" pollEnded: "পোল শেষ"
receiveFollowRequest: "প্রাপ্ত অনুসরণের অনুরোধসমূহ" receiveFollowRequest: "প্রাপ্ত অনুসরণের অনুরোধসমূহ"
followRequestAccepted: "গৃহীত অনুসরণের অনুরোধসমূহ" followRequestAccepted: "গৃহীত অনুসরণের অনুরোধসমূহ"
login: "প্রবেশ করুন"
app: "লিঙ্ক করা অ্যাপ থেকে বিজ্ঞপ্তি" app: "লিঙ্ক করা অ্যাপ থেকে বিজ্ঞপ্তি"
_actions: _actions:
followBack: "ফলো ব্যাক করেছে" followBack: "ফলো ব্যাক করেছে"
@ -1340,12 +1356,4 @@ _deck:
_webhookSettings: _webhookSettings:
name: "নাম" name: "নাম"
active: "চালু" active: "চালু"
_abuseReport:
_notificationRecipient:
_recipientType:
mail: "ইমেইল"
_moderationLogTypes:
suspend: "স্থগিত করা"
resetPassword: "পাসওয়ার্ড রিসেট করুন"
_reversi:
total: "মোট"

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,3 @@
--- ---
_lang_: "Dansk" _lang_: "Dansk"
headlineMisskey: ""
introMisskey: "ようこそMisskeyは、オープンソースの分散型マイクロブログサービスです。\n「ート」を作成して、いま起こっていることを共有したり、あなたについて皆に発信しよう📡\n「リアクション」機能で、皆のートに素早く反応を追加することもできます👍\n新しい世界を探検しよう🚀"

File diff suppressed because it is too large Load diff

View file

@ -104,6 +104,7 @@ clickToShow: "Κάντε κλικ για εμφάνιση"
add: "Προσθέστε" add: "Προσθέστε"
reaction: "Αντιδράσεις" reaction: "Αντιδράσεις"
reactions: "Αντιδράσεις" reactions: "Αντιδράσεις"
reactionSetting: "Αντιδράσεις για εμφάνιση στην επιλογή αντίδρασης"
reactionSettingDescription2: "Σύρετε για να αλλάξετε τη σειρά, κάντε κλικ για να διαγράψετε, πατήστε \"+\" για να προσθέσετε." reactionSettingDescription2: "Σύρετε για να αλλάξετε τη σειρά, κάντε κλικ για να διαγράψετε, πατήστε \"+\" για να προσθέσετε."
rememberNoteVisibility: "Θυμήσου τις ρυθμίσεις ορατότητας σημειώματος" rememberNoteVisibility: "Θυμήσου τις ρυθμίσεις ορατότητας σημειώματος"
attachCancel: "Διαγραφή αρχείου" attachCancel: "Διαγραφή αρχείου"
@ -171,11 +172,11 @@ explore: "Εξερευνήστε"
messageRead: "Διαβάστηκε" messageRead: "Διαβάστηκε"
startMessaging: "Ξεκινήστε μία συνομιλία" startMessaging: "Ξεκινήστε μία συνομιλία"
nUsersRead: "διαβάστηκε από {n}" nUsersRead: "διαβάστηκε από {n}"
tos: "Όροι χρήσης"
start: "Ας αρχίσουμε" start: "Ας αρχίσουμε"
home: "Κεντρικό" home: "Κεντρικό"
activity: "Δραστηριότητα" activity: "Δραστηριότητα"
images: "Εικόνες" images: "Εικόνες"
image: "Εικόνες"
birthday: "Γενέθλια" birthday: "Γενέθλια"
registeredDate: "Έγινε μέλος στις" registeredDate: "Έγινε μέλος στις"
location: "Τοποθεσία" location: "Τοποθεσία"
@ -227,6 +228,7 @@ userList: "Λίστες"
about: "Πληροφορίες" about: "Πληροφορίες"
moderator: "Συντονιστής" moderator: "Συντονιστής"
moderation: "Συντονισμός" moderation: "Συντονισμός"
cacheClear: "Εκκαθάριση προσωρινής μνήμης"
markAsReadAllNotifications: "Όλες οι ειδοποιήσεις διαβάστηκαν" markAsReadAllNotifications: "Όλες οι ειδοποιήσεις διαβάστηκαν"
members: "Μέλη" members: "Μέλη"
transfer: "Μεταφορά" transfer: "Μεταφορά"
@ -285,9 +287,6 @@ searchByGoogle: "Αναζήτηση"
file: "Αρχεία" file: "Αρχεία"
recommended: "Προτεινόμενα" recommended: "Προτεινόμενα"
cannotUploadBecauseNoFreeSpace: "Το ανέβασμα απέτυχε λόγω ανεπαρκούς Αποθηκευτικού Χώρου" cannotUploadBecauseNoFreeSpace: "Το ανέβασμα απέτυχε λόγω ανεπαρκούς Αποθηκευτικού Χώρου"
icon: "Εικονίδιο"
replies: "Απάντηση"
renotes: "Κοινοποίηση σημειώματος"
_email: _email:
_follow: _follow:
title: "Έχετε ένα νέο ακόλουθο" title: "Έχετε ένα νέο ακόλουθο"
@ -301,6 +300,10 @@ _theme:
_sfx: _sfx:
note: "Σημειώματα" note: "Σημειώματα"
notification: "Ειδοποιήσεις" notification: "Ειδοποιήσεις"
chat: "Συνομιλία"
chatBg: "Συνομιλία (Παρασκήνιο)"
antenna: "Αντένες"
channel: "Ειδοποιήσεις καναλιών"
_ago: _ago:
future: "Μελλοντικό" future: "Μελλοντικό"
justNow: "Μόλις τώρα" justNow: "Μόλις τώρα"
@ -354,7 +357,6 @@ _profile:
username: "Όνομα μέλους" username: "Όνομα μέλους"
_exportOrImport: _exportOrImport:
allNotes: "Όλα τα σημειώματα" allNotes: "Όλα τα σημειώματα"
clips: "Κλιπ"
followingList: "Ακολουθεί" followingList: "Ακολουθεί"
muteList: "Μέλη σε σίγαση" muteList: "Μέλη σε σίγαση"
blockingList: "Μπλοκαρισμένα μέλη" blockingList: "Μπλοκαρισμένα μέλη"
@ -378,7 +380,6 @@ _notification:
renote: "Κοινοποίηση σημειώματος" renote: "Κοινοποίηση σημειώματος"
quote: "Παράθεση" quote: "Παράθεση"
reaction: "Αντιδράσεις" reaction: "Αντιδράσεις"
login: "Σύνδεση"
_actions: _actions:
reply: "Απάντηση" reply: "Απάντηση"
renote: "Κοινοποίηση σημειώματος" renote: "Κοινοποίηση σημειώματος"
@ -393,7 +394,4 @@ _deck:
mentions: "Επισημάνσεις" mentions: "Επισημάνσεις"
_webhookSettings: _webhookSettings:
name: "Όνομα" name: "Όνομα"
_moderationLogTypes:
suspend: "Αποβολή"
_reversi:
total: "Σύνολο"

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,230 +0,0 @@
import * as fs from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
import * as yaml from 'js-yaml';
import ts from 'typescript';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const parameterRegExp = /\{(\w+)\}/g;
function createMemberType(item) {
if (typeof item !== 'string') {
return ts.factory.createTypeLiteralNode(createMembers(item));
}
const parameters = Array.from(
item.matchAll(parameterRegExp),
([, parameter]) => parameter,
);
return parameters.length
? ts.factory.createTypeReferenceNode(
ts.factory.createIdentifier('ParameterizedString'),
[
ts.factory.createUnionTypeNode(
parameters.map((parameter) =>
ts.factory.createStringLiteral(parameter),
),
),
],
)
: ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword);
}
function createMembers(record) {
return Object.entries(record).map(([k, v]) => {
const node = ts.factory.createPropertySignature(
undefined,
ts.factory.createStringLiteral(k),
undefined,
createMemberType(v),
);
if (typeof v === 'string') {
ts.addSyntheticLeadingComment(
node,
ts.SyntaxKind.MultiLineCommentTrivia,
`*
* ${v.replace(/\n/g, '\n * ')}
`,
true,
);
}
return node;
});
}
export default function generateDTS() {
const locale = yaml.load(fs.readFileSync(`${__dirname}/ja-JP.yml`, 'utf-8'));
const members = createMembers(locale);
const elements = [
ts.factory.createVariableStatement(
[ts.factory.createToken(ts.SyntaxKind.DeclareKeyword)],
ts.factory.createVariableDeclarationList(
[
ts.factory.createVariableDeclaration(
ts.factory.createIdentifier('kParameters'),
undefined,
ts.factory.createTypeOperatorNode(
ts.SyntaxKind.UniqueKeyword,
ts.factory.createKeywordTypeNode(ts.SyntaxKind.SymbolKeyword),
),
undefined,
),
],
ts.NodeFlags.Const,
),
),
ts.factory.createInterfaceDeclaration(
[ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],
ts.factory.createIdentifier('ParameterizedString'),
[
ts.factory.createTypeParameterDeclaration(
undefined,
ts.factory.createIdentifier('T'),
ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
),
],
undefined,
[
ts.factory.createPropertySignature(
undefined,
ts.factory.createComputedPropertyName(
ts.factory.createIdentifier('kParameters'),
),
undefined,
ts.factory.createTypeReferenceNode(
ts.factory.createIdentifier('T'),
undefined,
),
),
],
),
ts.factory.createInterfaceDeclaration(
[ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],
ts.factory.createIdentifier('ILocale'),
undefined,
undefined,
[
ts.factory.createIndexSignature(
undefined,
[
ts.factory.createParameterDeclaration(
undefined,
undefined,
ts.factory.createIdentifier('_'),
undefined,
ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
undefined,
),
],
ts.factory.createUnionTypeNode([
ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
ts.factory.createTypeReferenceNode(
ts.factory.createIdentifier('ParameterizedString'),
),
ts.factory.createTypeReferenceNode(
ts.factory.createIdentifier('ILocale'),
undefined,
),
]),
),
],
),
ts.factory.createInterfaceDeclaration(
[ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],
ts.factory.createIdentifier('Locale'),
undefined,
[
ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [
ts.factory.createExpressionWithTypeArguments(
ts.factory.createIdentifier('ILocale'),
undefined,
),
]),
],
members,
),
ts.factory.createVariableStatement(
[ts.factory.createToken(ts.SyntaxKind.DeclareKeyword)],
ts.factory.createVariableDeclarationList(
[
ts.factory.createVariableDeclaration(
ts.factory.createIdentifier('locales'),
undefined,
ts.factory.createTypeLiteralNode([
ts.factory.createIndexSignature(
undefined,
[
ts.factory.createParameterDeclaration(
undefined,
undefined,
ts.factory.createIdentifier('lang'),
undefined,
ts.factory.createKeywordTypeNode(
ts.SyntaxKind.StringKeyword,
),
undefined,
),
],
ts.factory.createTypeReferenceNode(
ts.factory.createIdentifier('Locale'),
undefined,
),
),
]),
undefined,
),
],
ts.NodeFlags.Const,
),
),
ts.factory.createFunctionDeclaration(
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
undefined,
ts.factory.createIdentifier('build'),
undefined,
[],
ts.factory.createTypeReferenceNode(
ts.factory.createIdentifier('Locale'),
undefined,
),
undefined,
),
ts.factory.createExportDefault(ts.factory.createIdentifier('locales')),
];
ts.addSyntheticLeadingComment(
elements[0],
ts.SyntaxKind.MultiLineCommentTrivia,
' eslint-disable ',
true,
);
ts.addSyntheticLeadingComment(
elements[0],
ts.SyntaxKind.SingleLineCommentTrivia,
' This file is generated by locales/generateDTS.js',
true,
);
ts.addSyntheticLeadingComment(
elements[0],
ts.SyntaxKind.SingleLineCommentTrivia,
' Do not edit this file directly.',
true,
);
const printed = ts
.createPrinter({
newLine: ts.NewLineKind.LineFeed,
})
.printList(
ts.ListFormat.MultiLine,
ts.factory.createNodeArray(elements),
ts.createSourceFile(
'index.d.ts',
'',
ts.ScriptTarget.ESNext,
true,
ts.ScriptKind.TS,
),
);
fs.writeFileSync(`${__dirname}/index.d.ts`, printed, 'utf-8');
}

View file

@ -1,5 +1,2 @@
--- ---
_lang_: "japanski"
ok: "OK"
gotIt: "Razumijem"
cancel: "otkazati"

View file

@ -1,18 +1,2 @@
--- ---
_lang_: "Japonè"
password: "modpas"
ok: "OK"
gotIt: "Konprann"
cancel: "anile"
noThankYou: "Sispann"
instance: "sèvè"
profile: "pwofil"
save: "kenbe"
delete: "efase"
instances: "sèvè"
remove: "efase"
smtpPass: "modpas"
_2fa:
renewTOTPCancel: "Sispann"
_widgets:
profile: "pwofil"

View file

@ -1,105 +0,0 @@
---
_lang_: "Magyar"
monthAndDay: "{month}.{day}."
search: "Keresés"
notifications: "Értesítések"
username: "Felhasználónév"
password: "Jelszó"
forgotPassword: "Elfelejtett jelszó"
ok: "OK"
gotIt: "Rendben"
cancel: "Mégse"
noThankYou: "Nem, köszönöm"
enterUsername: "Felhasználónév megadása"
renotedBy: "{user} Renotolta"
noNotes: "Nincs Note"
noNotifications: "Nincs értesítés"
instance: "Szerver"
settings: "Beállítások"
notificationSettings: "Értesítés beállításai"
basicSettings: "Alapbeállítás"
otherSettings: "Egyéb beállítások"
openInWindow: "Megnyitás ablakban"
profile: "Saját profil"
timeline: "Idővonal"
noAccountDescription: "Nincs leírás"
login: "Bejelentkezés"
loggingIn: "Belépés"
logout: "Kijelentkezés"
signup: "Regisztráció"
uploading: "Feltöltés"
save: "Mentés"
users: "Felhasználók"
addUser: "Felhasználó hozzáadása"
favorite: "Kedvencek"
favorites: "Kedvencek"
unfavorite: "Törlés a kedvencek közül."
favorited: "Kedvencek közé rakva."
alreadyFavorited: "Már a kedvencek között van."
cantFavorite: "Nem sikerült a kedvencek közé rakni."
pin: "Rögzítés"
unpin: "Rögzítés feloldása"
copyContent: "Tartalom másolása"
copyLink: "Hivatkozás Másolása"
delete: "Törlés"
deleteAndEdit: "Törlés és szerkesztés"
deleteAndEditConfirm: "Biztosan törlöd ezt a jegyzetet és újrafogalmazza? Így eveszíted az összes reakciót, renote-ot és választ."
addToList: "Hozzáadás a listákhoz"
privacy: "Adatvédelem"
makeFollowManuallyApprove: "Csak jóváhagyással követhetnek"
defaultNoteVisibility: "Alapértelmezett láthatóság"
follow: "Követés"
followRequest: "Követés kérése"
followRequests: "Követési kérések"
unfollow: "Követés visszavonása"
followRequestPending: "Függőben levő követési kérés"
enterEmoji: "Írj egy emoji-t"
renote: "Renote"
unrenote: "Renote visszavonása"
renoted: "Renotolva"
cantRenote: "Nem lehet Renotolni"
cantReRenote: "A Renote nem renotálható"
quote: "Idézet"
inChannelRenote: "Csak csatornán bellüli Renote"
inChannelQuote: "Csak csatornán bellüli idézet"
pinnedNote: "Csatolt jegyzet"
pinned: "Rögzítés"
you: "Te"
clickToShow: "Kattints ide"
sensitive: "Érzékeny"
add: "Hozzáad"
reaction: "Reakciók"
reactions: "Reakciók"
instances: "Szerver"
remove: "Törlés"
pinnedNotes: "Csatolt jegyzet"
smtpUser: "Felhasználónév"
smtpPass: "Jelszó"
user: "Felhasználók"
searchByGoogle: "Keresés"
renotes: "Renote"
_theme:
keys:
renote: "Renote"
_sfx:
notification: "Értesítések"
_2fa:
renewTOTPCancel: "Nem, köszönöm"
_widgets:
profile: "Saját profil"
notifications: "Értesítések"
timeline: "Idővonal"
_profile:
username: "Felhasználónév"
_notification:
_types:
renote: "Renote"
quote: "Idézet"
reaction: "Reakciók"
login: "Bejelentkezés"
_actions:
renote: "Renote"
_deck:
_columns:
notifications: "Értesítések"
tl: "Idővonal"

File diff suppressed because it is too large Load diff

10590
locales/index.d.ts vendored

File diff suppressed because it is too large Load diff

View file

@ -2,8 +2,8 @@
* Languages Loader * Languages Loader
*/ */
import * as fs from 'node:fs'; const fs = require('fs');
import * as yaml from 'js-yaml'; const yaml = require('js-yaml');
const merge = (...args) => args.reduce((a, c) => ({ const merge = (...args) => args.reduce((a, c) => ({
...a, ...a,
@ -15,7 +15,6 @@ const merge = (...args) => args.reduce((a, c) => ({
const languages = [ const languages = [
'ar-SA', 'ar-SA',
'ca-ES',
'cs-CZ', 'cs-CZ',
'da-DK', 'da-DK',
'de-DE', 'de-DE',
@ -52,41 +51,20 @@ const primaries = {
// 何故か文字列にバックスペース文字が混入することがあり、YAMLが壊れるので取り除く // 何故か文字列にバックスペース文字が混入することがあり、YAMLが壊れるので取り除く
const clean = (text) => text.replace(new RegExp(String.fromCodePoint(0x08), 'g'), ''); 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(`${__dirname}/${c}.yml`, '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), {});
// 空文字列が入ることがあり、フォールバックが動作しなくなるのでプロパティごと消す module.exports = Object.entries(locales)
const removeEmpty = (obj) => { .reduce((a, [k ,v]) => (a[k] = (() => {
for (const [k, v] of Object.entries(obj)) { const [lang] = k.split('-');
if (v === '') { switch (k) {
delete obj[k]; case 'ja-JP': return v;
} else if (typeof v === 'object') { case 'ja-KS':
removeEmpty(v); case 'en-US': return merge(locales['ja-JP'], v);
} default: return merge(
locales['ja-JP'],
locales['en-US'],
locales[`${lang}-${primaries[lang]}`] || {},
v
);
} }
return obj; })(), a), {});
};
removeEmpty(locales);
return Object.entries(locales)
.reduce((a, [k, v]) => (a[k] = (() => {
const [lang] = k.split('-');
switch (k) {
case 'ja-JP': return v;
case 'ja-KS':
case 'en-US': return merge(locales['ja-JP'], v);
default: return merge(
locales['ja-JP'],
locales['en-US'],
locales[`${lang}-${primaries[lang]}`] ?? {},
v
);
}
})(), a), {});
}
export default build();

Some files were not shown because too many files have changed in this diff Show more