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
2948 changed files with 67130 additions and 289553 deletions

View file

@ -1,236 +0,0 @@
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Misskey configuration
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# ┌─────┐
#───┘ 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: 3000
# ┌──────────────────────────┐
#───┘ PostgreSQL configuration └────────────────────────────────
db:
host: postgres
port: 5432
# Database name
db: postgres
# Auth
user: postgres
pass: ci
# 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
# ┌───────────────────────────┐
#───┘ 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: global
# ┌───────────────┐
#───┘ 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'
# ┌─────────────────────┐
#───┘ Other configuration └─────────────────────────────────────
# Whether disable HSTS
#disableHsts: true
# Number of worker processes
#clusterLimit: 1
# Job concurrency per worker
# deliverJobConcurrency: 128
# inboxJobConcurrency: 16
# relashionshipJobConcurrency: 16
# What's relashionshipJob?:
# Follow, unfollow, block and unblock(ings) while following-imports, etc. or account migrations.
# Job rate limiter
# deliverJobPerSec: 128
# inboxJobPerSec: 32
# relashionshipJobPerSec: 64
# Job attempts
# deliverJobMaxAttempts: 12
# inboxJobMaxAttempts: 8
# Local address used for outgoing requests
#outgoingAddress: 127.0.0.1
# IP address family used for outgoing request (ipv4, ipv6 or dual)
#outgoingAddressFamily: ipv4
# Amount of characters that can be used when writing notes. Longer notes will be rejected. (minimum: 1)
#maxNoteLength: 3000
# Amount of characters that will be saved for remote notes. Longer notes will be truncated to this length. (minimum: 1)
#maxRemoteNoteLength: 100000
# Amount of characters that can be used when writing content warnings. Longer warnings will be rejected. (minimum: 1)
#maxCwLength: 500
# Amount of characters that will be saved for remote content warnings. Longer warnings will be truncated to this length. (minimum: 1)
#maxRemoteCwLength: 5000
# Amount of characters that can be used when writing media descriptions (alt text). Longer descriptions will be rejected. (minimum: 1)
#maxAltTextLength: 20000
# Amount of characters that will be saved for remote media descriptions (alt text). Longer descriptions will be truncated to this length. (minimum: 1)
#maxRemoteAltTextLength: 100000
# 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)
# Proxy remote files by this instance or mediaProxy to prevent remote files from running in remote domains.
proxyRemoteFiles: true
# Movie Thumbnail Generation URL
# There is no reference implementation.
# For example, Misskey will point to the following URL:
# https://example.com/thumbnail.webp?thumbnail=1&url=https%3A%2F%2Fstorage.example.com%2Fpath%2Fto%2Fvideo.mp4
#videoThumbnailGenerator: https://example.com
# Sign outgoing ActivityPub GET request (default: true)
signToActivityPubGet: true
# Sign outgoing ActivityPub Activities (default: true)
# Linked Data signatures are cryptographic signatures attached to each activity to provide proof of authenticity.
# When using authorized fetch, this is often undesired as any signed activity can be forwarded to a blocked instance by relays and other instances.
# This setting allows admins to disable LD signatures for increased privacy, at the expense of fewer relayed activities and additional inbound fetch (GET) requests.
attachLdSignatureForRelays: true
# check that inbound ActivityPub GET requests are signed ("authorized fetch")
checkActivityPubGetSignature: false
# 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: [
# '127.0.0.1/32'
#]
#customMOTD: ['Hello World', 'The sharks rule all', 'Shonks']
# Upload or download file size limits (bytes)
#maxFileSize: 262144000
# CHMod-style permission bits to apply to uploaded files.
# Permission bits are specified as a base-8 string representing User/Group/Other permissions.
# This setting is only useful for custom deployments, such as using a reverse proxy to serve media.
#filePermissionBits: '644'

View file

@ -1,229 +0,0 @@
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Misskey configuration
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# ┌─────┐
#───┘ 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
# Amount of characters that can be used when writing notes. Longer notes will be rejected. (minimum: 1)
#maxNoteLength: 3000
# Amount of characters that will be saved for remote notes. Longer notes will be truncated to this length. (minimum: 1)
#maxRemoteNoteLength: 100000
# Amount of characters that can be used when writing content warnings. Longer warnings will be rejected. (minimum: 1)
#maxCwLength: 500
# Amount of characters that will be saved for remote content warnings. Longer warnings will be truncated to this length. (minimum: 1)
#maxRemoteCwLength: 5000
# Amount of characters that can be used when writing media descriptions (alt text). Longer descriptions will be rejected. (minimum: 1)
#maxAltTextLength: 20000
# Amount of characters that will be saved for remote media descriptions (alt text). Longer descriptions will be truncated to this length. (minimum: 1)
#maxRemoteAltTextLength: 100000
# 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
# CHMod-style permission bits to apply to uploaded files.
# Permission bits are specified as a base-8 string representing User/Group/Other permissions.
# This setting is only useful for custom deployments, such as using a reverse proxy to serve media.
#filePermissionBits: '644'

View file

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

View file

@ -2,68 +2,10 @@
# 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 WEHN 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
# ┌─────┐
#───┘ URL └─────────────────────────────────────────────────────
# Final accessible URL seen by a user.
# You can set url from an environment variable instead.
url: https://example.tld/
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
@ -96,11 +38,9 @@ db:
port: 5432
# Database name
# You can set db from an environment variable instead.
db: misskey
# Auth
# You can set user and pass from environment variables instead.
user: example-misskey-user
pass: example-misskey-pass
@ -111,23 +51,6 @@ db:
#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 └─────────────────────────────────────
@ -139,51 +62,15 @@ redis:
#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
# ┌─────────────────────────────┐
#───┘ Elasticsearch configuration └─────────────────────────────
#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 └─────────────────────────────
# You can set scope to local (default value) or global
# (include notes from remote).
#meilisearch:
# host: meilisearch
# port: 7700
# apiKey: ''
# ssl: true
# index: ''
# scope: global
#elasticsearch:
# host: localhost
# port: 9200
# ssl: false
# user:
# pass:
# ┌───────────────┐
#───┘ ID generation └───────────────────────────────────────────
@ -194,7 +81,6 @@ redis:
# 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
@ -202,22 +88,7 @@ redis:
# 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'
id: 'aid'
# ┌─────────────────────┐
#───┘ Other configuration └─────────────────────────────────────
@ -231,38 +102,18 @@ id: 'aidx'
# Job concurrency per worker
# deliverJobConcurrency: 128
# inboxJobConcurrency: 16
# relationshipJobConcurrency: 16
# What's relationshipJob?:
# Follow, unfollow, block and unblock(ings) while following-imports, etc. or account migrations.
# Job rate limiter
# deliverJobPerSec: 128
# inboxJobPerSec: 32
# relationshipJobPerSec: 64
# inboxJobPerSec: 16
# Job attempts
# deliverJobMaxAttempts: 12
# inboxJobMaxAttempts: 8
# Local address used for outgoing requests
#outgoingAddress: 127.0.0.1
# IP address family used for outgoing request (ipv4, ipv6 or dual)
#outgoingAddressFamily: ipv4
# Amount of characters that can be used when writing notes. Longer notes will be rejected. (minimum: 1)
#maxNoteLength: 3000
# Amount of characters that will be saved for remote notes. Longer notes will be truncated to this length. (minimum: 1)
#maxRemoteNoteLength: 100000
# Amount of characters that can be used when writing content warnings. Longer warnings will be rejected. (minimum: 1)
#maxCwLength: 500
# Amount of characters that will be saved for remote content warnings. Longer warnings will be truncated to this length. (minimum: 1)
#maxRemoteCwLength: 5000
# Amount of characters that can be used when writing media descriptions (alt text). Longer descriptions will be rejected. (minimum: 1)
#maxAltTextLength: 20000
# Amount of characters that will be saved for remote media descriptions (alt text). Longer descriptions will be truncated to this length. (minimum: 1)
#maxRemoteAltTextLength: 100000
# Proxy for HTTP/HTTPS
#proxy: http://127.0.0.1:3128
@ -281,39 +132,15 @@ proxyBypassHosts:
# Media Proxy
#mediaProxy: https://example.com/proxy
# Proxy remote files (default: true)
# Proxy remote files by this instance or mediaProxy to prevent remote files from running in remote domains.
proxyRemoteFiles: true
# Proxy remote files (default: false)
#proxyRemoteFiles: true
# Movie Thumbnail Generation URL
# There is no reference implementation.
# For example, Misskey will point to the following URL:
# https://example.com/thumbnail.webp?thumbnail=1&url=https%3A%2F%2Fstorage.example.com%2Fpath%2Fto%2Fvideo.mp4
#videoThumbnailGenerator: https://example.com
# Sign outgoing ActivityPub GET request (default: true)
# Sign to ActivityPub GET request (default: true)
signToActivityPubGet: true
# Sign outgoing ActivityPub Activities (default: true)
# Linked Data signatures are cryptographic signatures attached to each activity to provide proof of authenticity.
# When using authorized fetch, this is often undesired as any signed activity can be forwarded to a blocked instance by relays and other instances.
# This setting allows admins to disable LD signatures for increased privacy, at the expense of fewer relayed activities and additional inbound fetch (GET) requests.
attachLdSignatureForRelays: true
# check that inbound ActivityPub GET requests are signed ("authorized fetch")
checkActivityPubGetSignature: false
# 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: [
# '127.0.0.1/32'
#]
#customMOTD: ['Hello World', 'The sharks rule all', 'Shonks']
# Upload or download file size limits (bytes)
#maxFileSize: 262144000
# CHMod-style permission bits to apply to uploaded files.
# Permission bits are specified as a base-8 string representing User/Group/Other permissions.
# This setting is only useful for custom deployments, such as using a reverse proxy to serve media.
#filePermissionBits: '644'

View file

@ -2,63 +2,6 @@
# 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
# ┌─────┐
#───┘ URL └─────────────────────────────────────────────────────
@ -87,10 +30,6 @@ url: https://example.tld/
# The port that your Misskey server should listen on.
port: 3000
# You can also use UNIX domain socket.
# socket: /path/to/misskey.sock
# chmodSocket: '777'
# ┌──────────────────────────┐
#───┘ PostgreSQL configuration └────────────────────────────────
@ -99,10 +38,10 @@ db:
port: 5432
# Database name
db: sharkey
db: misskey
# Auth
user: sharkey
user: example-misskey-user
pass: example-misskey-pass
# Whether disable Caching queries
@ -112,23 +51,6 @@ db:
#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 └─────────────────────────────────────
@ -139,62 +61,16 @@ redis:
#pass: example-pass
#prefix: example-prefix
#db: 1
# You can specify more ioredis options...
#username: example-username
#redisForPubsub:
# ┌─────────────────────────────┐
#───┘ Elasticsearch configuration └─────────────────────────────
#elasticsearch:
# 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
#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: global
# port: 9200
# ssl: false
# user:
# pass:
# ┌───────────────┐
#───┘ ID generation └───────────────────────────────────────────
@ -205,7 +81,6 @@ redis:
# 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
@ -213,22 +88,7 @@ redis:
# 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'
id: 'aid'
# ┌─────────────────────┐
#───┘ Other configuration └─────────────────────────────────────
@ -240,40 +100,20 @@ id: 'aidx'
#clusterLimit: 1
# Job concurrency per worker
#deliverJobConcurrency: 128
#inboxJobConcurrency: 16
#relationshipJobConcurrency: 16
# What's relationshipJob?:
# Follow, unfollow, block and unblock(ings) while following-imports, etc. or account migrations.
# deliverJobConcurrency: 128
# inboxJobConcurrency: 16
# Job rate limiter
#deliverJobPerSec: 128
#inboxJobPerSec: 32
#relationshipJobPerSec: 64
# deliverJobPerSec: 128
# inboxJobPerSec: 16
# Job attempts
#deliverJobMaxAttempts: 12
#inboxJobMaxAttempts: 8
# Local address used for outgoing requests
#outgoingAddress: 127.0.0.1
# deliverJobMaxAttempts: 12
# inboxJobMaxAttempts: 8
# IP address family used for outgoing request (ipv4, ipv6 or dual)
#outgoingAddressFamily: ipv4
# Amount of characters that can be used when writing notes. Longer notes will be rejected. (minimum: 1)
#maxNoteLength: 3000
# Amount of characters that will be saved for remote notes. Longer notes will be truncated to this length. (minimum: 1)
#maxRemoteNoteLength: 100000
# Amount of characters that can be used when writing content warnings. Longer warnings will be rejected. (minimum: 1)
#maxCwLength: 500
# Amount of characters that will be saved for remote content warnings. Longer warnings will be truncated to this length. (minimum: 1)
#maxRemoteCwLength: 5000
# Amount of characters that can be used when writing media descriptions (alt text). Longer descriptions will be rejected. (minimum: 1)
#maxAltTextLength: 20000
# Amount of characters that will be saved for remote media descriptions (alt text). Longer descriptions will be truncated to this length. (minimum: 1)
#maxRemoteAltTextLength: 100000
# Proxy for HTTP/HTTPS
#proxy: http://127.0.0.1:3128
@ -295,9 +135,9 @@ proxyBypassHosts:
# * Perform image compression (on a different server resource than the main process)
#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.
proxyRemoteFiles: true
#proxyRemoteFiles: true
# Movie Thumbnail Generation URL
# There is no reference implementation.
@ -305,37 +145,12 @@ proxyRemoteFiles: true
# https://example.com/thumbnail.webp?thumbnail=1&url=https%3A%2F%2Fstorage.example.com%2Fpath%2Fto%2Fvideo.mp4
#videoThumbnailGenerator: https://example.com
# Sign outgoing ActivityPub GET request (default: true)
# Sign to ActivityPub GET request (default: true)
signToActivityPubGet: true
# Sign outgoing ActivityPub Activities (default: true)
# Linked Data signatures are cryptographic signatures attached to each activity to provide proof of authenticity.
# When using authorized fetch, this is often undesired as any signed activity can be forwarded to a blocked instance by relays and other instances.
# This setting allows admins to disable LD signatures for increased privacy, at the expense of fewer relayed activities and additional inbound fetch (GET) requests.
attachLdSignatureForRelays: true
# check that inbound ActivityPub GET requests are signed ("authorized fetch")
checkActivityPubGetSignature: false
# 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: [
# '127.0.0.1/32'
#]
#customMOTD: ['Hello World', 'The sharks rule all', 'Shonks']
# Upload or download file size limits (bytes)
#maxFileSize: 262144000
# timeout and maximum size for imports (e.g. note imports)
#import:
# downloadTimeout: 30
# maxFileSize: 262144000
# PID File of master process
#pidFile: /tmp/misskey.pid
# CHMod-style permission bits to apply to uploaded files.
# Permission bits are specified as a base-8 string representing User/Group/Other permissions.
# This setting is only useful for custom deployments, such as using a reverse proxy to serve media.
#filePermissionBits: '644'

View file

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

View file

@ -51,23 +51,6 @@ db:
#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 └─────────────────────────────────────
@ -79,47 +62,15 @@ redis:
#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
# ┌─────────────────────────────┐
#───┘ Elasticsearch configuration └─────────────────────────────
#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: ''
#elasticsearch:
# host: localhost
# port: 9200
# ssl: false
# user:
# pass:
# ┌───────────────┐
#───┘ ID generation └───────────────────────────────────────────
@ -130,7 +81,6 @@ redis:
# 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
@ -138,22 +88,7 @@ redis:
# 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'
id: 'aid'
# ┌─────────────────────┐
#───┘ Other configuration └─────────────────────────────────────
@ -170,7 +105,7 @@ id: 'aidx'
# Job rate limiter
# deliverJobPerSec: 128
# inboxJobPerSec: 32
# inboxJobPerSec: 16
# Job attempts
# deliverJobMaxAttempts: 12
@ -197,8 +132,8 @@ proxyBypassHosts:
# Media Proxy
#mediaProxy: https://example.com/proxy
# Proxy remote files (default: true)
proxyRemoteFiles: true
# Proxy remote files (default: false)
#proxyRemoteFiles: true
# Sign to ActivityPub GET request (default: true)
signToActivityPubGet: true

View file

@ -1,3 +1,5 @@
version: '3.8'
services:
app:
build:
@ -6,7 +8,6 @@ services:
volumes:
- ../:/workspace:cached
- node_modules:/workspace/node_modules
command: sleep infinity
@ -45,7 +46,6 @@ services:
volumes:
postgres-data:
redis-data:
node_modules:
networks:
internal_network:

View file

@ -2,16 +2,10 @@
set -xe
sudo chown node node_modules
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
sudo chown -R node /workspace
git submodule update --init
corepack install
corepack enable
pnpm config set store-dir /home/node/.local/share/pnpm/store
pnpm install --frozen-lockfile
cp .devcontainer/devcontainer.yml .config/default.yml
pnpm build
pnpm migrate
pnpm exec cypress install

View file

@ -7,11 +7,13 @@ Dockerfile
build/
built/
db/
.devcontainer/compose.yml
docker-compose.yml
elasticsearch/
node_modules/
packages/*/node_modules
redis/
files/
misskey-assets/
fluent-emojis/
.pnp.*
@ -27,4 +29,4 @@ fluent-emojis/
.idea/
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
insert_final_newline = true
end_of_line = lf
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml}]
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

@ -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 -->

7
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View file

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

23
.github/PULL_REQUEST_TEMPLATE/01_bug.md vendored Normal file
View file

@ -0,0 +1,23 @@
<!-- お読みください / README
PRありがとうございます PRを作成する前に、コントリビューションガイドをご確認ください:
Thank you for your PR! Before creating a PR, please check the contribution guide:
https://github.com/misskey-dev/misskey/blob/develop/CONTRIBUTING.md
-->
## What
<!-- このPRで何をしたのか どう変わるのか? -->
<!-- What did you do with this PR? How will it change things? -->
## Why
<!-- なぜそうするのか? どういう意図なのか? 何が困っているのか? -->
<!-- Why do you do it? What are your intentions? What is the problem? -->
## Additional info (optional)
<!-- テスト観点など -->
<!-- Test perspective, etc -->
## Checklist
- [ ] Read the [contribution guide](https://github.com/misskey-dev/misskey/blob/develop/CONTRIBUTING.md)
- [ ] Test working in a local environment
- [ ] (If needed) Update CHANGELOG.md
- [ ] (If possible) Add tests

View file

@ -0,0 +1,23 @@
<!-- お読みください / README
PRありがとうございます PRを作成する前に、コントリビューションガイドをご確認ください:
Thank you for your PR! Before creating a PR, please check the contribution guide:
https://github.com/misskey-dev/misskey/blob/develop/CONTRIBUTING.md
-->
## What
<!-- このPRで何をしたのか どう変わるのか? -->
<!-- What did you do with this PR? How will it change things? -->
## Why
<!-- なぜそうするのか? どういう意図なのか? 何が困っているのか? -->
<!-- Why do you do it? What are your intentions? What is the problem? -->
## Additional info (optional)
<!-- テスト観点など -->
<!-- Test perspective, etc -->
## Checklist
- [ ] Read the [contribution guide](https://github.com/misskey-dev/misskey/blob/develop/CONTRIBUTING.md)
- [ ] Test working in a local environment
- [ ] (If needed) Update CHANGELOG.md
- [ ] (If possible) Add tests

View file

@ -0,0 +1,20 @@
## Summary
This is a release PR.
For more information on the release instructions, please see:
https://github.com/misskey-dev/misskey/blob/develop/CONTRIBUTING.md#release
## For reviewers
- CHANGELOGに抜け漏れは無いか
- バージョンの上げ方は適切か
- 他にこのリリースに含めなければならない変更は無いか
- 全体的な変更内容を俯瞰し問題は無いか
- レビューされていないコミットがある場合は、それが問題ないか
- 最終的な動作確認を行い問題は無いか
などを確認し、リリースする準備が整っていると思われる場合は approve してください。
## Checklist
- [ ] package.jsonのバージョンが正しく更新されている
- [ ] CHANGELOGが過不足無く更新されている
- [ ] CIが全て通っている

32
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,32 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 0
- package-ecosystem: npm
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 0
- package-ecosystem: npm
directory: "/packages/backend"
schedule:
interval: daily
open-pull-requests-limit: 0
- package-ecosystem: npm
directory: "/packages/frontend"
schedule:
interval: daily
open-pull-requests-limit: 0
- package-ecosystem: npm
directory: "/packages/sw"
schedule:
interval: daily
open-pull-requests-limit: 0

12
.github/labeler.yml vendored Normal file
View file

@ -0,0 +1,12 @@
'⚙Server':
- packages/backend/**/*
'🖥Client':
- packages/frontend/**/*
'🧪Test':
- cypress/**/*
- packages/backend/test/**/*
'‼️ wrong locales':
- any: ['locales/*.yml', '!locales/ja-JP.yml']

15
.github/misskey/test.yml vendored Normal file
View file

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

23
.github/pull_request_template.md vendored Normal file
View file

@ -0,0 +1,23 @@
<!-- お読みください / README
PRありがとうございます PRを作成する前に、コントリビューションガイドをご確認ください:
Thank you for your PR! Before creating a PR, please check the contribution guide:
https://github.com/misskey-dev/misskey/blob/develop/CONTRIBUTING.md
-->
## What
<!-- このPRで何をしたのか どう変わるのか? -->
<!-- What did you do with this PR? How will it change things? -->
## Why
<!-- なぜそうするのか? どういう意図なのか? 何が困っているのか? -->
<!-- Why do you do it? What are your intentions? What is the problem? -->
## Additional info (optional)
<!-- テスト観点など -->
<!-- Test perspective, etc -->
## Checklist
- [ ] Read the [contribution guide](https://github.com/misskey-dev/misskey/blob/develop/CONTRIBUTING.md)
- [ ] Test working in a local environment
- [ ] (If needed) Update CHANGELOG.md
- [ ] (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

36
.github/workflows/api.yml vendored Normal file
View file

@ -0,0 +1,36 @@
name: API report
on: [push, pull_request]
jobs:
report:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3.3.0
- run: corepack enable
- name: Setup Node.js
uses: actions/setup-node@v3.6.0
with:
node-version: 18.x
cache: 'pnpm'
- name: Install dependencies
run: pnpm i --frozen-lockfile
- name: Build
run: pnpm --filter misskey-js build
- name: Check files
run: ls packages/misskey-js/built
- name: API report
run: pnpm --filter misskey-js api-prod
- name: Show report
if: always()
run: cat packages/misskey-js/temp/misskey-js.api.md

View file

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

43
.github/workflows/docker-develop.yml vendored Normal file
View file

@ -0,0 +1,43 @@
name: Publish Docker image (develop)
on:
push:
branches:
- develop
workflow_dispatch:
jobs:
push_to_registry:
name: Push Docker image to Docker Hub
runs-on: ubuntu-latest
if: github.repository == 'misskey-dev/misskey'
steps:
- name: Check out the repo
uses: actions/checkout@v3.3.0
- name: Set up Docker Buildx
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
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push to Docker Hub
uses: docker/build-push-action@v4
with:
builder: ${{ steps.buildx.outputs.name }}
context: .
push: true
platforms: ${{ steps.buildx.outputs.platforms }}
provenance: false
tags: misskey/misskey:develop
labels: develop
cache-from: type=gha
cache-to: type=gha,mode=max

49
.github/workflows/docker.yml vendored Normal file
View file

@ -0,0 +1,49 @@
name: Publish Docker image
on:
release:
types: [published]
workflow_dispatch:
jobs:
push_to_registry:
name: Push Docker image to Docker Hub
runs-on: ubuntu-latest
steps:
- name: Check out the repo
uses: actions/checkout@v3.3.0
- name: Set up Docker Buildx
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
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
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push to Docker Hub
uses: docker/build-push-action@v4
with:
builder: ${{ steps.buildx.outputs.name }}
context: .
push: true
platforms: ${{ steps.buildx.outputs.platforms }}
provenance: false
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

30
.github/workflows/dockle.yml vendored Normal file
View file

@ -0,0 +1,30 @@
---
name: Dockle
on:
push:
branches:
- master
- develop
pull_request:
jobs:
dockle:
runs-on: ubuntu-latest
env:
DOCKER_CONTENT_TRUST: 1
steps:
- uses: actions/checkout@v3.2.0
- run: |
curl -L -o dockle.deb "https://github.com/goodwithtech/dockle/releases/download/v0.4.10/dockle_0.4.10_Linux-64bit.deb"
sudo dpkg -i dockle.deb
- run: |
cp .config/docker_example.env .config/docker.env
cp ./docker-compose.yml.example ./docker-compose.yml
- run: |
docker compose up -d web
docker tag "$(docker compose images web | awk 'OFS=":" {print $4}' | tail -n +2)" misskey-web:latest
- run: |
cmd="dockle --exit-code 1 misskey-web:latest ${image_name}"
echo "> ${cmd}"
eval "${cmd}"

16
.github/workflows/labeler.yml vendored Normal file
View file

@ -0,0 +1,16 @@
name: "Pull Request Labeler"
on:
pull_request_target:
branches-ignore:
- 'l10n_develop'
jobs:
triage:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v4
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"

81
.github/workflows/lint.yml vendored Normal file
View file

@ -0,0 +1,81 @@
name: Lint
on:
push:
branches:
- master
- develop
pull_request:
jobs:
pnpm_install:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.3.0
with:
fetch-depth: 0
submodules: true
- uses: pnpm/action-setup@v2
with:
version: 7
run_install: false
- uses: actions/setup-node@v3.6.0
with:
node-version: 18.x
cache: 'pnpm'
- run: corepack enable
- run: pnpm i --frozen-lockfile
lint:
needs: [pnpm_install]
runs-on: ubuntu-latest
continue-on-error: true
strategy:
matrix:
workspace:
- backend
- frontend
- sw
- misskey-js
steps:
- uses: actions/checkout@v3.3.0
with:
fetch-depth: 0
submodules: true
- uses: pnpm/action-setup@v2
with:
version: 7
run_install: false
- uses: actions/setup-node@v3.6.0
with:
node-version: 18.x
cache: 'pnpm'
- run: corepack enable
- run: pnpm i --frozen-lockfile
- run: pnpm --filter ${{ matrix.workspace }} run eslint
typecheck:
needs: [pnpm_install]
runs-on: ubuntu-latest
continue-on-error: true
strategy:
matrix:
workspace:
- backend
- misskey-js
steps:
- uses: actions/checkout@v3.3.0
with:
fetch-depth: 0
submodules: true
- uses: pnpm/action-setup@v2
with:
version: 7
run_install: false
- uses: actions/setup-node@v3.6.0
with:
node-version: 18.x
cache: 'pnpm'
- run: corepack enable
- run: pnpm i --frozen-lockfile
- run: pnpm --filter ${{ matrix.workspace }} run typecheck

36
.github/workflows/ok-to-test.yml vendored Normal file
View file

@ -0,0 +1,36 @@
# If someone with write access comments "/ok-to-test" on a pull request, emit a repository_dispatch event
name: Ok To Test
on:
issue_comment:
types: [created]
jobs:
ok-to-test:
runs-on: ubuntu-latest
# Only run for PRs, not issue comments
if: ${{ github.event.issue.pull_request }}
steps:
# Generate a GitHub App installation access token from an App ID and private key
# To create a new GitHub App:
# https://developer.github.com/apps/building-github-apps/creating-a-github-app/
# See app.yml for an example app manifest
- name: Generate token
id: generate_token
uses: tibdex/github-app-token@v1
with:
app_id: ${{ secrets.DEPLOYBOT_APP_ID }}
private_key: ${{ secrets.DEPLOYBOT_PRIVATE_KEY }}
- name: Slash Command Dispatch
uses: peter-evans/slash-command-dispatch@v1
env:
TOKEN: ${{ steps.generate_token.outputs.token }}
with:
token: ${{ env.TOKEN }} # GitHub App installation access token
# token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} # PAT or OAuth token will also work
reaction-token: ${{ secrets.GITHUB_TOKEN }}
issue-type: pull-request
commands: deploy
named-args: true
permission: write

92
.github/workflows/pr-preview-deploy.yml vendored Normal file
View file

@ -0,0 +1,92 @@
# Run secret-dependent integration tests only after /deploy approval
on:
repository_dispatch:
types: [deploy-command]
name: Deploy preview environment
jobs:
# Repo owner has commented /deploy on a (fork-based) pull request
deploy-preview-environment:
runs-on: ubuntu-latest
if:
github.event.client_payload.slash_command.sha != '' &&
contains(github.event.client_payload.pull_request.head.sha, github.event.client_payload.slash_command.sha)
steps:
- uses: actions/github-script@v6.3.3
id: check-id
env:
number: ${{ github.event.client_payload.pull_request.number }}
job: ${{ github.job }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
result-encoding: string
script: |
const { data: pull } = await github.rest.pulls.get({
...context.repo,
pull_number: process.env.number
});
const ref = pull.head.sha;
const { data: checks } = await github.rest.checks.listForRef({
...context.repo,
ref
});
const check = checks.check_runs.filter(c => c.name === process.env.job);
return check[0].id;
- uses: actions/github-script@v6.3.3
env:
check_id: ${{ steps.check-id.outputs.result }}
details_url: ${{ github.server_url }}/${{ github.repository }}/runs/${{ github.run_id }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
await github.rest.checks.update({
...context.repo,
check_run_id: process.env.check_id,
status: 'in_progress',
details_url: process.env.details_url
});
# Check out merge commit
- name: Fork based /deploy checkout
uses: actions/checkout@v3.3.0
with:
ref: 'refs/pull/${{ github.event.client_payload.pull_request.number }}/merge'
# <insert integration tests needing secrets>
- name: Context
uses: okteto/context@latest
with:
token: ${{ secrets.OKTETO_TOKEN }}
- name: Deploy preview environment
uses: ikuradon/deploy-preview@latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
name: pr-${{ github.event.client_payload.pull_request.number }}-syuilo
timeout: 15m
# Update check run called "integration-fork"
- uses: actions/github-script@v6.3.3
id: update-check-run
if: ${{ always() }}
env:
# Conveniently, job.status maps to https://developer.github.com/v3/checks/runs/#update-a-check-run
conclusion: ${{ job.status }}
check_id: ${{ steps.check-id.outputs.result }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { data: result } = await github.rest.checks.update({
...context.repo,
check_run_id: process.env.check_id,
status: 'completed',
conclusion: process.env.conclusion
});
return result;

View file

@ -0,0 +1,54 @@
# file: .github/workflows/preview-closed.yaml
on:
pull_request:
types:
- closed
name: Destroy preview environment
jobs:
destroy-preview-environment:
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v6.3.3
id: check-conclusion
env:
number: ${{ github.event.number }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
result-encoding: string
script: |
const { data: pull } = await github.rest.pulls.get({
...context.repo,
pull_number: process.env.number
});
const ref = pull.head.sha;
const { data: checks } = await github.rest.checks.listForRef({
...context.repo,
ref
});
const check = checks.check_runs.filter(c => c.name === 'deploy-preview-environment');
if (check.length === 0) {
return;
}
const { data: result } = await github.rest.checks.get({
...context.repo,
check_run_id: check[0].id,
});
return result.conclusion;
- name: Context
if: steps.check-conclusion.outputs.result == 'success'
uses: okteto/context@latest
with:
token: ${{ secrets.OKTETO_TOKEN }}
- name: Destroy preview environment
if: steps.check-conclusion.outputs.result == 'success'
uses: okteto/destroy-preview@latest
with:
name: pr-${{ github.event.number }}-syuilo

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 }}

59
.github/workflows/test-backend.yml vendored Normal file
View file

@ -0,0 +1,59 @@
name: Test (backend)
on:
push:
branches:
- master
- develop
pull_request:
jobs:
jest:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x]
services:
postgres:
image: postgres:13
ports:
- 54312:5432
env:
POSTGRES_DB: test-misskey
POSTGRES_HOST_AUTH_METHOD: trust
redis:
image: redis:6
ports:
- 56312:6379
steps:
- uses: actions/checkout@v3.3.0
with:
submodules: true
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 7
run_install: false
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3.6.0
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 jest-and-coverage
- name: Upload Coverage
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./packages/backend/coverage/coverage-final.json

120
.github/workflows/test-frontend.yml vendored Normal file
View file

@ -0,0 +1,120 @@
name: Test (frontend)
on:
push:
branches:
- master
- develop
pull_request:
jobs:
vitest:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x]
steps:
- uses: actions/checkout@v3.3.0
with:
submodules: true
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 7
run_install: false
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3.6.0
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 frontend test-and-coverage
- name: Upload Coverage
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./packages/frontend/coverage/coverage-final.json
e2e:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version: [18.x]
browser: [chrome]
services:
postgres:
image: postgres:13
ports:
- 54312:5432
env:
POSTGRES_DB: test-misskey
POSTGRES_HOST_AUTH_METHOD: trust
redis:
image: redis:6
ports:
- 56312:6379
steps:
- uses: actions/checkout@v3.3.0
with:
submodules: true
# https://github.com/cypress-io/cypress-docker-images/issues/150
#- name: Install mplayer for FireFox
# run: sudo apt install mplayer -y
# if: ${{ matrix.browser == 'firefox' }}
#- uses: browser-actions/setup-firefox@latest
# if: ${{ matrix.browser == 'firefox' }}
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 7
run_install: false
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3.6.0
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- run: corepack enable
- run: pnpm i --frozen-lockfile
- name: Copy Configure
run: cp .github/misskey/test.yml .config
- name: Build
run: pnpm build
# https://github.com/cypress-io/cypress/issues/4351#issuecomment-559489091
- name: ALSA Env
run: echo -e 'pcm.!default {\n type hw\n card 0\n}\n\nctl.!default {\n type hw\n card 0\n}' > ~/.asoundrc
# XXX: This tries reinstalling Cypress if the binary is not cached
# Remove this when the cache issue is fixed
- name: Cypress install
run: pnpm exec cypress install
- name: Cypress run
uses: cypress-io/github-action@v5
with:
install: false
start: pnpm start:test
wait-on: 'http://localhost:61812'
headless: false
browser: ${{ matrix.browser }}
- uses: actions/upload-artifact@v2
if: failure()
with:
name: ${{ matrix.browser }}-cypress-screenshots
path: cypress/screenshots
- uses: actions/upload-artifact@v2
if: always()
with:
name: ${{ matrix.browser }}-cypress-videos
path: cypress/videos

52
.github/workflows/test-misskey-js.yml vendored Normal file
View file

@ -0,0 +1,52 @@
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: Test (misskey.js)
on:
push:
branches: [ develop ]
pull_request:
branches: [ develop ]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
- name: Checkout
uses: actions/checkout@v3.3.0
- run: corepack enable
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3.6.0
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- name: Install dependencies
run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml
run: git diff --exit-code pnpm-lock.yaml
- name: Build
run: pnpm --filter misskey-js build
- name: Test
run: pnpm --filter misskey-js test
env:
CI: true
- name: Upload Coverage
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./packages/misskey-js/coverage/coverage-final.json

25
.gitignore vendored
View file

@ -23,9 +23,6 @@ packages/sw/.yarn/cache
# pnpm
.pnpm-store
# eslint
**/.eslintcache
# Cypress
cypress/screenshots
cypress/videos
@ -38,21 +35,16 @@ coverage
!/.config/example.yml
!/.config/docker_example.yml
!/.config/docker_example.env
!/.config/cypress-devcontainer.yml
docker-compose.yml
compose.yml
.devcontainer/compose.yml
!/.devcontainer/compose.yml
!/.devcontainer/docker-compose.yml
# misskey
/build
built
built-test
js-built
/data
/.cache-loader
/db
/meili_data
/elasticsearch
npm-debug.log
*.pem
run.bat
@ -64,13 +56,6 @@ api-docs.json
/files
ormconfig.json
temp
/packages/frontend/src/**/*.stories.ts
tsdoc-metadata.json
misskey-assets
# Vite temporary files
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
# blender backups
*.blend1
@ -78,9 +63,3 @@ vite.config.ts.timestamp-*
*.blend3
*.blend4
*.blend5
# VSCode addon
.favorites.json
# Sharkey
/packages/megalodon/lib

View file

@ -1,114 +0,0 @@
stages:
- test
- deploy
testCommit:
stage: test
image: node:iron
services:
- postgres:15
- redis
variables:
POSTGRES_PASSWORD: ci
script:
- apt-get update && apt-get install -y git wget curl build-essential python3 ffmpeg
- cp .config/ci.yml .config/default.yml
- cp .config/ci.yml .config/test.yml
- corepack enable
- corepack prepare pnpm@latest --activate
- git submodule update --init
- pnpm install --frozen-lockfile
- pnpm run build
- pnpm run migrate
- pnpm run --filter='!megalodon' test
- pnpm run --filter=backend --filter=misskey-js lint
- pnpm run --filter=frontend --filter=frontend-embed eslint
cache:
key: test
policy: pull-push
when: on_success
paths:
- node_modules/
- packages/*/node_modules/
only:
- develop
- merge_requests
- stable
getImageTag:
stage: deploy
image: ubuntu:latest
script:
- apt-get update && apt-get install -y jq
- |
if test -n "$CI_COMMIT_TAG"; then
tag="$CI_COMMIT_TAG"
elif test "$CI_COMMIT_BRANCH" == "stable"; then
tag="latest"
elif test "$CI_COMMIT_BRANCH" == "develop"; then
tag="develop"
else
tag="$CI_COMMIT_BRANCH"
fi
version=$(cat package.json | jq -r '.version')
- echo "REGISTRY_PUSH_TAG=$tag" >> build.env
- echo "REGISTRY_PUSH_VERSION=$version" >> build.env
artifacts:
reports:
dotenv: build.env
only:
- stable
- develop
- tags
buildDocker:
stage: deploy
needs:
- job: getImageTag
artifacts: true
parallel:
matrix:
- ARCH: amd64
- ARCH: arm64
tags:
- ${ARCH}
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
script:
- >-
/kaniko/executor
--context "${CI_PROJECT_DIR}"
--dockerfile "${CI_PROJECT_DIR}/Dockerfile"
--destination "${CI_REGISTRY_IMAGE}:${REGISTRY_PUSH_VERSION}-${ARCH}"
only:
- stable
- develop
- tags
mergeManifests:
stage: deploy
needs:
- job: buildDocker
artifacts: false
- job: getImageTag
artifacts: true
tags:
- docker
image:
name: mplatform/manifest-tool:alpine
entrypoint: [""]
script:
- >-
manifest-tool
--username=${CI_REGISTRY_USER}
--password=${CI_REGISTRY_PASSWORD}
push from-args
--platforms linux/amd64,linux/arm64
--tags ${REGISTRY_PUSH_VERSION}
--template ${CI_REGISTRY_IMAGE}:${REGISTRY_PUSH_VERSION}-ARCH
--target ${CI_REGISTRY_IMAGE}:${REGISTRY_PUSH_TAG}
only:
- stable
- develop
- tags

View file

@ -1,35 +0,0 @@
<!-- 💖 Thanks for taking the time to fill out this bug report!
💁 Having trouble with deployment? [Ask the support chat.](https://discord.gg/4qUhaeeHmm)
🔒 Found a security vulnerability? [Please disclose it responsibly.](https://activitypub.software/TransFem-org/Sharkey/-/blob/develop/SECURITY.md)
🤝 By submitting this feature request, you agree to follow our [Contribution Guidelines.](https://activitypub.software/TransFem-org/Sharkey/-/blob/develop/CONTRIBUTING.md) -->
# **What happened?**
<!-- Please give us a brief description of what happened. -->
# **What did you expect to happen?**
<!-- Please give us a brief description of what you expected to happen. -->
# **Version**
<!-- What version of Sharkey is your instance running? You can find this by clicking your instance's logo at the top left and then clicking instance information. -->
# **Instance**
<!-- What instance of Sharkey are you using? -->
# **What type of issue is this?**
<!-- If this happens on your device and has to do with the user interface, it's client-side. If this happens on either with the API or the backend, or you got a server-side error in the client, it's server-side. -->
# **What browser are you using? (Client-side issues only)**
# **What operating system are you using? (Client-side issues only)**
# **How do you deploy Sharkey on your server? (Server-side issues only)**
# **What operating system are you using? (Server-side issues only)**
# **Relevant log output**
<!-- Please copy and paste any relevant log output. You can find your log by inspecting the page, and going to the "console" tab. This will be automatically formatted into code, so no need for backticks. -->
# **Contribution Guidelines**
By submitting this issue, you agree to follow our [Contribution Guidelines](https://activitypub.software/TransFem-org/Sharkey/-/blob/develop/CONTRIBUTING.md)
- [ ] I agree to follow this project's Contribution Guidelines
- [ ] I have searched the issue tracker for similar issues, and this is not a duplicate.

View file

@ -1,21 +0,0 @@
<!-- 💖 Thanks for taking the time to fill out this bug report!
💁 Having trouble with deployment? [Ask the support chat.](https://discord.gg/4qUhaeeHmm)
🔒 Found a security vulnerability? [Please disclose it responsibly.](https://activitypub.software/TransFem-org/Sharkey/-/blob/develop/SECURITY.md)
🤝 By submitting this feature request, you agree to follow our [Contribution Guidelines.](https://activitypub.software/TransFem-org/Sharkey/-/blob/develop/CONTRIBUTING.md) -->
# **What feature would you like implemented?**
<!-- Please give us a brief description of what you'd like. -->
# **Why should we add this feature?**
<!-- Please give us a brief description of why your feature is important. -->
# **Version**
<!-- What version of Sharkey is your instance running? You can find this by clicking your instance's logo at the top left and then clicking instance information. -->
# **Instance**
<!-- What instance of Sharkey are you using? -->
# **Contribution Guidelines**
By submitting this issue, you agree to follow our [Contribution Guidelines](https://activitypub.software/TransFem-org/Sharkey/-/blob/develop/CONTRIBUTING.md)
- [ ] I agree to follow this project's Contribution Guidelines
- [ ] I have searched the issue tracker for similar requests, and this is not a duplicate.

View file

@ -1,12 +0,0 @@
<!-- Thanks for taking the time to make Sharkey better! -->
# **What does this MR do?**
<!-- Please give us a brief description of what this PR does. -->
# **Contribution Guidelines**
By submitting this merge request, you agree to follow our [Contribution Guidelines](https://activitypub.software/TransFem-org/Sharkey/-/blob/develop/CONTRIBUTING.md)
- [ ] I agree to follow this project's Contribution Guidelines
- [ ] I have made sure to test this merge request
<!-- Uncomment if your merge request has multiple authors -->
<!-- Co-authored-by: Name <email@email.com> -->

6
.gitmodules vendored
View file

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

View file

@ -1 +1 @@
20.16.0
v18.13.0

2
.npmrc
View file

@ -1,2 +0,0 @@
@transfem-org:registry=https://activitypub.software/api/v4/packages/npm/
engine-strict = true

View file

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

21
.vscode/settings.json vendored
View file

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

File diff suppressed because it is too large Load diff

View file

@ -2,131 +2,45 @@
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
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.
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.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
Examples of behavior that contributes to creating a positive environment include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
community
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
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
any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address,
without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* 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
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
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.
Community leaders 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, and will communicate reasons for moderation
decisions when appropriate.
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.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
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.
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.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
<syuilotan@yahoo.co.jp>.
All complaints will be reviewed and investigated promptly and fairly.
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.
All community leaders are obligated to respect the privacy and security of the
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.
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.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
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
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View file

@ -1,63 +1,50 @@
# Contribution guide
We're glad you're interested in contributing to Sharkey! 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**
> This project uses Japanese as its major language, **but you do not need to translate and write the Issues/PRs in Japanese.**
> Also, you might receive comments on your Issue/PR in Japanese, but you do not need to reply to them in Japanese as well.\
> The accuracy of machine translation into Japanese is not high, so it will be easier for us to understand if you write it in the original language.
> It will also allow the reader to use the translation tool of their preference if necessary.
## Roadmap
See [ROADMAP.md](./ROADMAP.md) for the upstream Misskey roadmap.
See [ROADMAP.md](./ROADMAP.md)
## Issues
Before creating an issue, please check the following:
- To avoid duplication, please search for similar issues before creating a new issue.
- Do not use Issues to ask questions or troubleshooting.
- Issues should only be used to feature requests, suggestions, and bug tracking.
- Please ask questions or troubleshooting in [Discord](https://discord.gg/6VgKmEqHNk).
- 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.
### Recommended discussing before implementation
We welcome your proposal.
## Before implementation
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, *please open an issue*,
don't just start writing code. We may suggest different approaches, or
show that the "bug" is actually intended behaviour (and offer
work-arounds), or maybe we won't be able to merge your new feature
because it would make it too hard to incorporate future changes from
Misskey. Each of these examples have actually happened!
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.
On the other hand, it's very likely that we'll tell you "go
ahead!". We try our best to incorporate improvements from our users!
Also, when you start implementation, assign yourself to the Issue (if you cannot do it yourself, ask Committer to assign you).
By expressing your intention to work on the Issue, you can prevent conflicts in the work.
To the Committers: you should not assign someone on it before the Final Decision.
### How issues are triaged
The Committers may:
* close an issue that is not reproducible on latest stable release,
* merge an issue into another issue,
* split an issue into multiple issues,
* or re-open that has been closed for some reason which is not applicable anymore.
@syuilo reserves the Final Decision rights including whether the project will implement feature and how to implement, these rights are not always exercised.
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.
## Well-known branches
- **`stable`** branch is tracking the latest release and used for production purposes.
- **`master`** branch is tracking the latest release and used for production purposes.
- **`develop`** branch is where we work for the next release.
- When you create a PR, basically target it to this branch.
- **`l10n_develop`** branch is reserved for localization management.
## Creating a PR
Thank you for your PR! Before creating a PR, please check the following:
- If possible, prefix the title with a keyword that identifies the type of this PR, as shown below.
- `fix` / `refactor` / `feat` / `enhance` / `perf` / `chore` etc
- Also, make sure that the granularity of this PR is appropriate. Please do not include more than one type of change or interest in a single PR.
- `fix` / `refactor` / `feat` / `enhance` / `perf` / `chore` etc
- Also, make sure that the granularity of this PR is appropriate. Please do not include more than one type of change or interest in a single PR.
- If there is an Issue which will be resolved by this PR, please include a reference to the Issue in the text.
- Please add the summary of the changes to [`CHANGELOG.md`](CHANGELOG.md). However, this is not necessary for changes that do not affect the users, such as refactoring.
- Please add the summary of the changes to [`CHANGELOG.md`](/CHANGELOG.md). However, this is not necessary for changes that do not affect the users, such as refactoring.
- Check if there are any documents that need to be created or updated due to this change.
- If you have added a feature or fixed a bug, please add a test case if possible.
- Please make sure that tests and Lint are passed in advance.
- You can run it with `pnpm test` and `pnpm lint`. [See more info](#testing)
- You can run it with `pnpm test` and `pnpm lint`. [See more info](#testing)
- If this PR includes UI changes, please attach a screenshot in the text.
Thanks for your cooperation 🤗
@ -67,8 +54,8 @@ Be willing to comment on the good points and not just the things you want fixed
### Review perspective
- Scope
- Are the goals of the PR clear?
- Is the granularity of the PR appropriate?
- Are the goals of the PR clear?
- Is the granularity of the PR appropriate?
- Security
- Does merging this PR create a vulnerability?
- Performance
@ -79,22 +66,29 @@ Be willing to comment on the good points and not just the things you want fixed
- Are there any omissions or gaps?
- Does it check for anomalies?
## Deploy
The `/deploy` command by issue comment can be used to deploy the contents of a PR to the preview environment.
```
/deploy sha=<commit hash>
```
An actual domain will be assigned so you can test the federation.
## Merge
## Release
### 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.
- Into `stable` from `develop` branch.
- Into `master` from `develop` branch.
- The title must be in the format `Release: x.y.z`.
- `x.y.z` is the new version you are trying to release.
3. Deploy and perform a simple QA check. Also verify that the tests passed.
4. Merge it. (Do not squash commit)
5. Create a [release](https://activitypub.software/TransFem-org/Sharkey/-/releases)
- The target branch must be `stable`
5. Create a [release of GitHub](https://github.com/misskey-dev/misskey/releases)
- The target branch must be `master`
- The tag name must be the version
> [!NOTE]
> **Note**
> Why this instruction is necessary:
> - To perform final QA checks
> - To distribute responsibility
@ -111,32 +105,20 @@ If your language is not listed in Crowdin, please open an issue.
![Crowdin](https://d322cqt584bo4o.cloudfront.net/misskey/localized.svg)
## Icon Font (Shark Font)
Sharkey has its own Icon Font called Shark Font which can be found at https://activitypub.software/TransFem-org/shark-font
Build Instructions can all be found over there in the `README`.
If you have an Icon Suggestion or want to add an Icon please open an issue/merge request over at that repo.
When Updating the Font make sure to copy **all generated files** from the `dest` folder into `packages/backend/assets/fonts/sharkey-icons`
For the CSS simply copy the file content and replace the old content in `style.css` and for the WOFF, TTF and SVG simply replace them.
## Development
### Setup
Before developing, you have to set up environment. Misskey requires Redis, PostgreSQL, and FFmpeg.
During development, it is useful to use the
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
You could install them in system-wide (such as from package manager).
#### Use `docker compose`
You could obtain middleware container by typing `docker compose -f $PROJECT_ROOT/compose.local-db.yml up -d`.
#### Use Devcontainer
Devcontainer also has necessary setting. This method can be done by connecting from VSCode.
- 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.
### Dev Container
Instead of running `pnpm` locally, you can use Dev Container to set up your development environment.
To use Dev Container, open the project directory on VSCode with Dev Containers installed.
**Note:** If you are using Windows, please clone the repository with WSL. Using Git for Windows will result in broken files due to the difference in how newlines are handled.
@ -150,38 +132,14 @@ pnpm build
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
During development, it is useful to use the
```
``` bash
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
- Test codes are located in [`/packages/backend/test`](packages/backend/test).
- Test codes are located in [`/packages/backend/test`](/packages/backend/test).
### Run test
Create a config file.
@ -190,7 +148,7 @@ cp .github/misskey/test.yml .config/
```
Prepare DB/Redis for testing.
```
docker compose -f packages/backend/test/compose.yml up
docker compose -f packages/backend/test/docker-compose.yml up
```
Alternatively, prepare an empty (data can be erased) DB and edit `.config/test.yml`.
@ -207,14 +165,9 @@ pnpm jest -- foo.ts
### e2e tests
TODO
## Environment Variable
- `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
Sharkey uses GitLab CI for executing automated tests.
Configuration files are located in [`/.gitlab-ci.yml`](.gitlab-ci.yml).
Misskey uses GitHub Actions for executing automated tests.
Configuration files are located in [`/.github/workflows`](/.github/workflows).
## Vue
Misskey uses Vue(v3) as its front-end framework.
@ -229,7 +182,7 @@ niraxは、Misskeyで使用しているオリジナルのフロントエンド
### ルート定義
ルート定義は、以下の形式のオブジェクトの配列です。
```ts
``` ts
{
name?: string;
path: string;
@ -242,7 +195,7 @@ niraxは、Misskeyで使用しているオリジナルのフロントエンド
}
```
> [!WARNING]
> **Warning**
> 現状、ルートは定義された順に評価されます。
> たとえば、`/foo/:id`ルート定義の次に`/foo/bar`ルート定義がされていた場合、後者がマッチすることはありません。
@ -250,196 +203,7 @@ niraxは、Misskeyで使用しているオリジナルのフロントエンド
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
### 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?
Just execute `pnpm` to fix it.
@ -529,8 +293,7 @@ enumの列挙の内容の削除は、その値をもつレコードを全て削
### Migration作成方法
packages/backendで:
```sh
pnpm run build
pnpm dlx typeorm migration:generate -d ormconfig.js -o migration/<migration name>
pnpm dlx typeorm migration:generate -d ormconfig.js -o <migration name>
```
- 生成後、ファイルをmigration下に移してください
@ -543,7 +306,7 @@ https://github.com/misskey-dev/misskey/pull/10082
テキストhogeおよびfugaについて、片方を必須としつつ両方の指定もありうる場合:
```ts
```
export const paramDef = {
type: 'object',
properties: {
@ -570,87 +333,3 @@ marginはそのコンポーネントを使う側が設定する
## その他
### HTMLのクラス名で follow という単語は使わない
広告ブロッカーで誤ってブロックされる
### indexというファイル名を使うな
ESMではディレクトリインポートは廃止されているのと、ディレクトリインポートせずともファイル名が index だと何故か一部のライブラリ?でディレクトリインポートだと見做されてエラーになる
## CSS Recipe
### Lighten CSS vars
``` css
color: hsl(from var(--accent) h s calc(l + 10));
```
### Darken CSS vars
``` css
color: hsl(from var(--accent) h s calc(l - 10));
```
### Add alpha to CSS vars
``` css
color: color(from var(--accent) srgb r g b / 0.5);
```
## Merging from Misskey into Sharkey
Make sure you have both remotes in the same clone (`git remote add misskey
https://github.com/misskey-dev/misskey.git`), then:
git remote update
git checkout develop # this is Sharkey's develop
git checkout -m merge/$(date +%Y-%m-%d) # or whatever
git merge --no-ff misskey/develop
fix conflicts and *commit*! (conflicts in `pnpm-lock.yaml` can usually
be fixed by running `pnpm install`, it detects conflict markers and
seems to do a decent job)
*after that commit*, do all the extra work, on the same branch:
* copy all changes (commit after each step):
* in
`packages/backend/src/core/activitypub/models/ApNoteService.ts`,
from `createNote` to `updateNote`
* from `packages/backend/src/core/NoteCreateService.ts` to
`packages/backend/src/core/NoteEditService.vue`
* from `packages/backend/src/server/api/endpoints/notes/create.ts`
to `packages/backend/src/server/api/endpoints/notes/edit.ts`
* from `packages/frontend/src/components/MkNote*.vue` to
`packages/frontend/src/components/SkNote*.vue` (if sensible)
* from the global timeline to the bubble timeline
(`packages/backend/src/server/api/stream/channels/global-timeline.ts`,
`packages/backend/src/server/api/stream/channels/bubble-timeline.ts`,
`packages/frontend/src/timelines.ts`,
`packages/frontend/src/components/MkTimeline.vue`,
`packages/frontend/src/pages/timeline.vue`,
`packages/frontend/src/ui/deck/tl-column.vue`,
`packages/frontend/src/widgets/WidgetTimeline.vue`)
* check the changes against our `develop` (`git diff develop`) and
against Misskey (`git diff misskey/develop`)
* re-generate `misskey-js` (`pnpm build-misskey-js-with-types`) and commit
* build the frontend: `rm -rf built/; NODE_ENV=development pnpm
--filter=frontend --filter=frontend-embed build` (the `development`
tells it to keep some of the original filenames in the built files)
* make sure there aren't any new `ti-*` classes (Tabler Icons), and
replace them with appropriate `ph-*` ones (Phosphor Icons):
`grep -rP '["'\'']ti[ -](?!fw)' -- built/` should show you what to change.
NOTE: `ti-fw` is a special class that's defined by Misskey, leave it
alone
after every change, re-build the frontend and check again, until
there are no more `ti-*` classes in the built files
commit!
* double-check the new migration, that they won't conflict with our db
changes: `git diff develop -- packages/backend/migration/`
* `pnpm clean; pnpm build`
* run tests `pnpm --filter='!megalodon' test` (requires a test
database, [see above](#testing)) and fix as much as you can
* right now `megalodon` doesn't pass its tests, so we skip them
* run lint `pnpm --filter=backend lint` + `pnpm --filter=frontend
eslint` and fix as much as you can
Then push and open a Merge Request.

View file

@ -1,5 +1,5 @@
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.

View file

@ -1,86 +1,87 @@
# syntax = docker/dockerfile:1.4
ARG NODE_VERSION=20.16.0-alpine3.20
ARG NODE_VERSION=18.13.0-bullseye
FROM node:${NODE_VERSION} as build
# build assets & compile TypeScript
RUN apk add git linux-headers build-base
FROM --platform=$BUILDPLATFORM node:${NODE_VERSION} AS native-builder
ENV PYTHONUNBUFFERED=1
RUN apk add --update python3 && ln -sf python3 /usr/bin/python
RUN apk add py3-pip py3-setuptools
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
rm -f /etc/apt/apt.conf.d/docker-clean \
; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache \
&& apt-get update \
&& apt-get install -yqq --no-install-recommends \
build-essential
RUN corepack enable
WORKDIR /sharkey
WORKDIR /misskey
COPY --link ["pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "./"]
COPY --link ["scripts", "./scripts"]
COPY --link ["packages/backend/package.json", "./packages/backend/"]
COPY --link ["packages/frontend/package.json", "./packages/frontend/"]
COPY --link ["packages/sw/package.json", "./packages/sw/"]
COPY --link ["packages/misskey-js/package.json", "./packages/misskey-js/"]
RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \
pnpm i --frozen-lockfile --aggregate-output
COPY --link . ./
RUN git submodule update --init --recursive
RUN pnpm config set fetch-retries 5
ARG NODE_ENV=production
RUN git submodule update --init
RUN pnpm build
RUN rm -rf .git/
# build native dependencies for target platform
FROM --platform=$TARGETPLATFORM node:${NODE_VERSION} AS target-builder
RUN apt-get update \
&& apt-get install -yqq --no-install-recommends \
build-essential
RUN corepack enable
WORKDIR /misskey
COPY --link ["pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "./"]
COPY --link ["scripts", "./scripts"]
COPY --link ["packages/backend/package.json", "./packages/backend/"]
RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \
pnpm i --frozen-lockfile --aggregate-output
RUN pnpm build
RUN node scripts/trim-deps.mjs
RUN mv packages/frontend/assets sharkey-assets
RUN mv packages/frontend-embed/assets sharkey-embed-assets
RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \
pnpm prune
RUN rm -r node_modules packages/frontend packages/frontend-shared packages/frontend-embed packages/sw
RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \
pnpm i --prod --frozen-lockfile --aggregate-output
RUN rm -rf .git
FROM node:${NODE_VERSION}
FROM --platform=$TARGETPLATFORM node:${NODE_VERSION}-slim AS runner
ARG UID="991"
ARG GID="991"
RUN apk add ffmpeg tini jemalloc \
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ffmpeg tini curl \
&& corepack enable \
&& addgroup -g "${GID}" sharkey \
&& adduser -D -u "${UID}" -G sharkey -h /sharkey sharkey \
&& mkdir /sharkey/files \
&& chown sharkey:sharkey /sharkey/files \
&& find / -type d -path /sys -prune -o -type d -path /proc -prune -o -type f -perm /u+s -exec chmod u-s {} \; \
&& find / -type d -path /sys -prune -o -type d -path /proc -prune -o -type f -perm /g+s -exec chmod g-s {} \;
&& groupadd -g "${GID}" misskey \
&& useradd -l -u "${UID}" -g "${GID}" -m -d /misskey misskey \
&& find / -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 /g+s -ignore_readdir_race -exec chmod g-s {} \; \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists
USER sharkey
WORKDIR /sharkey
USER misskey
WORKDIR /misskey
# add package.json to add pnpm
COPY --chown=sharkey:sharkey ./package.json ./package.json
RUN corepack install
COPY --chown=misskey:misskey --from=target-builder /misskey/node_modules ./node_modules
COPY --chown=misskey:misskey --from=target-builder /misskey/packages/backend/node_modules ./packages/backend/node_modules
COPY --chown=misskey:misskey --from=native-builder /misskey/built ./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 . ./
COPY --chown=sharkey:sharkey --from=build /sharkey/node_modules ./node_modules
COPY --chown=sharkey:sharkey --from=build /sharkey/packages/backend/node_modules ./packages/backend/node_modules
COPY --chown=sharkey:sharkey --from=build /sharkey/packages/misskey-js/node_modules ./packages/misskey-js/node_modules
COPY --chown=sharkey:sharkey --from=build /sharkey/packages/misskey-reversi/node_modules ./packages/misskey-reversi/node_modules
COPY --chown=sharkey:sharkey --from=build /sharkey/packages/misskey-bubble-game/node_modules ./packages/misskey-bubble-game/node_modules
COPY --chown=sharkey:sharkey --from=build /sharkey/packages/megalodon/node_modules ./packages/megalodon/node_modules
COPY --chown=sharkey:sharkey --from=build /sharkey/built ./built
COPY --chown=sharkey:sharkey --from=build /sharkey/packages/misskey-js/built ./packages/misskey-js/built
COPY --chown=sharkey:sharkey --from=build /sharkey/packages/misskey-reversi/built ./packages/misskey-reversi/built
COPY --chown=sharkey:sharkey --from=build /sharkey/packages/misskey-bubble-game/built ./packages/misskey-bubble-game/built
COPY --chown=sharkey:sharkey --from=build /sharkey/packages/backend/built ./packages/backend/built
COPY --chown=sharkey:sharkey --from=build /sharkey/packages/megalodon/lib ./packages/megalodon/lib
COPY --chown=sharkey:sharkey --from=build /sharkey/fluent-emojis ./fluent-emojis
COPY --chown=sharkey:sharkey --from=build /sharkey/tossface-emojis/dist ./tossface-emojis/dist
COPY --chown=sharkey:sharkey --from=build /sharkey/sharkey-assets ./packages/frontend/assets
COPY --chown=sharkey:sharkey --from=build /sharkey/sharkey-embed-assets ./packages/frontend-embed/assets
COPY --chown=sharkey:sharkey pnpm-workspace.yaml ./pnpm-workspace.yaml
COPY --chown=sharkey:sharkey packages/backend/package.json ./packages/backend/package.json
COPY --chown=sharkey:sharkey packages/backend/scripts/check_connect.js ./packages/backend/scripts/check_connect.js
COPY --chown=sharkey:sharkey packages/backend/ormconfig.js ./packages/backend/ormconfig.js
COPY --chown=sharkey:sharkey packages/backend/migration ./packages/backend/migration
COPY --chown=sharkey:sharkey packages/backend/assets ./packages/backend/assets
COPY --chown=sharkey:sharkey packages/megalodon/package.json ./packages/megalodon/package.json
COPY --chown=sharkey:sharkey packages/misskey-js/package.json ./packages/misskey-js/package.json
COPY --chown=sharkey:sharkey packages/misskey-reversi/package.json ./packages/misskey-reversi/package.json
COPY --chown=sharkey:sharkey packages/misskey-bubble-game/package.json ./packages/misskey-bubble-game/package.json
ENV LD_PRELOAD=/usr/lib/libjemalloc.so.2
ENV NODE_ENV=production
ENTRYPOINT ["/sbin/tini", "--"]
HEALTHCHECK --interval=5s --retries=20 CMD ["/bin/bash", "/misskey/healthcheck.sh"]
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["pnpm", "run", "migrateandstart"]

View file

@ -1,16 +0,0 @@
# Basic Precautions
When using a service with Sharkey, there are several important points to keep in mind.
1. Because it is decentralized, there is no guarantee that data you upload will be deleted from all other servers even if you delete it once. (However, this applies to the internet in general.)
2. Even for posts made in private, there is no guarantee that the recipient's server will treat them as private in the same way. Please exercise caution when posting personal or confidential information. (Again, this applies to the internet in general.)
3. The "Drive" feature is NOT secure cloud storage. This feature exists for easier managing of your uploaded files.
Any data uploaded, whether shared via post or not, will be publicly accessible. Please use 3rd party cloud storage providers if you need to upload data with sensitive information of any kind.
4. Account deletion can be a resource-intensive process and may take a long time. In cases with a lot of uploaded data, it may even be impossible to delete an account.
5. Please disable ad blockers. Some servers may rely on advertising revenue to cover operating costs. Additionally, ad blockers can mistakenly block content and features unrelated to ads, potentially causing issues with the client's functionality and preventing normal use of Sharkey. Therefore, we recommend turning off ad blockers and similar features when using Sharkey.
Please understand these points and enjoy using the service.

View file

@ -1,47 +1,48 @@
<div align="center">
<a href="https://joinsharkey.org/">
<img src="https://activitypub.software/TransFem-org/Sharkey/-/raw/develop/packages/frontend/assets/sharkey.svg" alt="Sharkey logo" style="border-radius:50%" width="300"/>
<a href="https://misskey-hub.net">
<img src="./assets/title_float.svg" alt="Misskey logo" style="border-radius:50%" width="400"/>
</a>
**🌎 **[Sharkey](https://joinsharkey.org/)** is an open source, decentralized social media platform that's free forever! 🚀**
**🌎 **[Misskey](https://misskey-hub.net/)** is an open source, decentralized social media platform that's free forever! 🚀**
---
<a href="https://docs.joinsharkey.org/docs/install/fresh/">
<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>
<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>
<a href="./CONTRIBUTING.md">
<img src="https://custom-icon-badges.herokuapp.com/badge/become_a-contributor-A371F7?logoColor=A371F7&style=for-the-badge&logo=git-merge&labelColor=363B40" alt="become a contributor"/></a>
<a href="https://discord.gg/6VgKmEqHNk">
<a href="https://discord.gg/Wp8gVStHW3">
<img src="https://custom-icon-badges.herokuapp.com/badge/join_the-community-5865F2?logoColor=5865F2&style=for-the-badge&logo=discord&labelColor=363B40" alt="join the community"/></a>
<a href="https://opencollective.com/sharkey">
<img src="https://custom-icon-badges.herokuapp.com/badge/donate-81ACF4?logoColor=81ACF4&style=for-the-badge&logo=opencollective&labelColor=363B40" alt="donate"/></a>
<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>
---
[![codecov](https://codecov.io/gh/misskey-dev/misskey/branch/develop/graph/badge.svg?token=R6IQZ3QJOL)](https://codecov.io/gh/misskey-dev/misskey)
</div>
<div>
<a href="https://joinsharkey.org/"><img src="https://cdn.shonk.social/files/b671c81c-58cf-4f13-bc96-af0b0c96c667.webp" align="right" height="520px"/></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>
## ✨ Features
- **ActivityPub support**\
Not on Sharkey? No problem! Not only can Sharkey instances talk to each other, but you can make friends with people on other networks like Mastodon and Pixelfed!
- **Federated Backgrounds and Music status**\
You can add a background to your profile as well as a music status via ListenBrainz, show everyone what music you are currently listening to
- **Mastodon API**\
Sharkey implements the Mastodon API unlike normal Misskey
- **UI/UX Improvements**\
Sharkey makes some UI/UX improvements to make it easier to navigate
- **Sign-Up Approval**\
With Sharkey, you can enable sign-ups, subject to manual moderator approval and mandatory user-provided reasons for joining.
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**\
Sharkey 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.
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...
</div>
@ -50,4 +51,9 @@ With Sharkey, you can enable sign-ups, subject to manual moderator approval and
## Documentation
Sharkey Documentation can be found at [Sharkey Documentation](https://docs.joinsharkey.org/docs/install/fresh/)
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.
## Sponsors
<div align="center">
<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>

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.
- ~~Make the number of type errors zero (backend)~~ → Done ✔️
- Make the number of type errors zero (frontend)
- Improve CI
- ~~Fix tests~~ → Done ✔️
- 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.
- 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?
## (3) Improve scalability

View file

@ -1,9 +1,9 @@
# Reporting Security Issues
If you discover a security issue in Sharkey, please report it by sending an
email to [admin@transfem.org](mailto:admin@transfem.org).
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
bug report to the GitLab repository.
bug report to the GitHub repository.
Thanks for helping make Sharkey safe for everyone.
Thanks for helping make Misskey safe for everyone.

View file

@ -1,74 +0,0 @@
# Upgrade Notes
## 2024.10.0
### Hellspawns
Sharkey versions before 2024.10 suffered from a bug in the "Mark instance as NSFW" feature.
When a user from such an instance boosted a note, the boost would be converted to a hellspawn (pure renote with Content Warning).
Hellspawns are buggy and do not properly federate, so it may be desirable to correct any that already exist in the database.
The following script will correct any local or remote hellspawns in the database.
```postgresql
/* Remove "instance is marked as NSFW" hellspawns */
UPDATE "note"
SET "cw" = null
WHERE
"renoteId" IS NOT NULL
AND "text" IS NULL
AND "cw" = 'Instance is marked as NSFW'
AND "replyId" IS NULL
AND "hasPoll" = false
AND "fileIds" = '{}';
/* Fix legacy / user-created hellspawns */
UPDATE "note"
SET "text" = '.'
WHERE
"renoteId" IS NOT NULL
AND "text" IS NULL
AND "cw" IS NOT NULL
AND "replyId" IS NULL
AND "hasPoll" = false
AND "fileIds" = '{}';
```
## 2024.9.0
### Following Feed
When upgrading an existing instance to version 2024.9.0, the Following Feed will initially be empty.
The feed will gradually fill as new posts federate, but it may be desirable to back-fill the feed with existing data.
This database script will populate the feed with the latest post of each type for all users, ensuring that data is fully populated after the update.
Run this after migrations but before starting the instance.
Warning: the script may take a long time to execute!
```postgresql
INSERT INTO latest_note (user_id, note_id, is_public, is_reply, is_quote)
SELECT
"userId" as user_id,
id as note_id,
visibility = 'public' AS is_public,
"replyId" IS NOT NULL AS is_reply,
(
"renoteId" IS NOT NULL
AND (
text IS NOT NULL
OR cw IS NOT NULL
OR "replyId" IS NOT NULL
OR "hasPoll"
OR "fileIds" != '{}'
)
) AS is_quote
FROM note
WHERE ( -- Exclude pure renotes (boosts)
"renoteId" IS NULL
OR text IS NOT NULL
OR cw IS NOT NULL
OR "replyId" IS NOT NULL
OR "hasPoll"
OR "fileIds" != '{}'
)
ORDER BY id DESC -- This part is very important: it ensures that we only load the *latest* notes of each type. Do not remove it!
ON CONFLICT DO NOTHING; -- Any conflicts are guaranteed to be older notes that we can ignore.
```

View file

@ -72,75 +72,25 @@ db:
#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: localhost
port: 6379
#family: 0 # 0=Both, 4=IPv4, 6=IPv6
#pass: example-pass
#prefix: example-prefix
#db: 1
#redisForPubsub:
# ┌─────────────────────────────┐
#───┘ Elasticsearch configuration └─────────────────────────────
#elasticsearch:
# host: localhost
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #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: ''
# port: 9200
# ssl: false
# user:
# pass:
# ┌───────────────┐
#───┘ ID generation └───────────────────────────────────────────
@ -151,7 +101,6 @@ redis:
# 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
@ -159,23 +108,7 @@ redis:
# 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'
id: "aid"
# ┌─────────────────────┐
#───┘ Other configuration └─────────────────────────────────────
@ -191,7 +124,7 @@ id: "aidx"
# Job rate limiter
# deliverJobPerSec: 128
# inboxJobPerSec: 32
# inboxJobPerSec: 16
# Job attempts
# deliverJobMaxAttempts: 12
@ -216,15 +149,8 @@ id: "aidx"
# Media Proxy
#mediaProxy: https://example.com/proxy
# Sign outgoing ActivityPub GET request (default: true)
# Sign to ActivityPub GET request (default: true)
signToActivityPubGet: true
# Sign outgoing ActivityPub Activities (default: true)
# Linked Data signatures are cryptographic signatures attached to each activity to provide proof of authenticity.
# When using authorized fetch, this is often undesired as any signed activity can be forwarded to a blocked instance by relays and other instances.
# This setting allows admins to disable LD signatures for increased privacy, at the expense of fewer relayed activities and additional inbound fetch (GET) requests.
attachLdSignatureForRelays: true
# check that inbound ActivityPub GET requests are signed ("authorized fetch")
checkActivityPubGetSignature: false
#allowedPrivateNetworks: [
# '127.0.0.1/32'

View file

@ -27,7 +27,7 @@ spec:
ports:
- containerPort: 3000
- name: postgres
image: postgres:15-alpine
image: postgres:14-alpine
env:
- name: POSTGRES_USER
value: "example-misskey-user"
@ -38,7 +38,7 @@ spec:
ports:
- containerPort: 5432
- name: redis
image: redis:7-alpine
image: redis:alpine
ports:
- containerPort: 6379
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,97 +0,0 @@
services:
web:
# image: registry.activitypub.software/transfem-org/sharkey:latest
build: .
restart: always
links:
- db
- redis
# - mcaptcha
# - meilisearch
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
ports:
- "3000:3000"
networks:
- shonk
# env_file:
# - .config/docker.env
volumes:
- ./files:/sharkey/files
- ./.config:/sharkey/.config:ro
redis:
restart: always
image: redis:7-alpine
networks:
- shonk
volumes:
- ./redis:/data
healthcheck:
test: "redis-cli ping"
interval: 5s
retries: 20
db:
restart: always
image: postgres:15-alpine
networks:
- shonk
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
# mcaptcha:
# restart: always
# image: mcaptcha/mcaptcha:latest
# networks:
# shonk:
# aliases:
# - localhost
# ports:
# - 7493:7493
# env_file:
# - .config/docker.env
# environment:
# PORT: 7493
# MCAPTCHA_redis_URL: "redis://mcaptcha_redis/"
# MCAPTCHA_allow_registration: true
# MCAPTCHA_server_DOMAIN: "example.tld"
# depends_on:
# db:
# condition: service_healthy
# mcaptcha_redis:
# condition: service_healthy
#
# mcaptcha_redis:
# image: mcaptcha/cache:latest
# networks:
# - shonk
# 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
# - MEILI_MASTER_KEY=ChangeThis
# networks:
# - shonk
# volumes:
# - ./meili_data:/meili_data
networks:
shonk:

View file

@ -1,4 +1,4 @@
files:
- source: /sharkey-locales/en-US.yml
translation: /sharkey-locales/%locale%.yml
- source: /locales/ja-JP.yml
translation: /locales/%locale%.yml
update_option: update_as_unapproved

View file

@ -1,8 +1,3 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
describe('Before setup instance', () => {
beforeEach(() => {
cy.resetState();
@ -57,12 +52,6 @@ describe('After setup instance', () => {
cy.intercept('POST', '/api/signup').as('signup');
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-username] input').type('alice');
cy.get('[data-cy-signup-submit]').should('be.disabled');
@ -82,12 +71,6 @@ describe('After setup instance', () => {
// ユーザー名が重複している場合の挙動確認
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-password] input').type('alice1234');
cy.get('[data-cy-signup-password-retype] input').type('alice1234');
@ -166,62 +149,10 @@ describe('After user signed in', () => {
});
it('successfully loads', () => {
// 表示に時間がかかるのでデフォルト秒数だとタイムアウトする
cy.get('[data-cy-user-setup-continue]', { timeout: 30000 }).should('be.visible');
cy.get('[data-cy-open-post-form]').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', () => {
cy.get('[data-cy-open-post-form]').should('be.visible');
cy.get('[data-cy-open-post-form]').click();
cy.get('[data-cy-post-form-text]').type('Hello, Misskey!');
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', () => {
beforeEach(() => {
cy.resetState();
@ -16,10 +10,6 @@ describe('After user signed in', () => {
cy.registerUser('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(() => {
@ -29,26 +19,26 @@ describe('After user signed in', () => {
});
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', () => {
cy.get('[data-cy-widget-edit]').click();
cy.get('[data-cy-widget-select]').should('be.visible');
cy.get('.mk-widget-edit').click();
cy.get('.mk-widget-select').should('be.visible');
});
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]').should('have.length', 2);
});
function buildWidgetTest(widgetName) {
it(`${widgetName} widget should get added`, () => {
cy.get('[data-cy-widget-edit]').click();
cy.get('[data-cy-widget-select] select').select(widgetName, { force: true });
cy.get('.mk-widget-edit').click();
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-widget-add]').click({ force: true });
cy.get('.mk-widget-add').click({ force: true });
cy.get(`[data-cy-mkw-${widgetName}]`).should('exist');
});
}
@ -73,4 +63,3 @@ describe('After user signed in', () => {
buildWidgetTest('aiscript');
buildWidgetTest('aichan');
});
*/

View file

@ -30,13 +30,9 @@ Cypress.Commands.add('visitHome', () => {
})
Cypress.Commands.add('resetState', () => {
// iframe.contentWindow.indexedDB.deleteDatabase() がchromeのバグで使用できないため、indexedDBを無効化している。
// see https://github.com/misskey-dev/misskey/issues/13605#issuecomment-2053652123
/*
cy.window().then(win => {
cy.window(win => {
win.indexedDB.deleteDatabase('keyval-store');
});
*/
cy.request('POST', '/api/reset-db', {}).as('reset');
cy.get('@reset').its('status').should('equal', 204);
cy.reload(true);

View file

@ -21,8 +21,6 @@ import './commands'
Cypress.on('uncaught:exception', (err, runnable) => {
if ([
'The source image cannot be decoded',
// Chrome
'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

@ -0,0 +1,65 @@
version: "3"
services:
web:
build: .
restart: always
links:
- db
- redis
# - es
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
ports:
- "3000:3000"
networks:
- internal_network
- external_network
volumes:
- ./files:/misskey/files
- ./.config:/misskey/.config:ro
redis:
restart: always
image: redis:7-alpine
networks:
- internal_network
volumes:
- ./redis:/data
healthcheck:
test: "redis-cli ping"
interval: 5s
retries: 20
db:
restart: always
image: postgres:15-alpine
networks:
- internal_network
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
# es:
# restart: always
# image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.4.2
# environment:
# - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
# - "TAKE_FILE_OWNERSHIP=111"
# networks:
# - internal_network
# volumes:
# - ./elasticsearch:/usr/share/elasticsearch/data
networks:
internal_network:
internal: true
external_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!

View file

@ -1,251 +0,0 @@
/*
* SPDX-FileCopyrightText: dakkar and other Sharkey contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
/* This is a ESLint rule to report use of the `i18n.ts` and `i18n.tsx`
* objects that reference translation items that don't actually exist
* in the lexicon (the `locale/` files)
*/
/* given a MemberExpression node, collects all the member names
*
* e.g. for a bit of code like `foo=one.two.three`, `collectMembers`
* called on the node for `three` would return `['one', 'two',
* 'three']`
*/
function collectMembers(node) {
if (!node) return [];
if (node.type !== 'MemberExpression') return [];
// this is something like `foo[bar]`
if (node.computed) return [];
return [ node.property.name, ...collectMembers(node.parent) ];
}
/* given an object and an array of names, recursively descends the
* object via those names
*
* e.g. `walkDown({one:{two:{three:15}}},['one','two','three'])` would
* return 15
*/
function walkDown(locale, path) {
if (!locale) return null;
if (!path || path.length === 0 || !path[0]) return locale;
return walkDown(locale[path[0]], path.slice(1));
}
/* given a MemberExpression node, returns its attached CallExpression
* node if present
*
* e.g. for a bit of code like `foo=one.two.three()`,
* `findCallExpression` called on the node for `three` would return
* the node for function call (which is the parent of the `one` and
* `two` nodes, and holds the nodes for the argument list)
*
* if the code had been `foo=one.two.three`, `findCallExpression`
* would have returned null, because there's no function call attached
* to the MemberExpressions
*/
function findCallExpression(node) {
if (!node.parent) return null;
// the second half of this guard protects from cases like
// `foo(one.two.three)` where the CallExpression is parent of the
// MemberExpressions, but via `arguments`, not `callee`
if (node.parent.type === 'CallExpression' && node.parent.callee === node) return node.parent;
if (node.parent.type === 'MemberExpression') return findCallExpression(node.parent);
return null;
}
// same, but for Vue expressions (`<I18n :src="i18n.ts.foo">`)
function findVueExpression(node) {
if (!node.parent) return null;
if (node.parent.type.match(/^VExpr/) && node.parent.expression === node) return node.parent;
if (node.parent.type === 'MemberExpression') return findVueExpression(node.parent);
return null;
}
function areArgumentsOneObject(node) {
return node.arguments.length === 1 &&
node.arguments[0].type === 'ObjectExpression';
}
// only call if `areArgumentsOneObject(node)` is true
function getArgumentObjectProperties(node) {
return new Set(node.arguments[0].properties.map(
p => {
if (p.key && p.key.type === 'Identifier') return p.key.name;
return null;
},
));
}
function getTranslationParameters(translation) {
return new Set(Array.from(translation.matchAll(/\{(\w+)\}/g)).map( m => m[1] ));
}
function setDifference(a,b) {
const result = [];
for (const element of a.values()) {
if (!b.has(element)) {
result.push(element);
}
}
return result;
}
/* the actual rule body
*/
function theRuleBody(context,node) {
// we get the locale/translations via the options; it's the data
// that goes into a specific language's JSON file, see
// `scripts/build-assets.mjs`
const locale = context.options[0];
// sometimes we get MemberExpression nodes that have a
// *descendent* with the right identifier: skip them, we'll get
// the right ones as well
if (node.object?.name !== 'i18n') {
return;
}
// `method` is going to be `'ts'` or `'tsx'`, `path` is going to
// be the various translation steps/names
const [ method, ...path ] = collectMembers(node);
const pathStr = `i18n.${method}.${path.join('.')}`;
// does that path point to a real translation?
const translation = walkDown(locale, path);
if (!translation) {
context.report({
node,
message: `translation missing for ${pathStr}`,
});
return;
}
// we hit something weird, assume the programmers know what
// they're doing (this is usually some complicated slicing of
// the translation structure)
if (typeof(translation) !== 'string') return;
const callExpression = findCallExpression(node);
const vueExpression = findVueExpression(node);
// some more checks on how the translation is called
if (method === 'ts') {
// the `<I18n> component gets parametric translations via
// `i18n.ts.*`, but we error out elsewhere
if (translation.match(/\{/) && !vueExpression) {
context.report({
node,
message: `translation for ${pathStr} is parametric, but called via 'ts'`,
});
return;
}
if (callExpression) {
context.report({
node,
message: `translation for ${pathStr} is not parametric, but is called as a function`,
});
}
}
if (method === 'tsx') {
if (!translation.match(/\{/)) {
context.report({
node,
message: `translation for ${pathStr} is not parametric, but called via 'tsx'`,
});
return;
}
if (!callExpression && !vueExpression) {
context.report({
node,
message: `translation for ${pathStr} is parametric, but not called as a function`,
});
return;
}
// we're not currently checking arguments when used via the
// `<I18n>` component, because it's too complicated (also, it
// would have to be done inside the `if (method === 'ts')`)
if (!callExpression) return;
if (!areArgumentsOneObject(callExpression)) {
context.report({
node,
message: `translation for ${pathStr} should be called with a single object as argument`,
});
return;
}
const translationParameters = getTranslationParameters(translation);
const parameterCount = translationParameters.size;
const callArguments = getArgumentObjectProperties(callExpression);
const argumentCount = callArguments.size;
if (parameterCount !== argumentCount) {
context.report({
node,
message: `translation for ${pathStr} has ${parameterCount} parameters, but is called with ${argumentCount} arguments`,
});
}
// node 20 doesn't have `Set.difference`...
const extraArguments = setDifference(callArguments, translationParameters);
const missingArguments = setDifference(translationParameters, callArguments);
if (extraArguments.length > 0) {
context.report({
node,
message: `translation for ${pathStr} passes unused arguments ${extraArguments.join(' ')}`,
});
}
if (missingArguments.length > 0) {
context.report({
node,
message: `translation for ${pathStr} does not pass arguments ${missingArguments.join(' ')}`,
});
}
}
}
function theRule(context) {
// we get the locale/translations via the options; it's the data
// that goes into a specific language's JSON file, see
// `scripts/build-assets.mjs`
const locale = context.options[0];
// for all object member access that have an identifier 'i18n'...
return context.getSourceCode().parserServices.defineTemplateBodyVisitor(
{
// this is for <template> bits, needs work
'MemberExpression:has(Identifier[name=i18n])': (node) => theRuleBody(context, node),
},
{
// this is for normal code
'MemberExpression:has(Identifier[name=i18n])': (node) => theRuleBody(context, node),
},
);
}
module.exports = {
meta: {
type: 'problem',
docs: {
description: 'assert that all translations used are present in the locale files',
},
schema: [
// here we declare that we need the locale/translation as a
// generic object
{ type: 'object', additionalProperties: true },
],
},
create: theRule,
};

View file

@ -1,54 +0,0 @@
/*
* SPDX-FileCopyrightText: dakkar and other Sharkey contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
const {RuleTester} = require("eslint");
const localeRule = require("./locale");
const locale = { foo: { bar: 'ok', baz: 'good {x}' }, top: '123' };
const ruleTester = new RuleTester({
languageOptions: {
parser: require('vue-eslint-parser'),
ecmaVersion: 2015,
},
});
function testCase(code,errors) {
return { code, errors, options: [ locale ], filename: 'test.ts' };
}
function testCaseVue(code,errors) {
return { code, errors, options: [ locale ], filename: 'test.vue' };
}
ruleTester.run(
'sharkey-locale',
localeRule,
{
valid: [
testCase('i18n.ts.foo.bar'),
testCase('i18n.ts.top'),
testCase('i18n.tsx.foo.baz({x:1})'),
testCase('whatever.i18n.ts.blah.blah'),
testCase('whatever.i18n.tsx.does.not.matter'),
testCase('whatever(i18n.ts.foo.bar)'),
testCaseVue('<template><p>{{ i18n.ts.foo.bar }}</p></template>'),
testCaseVue('<template><I18n :src="i18n.ts.foo.baz"/></template>'),
// we don't detect the problem here, but should still accept it
testCase('i18n.ts.foo["something"]'),
testCase('i18n.ts.foo[something]'),
],
invalid: [
testCase('i18n.ts.not', 1),
testCase('i18n.tsx.deep.not', 1),
testCase('i18n.tsx.deep.not({x:12})', 1),
testCase('i18n.tsx.top({x:1})', 1),
testCase('i18n.ts.foo.baz', 1),
testCase('i18n.tsx.foo.baz', 1),
testCase('i18n.tsx.foo.baz({y:2})', 2),
testCaseVue('<template><p>{{ i18n.ts.not }}</p></template>', 1),
testCaseVue('<template><I18n :src="i18n.ts.not"/></template>', 1),
],
},
);

27
flake.lock generated
View file

@ -1,27 +0,0 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1733212471,
"narHash": "sha256-M1+uCoV5igihRfcUKrr1riygbe73/dzNnzPsmaLCmpo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "55d15ad12a74eb7d4646254e13638ad0c4128776",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

View file

@ -1,38 +0,0 @@
{
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
outputs = { self, nixpkgs }: {
nixosConfigurations.container = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules =
[
( import ./sharkey-service.nix )
({ pkgs, ... }: {
boot.isContainer = true;
# Let 'nixos-version --json' know about the Git revision
# of this flake.
system.configurationRevision = nixpkgs.lib.mkIf (self ? rev) self.rev;
# Network configuration.
networking.useDHCP = false;
networking.firewall.allowedTCPPorts = [ 3000 ];
system.stateVersion = "24.04";
services.sharkey = {
enable = true;
package = (pkgs.callPackage ./sharkey.nix {});
settings = {
url = "https://sharkey.localhost";
};
redis.createLocally = true;
database.createLocally = true;
};
})
];
};
};
}

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
# SPDX-FileCopyrightText: syuilo and misskey-project
# SPDX-License-Identifier: AGPL-3.0-only
PORT=$(grep '^port:' /sharkey/.config/default.yml | awk 'NR==1{print $2; exit}')
curl -Sfso/dev/null "http://localhost:${PORT}/healthz"
PORT=$(grep '^port:' /misskey/.config/default.yml | awk 'NR==1{print $2; exit}')
curl -s -S -o /dev/null "http://localhost:${PORT}"

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(--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_: "العربية"
headlineMisskey: "شبكة مرتبطة بالملاحظات"
introMisskey: "اهلا بك! ميسكي هو منصة تدوين مصغر لا مركزية ومفتوحة المصدر.\nيمكنك مشاركة \"ملاحظات\" عن ما يجري حولك، وإخبار الجميع عن نفسك 📡\nتسمح لك \"الانفعالات\" بتعبير عن شعورك حول ملاحظات الآخرين 👍\nاكتشف عالمًا جديدًا 🚀"
poweredByMisskeyDescription: "{name} هو إحدى الخِدمات التي تستخدم المنصة مفتوحة المصدر <b>ميسكي</b> (يشار إليه كمثيل ميسكي)"
monthAndDay: "{day}/{month}"
search: "البحث"
notifications: "الإشعارات"
@ -20,7 +19,6 @@ noNotes: "لم يُعثر على أية ملاحظات"
noNotifications: "ليس هناك أية اشعارات"
instance: "مثيل الخادم"
settings: "الاعدادات"
notificationSettings: "إعدادات الإشعارات"
basicSettings: "الاعدادات الأساسية"
otherSettings: "إعدادات أخرى"
openInWindow: "افتح في نافذة جديدة"
@ -41,23 +39,16 @@ unfavorite: "إزالة من المفضلة"
favorited: "أُضيف إلى المفضلة."
alreadyFavorited: "تمت إضافته بالفعل إلى المفضلة."
cantFavorite: "تعذرت الإضافة إلى المفضلة."
pin: "ثبتها على الصفحة الشخصية"
unpin: "فكها من ملفك الشخصي"
pin: "دبّسها على الصفحة الشخصية"
unpin: "ألغ تدبيسها من ملفك الشخصي"
copyContent: "انسخ المحتوى"
copyLink: "انسخ الرابط"
delete: "حذف"
deleteAndEdit: "إزالة وإعادة الصياغة"
deleteAndEditConfirm: "أمتأكد من حذف الملاحظة؟ ستفقد كل مشاركاتها، والتفاعلات، والردود عليها."
addToList: "أضفه إلى قائمة"
addToAntenna: "أضف إلى هوائي"
sendMessage: "أرسل رسالة"
copyRSS: "انسخ رابط RSS"
copyUsername: "انسخ اسم المستخدم"
copyUserId: "انسخ معرف المستخدم"
copyNoteId: "انسخ معرف الملاحظة"
copyFileId: "انسخ معرّف الملف"
copyFolderId: "انسخ معرّف المجلد"
copyProfileUrl: "انسخ رابط الملف الشخصي"
searchUser: "ابحث عن مستخدمين"
reply: "رد"
loadMore: "عرض المزيد"
@ -110,27 +101,23 @@ renoted: "أُعيد نشره"
cantRenote: "لا يمكن إعادة نشر الملاحظة"
cantReRenote: "لا يمكنك إعادة نشر ملاحظة معاد نشرها"
quote: "اقتبس"
inChannelRenote: "إعادة نشر في قناة"
inChannelQuote: "اقتباس في قناة"
pinnedNote: "ملاحظة مثبتة"
pinned: "ثبتها على الصفحة الشخصية"
pinnedNote: "ملاحظة مدبسة"
pinned: "دبّسها على الصفحة الشخصية"
you: "أنت"
clickToShow: "اضغط للعرض"
sensitive: "محتوى حساس"
add: "إضافة"
reaction: "التفاعلات"
reactions: "التفاعلات"
reactionSetting: "التفاعلات المراد عرضها في منتقي التفاعلات."
reactionSettingDescription2: "اسحب لترتيب ، انقر للحذف ، استخدم \"+\" للإضافة."
rememberNoteVisibility: "تذكر إعدادت مدى رؤية الملاحظات"
attachCancel: "أزل المرفق"
deleteFile: "حُذف الملف"
markAsSensitive: "علّمه كمحتوى حساس"
unmarkAsSensitive: "ألغ تعيينه كمحتوى حساس"
enterFileName: "ادخل اسم الملف"
mute: "اكتم"
unmute: "إلغاء الكتم"
renoteMute: "اكتم إعادة النشر"
renoteUnmute: "ارفع الكتم عن إعادة النشر"
block: "احجب"
unblock: "إلغاء الحجب"
suspend: "علِق"
@ -140,10 +127,7 @@ unblockConfirm: "أمتأكد من إلغاء حجب هذا الحساب؟"
suspendConfirm: "أمتأكد من تعليق الحساب؟"
unsuspendConfirm: "أمتأكد من إلغاء تعليق؟"
selectList: "اختر قائمة"
editList: "عدّل القائمة"
selectChannel: "اختر قناة"
selectAntenna: "اختر هوائيًا"
editAntenna: "عدّل الهوائي"
selectWidget: "اختر ودجة"
editWidgets: "عدّل الودجات"
editWidgetsExit: "تم"
@ -155,7 +139,6 @@ emojiUrl: "رابط الإيموجي"
addEmoji: "إضافة إيموجي"
settingGuide: "الإعدادات المستحسنة"
cacheRemoteFiles: "خزن مؤقتا الملفات البعيدة"
cacheRemoteFilesDescription: "إذا عُطل هذا الإعداد، ستُحمل الملفات من المثيل البعيد، هذا سيقلل من المساحة المستغلة على القرص لكن سيزيد حجم تدفق البيانات وهذا لأن الصور المصغرة لن تولّد."
flagAsBot: "علّمه كحساب آلي"
flagAsBotDescription: "فعّل هذا الخيار إذا كان هذا الحساب يُدار عبر برمجية. إذا فُعل فسيكون بمثابة علامة للمطورين الآخرين لتجنب سلاسل لا متناهية من التفاعل بين حسابات الآلية وضبط أنظمة ميسكي للتعامل مع هذا الحساب كآلي."
flagAsCat: "علّم هذا الحساب كحساب قط"
@ -214,7 +197,7 @@ blockedUsers: "الحسابات المحجوبة"
noUsers: "ليس هناك مستخدمون"
editProfile: "تعديل الملف التعريفي"
noteDeleteConfirm: "هل تريد حذف هذه الملاحظة؟"
pinLimitExceeded: "لا يمكنك تثبيت الملاحظات بعد الآن."
pinLimitExceeded: "لا يمكنك تدبيس الملاحظات بعد الآن."
intro: "لقد انتهت عملية تنصيب Misskey. الرجاء إنشاء حساب إداري."
done: "تمّ"
processing: "المعالجة جارية"
@ -267,16 +250,12 @@ noMoreHistory: "لا يوجد المزيد من التاريخ"
startMessaging: "ابدأ محادثة"
nUsersRead: "قرأه {n}"
agreeTo: "اوافق على {0}"
agree: "أقبل"
agreeBelow: "أقبل ما يلي"
basicNotesBeforeCreateAccount: "ملاحظات مهمة"
termsOfService: "شروط الخدمة"
tos: "شروط الخدمة"
start: "البداية"
home: "الرئيسي"
remoteUserCaution: "هذه المعلومات قد لا تكون مكتملة بما أن المستخدم من مثيل بعيد."
activity: "النشاط"
images: "صور"
image: "صور"
images: "الصور"
birthday: "تاريخ الميلاد"
yearsOld: "{age} سنة"
registeredDate: "انضم في"
@ -313,7 +292,7 @@ copyUrl: "انسخ الرابط"
rename: "إعادة التسمية"
avatar: "الصورة الرمزية"
banner: "الصورة الرأسية"
displayOfSensitiveMedia: "عرض المحتوى الحساس"
nsfw: "محتوى حساس"
whenServerDisconnected: "عند فقدان الاتصال بالخادم"
disconnectedFromServer: "قُطِع الإتصال بالخادم"
reload: "انعش"
@ -348,21 +327,20 @@ invite: "دعوة"
driveCapacityPerLocalAccount: "حصة التخزين لكل مستخدم محلي"
driveCapacityPerRemoteAccount: "حصة التخزين لكل مستخدم بعيد"
inMb: "بالميغابايت"
iconUrl: "رابط الأيقونة"
bannerUrl: "رابط صورة اللافتة"
backgroundImageUrl: "رابط صورة الخلفية"
basicInfo: "المعلومات الأساسية "
pinnedUsers: "المستخدمون المثبتون"
pinnedUsersDescription: "قائمة المستخدمين المثبتين في لسان \"استكشف\" ، اجعل كل اسم مستخدم في سطر لوحده."
pinnedPages: "الصفحات المثبتة"
pinnedPagesDescription: "أدخل مسار الصفحات التي تريد تثبيتها في أعلى هذا الموقع، اجعل كل مسار في سطر لوحده."
pinnedClipId: "معرّف المشبك المثبت"
pinnedNotes: "ملاحظة مثبتة"
pinnedUsers: "المستخدمون المدبسون"
pinnedUsersDescription: "قائمة المستخدمين المدبسين في لسان \"استكشف\" ، اجعل كل اسم مستخدم في سطر لوحده."
pinnedPages: "الصفحات المدبسة"
pinnedPagesDescription: "أدخل مسار الصفحات التي تريد تدبيسها في أعلى هذا الموقع، اجعل كل مسار في سطر لوحده."
pinnedClipId: "معرّف المشبك المدبس"
pinnedNotes: "ملاحظة مدبسة"
hcaptcha: "hCaptcha"
enableHcaptcha: "فعّل hCaptcha"
hcaptchaSiteKey: "مفتاح الموقع"
hcaptchaSecretKey: "المفتاح السري"
mcaptchaSiteKey: "مفتاح الموقع"
mcaptchaSecretKey: "المفتاح السري"
recaptcha: "reCAPTCHA"
enableRecaptcha: "تمكين reCAPTCHA"
recaptchaSiteKey: "مفتاح الموقع"
@ -379,7 +357,6 @@ antennaExcludeKeywords: "الكلمات المفتاحية المستثناة"
antennaKeywordsDescription: "افصل بينهم بمسافة لاستخدام معامل \"و\" أو بسطر لاستخدام معامل \"أو\""
notifyAntenna: "نبهني بصول ملاحظات جديدة"
withFileAntenna: "ملاحظات تحوي ملفات فقط"
enableServiceworker: "فعّل إرسال الإشعارات للمتصفح"
antennaUsersDescription: "اكتب اسم مستخدم لكل سطر"
caseSensitive: "حساسية حالة الأحرف"
withReplies: "بالردود"
@ -402,15 +379,11 @@ about: "عن"
aboutMisskey: "عن Misskey"
administrator: "المدير"
token: "الرمز المميز"
2fa: "الاستيثاق بعاملَيْن"
totp: "تطبيق استيثاق"
moderator: "مشرِف"
moderation: "الإشراف"
nUsersMentioned: "{n} مستخدمين أُشير إليهم"
securityKeyAndPasskey: "الأمن ومفاتيح الأمان"
securityKey: "مفتاح الأمان"
lastUsed: "آخر استخدام"
lastUsedAt: "آخر استخدام: {t}"
unregister: "إلغاء التسجيل"
passwordLessLogin: "لِج مِن دون كلمة سرية"
resetPassword: "أعد تعيين كلمتك السرية"
@ -420,6 +393,7 @@ share: "شارِك"
notFound: "غير موجود"
notFoundDescription: "تعذر العثور على صفحة يقود إليها هذا الرابط."
uploadFolder: "المجلد الافتراضي للرفع"
cacheClear: "مسح ذاكرة التخزين المؤقت"
markAsReadAllNotifications: "وضع جميع الإشعارات كأنها مقروءة"
markAsReadAllUnreadNotes: "علّم جميع الملاحظات كمقروءة"
markAsReadAllTalkMessages: "علّم جميع الرسائل كمقروءة"
@ -460,8 +434,6 @@ or: "أو"
language: "اللغة"
uiLanguage: "لغة واجهة المستخدم"
aboutX: "عن {x}"
emojiStyle: "نمط الوجوه التعبيرية"
showNoteActionsOnlyHover: "أظهر الإجراءات عند التمرير فوق الملاحظة"
noHistory: "السجل فارغ"
signinHistory: "تاريخ تسجيل الدخول"
doing: "انتظر لحظة"
@ -472,7 +444,6 @@ createAccount: "أنشئ حسابًا"
existingAccount: "الحسابات الموجودة"
regenerate: "أعِد التوليد"
fontSize: "حجم الخط"
limitTo: "سقفهُ لـ{x}"
noFollowRequests: "ليس لديك طلبات متابعة معلقة"
openImageInNewTab: "إفتح الصورة بصفحة جديدة"
dashboard: "لوحة التحكم"
@ -494,16 +465,13 @@ objectStoragePrefix: "البادئة"
objectStoragePrefixDesc: "ستُحفظ الملفات في مجلدات تحوي اسماءها هذه البادئة."
objectStorageEndpoint: "نقطة النهاية"
objectStorageRegion: "المنطقة"
objectStorageRegionDesc: "حدد منطقة مثل \"xx-east-1\". إذا كانت خدمتك لا تميز بين المناطق استخدم \"us-east-1\" أو اتركها فارغة إذا كنت تستخدم متغيرات البيئة أو ملفات ضبط AWS."
objectStorageUseSSL: "استخدم SSL"
objectStorageUseSSLDesc: "عطل هذا الخيار إذا لم ترد استخدام API عبر HTTPS"
objectStorageUseProxy: "اتصل عبر وكيل"
objectStorageUseProxyDesc: "عطل هذا الخيار إذا لم ترد استخدام API عبر وكيل"
objectStorageSetPublicRead: "عينها ك\"علنية\" عند الرفع"
serverLogs: "سجلات الخادم"
deleteAll: "حذف الكل"
showFixedPostForm: "أظهر نموذج الكتابة في أعلى الصفحة"
showFixedPostFormInChannel: "أظهر نموذج الكتابة في أعلى الخط الزمني (قنوات)"
newNoteRecived: "هناك ملاحظات جديدة"
sounds: "الرنات"
sound: "الرنات"
@ -538,12 +506,9 @@ userSuspended: "عُلق هذا المستخدم."
userSilenced: "كُتم هذا المستخدم."
yourAccountSuspendedTitle: "هذا الحساب معلق"
yourAccountSuspendedDescription: "عُلق الحساب بسبب انتهاك شروط خدمة المثيل و ما شابه. إذا أردت معرفة التفصيل تواصل مع مدير المثيل. رجاءً لا تنشئ حساب جديد."
accountDeleted: "حُذف الحساب"
accountDeletedDescription: "حُذف هذا الحساب."
menu: "القائمة"
divider: "فاصل"
addItem: "إضافة عنصر"
rearrange: "أعد الترتيب"
relays: "المُرَحلات"
addRelay: "إضافة مُرحّل"
inboxUrl: "رابط صندوق الوارد"
@ -566,8 +531,6 @@ author: "الكاتب"
leaveConfirm: "لديك تغييرات غير محفوظة. أتريد المتابعة دون حفظها؟"
manage: "إدارة "
plugins: "الإضافات"
preferencesBackups: "النُسخ الاحتياطية للإعدادات"
useBlurEffectForModal: "استخدم تأثير الطمس في المشروط"
useFullReactionPicker: "استخدم الحجم الكامل لمنتقي التفاعلات"
width: "العرض"
height: "الإرتفاع"
@ -626,7 +589,10 @@ abuseReported: "أُرسل البلاغ، شكرًا لك"
reporter: "المُبلّغ"
reporteeOrigin: "أصل البلاغ"
reporterOrigin: "أصل المُبلّغ"
forwardReport: "وجّه البلاغ إلى المثيل البعيد"
forwardReportIsAnonymous: "في المثيل البعيد سيظهر المبلّغ كحساب مجهول."
send: "أرسل"
abuseMarkAsResolved: "علّم البلاغ كمحلول"
openInNewTab: "افتح في لسان جديد"
defaultNavigationBehaviour: "سلوك الملاحة الافتراضي"
editTheseSettingsMayBreakAccount: "تعديل هذه الإعدادات قد يسبب عطبًا لحسابك"
@ -640,9 +606,7 @@ clip: "مِشبك"
createNew: "أنشِئ جديد"
optional: "اختياري"
createNewClip: "أنشئ مِشبكَا جديدًا"
confirmToUnclipAlreadyClippedNote: "هذه الملاحظة تنتمي للمشبك {name} سلفًا، أتريد حذفها منه⸮"
public: "علني"
private: "خاص"
i18nInfo: "يترجم متطوعون ميسكي إلى عدة لغات، يمكنك المساعدة عبر {link}"
manageAccessTokens: "إدارة رموز الوصول"
accountInfo: "معلومات الحساب"
@ -663,7 +627,6 @@ driveFilesCount: "عدد الملفات في قرص التخزين"
driveUsage: "المستغل من قرص التخزين"
noCrawle: "ارفض فهرسة زاحف الويب"
noCrawleDescription: "يطلب من محركات البحث ألّا يُفهرسوا ملفك الشخصي وملاحظات وصفحاتك وما شابه."
lockedAccountInfo: "ستكون هذه الملاحظة مرئية للجميع مالم تحدد مرئتيها إلى \"للمتابعين فقط\""
alwaysMarkSensitive: "علّم افتراضيًا جميع ملاحظاتي كذات محتوى حساس"
loadRawImages: "حمّل الصور الأصلية بدلًا من المصغرات"
disableShowingAnimatedImages: "لا تشغّل الصور المتحركة"
@ -677,13 +640,10 @@ contact: "التواصل"
useSystemFont: "استخدم الخط الافتراضية للنظام"
clips: "مشابك"
experimentalFeatures: "ميّزات اختبارية"
experimental: "اختباري"
developer: "المطور"
makeExplorable: "أظهر الحساب في صفحة \"استكشاف\""
makeExplorableDescription: "بتعطيل هذا الخيار لن يظهر حسابك في صفحة \"استكشاف\""
showGapBetweenNotesInTimeline: "أظهر فجوات بين المشاركات في الخيط الزمني"
left: "يسار"
center: "وسط"
wide: "عريض"
narrow: "رفيع"
reloadToApplySetting: "سيُطبق هذا الإعداد بعد إعادة تحميل الصفحة، أتريد إعادة تحميلها الآن؟"
@ -701,7 +661,6 @@ accentColor: "طابع لوني"
textColor: "لون النص"
saveAs: "احفظ كـ..."
advanced: "متقدم"
advancedSettings: "إعدادات متقدمة"
value: "القيمة"
createdAt: "أُنشئ في"
updatedAt: "حُدّث في"
@ -721,7 +680,6 @@ editCode: "حرر الشفرة"
apply: "تطبيق"
receiveAnnouncementFromInstance: "استلم إشعارات من هذا المثيل"
emailNotification: "إشعارات البريد الكتروني"
publish: "علني"
inChannelSearch: "ابحث عن قناة"
useReactionPickerForContextMenu: "افتح منتقي التفاعلات عند النقر بالزر الأيمن"
typingUsers: "{users} يكتب(ون)..."
@ -734,7 +692,7 @@ unlikeConfirm: "أتريد إلغاء إعجابك؟"
fullView: "ملء الشاشة"
quitFullView: "اخرج من وضع ملء للشاشة"
addDescription: "أضف وصفًا"
userPagePinTip: "لعرض ملاحظة هنا اختر \"ثبتها على الصفحة الشخصية\" من قائمة تلك الملاحظة."
userPagePinTip: "لعرض ملاحظة هنا اختر \"دبسها على الصفحة الشخصية\" من قائمة تلك الملاحظة."
notSpecifiedMentionWarning: "في الملاحظة ذكر لمستخدمين لن يستلموها."
info: "عن"
userInfo: "معلومات المستخدم"
@ -761,14 +719,12 @@ noMaintainerInformationWarning: "لم تُضبط معلومات المدير"
noBotProtectionWarning: "لم تضبط الحماية من الحسابات الآلية"
configure: "اضبط"
postToGallery: "انشر في المعرض"
postToHashtag: "انشر بهذا الوسم"
gallery: "المعرض"
recentPosts: "المشاركات الحديثة"
popularPosts: "المشاركات المتداولة"
shareWithNote: "شاركه في ملاحظة"
ads: "الإعلانات"
expiration: "ينتهي استطلاع الرأي في"
startingperiod: "ابدأ"
memo: "تذكير"
priority: "الأولوية"
high: "عالية"
@ -794,18 +750,13 @@ translate: "ترجم"
translatedFrom: "تُرجم من {x}"
accountDeletionInProgress: "حذف الحساب جارٍ"
usernameInfo: "الاسم الذي يميزك عن بافي مستخدمي هذا الخادم، يمكنك استخدام الحروف اللاتينية (a~z, A~Z) والأرقام (0~9) والشرطة السفلية (_). لا يمكنك تغييره بعد تسجيله."
devMode: "وضع المُطوّر"
keepCw: "أبقِ على تحذيرات المحتوى"
pubSub: "حسابات Pub/Sub"
lastCommunication: "آخر تواصل"
resolved: "عولج"
unresolved: "لم يعالج"
breakFollow: "إلغاء الاشتراك"
breakFollowConfirm: "أمتأكد من إزالة المتابِع ؟"
itsOn: "مفعّل"
itsOff: "معطّل"
on: "مفعل"
off: "معطل"
emailRequiredForSignup: "عنوان البريد الإلكتروني إلزامي للتسجيل"
unread: "غير مقروءة"
filter: "رشّح"
@ -816,7 +767,8 @@ makeReactionsPublicDescription: "هذا سيجعل قائمة تفاعلاتك
classic: "تقليدي"
muteThread: "اكتم النقاش"
unmuteThread: "ارفع الكتم عن النقاش"
continueThread: "اعرض بقية النقاش"
ffVisibility: "مرئية المتابِعين/المتابَعين"
ffVisibilityDescription: "يسمح لك بتحديد من يمكنهم رؤية متابِعيك ومتابَعيك."
deleteAccountConfirm: "سيحذف حسابك نهائيًا، أتريد المتابعة؟"
incorrectPassword: "كلمة السر خاطئة."
voteConfirm: "متيقِّن من تصويتك لـ {choice}؟"
@ -838,282 +790,23 @@ tenMinutes: "10 دقائق"
oneHour: "ساعة"
oneDay: "يوم"
oneWeek: "أسبوع"
oneMonth: "شهر"
failedToFetchAccountInformation: "تعذر جلب معلومات الحساب"
cropImage: "اقتصاص الصورة"
cropImageAsk: "أتريد اقتصاص هذه الصورة"
cropYes: "اقتص"
cropNo: "استخدمها كما هي"
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: "اقلب"
colored: "ملوّن"
refreshInterval: "مهلة التحديث"
label: "التسمية"
type: "نوع"
speed: "سرعة"
slow: "بطيء"
fast: "سريع"
sensitiveMediaDetection: "التعرف على المحتوى الحساس"
localOnly: "المحلي فقط"
remoteOnly: "بُعدي فقط"
failedToUpload: "فشل الرفع"
cannotUploadBecauseInappropriate: "تعذر رفع الملف لوجود محتوى حساس فيه."
cannotUploadBecauseNoFreeSpace: "تعذر رفع الملف لنقص مساحة التخزين."
cannotUploadBecauseExceedsFileSizeLimit: "تعذر رفع الملف بسبب تجاوز حجمه للحد المسموح"
beta: "بيتا"
enableAutoSensitive: "تعيين تلقائي كمحتوى حساس NSFW"
enableAutoSensitiveDescription: "عند الاستطاعة يسمح باكتشاف المحتوى حساس NSFW تلقائيًا في الوسائط باستخدام تعلم الآلة ووسمها تبعًا لذلك. قد يكون هذا الخيار مفعلا من جهة الخادم وسيعمل حتى وان عُطل."
activeEmailValidationDescription: "يتحقق من صحة عنوان البريد الإلكتروني بشكل أكثر حزمًا وذلك عبر تحديد ما إذا كان عنوان بريد إلكتروني مؤقت وإمكانية التواصل معه. إذا لم يحدد هذا الخيار فسيتحقق من نسق عنوان البريد الإلكتروني."
navbar: "شريط التنقل"
shuffle: "خلط"
account: "الحسابات"
move: "أنقل"
pushNotification: "إرسال الإشعارات"
subscribePushNotification: "فعّل إرسال الإشعارات"
unsubscribePushNotification: "عطل إرسال الإشعارات"
pushNotificationAlreadySubscribed: "إرسال الإشعارات مفعل سلفًا"
pushNotificationNotSupported: "متصفحك لا يدعم إرسال الإشعارات أو المثيل لا يدعمها."
sendPushNotificationReadMessage: "احذف الإشعارات فور قراءتها"
sendPushNotificationReadMessageCaption: "هذا قد يزيد من معدل استهلاك الطاقة لجهازك."
windowMaximize: "املأ الشاشة"
windowRestore: "استرجاع"
caption: "التعليق التوضيحي"
loggedInAsBot: "والج كآلي"
tools: "أدوات"
cannotLoad: "تعذر التحميل"
numberOfProfileView: "مشاهدات الملف الشخصي"
like: "أعجبني"
unlike: "ألغِ الإعجاب"
numberOfLikes: "الإعجابات"
show: "المظهر"
neverShow: "لا تظهره مجددًا"
remindMeLater: "ربما لاحقا"
didYouLikeMisskey: "هل أعجبك ميسكي؟"
pleaseDonate: "يستخدم {host} البرمجية الحرة ميسكي. نتمنى أن تتبرعوا للمشروع مما سيسمح لنا متابعة تطويره!"
roles: "الأدوار"
role: "الدور"
noRole: "لم يُعثر على دور"
normalUser: "مستخدم عادي"
undefined: "غير معرّف"
assign: "أسند"
unassign: "ألغ الإسناد"
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:
new: "دور جديد"
edit: "حرر الأدوار"
name: "اسم الدور"
description: "وصف الدور"
permission: "أذونات الدور"
assignTarget: "نوع الإسناد"
condition: "الشرط"
options: "خيارات"
policies: "السياسة العامة"
priority: "الأولوية"
_priority:
low: "منخفضة"
middle: "متوسط"
high: "عالية"
_options:
canManageCustomEmojis: "إدارة الإيموجي المخصصة"
pinMax: "حد عدد الملاحظات المثبتة"
_condition:
isLocal: "مستخدم محلي"
isRemote: "مستخدم بعيد"
_emailUnavailable:
used: "هذا البريد الإلكتروني مستخدم"
format: "صيغة البريد الإلكتروني غير صالحة"
@ -1156,10 +849,6 @@ _plugin:
install: "ثبّت إضافات"
installWarn: "رجاءً لا تثبت إضافات غير موثوقة."
manage: "إدارة الإضافات"
viewSource: "اظهر المصدر"
_preferencesBackups:
createdAt: "تم إنشاؤه: {date} {time}"
updatedAt: "آخر تحديث: {date} {time}"
_registry:
scope: "الحيّز"
key: "مفتاح"
@ -1175,6 +864,10 @@ _aboutMisskey:
donate: "تبرع لميسكي"
morePatrons: "نحن نقدر الدعم الذي قدمه العديد من الأشخاص الذين لم نذكرهم. شكرًا لكم 🥰"
patrons: "الداعمون"
_nsfw:
respect: "اخف الوسائط ذات المحتوى الحساس"
ignore: "اعرض الوسائط ذات المحتوى الحساس"
force: "اخف كل الوسائط"
_instanceTicker:
none: "لا تظهره بتاتًا"
remote: "أظهر للمستخدمين البِعاد"
@ -1200,6 +893,11 @@ _wordMute:
muteWords: "الكلمات المحظورة"
muteWordsDescription: "افصل بينهم بمسافة لاستخدام معامل \"و\" أو بسطر لاستخدام معامل \"أو\"."
muteWordsDescription2: "احصر الكلمات المفتاحية بين بين شرطتين مائلتين لاستخدامها كتعابير نمطية"
softDescription: "اخف الملاحظات التي تستوف الشروط من الخيط الزمني."
hardDescription: "اخف الملاحظات التي تستوف الشروط من الخيط الزمني.بالإضافة إلى أن هذه الملاحظات ستبقى مخفية حتى وإن تغيرت الشروط."
soft: "لينة"
hard: "قاسية"
mutedNotes: "الملاحظات المكتومة"
_instanceMute:
instanceMuteDescription: "هذه سيحجب كل ملاحظات الخوادم المحجوبة ومشاركاتها والردود على تلك الملاحظات حتى وإن كانت من خادم غير محجوب."
instanceMuteDescription2: "مدخلة لكل سطر"
@ -1252,12 +950,17 @@ _theme:
buttonBg: "خلفية الأزرار"
buttonHoverBg: "خلفية الأزرار (عند التمرير فوقها)"
inputBorder: "حواف حقل الإدخال"
listItemHoverBg: "خلفية عناصر القائمة (عند التمرير فوقها)"
driveFolderBg: "خلفية مجلد قرص التخزين"
messageBg: "خلفية المحادثة"
_sfx:
note: "الملاحظات"
noteMy: "ملاحظتي"
notification: "الإشعارات"
chat: "المحادثة"
chatBg: "المحادثة (الخلفية)"
antenna: "الهوائيات"
channel: "إشعارات القنات"
_ago:
future: "المستقبَل"
justNow: "اللحظة"
@ -1274,6 +977,29 @@ _time:
minute: "د"
hour: "سا"
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:
alreadyRegistered: "سجلت سلفًا جهازًا للاستيثاق بعاملين."
step1: "أولًا ثبّت تطبيق استيثاق على جهازك (مثل {a} و{b})."
@ -1351,7 +1077,6 @@ _widgets:
onlineUsers: "المتّصلون"
jobQueue: "قائمة الانتظار"
serverMetric: "إحصائيات الخادم"
userList: "قائمة المستخدمين"
_userList:
chooseList: "اختر قائمة"
_cw:
@ -1415,8 +1140,6 @@ _profile:
changeBanner: "غيّر اللافتة"
_exportOrImport:
allNotes: "كل الملاحظات"
favoritedNotes: " الملاحظات المفضلة"
clips: "مِشبك"
followingList: "المتابَعون"
muteList: "المستخدمون المكتومون"
blockingList: "المستخدمون المحجوبون"
@ -1435,8 +1158,6 @@ _charts:
notesTotal: "إجمالي الملاحظات"
filesIncDec: "تباين عدد الملفات"
filesTotal: "العدد الإجمالي للملفات"
storageUsageIncDec: "التباين في استغلال مساحة التخزين"
storageUsageTotal: "اجمالي مساحة التخزين المستغلة"
_instanceCharts:
requests: "الطلبات"
users: "تباين عدد المستخدمين"
@ -1482,7 +1203,7 @@ _pages:
url: "رابط الصفحة"
summary: "ملخص الصفحة"
alignCenter: "توسيط العناصر"
hideTitleWhenPinned: "اخف عنوان الصفحة عند تثبيتها في ملف الشخصي"
hideTitleWhenPinned: "اخف عنوان الصفحة عند تدبيسها في ملف الشخصي"
font: "الخط"
fontSerif: "Serif"
fontSansSerif: "Sans Serif"
@ -1497,7 +1218,7 @@ _pages:
text: "نص"
textarea: "حقل نصي"
section: "قسم"
image: "صور"
image: "الصور"
button: "زرّ"
note: "ملاحظة مضمّنة"
_note:
@ -1512,76 +1233,48 @@ _notification:
fileUploaded: "نجح رفع الملف"
youGotMention: "{name} أشار إليك"
youGotReply: "ردّ عليك {name}"
youGotQuote: "اقتبس {name} منشورك"
youRenoted: "أعاد {name} نشر منشورك"
youGotQuote: "اقتبس منك {name}"
youRenoted: "إعادت نشر من {name}"
youWereFollowed: "يتابعك"
youReceivedFollowRequest: "تلقيتَ طلب متابعة"
yourFollowRequestAccepted: "قُبل طلب المتابعة"
pollEnded: "انتهى الاستطلاع"
pollEnded: "ظهرت نتائج الاستطلاع"
unreadAntennaNote: "هوائي {name}"
_types:
all: "الكل"
follow: "متابِعون جدد"
mention: "الإشارات"
reply: "الردود"
renote: "أعاد النشر"
renote: "أعد النشر"
quote: "الاقتباسات"
reaction: "التفاعل"
receiveFollowRequest: "طلبات المتابعة"
reaction: "التفاعلات"
receiveFollowRequest: "طلبات المتابعة المتلقاة"
followRequestAccepted: "طلبات المتابعة المقبولة"
login: "لِج"
app: "إشعارات التطبيقات المرتبطة"
_actions:
followBack: "تابعك بالمثل"
reply: "رد"
renote: "أعد النشر"
_deck:
alwaysShowMainColumn: "أظهر العمود الأساسي دائمًا"
columnAlign: "محاذاة الأعمدة"
addColumn: "إضافة عمود"
swapLeft: "التحريك إلى اليسار"
swapRight: "التحريك إلى اليمين"
swapUp: "التحريك إلى الأعلى"
swapDown: "التحريك إلى الأسفل"
profile: "حسابي الشخصي"
newProfile: "ملف تعريفي جديد"
deleteProfile: "حذف الملف التعريفي"
alwaysShowMainColumn: "أظهر العمود الرئيسي دائمًا"
columnAlign: "حاذِ الأعمدة"
addColumn: "أضف عمودًا"
swapLeft: "حرّك لليسار"
swapRight: "حرّك لليمين"
swapUp: "حرّك لأعلى"
swapDown: "حرّك لأسفل"
profile: "الملف الشخصي"
_columns:
main: "الرئيسية"
widgets: "التطبيقات المُصغّرة"
main: "الرئيسي"
widgets: "الودجات"
notifications: "الإشعارات"
tl: "الخط الزمني"
tl: "الخيط الزمني"
antenna: "الهوائيات"
list: "القوائم"
channel: "القنوات"
mentions: "الإشارات"
direct: "مباشرة"
_webhookSettings:
name: "الاسم"
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: "يتعذر الاتصال بالخادم"
name: "الإسم"
active: "مفعّل"

View file

@ -2,7 +2,6 @@
_lang_: "বাংলা"
headlineMisskey: "নোট ব্যাবহার করে সংযুক্ত নেটওয়ার্ক"
introMisskey: "স্বাগতম! মিসকি একটি ওপেন সোর্স, ডিসেন্ট্রালাইজড মাইক্রোব্লগিং পরিষেবা। \n\"নোট\" তৈরির মাধ্যমে যা ঘটছে তা সবার সাথে শেয়ার করুন 📡\n\"রিঅ্যাকশন\" গুলির মাধ্যমে যেকোনো নোট সম্পর্কে আপনার অনুভূতি ব্যাক্ত করতে পারেন 👍\nএকটি নতুন দুনিয়া ঘুরে দেখুন 🚀\n"
poweredByMisskeyDescription: "{name} হল ওপেন সোর্স প্ল্যাটফর্ম <b>Misskey</b>-এর সার্ভারগুলির একটি৷"
monthAndDay: "{day}/{month}"
search: "খুঁজুন"
notifications: "বিজ্ঞপ্তি"
@ -13,14 +12,12 @@ fetchingAsApObject: "ফেডিভার্স থেকে খবর আন
ok: "ঠিক"
gotIt: "বুঝেছি"
cancel: "বাতিল"
noThankYou: "না, ধন্যবাদ"
enterUsername: "ইউজারনেম লিখুন"
renotedBy: "{user} রিনোট করেছেন"
noNotes: "কোন নোট নেই"
noNotifications: "কোনো বিজ্ঞপ্তি নেই"
instance: "ইন্সট্যান্স"
settings: "সেটিংস"
notificationSettings: "বিজ্ঞপ্তির সেটিংস"
basicSettings: "সাধারণ সেটিংস"
otherSettings: "অন্যান্য সেটিংস"
openInWindow: "নতুন উইন্ডোতে খুলা"
@ -45,20 +42,12 @@ pin: "পিন করা"
unpin: "পিন সরান"
copyContent: "বিষয়বস্তু কপি করুন"
copyLink: "লিঙ্ক কপি করুন"
copyLinkRenote: "রিনোট লিঙ্ক কপি করুন"
delete: "মুছুন"
deleteAndEdit: "মুছুন এবং সম্পাদনা করুন"
deleteAndEditConfirm: "আপনি কি এই নোটটি মুছে এটি সম্পাদনা করার বিষয়ে নিশ্চিত? আপনি এটির সমস্ত রিঅ্যাকশন, রিনোট এবং জবাব হারাবেন।"
addToList: "লিস্ট এ যোগ করুন"
addToAntenna: "অ্যান্টেনা এ যোগ করুন"
sendMessage: "একটি বার্তা পাঠান"
copyRSS: "RSS কপি করুন"
copyUsername: "ব্যবহারকারীর নাম কপি করুন"
copyUserId: "ব্যবহারকারীর ID কপি করুন"
copyNoteId: "নোটের ID কপি করুন"
copyFileId: "ফাইল ID কপি করুন"
copyFolderId: "ফোল্ডার ID কপি করুন"
copyProfileUrl: "প্রোফাইল URL কপি করুন"
searchUser: "ব্যবহারকারী খুঁজুন..."
reply: "জবাব"
loadMore: "আরও দেখুন"
@ -111,8 +100,6 @@ renoted: "রিনোট করা হয়েছে"
cantRenote: "এই নোটটি রিনোট করা যাবে না।"
cantReRenote: "রিনোটকে রিনোট করা যাবে না।"
quote: "উদ্ধৃতি"
inChannelRenote: "চ্যানেলে রিনোট"
inChannelQuote: "চ্যানেলে উদ্ধৃতি"
pinnedNote: "পিন করা নোট"
pinned: "পিন করা"
you: "আপনি"
@ -121,10 +108,7 @@ sensitive: "সংবেদনশীল বিষয়বস্তু"
add: "যুক্ত করুন"
reaction: "প্রতিক্রিয়া"
reactions: "প্রতিক্রিয়া"
emojiPicker: "ইমোজি পিকার"
pinnedEmojisForReactionSettingDescription: "রিঅ্যাকশন দেয়ার সময় আপনি ইমোজিটিকে পিন করা এবং প্রদর্শিত হওয়ার জন্য সেট করতে পারেন।"
pinnedEmojisSettingDescription: "ইমোজি ইনপুট দেয়ার সময় আপনি ইমোজিটিকে পিন করা এবং প্রদর্শিত হওয়ার জন্য সেট করতে পারেন।"
emojiPickerDisplay: "পিকার ডিসপ্লে"
reactionSetting: "রিঅ্যাকশন পিকারে যেসকল প্রতিক্রিয়া দেখানো হবে"
reactionSettingDescription2: "পুনরায় সাজাতে টেনে আনুন, মুছতে ক্লিক করুন, যোগ করতে + টিপুন।"
rememberNoteVisibility: "নোটের দৃশ্যমান্যতার সেটিংস মনে রাখুন"
attachCancel: "অ্যাটাচমেন্ট সরান "
@ -268,12 +252,12 @@ noMoreHistory: "আর কোন ইতিহাস নেই"
startMessaging: "চ্যাট শুরু করুন"
nUsersRead: "{n} জন পড়েছেন"
agreeTo: "{0} এর প্রতি আমি সম্মত"
tos: "পরিষেবার শর্তাদি"
start: "শুরু করুন"
home: "মূল পাতা"
remoteUserCaution: "এই ব্যাবহারকারী রিমোট ইন্সট্যান্সের, নিম্নক্ত তথ্য অসম্পূর্ণ হতে পারে।"
activity: "কার্যকলাপ"
images: "ছবি"
image: "ছবি"
birthday: "জন্মদিন"
yearsOld: "{age} বছর"
registeredDate: "যোগদানের তারিখ"
@ -310,6 +294,7 @@ copyUrl: "URL কপি করুন"
rename: "পুনঃনামকরণ"
avatar: "প্রোফাইল ছবি"
banner: "ব্যানার"
nsfw: "সংবেদনশীল বিষয়বস্তু"
whenServerDisconnected: "সার্ভারের সাথে সংযোগ বিচ্ছিন্ন হয়ে গেলে"
disconnectedFromServer: "সার্ভার থেকে সংযোগ বিচ্ছিন্ন হয়েছে"
reload: "আবার লোড করুন"
@ -344,6 +329,7 @@ invite: "আমন্ত্রণ"
driveCapacityPerLocalAccount: "প্রত্যেক স্থানীয় ব্যাবহারকারীর জন্য ড্রাইভের জায়গা"
driveCapacityPerRemoteAccount: "প্রত্যেক রিমোট ব্যাবহারকারীর জন্য ড্রাইভের জায়গা"
inMb: "মেগাবাইটে লিখুন"
iconUrl: "আইকনের URL (ফ্যাভিকন, ইত্যাদি)"
bannerUrl: "ব্যানার ছবির URL"
backgroundImageUrl: "পটভূমির চিত্রের URL"
basicInfo: "আপনার ব্যক্তিগত তথ্য"
@ -357,8 +343,6 @@ hcaptcha: "hCaptcha"
enableHcaptcha: "hCaptcha চালু করুন"
hcaptchaSiteKey: "সাইট কী"
hcaptchaSecretKey: "সিক্রেট কী"
mcaptchaSiteKey: "সাইট কী"
mcaptchaSecretKey: "সিক্রেট কী"
recaptcha: "reCAPTCHA"
enableRecaptcha: "reCAPTCHA চালু করুন"
recaptchaSiteKey: "সাইট কী"
@ -411,6 +395,7 @@ share: "শেয়ার"
notFound: "পাওয়া যায়নি"
notFoundDescription: "এই URL-এর সাথে সম্পর্কিত কোনো পৃষ্ঠা নেই।"
uploadFolder: "আপলোডের জন্য ডিফল্ট ফোল্ডার"
cacheClear: "ক্যাশ পরিষ্কার করুন"
markAsReadAllNotifications: "সমস্ত বিজ্ঞপ্তিগুলি পঠিত হিসাবে চিহ্নিত করুন"
markAsReadAllUnreadNotes: "সমস্ত নোটগুলি পঠিত হিসাবে চিহ্নিত করুন"
markAsReadAllTalkMessages: "সমস্ত মেসেজ পঠিত হিসাবে চিহ্নিত করুন"
@ -451,6 +436,7 @@ or: "অথবা"
language: "ভাষা"
uiLanguage: "UI এর ভাষা"
aboutX: "{x} সম্পর্কে"
disableDrawer: "ড্রয়ার মেনু প্রদর্শন করবেন না"
noHistory: "কোনো ইতিহাস নেই"
signinHistory: "প্রবেশ করার ইতিহাস"
doing: "প্রক্রিয়া করছে..."
@ -624,7 +610,10 @@ abuseReported: "আপনার অভিযোগটি দাখিল কর
reporter: "অভিযোগকারী"
reporteeOrigin: "অভিযোগটির উৎস"
reporterOrigin: "অভিযোগকারীর উৎস"
forwardReport: "রিমোট ইন্সত্যান্সে অভিযোগটি পাঠান"
forwardReportIsAnonymous: "আপনার তথ্য রিমোট ইন্সত্যান্সে পাঠানো হবে না এবং একটি বেনামী সিস্টেম অ্যাকাউন্ট হিসাবে প্রদর্শিত হবে।"
send: "পাঠান"
abuseMarkAsResolved: "অভিযোগটিকে সমাধাকৃত হিসাবে চিহ্নিত করুন"
openInNewTab: "নতুন ট্যাবে খুলুন"
openInSideView: "সাইড ভিউতে খুলুন"
defaultNavigationBehaviour: "ডিফল্ট নেভিগেশন"
@ -640,7 +629,6 @@ createNew: "নতুন"
optional: "প্রয়োজনীয় নয়"
createNewClip: "নতুন ক্লিপ তৈরি করুন"
public: "সর্বজনীন"
private: "ব্যাক্তিগত"
i18nInfo: "Misskey স্বেচ্ছাসেবকদের দ্বারা বিভিন্ন ভাষায় অনুবাদ করা হচ্ছে। আপনি {link} এ গিয়ে অনুবাদে সহযোগিতা করতে পারেন।"
manageAccessTokens: "অ্যাক্সেস টোকেন পরিচালনা করুন"
accountInfo: "অ্যাকাউন্টের তথ্য"
@ -808,6 +796,8 @@ makeReactionsPublicDescription: "আপনার পূর্ববর্তী
classic: "ক্লাসিক"
muteThread: "থ্রেড মিউট করুন"
unmuteThread: "থ্রেড আনমিউট করুন"
ffVisibility: "অনুসরণ/অনুসরণকারীদের দৃশ্যমান্যতা"
ffVisibilityDescription: "আপনি কাকে অনুসরণ করেন এবং কে আপনাকে অনুসরণ করে, সেটা কারা দেখতে পাবে তা নির্ধারণ করে।"
continueThread: "আরো থ্রেড দেখুন"
deleteAccountConfirm: "আপনার অ্যাকাউন্ট মুছে ফেলা হবে। ঠিক আছে?"
incorrectPassword: "আপনার দেওয়া পাসওয়ার্ডটি ভুল।"
@ -846,17 +836,6 @@ account: "অ্যাকাউন্টগুলি"
like: "পছন্দ করা"
show: "প্রদর্শন"
color: "রং"
horizontal: "পাশে"
youFollowing: "অনুসরণ করা হচ্ছে"
icon: "প্রোফাইল ছবি"
replies: "জবাব"
renotes: "রিনোট"
sourceCode: "সোর্স কোড"
flip: "উল্টান"
_delivery:
stop: "স্থগিত করা হয়েছে"
_type:
none: "প্রকাশ করা হচ্ছে"
_role:
priority: "অগ্রাধিকার"
_priority:
@ -906,7 +885,6 @@ _plugin:
install: "প্লাগইন ইন্সটল করুন"
installWarn: "অবিশ্বস্ত প্লাগইন ইনস্টল করবেন না।"
manage: "প্লাগইন ম্যানেজ করুন"
viewSource: "উৎস দেখুন"
_registry:
scope: "স্কোপ"
key: "কী"
@ -922,6 +900,10 @@ _aboutMisskey:
donate: "Misskey তে দান করুন"
morePatrons: "আরও অনেকে আমাদের সাহায্য করছেন। তাদের সবাইকে ধন্যবাদ 🥰"
patrons: "সমর্থনকারী"
_nsfw:
respect: "স্পর্শকাতর মিডিয়া লুকান"
ignore: "স্পর্শকাতর মিডিয়া লুকাবেন না"
force: "সকল মিডিয়া লুকান"
_instanceTicker:
none: "দেখাবেন না"
remote: "রিমোট ব্যাবহারকারীদের জন্য দেখান"
@ -949,6 +931,11 @@ _wordMute:
muteWords: "নিঃশব্দ করা শব্দগুলি"
muteWordsDescription: "স্পেস দিয়ে আলাদা করলে AND শর্ত তৈরি হবে এবং আলাদা লাইনে লিখলে OR শর্ত তৈরি হবে।"
muteWordsDescription2: "রেগুলার এক্সপ্রেশন ব্যবহার করতে স্ল্যাশ দিয়ে কীওয়ার্ডকে ঘিরে রাখুন।"
softDescription: "টাইমলাইন থেকে নির্দিষ্ট শর্তানুযায়ী নোট লুকিয়ে রাখে।"
hardDescription: "নির্দিষ্ট শর্তানুযায়ী নোটগুলিকে টাইমলাইন থেকে বাদ দেয়। আপনি শর্ত পরিবর্তন করলেও যে নোটগুলি যোগ করা হয়নি সেগুলি বাদ দেওয়া হবে।"
soft: "নমনীয়"
hard: "কঠোর"
mutedNotes: "মিউট করা নোটগুলি"
_instanceMute:
instanceMuteDescription: "কনফিগার করা ইন্সট্যান্সের সব নোট এবং রিনোট মিউট করুন, মিউট করা ইন্সট্যান্সের ব্যবহারকারীদের উত্তর সহ।"
instanceMuteDescription2: "প্রতিটিকে আলাদা লাইনে লিখুন"
@ -1012,11 +999,15 @@ _theme:
infoFg: "তথ্যের পাঠ্য"
infoWarnBg: "ওয়ার্নিং এর পটভূমি"
infoWarnFg: "ওয়ার্নিং এর পাঠ্য"
cwBg: "CW বাটনের পটভূমি"
cwFg: "CW বাটনের পাঠ্য"
cwHoverBg: "CW বাটনের পটভূমি (হভার)"
toastBg: "বিজ্ঞপ্তির পটভূমি"
toastFg: "বিজ্ঞপ্তির পাঠ্য"
buttonBg: "বাটনের পটভূমি"
buttonHoverBg: "বাটনের পটভূমি (হভার)"
inputBorder: "ইনপুট ফিল্ডের বর্ডার"
listItemHoverBg: "লিস্ট আইটেমের পটভূমি (হোভার)"
driveFolderBg: "ড্রাইভ ফোল্ডারের পটভূমি"
wallpaperOverlay: "ওয়ালপেপার ওভারলে"
badge: "ব্যাজ"
@ -1028,6 +1019,10 @@ _sfx:
note: "নোটগুলি"
noteMy: "নোট (আপনার)"
notification: "বিজ্ঞপ্তি"
chat: "চ্যাট"
chatBg: "চ্যাট (ব্যাকগ্রাউন্ড)"
antenna: "অ্যান্টেনাগুলি"
channel: "চ্যানেলের বিজ্ঞপ্তি"
_ago:
future: "ভবিষ্যৎ"
justNow: "এইমাত্র"
@ -1044,14 +1039,37 @@ _time:
minute: "মিনিট"
hour: "ঘণ্টা"
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:
alreadyRegistered: "আপনি ইতিমধ্যে একটি 2-ফ্যাক্টর অথেনটিকেশন ডিভাইস নিবন্ধন করেছেন৷"
step1: "প্রথমে, আপনার ডিভাইসে {a} বা {b} এর মতো একটি অথেনটিকেশন অ্যাপ ইনস্টল করুন৷"
step2: "এরপরে, অ্যাপের সাহায্যে প্রদর্শিত QR কোডটি স্ক্যান করুন।"
step2Url: "ডেস্কটপ অ্যাপে, নিম্নলিখিত URL লিখুন:"
step3: "অ্যাপে প্রদর্শিত টোকেনটি লিখুন এবং আপনার কাজ শেষ।"
step4: "আপনাকে এখন থেকে লগ ইন করার সময়, এইভাবে টোকেন লিখতে হবে।"
securityKeyInfo: "আপনি একটি হার্ডওয়্যার সিকিউরিটি কী ব্যবহার করে লগ ইন করতে পারেন যা FIDO2 বা ডিভাইসের ফিঙ্গারপ্রিন্ট সেন্সর বা পিন সমর্থন করে৷"
renewTOTPCancel: "না, ধন্যবাদ"
_permissions:
"read:account": "অ্যাকাউন্টের তথ্য দেখুন"
"write:account": "অ্যাকাউন্টের তথ্য সম্পাদন করুন"
@ -1190,7 +1208,6 @@ _profile:
changeBanner: "ব্যানার পরিবর্তন করুন"
_exportOrImport:
allNotes: "সকল নোট"
clips: "ক্লিপ"
followingList: "অনুসরণ করা হচ্ছে"
muteList: "মিউট"
blockingList: "ব্লক"
@ -1309,7 +1326,6 @@ _notification:
pollEnded: "পোল শেষ"
receiveFollowRequest: "প্রাপ্ত অনুসরণের অনুরোধসমূহ"
followRequestAccepted: "গৃহীত অনুসরণের অনুরোধসমূহ"
login: "প্রবেশ করুন"
app: "লিঙ্ক করা অ্যাপ থেকে বিজ্ঞপ্তি"
_actions:
followBack: "ফলো ব্যাক করেছে"
@ -1340,12 +1356,4 @@ _deck:
_webhookSettings:
name: "নাম"
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"
headlineMisskey: ""
introMisskey: "ようこそMisskeyは、オープンソースの分散型マイクロブログサービスです。\n「ート」を作成して、いま起こっていることを共有したり、あなたについて皆に発信しよう📡\n「リアクション」機能で、皆のートに素早く反応を追加することもできます👍\n新しい世界を探検しよう🚀"

File diff suppressed because it is too large Load diff

View file

@ -104,6 +104,7 @@ clickToShow: "Κάντε κλικ για εμφάνιση"
add: "Προσθέστε"
reaction: "Αντιδράσεις"
reactions: "Αντιδράσεις"
reactionSetting: "Αντιδράσεις για εμφάνιση στην επιλογή αντίδρασης"
reactionSettingDescription2: "Σύρετε για να αλλάξετε τη σειρά, κάντε κλικ για να διαγράψετε, πατήστε \"+\" για να προσθέσετε."
rememberNoteVisibility: "Θυμήσου τις ρυθμίσεις ορατότητας σημειώματος"
attachCancel: "Διαγραφή αρχείου"
@ -171,11 +172,11 @@ explore: "Εξερευνήστε"
messageRead: "Διαβάστηκε"
startMessaging: "Ξεκινήστε μία συνομιλία"
nUsersRead: "διαβάστηκε από {n}"
tos: "Όροι χρήσης"
start: "Ας αρχίσουμε"
home: "Κεντρικό"
activity: "Δραστηριότητα"
images: "Εικόνες"
image: "Εικόνες"
birthday: "Γενέθλια"
registeredDate: "Έγινε μέλος στις"
location: "Τοποθεσία"
@ -227,6 +228,7 @@ userList: "Λίστες"
about: "Πληροφορίες"
moderator: "Συντονιστής"
moderation: "Συντονισμός"
cacheClear: "Εκκαθάριση προσωρινής μνήμης"
markAsReadAllNotifications: "Όλες οι ειδοποιήσεις διαβάστηκαν"
members: "Μέλη"
transfer: "Μεταφορά"
@ -285,9 +287,6 @@ searchByGoogle: "Αναζήτηση"
file: "Αρχεία"
recommended: "Προτεινόμενα"
cannotUploadBecauseNoFreeSpace: "Το ανέβασμα απέτυχε λόγω ανεπαρκούς Αποθηκευτικού Χώρου"
icon: "Εικονίδιο"
replies: "Απάντηση"
renotes: "Κοινοποίηση σημειώματος"
_email:
_follow:
title: "Έχετε ένα νέο ακόλουθο"
@ -301,6 +300,10 @@ _theme:
_sfx:
note: "Σημειώματα"
notification: "Ειδοποιήσεις"
chat: "Συνομιλία"
chatBg: "Συνομιλία (Παρασκήνιο)"
antenna: "Αντένες"
channel: "Ειδοποιήσεις καναλιών"
_ago:
future: "Μελλοντικό"
justNow: "Μόλις τώρα"
@ -354,7 +357,6 @@ _profile:
username: "Όνομα μέλους"
_exportOrImport:
allNotes: "Όλα τα σημειώματα"
clips: "Κλιπ"
followingList: "Ακολουθεί"
muteList: "Μέλη σε σίγαση"
blockingList: "Μπλοκαρισμένα μέλη"
@ -378,7 +380,6 @@ _notification:
renote: "Κοινοποίηση σημειώματος"
quote: "Παράθεση"
reaction: "Αντιδράσεις"
login: "Σύνδεση"
_actions:
reply: "Απάντηση"
renote: "Κοινοποίηση σημειώματος"
@ -393,7 +394,4 @@ _deck:
mentions: "Επισημάνσεις"
_webhookSettings:
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,237 +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';
import { merge } from './index.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// braces preceded by backslashes are literal, they don't represent
// parameters; they get cleaned up by `locales/index.js` before
// getting shipped to the browser
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 sharkeyLocale = yaml.load(fs.readFileSync(`${__dirname}/../sharkey-locales/en-US.yml`, 'utf-8'));
const misskeyLocale = yaml.load(fs.readFileSync(`${__dirname}/ja-JP.yml`, 'utf-8'));
const locale = merge(misskeyLocale, sharkeyLocale);
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_: "Japán"
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

11393
locales/index.d.ts vendored

File diff suppressed because it is too large Load diff

View file

@ -2,10 +2,10 @@
* Languages Loader
*/
import * as fs from 'node:fs';
import * as yaml from 'js-yaml';
const fs = require('fs');
const yaml = require('js-yaml');
export const merge = (...args) => args.reduce((a, c) => ({
const merge = (...args) => args.reduce((a, c) => ({
...a,
...c,
...Object.entries(a)
@ -49,50 +49,22 @@ const primaries = {
};
// 何故か文字列にバックスペース文字が混入することがあり、YAMLが壊れるので取り除く
//
// also, we remove the backslashes in front of open braces (the
// backslashes are only needed to tell `generateDTS.js` that the
// braces do not represent parameters)
const clean = (text) => text.replace(new RegExp(String.fromCodePoint(0x08), 'g'), '').replaceAll(new RegExp(/\\+\{/,'g'), '{');
const clean = (text) => text.replace(new RegExp(String.fromCodePoint(0x08), 'g'), '');
export function build() {
// 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 sharkeyLocales = languages.reduce((a, c) => (a[c] = yaml.load(clean(fs.readFileSync(new URL(`../sharkey-locales/${c}.yml`, metaUrl), 'utf-8'))) || {}, a), {});
const misskeyLocales = languages.reduce((a, c) => (a[c] = yaml.load(clean(fs.readFileSync(new URL(`${c}.yml`, metaUrl), 'utf-8'))) || {}, a), {});
// merge sharkey and misskey's locales. the second argument (sharkey) overwrites the first argument (misskey).
const locales = merge(misskeyLocales, sharkeyLocales);
const locales = languages.reduce((a, c) => (a[c] = yaml.load(clean(fs.readFileSync(`${__dirname}/${c}.yml`, 'utf-8'))) || {}, a), {});
// 空文字列が入ることがあり、フォールバックが動作しなくなるのでプロパティごと消す
const removeEmpty = (obj) => {
for (const [k, v] of Object.entries(obj)) {
if (v === '') {
delete obj[k];
} else if (typeof v === 'object') {
removeEmpty(v);
}
module.exports = 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
);
}
return obj;
};
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();
})(), a), {});

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,3 +1,2 @@
---
_lang_: "la .lojban."
headlineMisskey: "lo se tcana noi jorne fi loi notci"

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