mirror of
https://github.com/misskey-dev/misskey.git
synced 2026-05-05 13:35:52 +02:00
Compare commits
106 Commits
copilot/bu
...
renovate/f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
98d8c42b17 | ||
|
|
4bc0026900 | ||
|
|
faf2399e31 | ||
|
|
106fffdcfe | ||
|
|
141964e57c | ||
|
|
41592eafb3 | ||
|
|
2a14025c29 | ||
|
|
75b5dc1cd8 | ||
|
|
ee0eeb052f | ||
|
|
ece4efcefe | ||
|
|
cd973b252a | ||
|
|
666f78e676 | ||
|
|
cf89c4e363 | ||
|
|
bf41e9edd1 | ||
|
|
f92c187e2b | ||
|
|
8c5572dd3b | ||
|
|
e18b92823f | ||
|
|
2d709ceeb4 | ||
|
|
38b3eecc8c | ||
|
|
f6fc78f578 | ||
|
|
6e99acf7a7 | ||
|
|
553a147396 | ||
|
|
7bcfeba7e5 | ||
|
|
4f65c1529b | ||
|
|
589ae8d4c6 | ||
|
|
0be4405a79 | ||
|
|
2fba2e7049 | ||
|
|
96b03a7179 | ||
|
|
cdb958cdf0 | ||
|
|
245775ea87 | ||
|
|
40d55fc6a3 | ||
|
|
9c22538454 | ||
|
|
a1ba403f9a | ||
|
|
443e1ed29e | ||
|
|
b5454cb2c4 | ||
|
|
8577f10456 | ||
|
|
16ffd88ecc | ||
|
|
866e675134 | ||
|
|
01aa56c602 | ||
|
|
ff7d2c1083 | ||
|
|
404fca6c2d | ||
|
|
3fe0477cac | ||
|
|
97d485bdd2 | ||
|
|
4285303c81 | ||
|
|
14f58255ee | ||
|
|
b69b0acf59 | ||
|
|
7a5430199f | ||
|
|
c32307dca4 | ||
|
|
bc78bb9b8e | ||
|
|
a33b003282 | ||
|
|
74e847a04d | ||
|
|
06657c81d3 | ||
|
|
5c5e965151 | ||
|
|
b07a1e692f | ||
|
|
78348007ed | ||
|
|
92f1e599db | ||
|
|
26b5979c76 | ||
|
|
b1048525d2 | ||
|
|
4c31eb409c | ||
|
|
f739cb6270 | ||
|
|
81bacb6203 | ||
|
|
ee8dccea2f | ||
|
|
6d00645bc7 | ||
|
|
baeed4bc80 | ||
|
|
dba44daf9c | ||
|
|
46e6dd99d1 | ||
|
|
f48af7f73b | ||
|
|
834e8b4c24 | ||
|
|
7ef0c96758 | ||
|
|
b10074e939 | ||
|
|
260dbd150b | ||
|
|
79cbbcfe0f | ||
|
|
c893f85864 | ||
|
|
24d4ffa2ec | ||
|
|
0b931daefd | ||
|
|
cc05d93194 | ||
|
|
90345591bb | ||
|
|
730227f353 | ||
|
|
4acb37ee9d | ||
|
|
7025769c69 | ||
|
|
1a4ef8769f | ||
|
|
055cd0c250 | ||
|
|
d35ddc77d2 | ||
|
|
8d871a58e3 | ||
|
|
99b0b436e0 | ||
|
|
e3d5b95672 | ||
|
|
0d52145b2b | ||
|
|
467404d5bb | ||
|
|
99e25784ad | ||
|
|
9e1e40d35a | ||
|
|
8eb6e29d2c | ||
|
|
2d198a711b | ||
|
|
e0b872dc09 | ||
|
|
711b86ab7d | ||
|
|
e8b4dae553 | ||
|
|
36d404818d | ||
|
|
cb03f3f013 | ||
|
|
c109bec013 | ||
|
|
6fa4eb8c4f | ||
|
|
5fb4caa14b | ||
|
|
bc1f83664f | ||
|
|
78435dc8d4 | ||
|
|
d74aded35f | ||
|
|
d605680524 | ||
|
|
1096ce8e4a | ||
|
|
8e6fffee68 |
@@ -107,13 +107,51 @@ port: 3000
|
|||||||
|
|
||||||
# Proxy trust settings
|
# Proxy trust settings
|
||||||
#
|
#
|
||||||
# Changes how the server interpret the origin IP of the request.
|
# Specifies the IP addresses that Misskey will use as trusted
|
||||||
|
# reverse proxies (e.g., nginx, Cloudflare). This affects how
|
||||||
|
# Misskey determines the source IP for each request and is used
|
||||||
|
# for important rate limiting and security features. If the value
|
||||||
|
# is not set correctly, Misskey may use the IP address of the
|
||||||
|
# reverse proxy instead of the actual source IP, which may lead to
|
||||||
|
# unintended rate limiting or security vulnerabilities.
|
||||||
|
# By default, the loopback network and private network address
|
||||||
|
# ranges shown below are trusted.
|
||||||
|
# If you are using a single reverse proxy and it is on the same
|
||||||
|
# machine or the same private network as Misskey, it is unlikely you
|
||||||
|
# need to change this setting, and the default setting is fine.
|
||||||
|
# Also, if you are using multiple reverse proxy servers and they are
|
||||||
|
# all on the same private network as Misskey, the default setting
|
||||||
|
# is fine.
|
||||||
|
# However, if you are using a reverse proxy server that accesses
|
||||||
|
# Misskey web servers and streaming servers via public IP addresses
|
||||||
|
# (for example, Cloudflare), you must set this variable.
|
||||||
|
# When changing this setting, you can use one of the following values:
|
||||||
#
|
#
|
||||||
# Any format supported by Fastify is accepted.
|
# - true: Trust all proxies
|
||||||
# Default: do not trust any proxies (i.e. trustProxy: false)
|
# - false: Do not trust any proxies
|
||||||
# See: https://fastify.dev/docs/latest/reference/server/#trustproxy
|
# - IP address, IP address range, or array of them: Trust hops that
|
||||||
|
# match the specified criteria.
|
||||||
|
# - Integer: Trust the nth hop from the front-facing proxy server as
|
||||||
|
# the client.
|
||||||
|
# For more information on how to configure this setting, please refer
|
||||||
|
# to the Fastify documentation:
|
||||||
|
# https://fastify.dev/docs/latest/Reference/Server/#trustproxy
|
||||||
#
|
#
|
||||||
# trustProxy: false
|
# Note that if this variable is set, it overrides the default range,
|
||||||
|
# so if you have both an external reverse proxy and a proxy on the
|
||||||
|
# local host, you must include both IPs (or IP ranges).
|
||||||
|
#
|
||||||
|
#trustProxy:
|
||||||
|
# - '10.0.0.0/8'
|
||||||
|
# - '172.16.0.0/12'
|
||||||
|
# - '192.168.0.0/16'
|
||||||
|
# - '127.0.0.1/32'
|
||||||
|
# - '::1/128'
|
||||||
|
# - 'fc00::/7'
|
||||||
|
# # Example: If you are using some external reverse proxies like CDNs,
|
||||||
|
# # you may need to add the CDN IP ranges here.
|
||||||
|
# # If you're using Cloudflare, you can find IP Ranges at:
|
||||||
|
# # https://www.cloudflare.com/ips/
|
||||||
|
|
||||||
# ┌──────────────────────────┐
|
# ┌──────────────────────────┐
|
||||||
#───┘ PostgreSQL configuration └────────────────────────────────
|
#───┘ PostgreSQL configuration └────────────────────────────────
|
||||||
@@ -283,6 +321,10 @@ id: 'aidx'
|
|||||||
# Whether disable HSTS
|
# Whether disable HSTS
|
||||||
#disableHsts: true
|
#disableHsts: true
|
||||||
|
|
||||||
|
# Enable internal IP-based rate limiting (default: true)
|
||||||
|
# To configure them in reverse proxy instead, set this to false.
|
||||||
|
#enableIpRateLimit: true
|
||||||
|
|
||||||
# Number of worker processes
|
# Number of worker processes
|
||||||
#clusterLimit: 1
|
#clusterLimit: 1
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
Dockerfile
|
Dockerfile
|
||||||
build/
|
build/
|
||||||
built/
|
built/
|
||||||
|
src-js/
|
||||||
db/
|
db/
|
||||||
.devcontainer/compose.yml
|
.devcontainer/compose.yml
|
||||||
node_modules/
|
node_modules/
|
||||||
|
|||||||
4
.github/ISSUE_TEMPLATE/01_bug-report.yml
vendored
4
.github/ISSUE_TEMPLATE/01_bug-report.yml
vendored
@@ -54,7 +54,7 @@ body:
|
|||||||
* Model and OS of the device(s): MacBook Pro (14inch, 2021), macOS Ventura 13.4
|
* Model and OS of the device(s): MacBook Pro (14inch, 2021), macOS Ventura 13.4
|
||||||
* Browser: Chrome 113.0.5672.126
|
* Browser: Chrome 113.0.5672.126
|
||||||
* Server URL: misskey.example.com
|
* Server URL: misskey.example.com
|
||||||
* Misskey: 2025.x.x
|
* Misskey: 2026.x.x
|
||||||
value: |
|
value: |
|
||||||
* Model and OS of the device(s):
|
* Model and OS of the device(s):
|
||||||
* Browser:
|
* Browser:
|
||||||
@@ -74,7 +74,7 @@ body:
|
|||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
* Installation Method or Hosting Service: docker compose, k8s/docker, systemd, "Misskey install shell script", development environment
|
* Installation Method or Hosting Service: docker compose, k8s/docker, systemd, "Misskey install shell script", development environment
|
||||||
* Misskey: 2025.x.x
|
* Misskey: 2026.x.x
|
||||||
* Node: 20.x.x
|
* Node: 20.x.x
|
||||||
* PostgreSQL: 18.x.x
|
* PostgreSQL: 18.x.x
|
||||||
* Redis: 7.x.x
|
* Redis: 7.x.x
|
||||||
|
|||||||
4
.github/workflows/api-misskey-js.yml
vendored
4
.github/workflows/api-misskey-js.yml
vendored
@@ -16,13 +16,13 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4.3.0
|
uses: actions/checkout@v6.0.1
|
||||||
|
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.2.0
|
uses: pnpm/action-setup@v4.2.0
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4.4.0
|
uses: actions/setup-node@v6.1.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|||||||
4
.github/workflows/changelog-check.yml
vendored
4
.github/workflows/changelog-check.yml
vendored
@@ -12,9 +12,9 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout head
|
- name: Checkout head
|
||||||
uses: actions/checkout@v4.3.0
|
uses: actions/checkout@v6.0.1
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4.4.0
|
uses: actions/setup-node@v6.1.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
|
|
||||||
|
|||||||
22
.github/workflows/check-misskey-js-autogen.yml
vendored
22
.github/workflows/check-misskey-js-autogen.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
|||||||
if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }}
|
if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }}
|
||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v4.3.0
|
uses: actions/checkout@v6.0.1
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
@@ -29,7 +29,7 @@ jobs:
|
|||||||
|
|
||||||
- name: setup node
|
- name: setup node
|
||||||
id: setup-node
|
id: setup-node
|
||||||
uses: actions/setup-node@v4.4.0
|
uses: actions/setup-node@v6.1.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
@@ -53,7 +53,7 @@ jobs:
|
|||||||
|
|
||||||
# packages/misskey-js/generator/built/autogen
|
# packages/misskey-js/generator/built/autogen
|
||||||
- name: Upload Generated
|
- name: Upload Generated
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: generated-misskey-js
|
name: generated-misskey-js
|
||||||
path: packages/misskey-js/generator/built/autogen
|
path: packages/misskey-js/generator/built/autogen
|
||||||
@@ -66,14 +66,14 @@ jobs:
|
|||||||
if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }}
|
if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }}
|
||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v4.3.0
|
uses: actions/checkout@v6.0.1
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
ref: refs/pull/${{ github.event.pull_request.number }}/merge
|
ref: refs/pull/${{ github.event.pull_request.number }}/merge
|
||||||
|
|
||||||
- name: Upload From Merged
|
- name: Upload From Merged
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: actual-misskey-js
|
name: actual-misskey-js
|
||||||
path: packages/misskey-js/src/autogen
|
path: packages/misskey-js/src/autogen
|
||||||
@@ -86,13 +86,13 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- name: download generated-misskey-js
|
- name: download generated-misskey-js
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: generated-misskey-js
|
name: generated-misskey-js
|
||||||
path: misskey-js-generated
|
path: misskey-js-generated
|
||||||
|
|
||||||
- name: download actual-misskey-js
|
- name: download actual-misskey-js
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: actual-misskey-js
|
name: actual-misskey-js
|
||||||
path: misskey-js-actual
|
path: misskey-js-actual
|
||||||
@@ -113,9 +113,9 @@ jobs:
|
|||||||
|
|
||||||
- name: send message
|
- name: send message
|
||||||
if: steps.check-changes.outputs.changes == 'true'
|
if: steps.check-changes.outputs.changes == 'true'
|
||||||
uses: thollander/actions-comment-pull-request@v2
|
uses: thollander/actions-comment-pull-request@v3
|
||||||
with:
|
with:
|
||||||
comment_tag: check-misskey-js-autogen
|
comment-tag: check-misskey-js-autogen
|
||||||
message: |-
|
message: |-
|
||||||
Thank you for sending us a great Pull Request! 👍
|
Thank you for sending us a great Pull Request! 👍
|
||||||
Please regenerate misskey-js type definitions! 🙏
|
Please regenerate misskey-js type definitions! 🙏
|
||||||
@@ -127,9 +127,9 @@ jobs:
|
|||||||
|
|
||||||
- name: send message
|
- name: send message
|
||||||
if: steps.check-changes.outputs.changes == 'false'
|
if: steps.check-changes.outputs.changes == 'false'
|
||||||
uses: thollander/actions-comment-pull-request@v2
|
uses: thollander/actions-comment-pull-request@v3
|
||||||
with:
|
with:
|
||||||
comment_tag: check-misskey-js-autogen
|
comment-tag: check-misskey-js-autogen
|
||||||
mode: delete
|
mode: delete
|
||||||
message: "Thank you!"
|
message: "Thank you!"
|
||||||
create_if_not_exists: false
|
create_if_not_exists: false
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4.3.0
|
uses: actions/checkout@v6.0.1
|
||||||
- name: Check version
|
- name: Check version
|
||||||
run: |
|
run: |
|
||||||
if [ "$(jq -r '.version' package.json)" != "$(jq -r '.version' packages/misskey-js/package.json)" ]; then
|
if [ "$(jq -r '.version' package.json)" != "$(jq -r '.version' packages/misskey-js/package.json)" ]; then
|
||||||
|
|||||||
2
.github/workflows/check-spdx-license-id.yml
vendored
2
.github/workflows/check-spdx-license-id.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4.3.0
|
uses: actions/checkout@v6.0.1
|
||||||
- name: Check
|
- name: Check
|
||||||
run: |
|
run: |
|
||||||
counter=0
|
counter=0
|
||||||
|
|||||||
2
.github/workflows/check_copyright_year.yml
vendored
2
.github/workflows/check_copyright_year.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
|||||||
check_copyright_year:
|
check_copyright_year:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.3.0
|
- uses: actions/checkout@v6.0.1
|
||||||
- run: |
|
- run: |
|
||||||
if [ "$(grep Copyright COPYING | sed -e 's/.*2014-\([0-9]*\) .*/\1/g')" -ne "$(date +%Y)" ]; then
|
if [ "$(grep Copyright COPYING | sed -e 's/.*2014-\([0-9]*\) .*/\1/g')" -ne "$(date +%Y)" ]; then
|
||||||
echo "Please change copyright year!"
|
echo "Please change copyright year!"
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ jobs:
|
|||||||
wait_time: ${{ steps.get-wait-time.outputs.wait_time }}
|
wait_time: ${{ steps.get-wait-time.outputs.wait_time }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4.3.0
|
uses: actions/checkout@v6.0.1
|
||||||
|
|
||||||
- name: Check allowed users
|
- name: Check allowed users
|
||||||
id: check-allowed-users
|
id: check-allowed-users
|
||||||
|
|||||||
6
.github/workflows/docker-develop.yml
vendored
6
.github/workflows/docker-develop.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
|||||||
platform=${{ matrix.platform }}
|
platform=${{ matrix.platform }}
|
||||||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||||
- name: Check out the repo
|
- name: Check out the repo
|
||||||
uses: actions/checkout@v4.3.0
|
uses: actions/checkout@v6.0.1
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
- name: Log in to Docker Hub
|
- name: Log in to Docker Hub
|
||||||
@@ -53,7 +53,7 @@ jobs:
|
|||||||
digest="${{ steps.build.outputs.digest }}"
|
digest="${{ steps.build.outputs.digest }}"
|
||||||
touch "/tmp/digests/${digest#sha256:}"
|
touch "/tmp/digests/${digest#sha256:}"
|
||||||
- name: Upload digest
|
- name: Upload digest
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: digests-${{ env.PLATFORM_PAIR }}
|
name: digests-${{ env.PLATFORM_PAIR }}
|
||||||
path: /tmp/digests/*
|
path: /tmp/digests/*
|
||||||
@@ -66,7 +66,7 @@ jobs:
|
|||||||
- build
|
- build
|
||||||
steps:
|
steps:
|
||||||
- name: Download digests
|
- name: Download digests
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v7
|
||||||
with:
|
with:
|
||||||
path: /tmp/digests
|
path: /tmp/digests
|
||||||
pattern: digests-*
|
pattern: digests-*
|
||||||
|
|||||||
6
.github/workflows/docker.yml
vendored
6
.github/workflows/docker.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
|||||||
platform=${{ matrix.platform }}
|
platform=${{ matrix.platform }}
|
||||||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||||
- name: Check out the repo
|
- name: Check out the repo
|
||||||
uses: actions/checkout@v4.3.0
|
uses: actions/checkout@v6.0.1
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
@@ -64,7 +64,7 @@ jobs:
|
|||||||
digest="${{ steps.build.outputs.digest }}"
|
digest="${{ steps.build.outputs.digest }}"
|
||||||
touch "/tmp/digests/${digest#sha256:}"
|
touch "/tmp/digests/${digest#sha256:}"
|
||||||
- name: Upload digest
|
- name: Upload digest
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: digests-${{ env.PLATFORM_PAIR }}
|
name: digests-${{ env.PLATFORM_PAIR }}
|
||||||
path: /tmp/digests/*
|
path: /tmp/digests/*
|
||||||
@@ -77,7 +77,7 @@ jobs:
|
|||||||
- build
|
- build
|
||||||
steps:
|
steps:
|
||||||
- name: Download digests
|
- name: Download digests
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v7
|
||||||
with:
|
with:
|
||||||
path: /tmp/digests
|
path: /tmp/digests
|
||||||
pattern: digests-*
|
pattern: digests-*
|
||||||
|
|||||||
41
.github/workflows/dockle.yml
vendored
41
.github/workflows/dockle.yml
vendored
@@ -11,38 +11,43 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
dockle:
|
dockle:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
env:
|
env:
|
||||||
DOCKER_CONTENT_TRUST: 1
|
DOCKER_CONTENT_TRUST: 1
|
||||||
DOCKLE_VERSION: 0.4.15
|
DOCKLE_VERSION: 0.4.15
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.3.0
|
- uses: actions/checkout@v6.0.1
|
||||||
|
|
||||||
- name: Download and install dockle v${{ env.DOCKLE_VERSION }}
|
- name: Download and install dockle v${{ env.DOCKLE_VERSION }}
|
||||||
run: |
|
run: |
|
||||||
|
set -eux
|
||||||
curl -L -o dockle.deb "https://github.com/goodwithtech/dockle/releases/download/v${DOCKLE_VERSION}/dockle_${DOCKLE_VERSION}_Linux-64bit.deb"
|
curl -L -o dockle.deb "https://github.com/goodwithtech/dockle/releases/download/v${DOCKLE_VERSION}/dockle_${DOCKLE_VERSION}_Linux-64bit.deb"
|
||||||
sudo dpkg -i dockle.deb
|
sudo dpkg -i dockle.deb
|
||||||
|
|
||||||
- run: |
|
- name: Build web image (docker build)
|
||||||
cp .config/docker_example.env .config/docker.env
|
|
||||||
cp ./compose_example.yml ./compose.yml
|
|
||||||
|
|
||||||
- run: |
|
|
||||||
docker compose up -d web
|
|
||||||
IMAGE_ID=$(docker compose images --format json web | jq -r '.[0].ID')
|
|
||||||
docker tag "${IMAGE_ID}" misskey-web:latest
|
|
||||||
|
|
||||||
- name: Prune docker junk (optional but recommended)
|
|
||||||
run: |
|
run: |
|
||||||
docker system prune -af
|
set -eux
|
||||||
docker volume prune -f
|
docker build -t "misskey-web:ci" .
|
||||||
|
docker image ls
|
||||||
|
|
||||||
- name: Save image for Dockle
|
- name: Mount tmpfs for Dockle tar
|
||||||
|
env:
|
||||||
|
TMPFS_SIZE: 8G
|
||||||
run: |
|
run: |
|
||||||
docker save misskey-web:latest -o ./misskey-web.tar
|
set -eux
|
||||||
ls -lh ./misskey-web.tar
|
sudo mkdir -p /mnt/dockle-tmp
|
||||||
|
sudo mount -t tmpfs -o size=${{ env.TMPFS_SIZE }} tmpfs /mnt/dockle-tmp
|
||||||
|
free -h
|
||||||
|
df -h
|
||||||
|
|
||||||
- name: Run Dockle with tar input
|
- name: Save image tar into tmpfs
|
||||||
run: |
|
run: |
|
||||||
dockle --exit-code 1 --input ./misskey-web.tar
|
set -eux
|
||||||
|
docker save misskey-web:ci -o /mnt/dockle-tmp/misskey-web.tar
|
||||||
|
ls -lh /mnt/dockle-tmp/misskey-web.tar
|
||||||
|
|
||||||
|
- name: Run Dockle Scan (tar input)
|
||||||
|
run: |
|
||||||
|
set -eux
|
||||||
|
dockle --exit-code 1 --input /mnt/dockle-tmp/misskey-web.tar
|
||||||
|
|||||||
8
.github/workflows/get-api-diff.yml
vendored
8
.github/workflows/get-api-diff.yml
vendored
@@ -25,14 +25,14 @@ jobs:
|
|||||||
ref: refs/pull/${{ github.event.number }}/merge
|
ref: refs/pull/${{ github.event.number }}/merge
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.3.0
|
- uses: actions/checkout@v6.0.1
|
||||||
with:
|
with:
|
||||||
ref: ${{ matrix.ref }}
|
ref: ${{ matrix.ref }}
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.2.0
|
uses: pnpm/action-setup@v4.2.0
|
||||||
- name: Use Node.js
|
- name: Use Node.js
|
||||||
uses: actions/setup-node@v4.4.0
|
uses: actions/setup-node@v6.1.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
@@ -48,7 +48,7 @@ jobs:
|
|||||||
- name: Copy API.json
|
- name: Copy API.json
|
||||||
run: cp packages/backend/built/api.json ${{ matrix.api-json-name }}
|
run: cp packages/backend/built/api.json ${{ matrix.api-json-name }}
|
||||||
- name: Upload Artifact
|
- name: Upload Artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: api-artifact-${{ matrix.api-json-name }}
|
name: api-artifact-${{ matrix.api-json-name }}
|
||||||
path: ${{ matrix.api-json-name }}
|
path: ${{ matrix.api-json-name }}
|
||||||
@@ -61,7 +61,7 @@ jobs:
|
|||||||
PR_NUMBER: ${{ github.event.number }}
|
PR_NUMBER: ${{ github.event.number }}
|
||||||
run: |
|
run: |
|
||||||
echo "$PR_NUMBER" > ./pr_number
|
echo "$PR_NUMBER" > ./pr_number
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: api-artifact-pr-number
|
name: api-artifact-pr-number
|
||||||
path: pr_number
|
path: pr_number
|
||||||
|
|||||||
8
.github/workflows/get-backend-memory.yml
vendored
8
.github/workflows/get-backend-memory.yml
vendored
@@ -40,14 +40,14 @@ jobs:
|
|||||||
- 56312:6379
|
- 56312:6379
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.3.0
|
- uses: actions/checkout@v6.0.1
|
||||||
with:
|
with:
|
||||||
ref: ${{ matrix.ref }}
|
ref: ${{ matrix.ref }}
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.2.0
|
uses: pnpm/action-setup@v4.2.0
|
||||||
- name: Use Node.js
|
- name: Use Node.js
|
||||||
uses: actions/setup-node@v4.4.0
|
uses: actions/setup-node@v6.1.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
@@ -67,7 +67,7 @@ jobs:
|
|||||||
# Start the server and measure memory usage
|
# Start the server and measure memory usage
|
||||||
node packages/backend/scripts/measure-memory.mjs > ${{ matrix.memory-json-name }}
|
node packages/backend/scripts/measure-memory.mjs > ${{ matrix.memory-json-name }}
|
||||||
- name: Upload Artifact
|
- name: Upload Artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: memory-artifact-${{ matrix.memory-json-name }}
|
name: memory-artifact-${{ matrix.memory-json-name }}
|
||||||
path: ${{ matrix.memory-json-name }}
|
path: ${{ matrix.memory-json-name }}
|
||||||
@@ -81,7 +81,7 @@ jobs:
|
|||||||
PR_NUMBER: ${{ github.event.number }}
|
PR_NUMBER: ${{ github.event.number }}
|
||||||
run: |
|
run: |
|
||||||
echo "$PR_NUMBER" > ./pr_number
|
echo "$PR_NUMBER" > ./pr_number
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: memory-artifact-pr-number
|
name: memory-artifact-pr-number
|
||||||
path: pr_number
|
path: pr_number
|
||||||
|
|||||||
2
.github/workflows/labeler.yml
vendored
2
.github/workflows/labeler.yml
vendored
@@ -11,6 +11,6 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/labeler@v5
|
- uses: actions/labeler@v6
|
||||||
with:
|
with:
|
||||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
|
|||||||
12
.github/workflows/lint.yml
vendored
12
.github/workflows/lint.yml
vendored
@@ -36,13 +36,13 @@ jobs:
|
|||||||
pnpm_install:
|
pnpm_install:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.3.0
|
- uses: actions/checkout@v6.0.1
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.2.0
|
uses: pnpm/action-setup@v4.2.0
|
||||||
- uses: actions/setup-node@v4.4.0
|
- uses: actions/setup-node@v6.1.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
@@ -69,13 +69,13 @@ jobs:
|
|||||||
eslint-cache-version: v1
|
eslint-cache-version: v1
|
||||||
eslint-cache-path: ${{ github.workspace }}/node_modules/.cache/eslint-${{ matrix.workspace }}
|
eslint-cache-path: ${{ github.workspace }}/node_modules/.cache/eslint-${{ matrix.workspace }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.3.0
|
- uses: actions/checkout@v6.0.1
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.2.0
|
uses: pnpm/action-setup@v4.2.0
|
||||||
- uses: actions/setup-node@v4.4.0
|
- uses: actions/setup-node@v6.1.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
@@ -100,13 +100,13 @@ jobs:
|
|||||||
- sw
|
- sw
|
||||||
- misskey-js
|
- misskey-js
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.3.0
|
- uses: actions/checkout@v6.0.1
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.2.0
|
uses: pnpm/action-setup@v4.2.0
|
||||||
- uses: actions/setup-node@v4.4.0
|
- uses: actions/setup-node@v6.1.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|||||||
4
.github/workflows/locale.yml
vendored
4
.github/workflows/locale.yml
vendored
@@ -16,13 +16,13 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.3.0
|
- uses: actions/checkout@v6.0.1
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.2.0
|
uses: pnpm/action-setup@v4.2.0
|
||||||
- uses: actions/setup-node@v4.4.0
|
- uses: actions/setup-node@v6.1.0
|
||||||
with:
|
with:
|
||||||
node-version-file: ".node-version"
|
node-version-file: ".node-version"
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
|
|||||||
4
.github/workflows/on-release-created.yml
vendored
4
.github/workflows/on-release-created.yml
vendored
@@ -16,13 +16,13 @@ jobs:
|
|||||||
id-token: write
|
id-token: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.3.0
|
- uses: actions/checkout@v6.0.1
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.2.0
|
uses: pnpm/action-setup@v4.2.0
|
||||||
- name: Use Node.js
|
- name: Use Node.js
|
||||||
uses: actions/setup-node@v4.4.0
|
uses: actions/setup-node@v6.1.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|||||||
2
.github/workflows/release-edit-with-push.yml
vendored
2
.github/workflows/release-edit-with-push.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
|||||||
edit:
|
edit:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
# headが$GITHUB_REF_NAME, baseが$STABLE_BRANCHかつopenのPRを1つ取得
|
# headが$GITHUB_REF_NAME, baseが$STABLE_BRANCHかつopenのPRを1つ取得
|
||||||
- name: Get PR
|
- name: Get PR
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
2
.github/workflows/release-with-dispatch.yml
vendored
2
.github/workflows/release-with-dispatch.yml
vendored
@@ -36,7 +36,7 @@ jobs:
|
|||||||
outputs:
|
outputs:
|
||||||
pr_number: ${{ steps.get_pr.outputs.pr_number }}
|
pr_number: ${{ steps.get_pr.outputs.pr_number }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
# headが$GITHUB_REF_NAME, baseが$STABLE_BRANCHかつopenのPRを1つ取得
|
# headが$GITHUB_REF_NAME, baseが$STABLE_BRANCHかつopenのPRを1つ取得
|
||||||
- name: Get PRs
|
- name: Get PRs
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
24
.github/workflows/report-api-diff.yml
vendored
24
.github/workflows/report-api-diff.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
|||||||
# api-artifact
|
# api-artifact
|
||||||
steps:
|
steps:
|
||||||
- name: Download artifact
|
- name: Download artifact
|
||||||
uses: actions/github-script@v7.1.0
|
uses: actions/github-script@v8.0.0
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
@@ -60,7 +60,7 @@ jobs:
|
|||||||
- name: Echo full diff
|
- name: Echo full diff
|
||||||
run: cat ./api-full.json.diff
|
run: cat ./api-full.json.diff
|
||||||
- name: Upload full diff to Artifact
|
- name: Upload full diff to Artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: api-artifact
|
name: api-artifact
|
||||||
path: |
|
path: |
|
||||||
@@ -73,9 +73,9 @@ jobs:
|
|||||||
HEADER="このPRによるapi.jsonの差分"
|
HEADER="このPRによるapi.jsonの差分"
|
||||||
FOOTER="[Get diff files from Workflow Page](https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID})"
|
FOOTER="[Get diff files from Workflow Page](https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID})"
|
||||||
DIFF_BYTES="$(stat ./api.json.diff -c '%s' | tr -d '\n')"
|
DIFF_BYTES="$(stat ./api.json.diff -c '%s' | tr -d '\n')"
|
||||||
|
|
||||||
echo "$HEADER" > ./output.md
|
echo "$HEADER" > ./output.md
|
||||||
|
|
||||||
if (( "$DIFF_BYTES" <= 1 )); then
|
if (( "$DIFF_BYTES" <= 1 )); then
|
||||||
echo '差分はありません。' >> ./output.md
|
echo '差分はありません。' >> ./output.md
|
||||||
else
|
else
|
||||||
@@ -87,18 +87,18 @@ jobs:
|
|||||||
echo '```' >> ./output.md
|
echo '```' >> ./output.md
|
||||||
echo '</details>' >> .output.md
|
echo '</details>' >> .output.md
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "$FOOTER" >> ./output.md
|
echo "$FOOTER" >> ./output.md
|
||||||
- uses: thollander/actions-comment-pull-request@v2
|
- uses: thollander/actions-comment-pull-request@v3
|
||||||
with:
|
with:
|
||||||
pr_number: ${{ steps.load-pr-num.outputs.pr-number }}
|
pr-number: ${{ steps.load-pr-num.outputs.pr-number }}
|
||||||
comment_tag: show_diff
|
comment-tag: show_diff
|
||||||
filePath: ./output.md
|
file-path: ./output.md
|
||||||
- name: Tell error to PR
|
- name: Tell error to PR
|
||||||
uses: thollander/actions-comment-pull-request@v2
|
uses: thollander/actions-comment-pull-request@v3
|
||||||
if: failure() && steps.load-pr-num.outputs.pr-number
|
if: failure() && steps.load-pr-num.outputs.pr-number
|
||||||
with:
|
with:
|
||||||
pr_number: ${{ steps.load-pr-num.outputs.pr-number }}
|
pr-number: ${{ steps.load-pr-num.outputs.pr-number }}
|
||||||
comment_tag: show_diff_error
|
comment-tag: show_diff_error
|
||||||
message: |
|
message: |
|
||||||
api.jsonの差分作成中にエラーが発生しました。詳細は[Workflowのログ](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})を確認してください。
|
api.jsonの差分作成中にエラーが発生しました。詳細は[Workflowのログ](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})を確認してください。
|
||||||
|
|||||||
16
.github/workflows/report-backend-memory.yml
vendored
16
.github/workflows/report-backend-memory.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Download artifact
|
- name: Download artifact
|
||||||
uses: actions/github-script@v7.1.0
|
uses: actions/github-script@v8.0.0
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
@@ -107,16 +107,16 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo "$FOOTER" >> ./output.md
|
echo "$FOOTER" >> ./output.md
|
||||||
- uses: thollander/actions-comment-pull-request@v2
|
- uses: thollander/actions-comment-pull-request@v3
|
||||||
with:
|
with:
|
||||||
pr_number: ${{ steps.load-pr-num.outputs.pr-number }}
|
pr-number: ${{ steps.load-pr-num.outputs.pr-number }}
|
||||||
comment_tag: show_memory_diff
|
comment-tag: show_memory_diff
|
||||||
filePath: ./output.md
|
file-path: ./output.md
|
||||||
- name: Tell error to PR
|
- name: Tell error to PR
|
||||||
uses: thollander/actions-comment-pull-request@v2
|
uses: thollander/actions-comment-pull-request@v3
|
||||||
if: failure() && steps.load-pr-num.outputs.pr-number
|
if: failure() && steps.load-pr-num.outputs.pr-number
|
||||||
with:
|
with:
|
||||||
pr_number: ${{ steps.load-pr-num.outputs.pr-number }}
|
pr-number: ${{ steps.load-pr-num.outputs.pr-number }}
|
||||||
comment_tag: show_memory_diff_error
|
comment-tag: show_memory_diff_error
|
||||||
message: |
|
message: |
|
||||||
An error occurred while comparing backend memory usage. See [workflow logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details.
|
An error occurred while comparing backend memory usage. See [workflow logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details.
|
||||||
|
|||||||
2
.github/workflows/request-release-review.yml
vendored
2
.github/workflows/request-release-review.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- name: Reply
|
- name: Reply
|
||||||
uses: actions/github-script@v6
|
uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const body = `To dev team (@misskey-dev/dev):
|
const body = `To dev team (@misskey-dev/dev):
|
||||||
|
|||||||
10
.github/workflows/storybook.yml
vendored
10
.github/workflows/storybook.yml
vendored
@@ -22,12 +22,12 @@ jobs:
|
|||||||
NODE_OPTIONS: "--max_old_space_size=7168"
|
NODE_OPTIONS: "--max_old_space_size=7168"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.3.0
|
- uses: actions/checkout@v6.0.1
|
||||||
if: github.event_name != 'pull_request_target'
|
if: github.event_name != 'pull_request_target'
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: true
|
submodules: true
|
||||||
- uses: actions/checkout@v4.3.0
|
- uses: actions/checkout@v6.0.1
|
||||||
if: github.event_name == 'pull_request_target'
|
if: github.event_name == 'pull_request_target'
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
@@ -39,7 +39,7 @@ jobs:
|
|||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.2.0
|
uses: pnpm/action-setup@v4.2.0
|
||||||
- name: Use Node.js
|
- name: Use Node.js
|
||||||
uses: actions/setup-node@v4.4.0
|
uses: actions/setup-node@v6.1.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
@@ -90,7 +90,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
||||||
- name: Notify that Chromatic detects changes
|
- name: Notify that Chromatic detects changes
|
||||||
uses: actions/github-script@v7.1.0
|
uses: actions/github-script@v8.0.0
|
||||||
if: github.event_name != 'pull_request_target' && steps.chromatic_push.outputs.success == 'false'
|
if: github.event_name != 'pull_request_target' && steps.chromatic_push.outputs.success == 'false'
|
||||||
with:
|
with:
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -102,7 +102,7 @@ jobs:
|
|||||||
body: 'Chromatic detects changes. Please [review the changes on Chromatic](https://www.chromatic.com/builds?appId=6428f7d7b962f0b79f97d6e4).'
|
body: 'Chromatic detects changes. Please [review the changes on Chromatic](https://www.chromatic.com/builds?appId=6428f7d7b962f0b79f97d6e4).'
|
||||||
})
|
})
|
||||||
- name: Upload Artifacts
|
- name: Upload Artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: storybook
|
name: storybook
|
||||||
path: packages/frontend/storybook-static
|
path: packages/frontend/storybook-static
|
||||||
|
|||||||
19
.github/workflows/test-backend.yml
vendored
19
.github/workflows/test-backend.yml
vendored
@@ -48,9 +48,16 @@ jobs:
|
|||||||
image: redis:7
|
image: redis:7
|
||||||
ports:
|
ports:
|
||||||
- 56312:6379
|
- 56312:6379
|
||||||
|
meilisearch:
|
||||||
|
image: getmeili/meilisearch:v1.3.4
|
||||||
|
ports:
|
||||||
|
- 57712:7700
|
||||||
|
env:
|
||||||
|
MEILI_NO_ANALYTICS: true
|
||||||
|
MEILI_ENV: development
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.3.0
|
- uses: actions/checkout@v6.0.1
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
@@ -86,7 +93,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
- name: Use Node.js
|
- name: Use Node.js
|
||||||
uses: actions/setup-node@v4.4.0
|
uses: actions/setup-node@v6.1.0
|
||||||
with:
|
with:
|
||||||
node-version-file: ${{ matrix.node-version-file }}
|
node-version-file: ${{ matrix.node-version-file }}
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
@@ -129,13 +136,13 @@ jobs:
|
|||||||
- 56312:6379
|
- 56312:6379
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.3.0
|
- uses: actions/checkout@v6.0.1
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.2.0
|
uses: pnpm/action-setup@v4.2.0
|
||||||
- name: Use Node.js
|
- name: Use Node.js
|
||||||
uses: actions/setup-node@v4.4.0
|
uses: actions/setup-node@v6.1.0
|
||||||
with:
|
with:
|
||||||
node-version-file: ${{ matrix.node-version-file }}
|
node-version-file: ${{ matrix.node-version-file }}
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
@@ -173,7 +180,7 @@ jobs:
|
|||||||
POSTGRES_HOST_AUTH_METHOD: trust
|
POSTGRES_HOST_AUTH_METHOD: trust
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.3.0
|
- uses: actions/checkout@v6.0.1
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
@@ -182,7 +189,7 @@ jobs:
|
|||||||
id: current-date
|
id: current-date
|
||||||
run: echo "today=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
|
run: echo "today=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
|
||||||
- name: Use Node.js
|
- name: Use Node.js
|
||||||
uses: actions/setup-node@v4.4.0
|
uses: actions/setup-node@v6.1.0
|
||||||
with:
|
with:
|
||||||
node-version-file: ${{ matrix.node-version-file }}
|
node-version-file: ${{ matrix.node-version-file }}
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|||||||
4
.github/workflows/test-federation.yml
vendored
4
.github/workflows/test-federation.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
|||||||
- .node-version
|
- .node-version
|
||||||
- .github/min.node-version
|
- .github/min.node-version
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
@@ -68,7 +68,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
- name: Use Node.js
|
- name: Use Node.js
|
||||||
uses: actions/setup-node@v4.4.0
|
uses: actions/setup-node@v6.1.0
|
||||||
with:
|
with:
|
||||||
node-version-file: ${{ matrix.node-version-file }}
|
node-version-file: ${{ matrix.node-version-file }}
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|||||||
12
.github/workflows/test-frontend.yml
vendored
12
.github/workflows/test-frontend.yml
vendored
@@ -28,13 +28,13 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.3.0
|
- uses: actions/checkout@v6.0.1
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.2.0
|
uses: pnpm/action-setup@v4.2.0
|
||||||
- name: Use Node.js
|
- name: Use Node.js
|
||||||
uses: actions/setup-node@v4.4.0
|
uses: actions/setup-node@v6.1.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
@@ -76,7 +76,7 @@ jobs:
|
|||||||
- 56312:6379
|
- 56312:6379
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.3.0
|
- uses: actions/checkout@v6.0.1
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
# https://github.com/cypress-io/cypress-docker-images/issues/150
|
# https://github.com/cypress-io/cypress-docker-images/issues/150
|
||||||
@@ -88,7 +88,7 @@ jobs:
|
|||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.2.0
|
uses: pnpm/action-setup@v4.2.0
|
||||||
- name: Use Node.js
|
- name: Use Node.js
|
||||||
uses: actions/setup-node@v4.4.0
|
uses: actions/setup-node@v6.1.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
@@ -113,12 +113,12 @@ jobs:
|
|||||||
wait-on: 'http://localhost:61812'
|
wait-on: 'http://localhost:61812'
|
||||||
headed: true
|
headed: true
|
||||||
browser: ${{ matrix.browser }}
|
browser: ${{ matrix.browser }}
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v6
|
||||||
if: failure()
|
if: failure()
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.browser }}-cypress-screenshots
|
name: ${{ matrix.browser }}-cypress-screenshots
|
||||||
path: cypress/screenshots
|
path: cypress/screenshots
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v6
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.browser }}-cypress-videos
|
name: ${{ matrix.browser }}-cypress-videos
|
||||||
|
|||||||
4
.github/workflows/test-misskey-js.yml
vendored
4
.github/workflows/test-misskey-js.yml
vendored
@@ -22,13 +22,13 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4.3.0
|
uses: actions/checkout@v6.0.1
|
||||||
|
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.2.0
|
uses: pnpm/action-setup@v4.2.0
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4.4.0
|
uses: actions/setup-node@v6.1.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|||||||
4
.github/workflows/test-production.yml
vendored
4
.github/workflows/test-production.yml
vendored
@@ -16,13 +16,13 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.3.0
|
- uses: actions/checkout@v6.0.1
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.2.0
|
uses: pnpm/action-setup@v4.2.0
|
||||||
- name: Use Node.js
|
- name: Use Node.js
|
||||||
uses: actions/setup-node@v4.4.0
|
uses: actions/setup-node@v6.1.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|||||||
4
.github/workflows/validate-api-json.yml
vendored
4
.github/workflows/validate-api-json.yml
vendored
@@ -17,13 +17,13 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.3.0
|
- uses: actions/checkout@v6.0.1
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.2.0
|
uses: pnpm/action-setup@v4.2.0
|
||||||
- name: Use Node.js
|
- name: Use Node.js
|
||||||
uses: actions/setup-node@v4.4.0
|
uses: actions/setup-node@v6.1.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -46,6 +46,7 @@ docker-compose.yml
|
|||||||
built
|
built
|
||||||
built-test
|
built-test
|
||||||
js-built
|
js-built
|
||||||
|
src-js
|
||||||
/data
|
/data
|
||||||
/.cache-loader
|
/.cache-loader
|
||||||
/db
|
/db
|
||||||
|
|||||||
63
CHANGELOG.md
63
CHANGELOG.md
@@ -1,11 +1,70 @@
|
|||||||
## Unreleased
|
## 2026.1.0
|
||||||
|
|
||||||
|
### Note
|
||||||
|
- `users/following` の `birthday` プロパティは非推奨になりました。代わりに `users/get-following-birthday-users` をご利用ください。
|
||||||
|
|
||||||
### General
|
### General
|
||||||
-
|
- Enhance: 「もうすぐ誕生日のユーザー」ウィジェットで、誕生日が至近のユーザーも表示できるように
|
||||||
|
(Cherry-picked from https://github.com/MisskeyIO/misskey)
|
||||||
|
- 「今日誕生日のユーザー」は「もうすぐ誕生日のユーザー」に名称変更されました
|
||||||
|
- 依存関係の更新
|
||||||
|
|
||||||
|
### Client
|
||||||
|
- Enhance: ドライブのファイル一覧で自動でもっと見るを利用可能に
|
||||||
|
- Enhance: ウィジェットの表示設定をプレビューを見ながら行えるように
|
||||||
|
- Enhance: ウィジェットの設定項目のラベルの多言語対応
|
||||||
|
- Enhance: パフォーマンスの向上
|
||||||
|
- Fix: ドライブクリーナーでファイルを削除しても画面に反映されない問題を修正 #16061
|
||||||
|
- Fix: 非ログイン時にログインを求めるダイアログが表示された後にダイアログのぼかしが解除されず操作不能になることがある問題を修正
|
||||||
|
- Fix: ドライブのソートが「登録日(昇順)」の場合に正しく動作しない問題を修正
|
||||||
|
- Fix: 高度なMFMのピッカーを使用する際の挙動を改善
|
||||||
|
- Fix: 管理画面でアーカイブ済のお知らせを表示した際にアクティブなお知らせが多い旨の警告が出る問題を修正
|
||||||
|
- Fix: ファイルタブのセンシティブメディアを開く際に確認ダイアログを出す設定が適用されない問題を修正
|
||||||
|
- Fix: 2月29日を誕生日に設定している場合、閏年以外は3月1日を誕生日として扱うように修正
|
||||||
|
|
||||||
|
### Server
|
||||||
|
- Enhance: OAuthのクライアント情報取得(Client Information Discovery)において、IndieWeb Living Standard 11 July 2024で定義されているJSONドキュメント形式に対応しました
|
||||||
|
- JSONによるClient Information Discoveryを行うには、レスポンスの`Content-Type`ヘッダーが`application/json`である必要があります
|
||||||
|
- 従来の実装(12 February 2022版・HTML Microformat形式)も引き続きサポートされます
|
||||||
|
- Enhance: メモリ使用量を削減
|
||||||
|
|
||||||
|
## 2025.12.2
|
||||||
|
|
||||||
|
### Note
|
||||||
|
v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false`に変更」について、正しく環境に応じた設定を行わないとサインインが困難になるといった状態を緩和するために、以下の対応を行いました。
|
||||||
|
|
||||||
|
**正しく設定しないと、上記のような不具合の原因となったり、セキュリティリスクが高まったりする可能性があります。必ず現在のconfigをご確認の上、必要に応じて値を変更してください。**
|
||||||
|
|
||||||
|
- `trustProxy`について、デフォルト(configに値が設定されていない状態)ではループバックアドレスとローカルIPアドレス空間を信頼するようにしました。
|
||||||
|
- `trustProxy`の設定方法について、より詳細に記述しました。
|
||||||
|
- リバースプロキシやCDNなどのより上流のレイヤでレートリミットを設定したい場合や、緊急時の一時的な緩和策として、Misskey内部でのIPアドレスペースでのレートリミットを無効化できるようにしました。
|
||||||
|
|
||||||
|
### General
|
||||||
|
- 依存関係の更新
|
||||||
|
|
||||||
|
### Client
|
||||||
|
- Enhance: デッキのUI説明を追加
|
||||||
|
- Enhance: 設定がブラウザによって消去されないようにするオプションを追加
|
||||||
|
- Fix: バージョン表記のないPlayが正しく動作しない問題を修正
|
||||||
|
バージョン表記のないものは v0.x 系として実行されます。v1.x 系で動作させたい場合は必ずバージョン表記を含めてください。
|
||||||
|
- Fix: デッキUIでメニュー位置を下にしているとプロファイル削除ボタンが表示されないのを修正
|
||||||
|
- Fix: 一部のUnicode絵文字のリアクションがボタンにならない問題を修正
|
||||||
|
|
||||||
|
### Server
|
||||||
|
- Enhance: Misskey内部でのIPアドレスペースでのレートリミットを無効化できるように
|
||||||
|
- リバースプロキシやCDNなど別のレイヤで別途レートリミットを設定する場合や、ローカルでのテスト用途等として利用することを想定しています。
|
||||||
|
- デフォルトは `enableIpRateLimit: true`(Misskey内部でのIPアドレスペースでのレートリミットは有効)です。
|
||||||
|
- Fix: コントロールパネルのジョブキューページで使用される一部APIの応答速度を改善
|
||||||
|
|
||||||
|
## 2025.12.1
|
||||||
|
|
||||||
### Client
|
### Client
|
||||||
- Fix: 特定の条件下でMisskeyが起動せず空白のページが表示されることがある問題を軽減
|
- Fix: 特定の条件下でMisskeyが起動せず空白のページが表示されることがある問題を軽減
|
||||||
- Fix: 初回読み込み時などに、言語設定で不整合が発生することがある問題を修正
|
- Fix: 初回読み込み時などに、言語設定で不整合が発生することがある問題を修正
|
||||||
|
- Fix: 削除されたノートのリノートが正しく動作されない問題を修正
|
||||||
|
- Fix: チャンネルオーナーが削除済みの時にチャンネルのヘッダーメニューが表示されない不具合を修正
|
||||||
|
- Fix: ドライブで登録日以外でソートする場合は月でグループ化して表示しないように
|
||||||
|
- Fix: `null` を返す note_view_intrruptor プラグインが動作しない問題を修正
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
- Fix: ジョブキューでSentryが有効にならない問題を修正
|
- Fix: ジョブキューでSentryが有効にならない問題を修正
|
||||||
|
|||||||
2
COPYING
2
COPYING
@@ -1,5 +1,5 @@
|
|||||||
Unless otherwise stated this repository is
|
Unless otherwise stated this repository is
|
||||||
Copyright © 2014-2025 syuilo and contributors
|
Copyright © 2014-2026 syuilo and contributors
|
||||||
|
|
||||||
And is distributed under The GNU Affero General Public License Version 3, you should have received a copy of the license file as LICENSE.
|
And is distributed under The GNU Affero General Public License Version 3, you should have received a copy of the license file as LICENSE.
|
||||||
|
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ COPY --chown=misskey:misskey --from=native-builder /misskey/packages/misskey-js/
|
|||||||
COPY --chown=misskey:misskey --from=native-builder /misskey/packages/misskey-reversi/built ./packages/misskey-reversi/built
|
COPY --chown=misskey:misskey --from=native-builder /misskey/packages/misskey-reversi/built ./packages/misskey-reversi/built
|
||||||
COPY --chown=misskey:misskey --from=native-builder /misskey/packages/misskey-bubble-game/built ./packages/misskey-bubble-game/built
|
COPY --chown=misskey:misskey --from=native-builder /misskey/packages/misskey-bubble-game/built ./packages/misskey-bubble-game/built
|
||||||
COPY --chown=misskey:misskey --from=native-builder /misskey/packages/backend/built ./packages/backend/built
|
COPY --chown=misskey:misskey --from=native-builder /misskey/packages/backend/built ./packages/backend/built
|
||||||
|
COPY --chown=misskey:misskey --from=native-builder /misskey/packages/backend/src-js ./packages/backend/src-js
|
||||||
COPY --chown=misskey:misskey --from=native-builder /misskey/packages/i18n/built ./packages/i18n/built
|
COPY --chown=misskey:misskey --from=native-builder /misskey/packages/i18n/built ./packages/i18n/built
|
||||||
COPY --chown=misskey:misskey --from=native-builder /misskey/fluent-emojis /misskey/fluent-emojis
|
COPY --chown=misskey:misskey --from=native-builder /misskey/fluent-emojis /misskey/fluent-emojis
|
||||||
COPY --chown=misskey:misskey . ./
|
COPY --chown=misskey:misskey . ./
|
||||||
|
|||||||
12
README.md
12
README.md
@@ -26,6 +26,8 @@
|
|||||||
|
|
||||||
[](https://deepwiki.com/misskey-dev/misskey)
|
[](https://deepwiki.com/misskey-dev/misskey)
|
||||||
|
|
||||||
|
<a href="https://flatt.tech/oss/gmo/trampoline" target="_blank"><img src="https://flatt.tech/assets/images/badges/gmo-oss.svg" height="24px"/></a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
## Thanks
|
## Thanks
|
||||||
@@ -49,3 +51,13 @@ Thanks to [Crowdin](https://crowdin.com/) for providing the localization platfor
|
|||||||
<a href="https://hub.docker.com/"><img src="https://user-images.githubusercontent.com/20679825/230148221-f8e73a32-a49b-47c3-9029-9a15c3824f92.png" height="30" alt="Docker" /></a>
|
<a href="https://hub.docker.com/"><img src="https://user-images.githubusercontent.com/20679825/230148221-f8e73a32-a49b-47c3-9029-9a15c3824f92.png" height="30" alt="Docker" /></a>
|
||||||
|
|
||||||
Thanks to [Docker](https://hub.docker.com/) for providing the container platform that helps us run Misskey in production.
|
Thanks to [Docker](https://hub.docker.com/) for providing the container platform that helps us run Misskey in production.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
Support us with a ⭐ !
|
||||||
|
|
||||||
|
[](https://star-history.com/#misskey-dev/misskey&Date)
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ services:
|
|||||||
env_file:
|
env_file:
|
||||||
- .config/docker.env
|
- .config/docker.env
|
||||||
volumes:
|
volumes:
|
||||||
- ./db:/var/lib/postgresql/data
|
- ./db:/var/lib/postgresql
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"
|
test: "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"
|
||||||
interval: 5s
|
interval: 5s
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ services:
|
|||||||
env_file:
|
env_file:
|
||||||
- .config/docker.env
|
- .config/docker.env
|
||||||
volumes:
|
volumes:
|
||||||
- ./db:/var/lib/postgresql/data
|
- ./db:/var/lib/postgresql
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"
|
test: "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"
|
||||||
interval: 5s
|
interval: 5s
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ files: "Dateien"
|
|||||||
download: "Herunterladen"
|
download: "Herunterladen"
|
||||||
driveFileDeleteConfirm: "Möchtest du die Datei „{name}“ wirklich löschen? Einige Inhalte, die diese Datei verwenden, werden auch verschwinden."
|
driveFileDeleteConfirm: "Möchtest du die Datei „{name}“ wirklich löschen? Einige Inhalte, die diese Datei verwenden, werden auch verschwinden."
|
||||||
unfollowConfirm: "Möchtest du {name} wirklich nicht mehr folgen?"
|
unfollowConfirm: "Möchtest du {name} wirklich nicht mehr folgen?"
|
||||||
|
rejectFollowRequestConfirm: "Möchtest du die Follow-Anfrage von {name} ablehnen?"
|
||||||
exportRequested: "Du hast einen Export angefragt. Dies kann etwas Zeit in Anspruch nehmen. Sobald der Export abgeschlossen ist, wird er deiner Drive hinzugefügt."
|
exportRequested: "Du hast einen Export angefragt. Dies kann etwas Zeit in Anspruch nehmen. Sobald der Export abgeschlossen ist, wird er deiner Drive hinzugefügt."
|
||||||
importRequested: "Du hast einen Import angefragt. Dies kann etwas Zeit in Anspruch nehmen."
|
importRequested: "Du hast einen Import angefragt. Dies kann etwas Zeit in Anspruch nehmen."
|
||||||
lists: "Listen"
|
lists: "Listen"
|
||||||
@@ -1018,6 +1019,7 @@ pushNotificationAlreadySubscribed: "Push-Benachrichtigungen sind bereits aktivie
|
|||||||
pushNotificationNotSupported: "Entweder dein Browser oder deine Instanz unterstützt Push-Benachrichtigungen nicht"
|
pushNotificationNotSupported: "Entweder dein Browser oder deine Instanz unterstützt Push-Benachrichtigungen nicht"
|
||||||
sendPushNotificationReadMessage: "Push-Benachrichtigungen löschen, sobald sie gelesen wurden"
|
sendPushNotificationReadMessage: "Push-Benachrichtigungen löschen, sobald sie gelesen wurden"
|
||||||
sendPushNotificationReadMessageCaption: "Dies kann gegebenenfalls den Batterieverbrauch deines Gerätes erhöhen."
|
sendPushNotificationReadMessageCaption: "Dies kann gegebenenfalls den Batterieverbrauch deines Gerätes erhöhen."
|
||||||
|
pleaseAllowPushNotification: "Bitte erlauben Sie Benachrichtigungen in Ihrem Browser."
|
||||||
windowMaximize: "Maximieren"
|
windowMaximize: "Maximieren"
|
||||||
windowMinimize: "Minimieren"
|
windowMinimize: "Minimieren"
|
||||||
windowRestore: "Wiederherstellen"
|
windowRestore: "Wiederherstellen"
|
||||||
@@ -1054,6 +1056,7 @@ permissionDeniedError: "Aktion verweigert"
|
|||||||
permissionDeniedErrorDescription: "Dieses Benutzerkonto besitzt nicht die Berechtigung, um diese Aktion auszuführen."
|
permissionDeniedErrorDescription: "Dieses Benutzerkonto besitzt nicht die Berechtigung, um diese Aktion auszuführen."
|
||||||
preset: "Vorlage"
|
preset: "Vorlage"
|
||||||
selectFromPresets: "Aus Vorlagen wählen"
|
selectFromPresets: "Aus Vorlagen wählen"
|
||||||
|
custom: "Benutzerdefiniert"
|
||||||
achievements: "Errungenschaften"
|
achievements: "Errungenschaften"
|
||||||
gotInvalidResponseError: "Ungültige Antwort des Servers"
|
gotInvalidResponseError: "Ungültige Antwort des Servers"
|
||||||
gotInvalidResponseErrorDescription: "Eventuell ist der Server momentan nicht erreichbar oder untergeht Wartungsarbeiten. Bitte versuche es später noch einmal."
|
gotInvalidResponseErrorDescription: "Eventuell ist der Server momentan nicht erreichbar oder untergeht Wartungsarbeiten. Bitte versuche es später noch einmal."
|
||||||
@@ -1243,6 +1246,7 @@ releaseToRefresh: "Zum Aktualisieren loslassen"
|
|||||||
refreshing: "Wird aktualisiert..."
|
refreshing: "Wird aktualisiert..."
|
||||||
pullDownToRefresh: "Zum Aktualisieren ziehen"
|
pullDownToRefresh: "Zum Aktualisieren ziehen"
|
||||||
useGroupedNotifications: "Benachrichtigungen gruppieren"
|
useGroupedNotifications: "Benachrichtigungen gruppieren"
|
||||||
|
emailVerificationFailedError: "Es gab ein Problem bei der Überprüfung Ihrer E-Mail-Adresse. Der Link ist möglicherweise abgelaufen."
|
||||||
cwNotationRequired: "Ist \"Inhaltswarnung verwenden\" aktiviert, muss eine Beschreibung gegeben werden."
|
cwNotationRequired: "Ist \"Inhaltswarnung verwenden\" aktiviert, muss eine Beschreibung gegeben werden."
|
||||||
doReaction: "Reagieren"
|
doReaction: "Reagieren"
|
||||||
code: "Code"
|
code: "Code"
|
||||||
@@ -1370,7 +1374,12 @@ defaultImageCompressionLevel: "Standard-Bildkomprimierungsstufe"
|
|||||||
defaultImageCompressionLevel_description: "Ein niedrigerer Wert erhält die Bildqualität, erhöht aber die Dateigröße. <br>Höhere Werte reduzieren die Dateigröße, verringern aber die Bildqualität."
|
defaultImageCompressionLevel_description: "Ein niedrigerer Wert erhält die Bildqualität, erhöht aber die Dateigröße. <br>Höhere Werte reduzieren die Dateigröße, verringern aber die Bildqualität."
|
||||||
inMinutes: "Minute(n)"
|
inMinutes: "Minute(n)"
|
||||||
inDays: "Tag(en)"
|
inDays: "Tag(en)"
|
||||||
|
safeModeEnabled: "Der abgesicherte Modus ist aktiviert."
|
||||||
|
schedule: "Planen"
|
||||||
|
scheduled: "Geplant"
|
||||||
widgets: "Widgets"
|
widgets: "Widgets"
|
||||||
|
deviceInfo: "Geräteinformation"
|
||||||
|
youAreAdmin: "Sie sind ein Administrator"
|
||||||
presets: "Vorlage"
|
presets: "Vorlage"
|
||||||
_imageEditing:
|
_imageEditing:
|
||||||
_vars:
|
_vars:
|
||||||
|
|||||||
@@ -83,6 +83,8 @@ files: "Files"
|
|||||||
download: "Download"
|
download: "Download"
|
||||||
driveFileDeleteConfirm: "Are you sure you want to delete \"{name}\"? All notes with this file attached will also be deleted."
|
driveFileDeleteConfirm: "Are you sure you want to delete \"{name}\"? All notes with this file attached will also be deleted."
|
||||||
unfollowConfirm: "Are you sure you want to unfollow {name}?"
|
unfollowConfirm: "Are you sure you want to unfollow {name}?"
|
||||||
|
cancelFollowRequestConfirm: "Are you sure that you want to cancel your follow request to {name}?"
|
||||||
|
rejectFollowRequestConfirm: "Are you sure that you want to reject the follow request from {name}?"
|
||||||
exportRequested: "You've requested an export. This may take a while. It will be added to your Drive once completed."
|
exportRequested: "You've requested an export. This may take a while. It will be added to your Drive once completed."
|
||||||
importRequested: "You've requested an import. This may take a while."
|
importRequested: "You've requested an import. This may take a while."
|
||||||
lists: "Lists"
|
lists: "Lists"
|
||||||
|
|||||||
@@ -1252,7 +1252,7 @@ detachAll: "Quitar todo"
|
|||||||
angle: "Ángulo"
|
angle: "Ángulo"
|
||||||
flip: "Echar de un capirotazo"
|
flip: "Echar de un capirotazo"
|
||||||
showAvatarDecorations: "Mostrar decoraciones de avatar"
|
showAvatarDecorations: "Mostrar decoraciones de avatar"
|
||||||
releaseToRefresh: "Soltar para recargar"
|
releaseToRefresh: "Suelta para recargar"
|
||||||
refreshing: "Recargando..."
|
refreshing: "Recargando..."
|
||||||
pullDownToRefresh: "Tira hacia abajo para recargar"
|
pullDownToRefresh: "Tira hacia abajo para recargar"
|
||||||
useGroupedNotifications: "Mostrar notificaciones agrupadas"
|
useGroupedNotifications: "Mostrar notificaciones agrupadas"
|
||||||
|
|||||||
@@ -1406,6 +1406,7 @@ youAreAdmin: "あなたは管理者です"
|
|||||||
frame: "フレーム"
|
frame: "フレーム"
|
||||||
presets: "プリセット"
|
presets: "プリセット"
|
||||||
zeroPadding: "ゼロ埋め"
|
zeroPadding: "ゼロ埋め"
|
||||||
|
nothingToConfigure: "設定項目はありません"
|
||||||
|
|
||||||
_imageEditing:
|
_imageEditing:
|
||||||
_vars:
|
_vars:
|
||||||
@@ -1557,6 +1558,9 @@ _settings:
|
|||||||
showPageTabBarBottom: "ページのタブバーを下部に表示"
|
showPageTabBarBottom: "ページのタブバーを下部に表示"
|
||||||
emojiPaletteBanner: "絵文字ピッカーに固定表示するプリセットをパレットとして登録したり、ピッカーの表示方法をカスタマイズしたりできます。"
|
emojiPaletteBanner: "絵文字ピッカーに固定表示するプリセットをパレットとして登録したり、ピッカーの表示方法をカスタマイズしたりできます。"
|
||||||
enableAnimatedImages: "アニメーション画像を有効にする"
|
enableAnimatedImages: "アニメーション画像を有効にする"
|
||||||
|
settingsPersistence_title: "設定の永続化"
|
||||||
|
settingsPersistence_description1: "設定の永続化を有効にすると、設定情報が失われるのを防止できます。"
|
||||||
|
settingsPersistence_description2: "環境によっては有効化できない場合があります。"
|
||||||
|
|
||||||
_chat:
|
_chat:
|
||||||
showSenderName: "送信者の名前を表示"
|
showSenderName: "送信者の名前を表示"
|
||||||
@@ -2596,9 +2600,48 @@ _widgets:
|
|||||||
_userList:
|
_userList:
|
||||||
chooseList: "リストを選択"
|
chooseList: "リストを選択"
|
||||||
clicker: "クリッカー"
|
clicker: "クリッカー"
|
||||||
birthdayFollowings: "今日誕生日のユーザー"
|
birthdayFollowings: "もうすぐ誕生日のユーザー"
|
||||||
chat: "ダイレクトメッセージ"
|
chat: "ダイレクトメッセージ"
|
||||||
|
|
||||||
|
_widgetOptions:
|
||||||
|
showHeader: "ヘッダーを表示"
|
||||||
|
transparent: "背景を透明にする"
|
||||||
|
height: "高さ"
|
||||||
|
_button:
|
||||||
|
colored: "色付き"
|
||||||
|
_clock:
|
||||||
|
size: "サイズ"
|
||||||
|
thickness: "針の太さ"
|
||||||
|
thicknessThin: "細い"
|
||||||
|
thicknessMedium: "普通"
|
||||||
|
thicknessThick: "太い"
|
||||||
|
graduations: "文字盤の目盛り"
|
||||||
|
graduationDots: "ドット"
|
||||||
|
graduationArabic: "アラビア数字"
|
||||||
|
fadeGraduations: "目盛りをフェード"
|
||||||
|
sAnimation: "秒針のアニメーション"
|
||||||
|
sAnimationElastic: "リアル"
|
||||||
|
sAnimationEaseOut: "滑らか"
|
||||||
|
twentyFour: "24時間表示"
|
||||||
|
labelTime: "時刻"
|
||||||
|
labelTz: "タイムゾーン"
|
||||||
|
labelTimeAndTz: "時刻とタイムゾーン"
|
||||||
|
timezone: "タイムゾーン"
|
||||||
|
showMs: "ミリ秒を表示"
|
||||||
|
showLabel: "ラベルを表示"
|
||||||
|
_jobQueue:
|
||||||
|
sound: "音を鳴らす"
|
||||||
|
_rss:
|
||||||
|
url: "RSSフィードのURL"
|
||||||
|
refreshIntervalSec: "更新間隔(秒)"
|
||||||
|
maxEntries: "最大表示件数"
|
||||||
|
_rssTicker:
|
||||||
|
shuffle: "表示順をシャッフル"
|
||||||
|
duration: "ティッカーのスクロール速度(秒)"
|
||||||
|
reverse: "逆方向にスクロール"
|
||||||
|
_birthdayFollowings:
|
||||||
|
period: "期間"
|
||||||
|
|
||||||
_cw:
|
_cw:
|
||||||
hide: "隠す"
|
hide: "隠す"
|
||||||
show: "もっと見る"
|
show: "もっと見る"
|
||||||
@@ -2890,6 +2933,15 @@ _deck:
|
|||||||
usedAsMinWidthWhenFlexible: "「幅を自動調整」が有効の場合、これが幅の最小値となります"
|
usedAsMinWidthWhenFlexible: "「幅を自動調整」が有効の場合、これが幅の最小値となります"
|
||||||
flexible: "幅を自動調整"
|
flexible: "幅を自動調整"
|
||||||
enableSyncBetweenDevicesForProfiles: "プロファイル情報のデバイス間同期を有効にする"
|
enableSyncBetweenDevicesForProfiles: "プロファイル情報のデバイス間同期を有効にする"
|
||||||
|
showHowToUse: "UIの説明を見る"
|
||||||
|
|
||||||
|
_howToUse:
|
||||||
|
addColumn_title: "カラム追加"
|
||||||
|
addColumn_description: "カラムの種類を選んで追加できます。"
|
||||||
|
settings_title: "UI設定"
|
||||||
|
settings_description: "デッキUIの詳細設定を行えます。"
|
||||||
|
switchProfile_title: "プロファイル切り替え"
|
||||||
|
switchProfile_description: "UIのレイアウトをプロファイルとして保存し、いつでも切り替えられるようにできます。"
|
||||||
|
|
||||||
_columns:
|
_columns:
|
||||||
main: "メイン"
|
main: "メイン"
|
||||||
@@ -3406,7 +3458,6 @@ _imageEffector:
|
|||||||
title: "エフェクト"
|
title: "エフェクト"
|
||||||
addEffect: "エフェクトを追加"
|
addEffect: "エフェクトを追加"
|
||||||
discardChangesConfirm: "変更を破棄して終了しますか?"
|
discardChangesConfirm: "変更を破棄して終了しますか?"
|
||||||
nothingToConfigure: "設定項目はありません"
|
|
||||||
failedToLoadImage: "画像の読み込みに失敗しました"
|
failedToLoadImage: "画像の読み込みに失敗しました"
|
||||||
|
|
||||||
_fxs:
|
_fxs:
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ copyRemoteLink: "复制远程链接"
|
|||||||
copyLinkRenote: "复制转帖链接"
|
copyLinkRenote: "复制转帖链接"
|
||||||
delete: "删除"
|
delete: "删除"
|
||||||
deleteAndEdit: "删除并编辑"
|
deleteAndEdit: "删除并编辑"
|
||||||
deleteAndEditConfirm: "要删除此帖并再次编辑吗?对此帖的所有回应、转发和回复也将被删除。"
|
deleteAndEditConfirm: "要删除此帖并再次编辑吗?此帖下所有的回应、转发和回复也将被删除。"
|
||||||
addToList: "添加至列表"
|
addToList: "添加至列表"
|
||||||
addToAntenna: "添加到天线"
|
addToAntenna: "添加到天线"
|
||||||
sendMessage: "发送消息"
|
sendMessage: "发送消息"
|
||||||
@@ -136,7 +136,7 @@ emojiPicker: "表情符号选择器"
|
|||||||
pinnedEmojisForReactionSettingDescription: "可以设置发表回应时置顶显示的表情符号"
|
pinnedEmojisForReactionSettingDescription: "可以设置发表回应时置顶显示的表情符号"
|
||||||
pinnedEmojisSettingDescription: "可以设置输入表情符号时置顶显示的表情符号"
|
pinnedEmojisSettingDescription: "可以设置输入表情符号时置顶显示的表情符号"
|
||||||
emojiPickerDisplay: "选择器显示设置"
|
emojiPickerDisplay: "选择器显示设置"
|
||||||
overwriteFromPinnedEmojisForReaction: "从「置顶(回应)」设置覆盖"
|
overwriteFromPinnedEmojisForReaction: "使用「置顶(回应)」设置覆盖"
|
||||||
overwriteFromPinnedEmojis: "从全局设置覆盖"
|
overwriteFromPinnedEmojis: "从全局设置覆盖"
|
||||||
reactionSettingDescription2: "拖动重新排序,单击删除,点击 + 添加。"
|
reactionSettingDescription2: "拖动重新排序,单击删除,点击 + 添加。"
|
||||||
rememberNoteVisibility: "保存上次设置的可见性"
|
rememberNoteVisibility: "保存上次设置的可见性"
|
||||||
@@ -153,8 +153,8 @@ block: "拉黑"
|
|||||||
unblock: "取消拉黑"
|
unblock: "取消拉黑"
|
||||||
suspend: "冻结"
|
suspend: "冻结"
|
||||||
unsuspend: "解除冻结"
|
unsuspend: "解除冻结"
|
||||||
blockConfirm: "确定要拉黑吗?"
|
blockConfirm: "确定要屏蔽吗?"
|
||||||
unblockConfirm: "确定要取消拉黑吗?"
|
unblockConfirm: "确定要取消屏蔽吗?"
|
||||||
suspendConfirm: "要冻结吗?"
|
suspendConfirm: "要冻结吗?"
|
||||||
unsuspendConfirm: "要解除冻结吗?"
|
unsuspendConfirm: "要解除冻结吗?"
|
||||||
selectList: "选择列表"
|
selectList: "选择列表"
|
||||||
@@ -174,7 +174,7 @@ emojiUrl: "emoji 地址"
|
|||||||
addEmoji: "添加表情符号"
|
addEmoji: "添加表情符号"
|
||||||
settingGuide: "推荐配置"
|
settingGuide: "推荐配置"
|
||||||
cacheRemoteFiles: "缓存远程文件"
|
cacheRemoteFiles: "缓存远程文件"
|
||||||
cacheRemoteFilesDescription: "启用此设定时,将在此服务器上缓存远程文件。虽然可以加快图片显示的速度,但是相对的会消耗大量的服务器存储空间。用户角色内的网盘容量决定了这个远程用户能在服务器上保留多少缓存。当超出了这个限制时,旧的文件将从缓存中被删除,成为链接。当禁用此设定时,则是从一开始就将远程文件保留为链接。此时推荐将 default.yml 的 proxyRemoteFiles 设置为 true 以优化缩略图生成及保护用户隐私。"
|
cacheRemoteFilesDescription: "启用此设定时,将在此服务器上缓存远程文件。虽然可以加快图片显示的速度,但是相对的会消耗大量的服务器存储空间。用户角色内的网盘容量决定了这个远程用户能在服务器上保留多少缓存。当超出了这个限制时,旧的文件将从缓存中被删除,成为链接。当禁用此设定时,则是从一开始就将远程文件保留为链接。此时推荐将 的 proxyRemoteFiles 设置为 true 以优化缩略图生成及保护用户隐私。"
|
||||||
youCanCleanRemoteFilesCache: "可以使用文件管理的🗑️按钮来删除所有的缓存。"
|
youCanCleanRemoteFilesCache: "可以使用文件管理的🗑️按钮来删除所有的缓存。"
|
||||||
cacheRemoteSensitiveFiles: "缓存远程敏感媒体文件"
|
cacheRemoteSensitiveFiles: "缓存远程敏感媒体文件"
|
||||||
cacheRemoteSensitiveFilesDescription: "如果禁用这项设定,远程服务器的敏感媒体将不会被缓存,而是直接链接。"
|
cacheRemoteSensitiveFilesDescription: "如果禁用这项设定,远程服务器的敏感媒体将不会被缓存,而是直接链接。"
|
||||||
@@ -184,7 +184,7 @@ flagAsCat: "喵!!!!!!!!!!!!"
|
|||||||
flagAsCatDescription: "喵喵喵??"
|
flagAsCatDescription: "喵喵喵??"
|
||||||
flagShowTimelineReplies: "在时间线上显示帖子的回复"
|
flagShowTimelineReplies: "在时间线上显示帖子的回复"
|
||||||
flagShowTimelineRepliesDescription: "启用时,时间线除了显示用户的帖子外,还会显示其他用户对帖子的回复。"
|
flagShowTimelineRepliesDescription: "启用时,时间线除了显示用户的帖子外,还会显示其他用户对帖子的回复。"
|
||||||
autoAcceptFollowed: "自动允许来自我关注的用户对我的关注请求"
|
autoAcceptFollowed: "自动允许回关请求"
|
||||||
addAccount: "添加账户"
|
addAccount: "添加账户"
|
||||||
reloadAccountsList: "更新账户列表"
|
reloadAccountsList: "更新账户列表"
|
||||||
loginFailed: "登录失败"
|
loginFailed: "登录失败"
|
||||||
@@ -247,8 +247,8 @@ mediaSilencedInstancesDescription: "设置要隐藏媒体文件的服务器,
|
|||||||
federationAllowedHosts: "允许联合的服务器"
|
federationAllowedHosts: "允许联合的服务器"
|
||||||
federationAllowedHostsDescription: "设定允许联合的服务器,以换行分隔。"
|
federationAllowedHostsDescription: "设定允许联合的服务器,以换行分隔。"
|
||||||
muteAndBlock: "屏蔽/拉黑"
|
muteAndBlock: "屏蔽/拉黑"
|
||||||
mutedUsers: "已屏蔽用户"
|
mutedUsers: "已静音的用户"
|
||||||
blockedUsers: "已拉黑的用户"
|
blockedUsers: "已屏蔽的用户"
|
||||||
noUsers: "无用户"
|
noUsers: "无用户"
|
||||||
editProfile: "编辑资料"
|
editProfile: "编辑资料"
|
||||||
noteDeleteConfirm: "确定要删除该帖子吗?"
|
noteDeleteConfirm: "确定要删除该帖子吗?"
|
||||||
@@ -1344,7 +1344,7 @@ skip: "跳过"
|
|||||||
restore: "恢复"
|
restore: "恢复"
|
||||||
syncBetweenDevices: "设备间同步"
|
syncBetweenDevices: "设备间同步"
|
||||||
preferenceSyncConflictTitle: "服务器上已存在设定值"
|
preferenceSyncConflictTitle: "服务器上已存在设定值"
|
||||||
preferenceSyncConflictText: "服务器上已有此设置的设定值。要覆盖哪个设定值?"
|
preferenceSyncConflictText: "即将保存设定值到服务器,但检测到服务器上已有此设置的设定值。要使用哪个设定值?"
|
||||||
preferenceSyncConflictChoiceMerge: "合并"
|
preferenceSyncConflictChoiceMerge: "合并"
|
||||||
preferenceSyncConflictChoiceServer: "服务器上的设定值"
|
preferenceSyncConflictChoiceServer: "服务器上的设定值"
|
||||||
preferenceSyncConflictChoiceDevice: "设备上的设定值"
|
preferenceSyncConflictChoiceDevice: "设备上的设定值"
|
||||||
@@ -3270,7 +3270,7 @@ _watermarkEditor:
|
|||||||
driveFileTypeWarn: "不支持此文件"
|
driveFileTypeWarn: "不支持此文件"
|
||||||
driveFileTypeWarnDescription: "请选择图像文件"
|
driveFileTypeWarnDescription: "请选择图像文件"
|
||||||
title: "编辑水印"
|
title: "编辑水印"
|
||||||
cover: "覆盖全体"
|
cover: "覆盖所有"
|
||||||
repeat: "平铺"
|
repeat: "平铺"
|
||||||
preserveBoundingRect: "调整为旋转时不超出范围"
|
preserveBoundingRect: "调整为旋转时不超出范围"
|
||||||
opacity: "不透明度"
|
opacity: "不透明度"
|
||||||
|
|||||||
41
package.json
41
package.json
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"version": "2025.12.0",
|
"version": "2026.1.0-alpha.4",
|
||||||
"codename": "nasubi",
|
"codename": "nasubi",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/misskey-dev/misskey.git"
|
"url": "https://github.com/misskey-dev/misskey.git"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.24.0",
|
"packageManager": "pnpm@10.27.0",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/misskey-js",
|
"packages/misskey-js",
|
||||||
"packages/i18n",
|
"packages/i18n",
|
||||||
@@ -23,12 +23,12 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"compile-config": "cd packages/backend && pnpm compile-config",
|
"compile-config": "cd packages/backend && pnpm compile-config",
|
||||||
"build-pre": "node ./scripts/build-pre.js",
|
"build-pre": "node scripts/build-pre.mjs",
|
||||||
"build-assets": "node ./scripts/build-assets.mjs",
|
"build-assets": "node ./scripts/build-assets.mjs",
|
||||||
"build": "pnpm build-pre && pnpm -r build && pnpm build-assets",
|
"build": "pnpm build-pre && pnpm -r build && pnpm build-assets",
|
||||||
"build-storybook": "pnpm --filter frontend build-storybook",
|
"build-storybook": "pnpm --filter frontend build-storybook",
|
||||||
"build-misskey-js-with-types": "pnpm build-pre && pnpm --filter backend... --filter=!misskey-js build && pnpm --filter backend generate-api-json --no-build && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api",
|
"build-misskey-js-with-types": "pnpm build-pre && pnpm --filter backend... --filter=!misskey-js build && pnpm --filter backend generate-api-json --no-build && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api",
|
||||||
"start": "pnpm check:connect && cd packages/backend && pnpm compile-config && node ./built/boot/entry.js",
|
"start": "cd packages/backend && pnpm compile-config && node ./built/boot/entry.js",
|
||||||
"start:inspect": "cd packages/backend && pnpm compile-config && node --inspect ./built/boot/entry.js",
|
"start:inspect": "cd packages/backend && pnpm compile-config && node --inspect ./built/boot/entry.js",
|
||||||
"start:test": "ncp ./.github/misskey/test.yml ./.config/test.yml && cd packages/backend && cross-env NODE_ENV=test pnpm compile-config && cross-env NODE_ENV=test node ./built/boot/entry.js",
|
"start:test": "ncp ./.github/misskey/test.yml ./.config/test.yml && cd packages/backend && cross-env NODE_ENV=test pnpm compile-config && cross-env NODE_ENV=test node ./built/boot/entry.js",
|
||||||
"cli": "cd packages/backend && pnpm cli",
|
"cli": "cd packages/backend && pnpm cli",
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
"migrateandstart": "pnpm migrate && pnpm start",
|
"migrateandstart": "pnpm migrate && pnpm start",
|
||||||
"watch": "pnpm dev",
|
"watch": "pnpm dev",
|
||||||
"dev": "node scripts/dev.mjs",
|
"dev": "node scripts/dev.mjs",
|
||||||
"lint": "pnpm -r lint",
|
"lint": "pnpm --no-bail -r lint",
|
||||||
"cy:open": "pnpm cypress open --config-file=cypress.config.ts",
|
"cy:open": "pnpm cypress open --config-file=cypress.config.ts",
|
||||||
"cy:run": "pnpm cypress run",
|
"cy:run": "pnpm cypress run",
|
||||||
"e2e": "pnpm start-server-and-test start:test http://localhost:61812 cy:run",
|
"e2e": "pnpm start-server-and-test start:test http://localhost:61812 cy:run",
|
||||||
@@ -48,40 +48,39 @@
|
|||||||
"jest-and-coverage": "cd packages/backend && pnpm jest-and-coverage",
|
"jest-and-coverage": "cd packages/backend && pnpm jest-and-coverage",
|
||||||
"test": "pnpm -r test",
|
"test": "pnpm -r test",
|
||||||
"test-and-coverage": "pnpm -r test-and-coverage",
|
"test-and-coverage": "pnpm -r test-and-coverage",
|
||||||
"clean": "node ./scripts/clean.js",
|
"clean": "node scripts/clean.mjs",
|
||||||
"clean-all": "node ./scripts/clean-all.js",
|
"clean-all": "node scripts/clean-all.mjs",
|
||||||
"cleanall": "pnpm clean-all"
|
"cleanall": "pnpm clean-all"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"chokidar": "4.0.3",
|
"chokidar": "5.0.0",
|
||||||
"lodash": "4.17.21"
|
"lodash": "4.17.21"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cssnano": "7.1.2",
|
"cssnano": "7.1.2",
|
||||||
"esbuild": "0.27.0",
|
"esbuild": "0.27.2",
|
||||||
"execa": "9.6.0",
|
"execa": "9.6.1",
|
||||||
"fast-glob": "3.3.3",
|
|
||||||
"glob": "13.0.0",
|
|
||||||
"ignore-walk": "8.0.0",
|
"ignore-walk": "8.0.0",
|
||||||
"js-yaml": "4.1.1",
|
"js-yaml": "4.1.1",
|
||||||
"postcss": "8.5.6",
|
"postcss": "8.5.6",
|
||||||
"tar": "7.5.2",
|
"tar": "7.5.2",
|
||||||
"terser": "5.44.1",
|
"terser": "5.44.1"
|
||||||
"typescript": "5.9.3"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "9.39.1",
|
"@eslint/js": "9.39.2",
|
||||||
"@misskey-dev/eslint-plugin": "2.2.0",
|
"@misskey-dev/eslint-plugin": "2.2.0",
|
||||||
"@types/js-yaml": "4.0.9",
|
"@types/js-yaml": "4.0.9",
|
||||||
"@types/node": "24.10.1",
|
"@types/node": "24.10.4",
|
||||||
"@typescript-eslint/eslint-plugin": "8.47.0",
|
"@typescript-eslint/eslint-plugin": "8.50.1",
|
||||||
"@typescript-eslint/parser": "8.47.0",
|
"@typescript-eslint/parser": "8.50.1",
|
||||||
|
"@typescript/native-preview": "7.0.0-dev.20251226.1",
|
||||||
"cross-env": "10.1.0",
|
"cross-env": "10.1.0",
|
||||||
"cypress": "15.7.0",
|
"cypress": "15.8.1",
|
||||||
"eslint": "9.39.1",
|
"eslint": "9.39.2",
|
||||||
"globals": "16.5.0",
|
"globals": "16.5.0",
|
||||||
"ncp": "2.0.0",
|
"ncp": "2.0.0",
|
||||||
"pnpm": "10.24.0",
|
"pnpm": "10.27.0",
|
||||||
|
"typescript": "5.9.3",
|
||||||
"start-server-and-test": "2.1.3"
|
"start-server-and-test": "2.1.3"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ window.onload = async () => {
|
|||||||
const account = JSON.parse(localStorage.getItem('account'));
|
const account = JSON.parse(localStorage.getItem('account'));
|
||||||
const i = account.token;
|
const i = account.token;
|
||||||
|
|
||||||
const api = (endpoint, data = {}) => {
|
const _api = (endpoint, data = {}) => {
|
||||||
const promise = new Promise((resolve, reject) => {
|
const promise = new Promise((resolve, reject) => {
|
||||||
// Append a credential
|
// Append a credential
|
||||||
if (i) data.i = i;
|
if (i) data.i = i;
|
||||||
|
|||||||
121
packages/backend/build.js
Normal file
121
packages/backend/build.js
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
import fs from 'node:fs';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import { dirname, join } from 'node:path';
|
||||||
|
import { build } from 'esbuild';
|
||||||
|
import { swcPlugin } from 'esbuild-plugin-swc';
|
||||||
|
|
||||||
|
const _filename = fileURLToPath(import.meta.url);
|
||||||
|
const _dirname = dirname(_filename);
|
||||||
|
const _package = JSON.parse(fs.readFileSync(_dirname + '/package.json', 'utf-8'));
|
||||||
|
|
||||||
|
const resolveTsPathsPlugin = {
|
||||||
|
name: 'resolve-ts-paths',
|
||||||
|
setup(build) {
|
||||||
|
build.onResolve({ filter: /^\.{1,2}\/.*\.js$/ }, (args) => {
|
||||||
|
if (args.importer) {
|
||||||
|
const absPath = join(args.resolveDir, args.path);
|
||||||
|
const tsPath = absPath.slice(0, -3) + '.ts';
|
||||||
|
if (fs.existsSync(tsPath)) return { path: tsPath };
|
||||||
|
const tsxPath = absPath.slice(0, -3) + '.tsx';
|
||||||
|
if (fs.existsSync(tsxPath)) return { path: tsxPath };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const externalIpaddrPlugin = {
|
||||||
|
name: 'external-ipaddr',
|
||||||
|
setup(build) {
|
||||||
|
build.onResolve({ filter: /^ipaddr\.js$/ }, (args) => {
|
||||||
|
return { path: args.path, external: true };
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @type {import('esbuild').BuildOptions} */
|
||||||
|
const options = {
|
||||||
|
entryPoints: ['./src/boot/entry.ts'],
|
||||||
|
minify: true,
|
||||||
|
keepNames: true,
|
||||||
|
bundle: true,
|
||||||
|
outdir: './built/boot',
|
||||||
|
target: 'node22',
|
||||||
|
platform: 'node',
|
||||||
|
format: 'esm',
|
||||||
|
sourcemap: 'linked',
|
||||||
|
packages: 'external',
|
||||||
|
banner: {
|
||||||
|
js: 'import { createRequire as topLevelCreateRequire } from "module";' +
|
||||||
|
'import ___url___ from "url";' +
|
||||||
|
'const require = topLevelCreateRequire(import.meta.url);' +
|
||||||
|
'const __filename = ___url___.fileURLToPath(import.meta.url);' +
|
||||||
|
'const __dirname = ___url___.fileURLToPath(new URL(".", import.meta.url));',
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
externalIpaddrPlugin,
|
||||||
|
resolveTsPathsPlugin,
|
||||||
|
swcPlugin({
|
||||||
|
jsc: {
|
||||||
|
parser: {
|
||||||
|
syntax: 'typescript',
|
||||||
|
decorators: true,
|
||||||
|
dynamicImport: true,
|
||||||
|
},
|
||||||
|
transform: {
|
||||||
|
legacyDecorator: true,
|
||||||
|
decoratorMetadata: true,
|
||||||
|
},
|
||||||
|
experimental: {
|
||||||
|
keepImportAssertions: true,
|
||||||
|
},
|
||||||
|
baseUrl: join(_dirname, 'src'),
|
||||||
|
paths: {
|
||||||
|
'@/*': ['*'],
|
||||||
|
},
|
||||||
|
target: 'esnext',
|
||||||
|
keepClassNames: true,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
externalIpaddrPlugin,
|
||||||
|
],
|
||||||
|
// external: [
|
||||||
|
// 'slacc-*',
|
||||||
|
// 'class-transformer',
|
||||||
|
// 'class-validator',
|
||||||
|
// '@sentry/*',
|
||||||
|
// '@nestjs/websockets/socket-module',
|
||||||
|
// '@nestjs/microservices/microservices-module',
|
||||||
|
// '@nestjs/microservices',
|
||||||
|
// '@napi-rs/canvas-win32-x64-msvc',
|
||||||
|
// 'mock-aws-s3',
|
||||||
|
// 'aws-sdk',
|
||||||
|
// 'nock',
|
||||||
|
// 'sharp',
|
||||||
|
// 'jsdom',
|
||||||
|
// 're2',
|
||||||
|
// '@napi-rs/canvas',
|
||||||
|
// ],
|
||||||
|
};
|
||||||
|
|
||||||
|
const args = process.argv.slice(2).map(arg => arg.toLowerCase());
|
||||||
|
|
||||||
|
if (!args.includes('--no-clean')) {
|
||||||
|
fs.rmSync('./built', { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
await buildSrc();
|
||||||
|
|
||||||
|
async function buildSrc() {
|
||||||
|
console.log(`[${_package.name}] start building...`);
|
||||||
|
|
||||||
|
await build(options)
|
||||||
|
.then(() => {
|
||||||
|
console.log(`[${_package.name}] build succeeded.`);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
process.stderr.write(err.stderr || err.message || err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`[${_package.name}] finish building.`);
|
||||||
|
}
|
||||||
@@ -25,7 +25,6 @@ export default [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
'@typescript-eslint/no-unused-vars': 'off',
|
|
||||||
'import/order': ['warn', {
|
'import/order': ['warn', {
|
||||||
groups: [
|
groups: [
|
||||||
'builtin',
|
'builtin',
|
||||||
|
|||||||
20
packages/backend/migration/1767169026317-birthday-index.js
Normal file
20
packages/backend/migration/1767169026317-birthday-index.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class BirthdayIndex1767169026317 {
|
||||||
|
name = 'BirthdayIndex1767169026317'
|
||||||
|
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`DROP INDEX "public"."IDX_de22cd2b445eee31ae51cdbe99"`);
|
||||||
|
await queryRunner.query(`CREATE OR REPLACE FUNCTION get_birthday_date(birthday TEXT) RETURNS SMALLINT AS $$ BEGIN RETURN CAST((SUBSTR(birthday, 6, 2) || SUBSTR(birthday, 9, 2)) AS SMALLINT); END; $$ LANGUAGE plpgsql IMMUTABLE;`);
|
||||||
|
await queryRunner.query(`CREATE INDEX "IDX_USERPROFILE_BIRTHDAY_DATE" ON "user_profile" (get_birthday_date("birthday"))`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`CREATE INDEX "IDX_de22cd2b445eee31ae51cdbe99" ON "user_profile" (substr("birthday", 6, 5))`);
|
||||||
|
await queryRunner.query(`DROP INDEX "public"."IDX_USERPROFILE_BIRTHDAY_DATE"`);
|
||||||
|
await queryRunner.query(`DROP FUNCTION IF EXISTS get_birthday_date(birthday TEXT)`);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
import { loadConfig } from './built/config.js';
|
import { loadConfig } from './src-js/config.js';
|
||||||
import { entities } from './built/postgres.js';
|
import { entities } from './src-js/postgres.js';
|
||||||
|
|
||||||
const isConcurrentIndexMigrationEnabled = process.env.MISSKEY_MIGRATION_CREATE_INDEX_CONCURRENTLY === '1';
|
const isConcurrentIndexMigrationEnabled = process.env.MISSKEY_MIGRATION_CREATE_INDEX_CONCURRENTLY === '1';
|
||||||
|
|
||||||
|
|||||||
@@ -12,17 +12,17 @@
|
|||||||
"start:test": "cross-env NODE_ENV=test pnpm compile-config && cross-env NODE_ENV=test node ./built/boot/entry.js",
|
"start:test": "cross-env NODE_ENV=test pnpm compile-config && cross-env NODE_ENV=test node ./built/boot/entry.js",
|
||||||
"migrate": "pnpm compile-config && pnpm typeorm migration:run -d ormconfig.js",
|
"migrate": "pnpm compile-config && pnpm typeorm migration:run -d ormconfig.js",
|
||||||
"revert": "pnpm compile-config && pnpm typeorm migration:revert -d ormconfig.js",
|
"revert": "pnpm compile-config && pnpm typeorm migration:revert -d ormconfig.js",
|
||||||
"cli": "pnpm compile-config && node ./built/boot/cli.js",
|
"cli": "pnpm compile-config && node ./src-js/boot/cli.js",
|
||||||
"check:connect": "pnpm compile-config && node ./scripts/check_connect.js",
|
"check:connect": "pnpm compile-config && node ./scripts/check_connect.js",
|
||||||
"compile-config": "node ./scripts/compile_config.js",
|
"compile-config": "node ./scripts/compile_config.js",
|
||||||
"build": "swc src -d built -D --strip-leading-paths",
|
"build": "swc src -d src-js -D --strip-leading-paths && node ./build.js",
|
||||||
"build:test": "swc test-server -d built-test -D --config-file test-server/.swcrc --strip-leading-paths",
|
"build:test": "swc test-server -d built-test -D --config-file test-server/.swcrc --strip-leading-paths",
|
||||||
"watch:swc": "swc src -d built -D -w --strip-leading-paths",
|
"watch:swc": "swc src -d built -D -w --strip-leading-paths",
|
||||||
"build:tsc": "tsc -p tsconfig.json && tsc-alias -p tsconfig.json",
|
"build:tsc": "tsgo -p tsconfig.json && tsc-alias -p tsconfig.json",
|
||||||
"watch": "pnpm compile-config && node ./scripts/watch.mjs",
|
"watch": "pnpm compile-config && node ./scripts/watch.mjs",
|
||||||
"restart": "pnpm build && pnpm start",
|
"restart": "pnpm build && pnpm start",
|
||||||
"dev": "pnpm compile-config && node ./scripts/dev.mjs",
|
"dev": "pnpm compile-config && node ./scripts/dev.mjs",
|
||||||
"typecheck": "tsc --noEmit && tsc -p test --noEmit && tsc -p test-federation --noEmit",
|
"typecheck": "tsgo --noEmit && tsgo -p test --noEmit && tsgo -p test-federation --noEmit",
|
||||||
"eslint": "eslint --quiet \"{src,test-federation}/**/*.ts\"",
|
"eslint": "eslint --quiet \"{src,test-federation}/**/*.ts\"",
|
||||||
"lint": "pnpm typecheck && pnpm eslint",
|
"lint": "pnpm typecheck && pnpm eslint",
|
||||||
"jest": "cross-env NODE_ENV=test pnpm compile-config && cross-env NODE_ENV=test node ./jest.js --forceExit --config jest.config.unit.cjs",
|
"jest": "cross-env NODE_ENV=test pnpm compile-config && cross-env NODE_ENV=test node ./jest.js --forceExit --config jest.config.unit.cjs",
|
||||||
@@ -41,20 +41,20 @@
|
|||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@swc/core-android-arm64": "1.3.11",
|
"@swc/core-android-arm64": "1.3.11",
|
||||||
"@swc/core-darwin-arm64": "1.15.3",
|
"@swc/core-darwin-arm64": "1.15.7",
|
||||||
"@swc/core-darwin-x64": "1.15.3",
|
"@swc/core-darwin-x64": "1.15.7",
|
||||||
"@swc/core-freebsd-x64": "1.3.11",
|
"@swc/core-freebsd-x64": "1.3.11",
|
||||||
"@swc/core-linux-arm-gnueabihf": "1.15.3",
|
"@swc/core-linux-arm-gnueabihf": "1.15.7",
|
||||||
"@swc/core-linux-arm64-gnu": "1.15.3",
|
"@swc/core-linux-arm64-gnu": "1.15.7",
|
||||||
"@swc/core-linux-arm64-musl": "1.15.3",
|
"@swc/core-linux-arm64-musl": "1.15.7",
|
||||||
"@swc/core-linux-x64-gnu": "1.15.3",
|
"@swc/core-linux-x64-gnu": "1.15.7",
|
||||||
"@swc/core-linux-x64-musl": "1.15.3",
|
"@swc/core-linux-x64-musl": "1.15.7",
|
||||||
"@swc/core-win32-arm64-msvc": "1.15.3",
|
"@swc/core-win32-arm64-msvc": "1.15.7",
|
||||||
"@swc/core-win32-ia32-msvc": "1.15.3",
|
"@swc/core-win32-ia32-msvc": "1.15.7",
|
||||||
"@swc/core-win32-x64-msvc": "1.15.3",
|
"@swc/core-win32-x64-msvc": "1.15.7",
|
||||||
"@tensorflow/tfjs": "4.22.0",
|
"@tensorflow/tfjs": "4.22.0",
|
||||||
"@tensorflow/tfjs-node": "4.22.0",
|
"@tensorflow/tfjs-node": "4.22.0",
|
||||||
"bufferutil": "4.0.9",
|
"bufferutil": "4.1.0",
|
||||||
"slacc-android-arm-eabi": "0.0.10",
|
"slacc-android-arm-eabi": "0.0.10",
|
||||||
"slacc-android-arm64": "0.0.10",
|
"slacc-android-arm64": "0.0.10",
|
||||||
"slacc-darwin-arm64": "0.0.10",
|
"slacc-darwin-arm64": "0.0.10",
|
||||||
@@ -68,34 +68,33 @@
|
|||||||
"slacc-linux-x64-musl": "0.0.10",
|
"slacc-linux-x64-musl": "0.0.10",
|
||||||
"slacc-win32-arm64-msvc": "0.0.10",
|
"slacc-win32-arm64-msvc": "0.0.10",
|
||||||
"slacc-win32-x64-msvc": "0.0.10",
|
"slacc-win32-x64-msvc": "0.0.10",
|
||||||
"utf-8-validate": "6.0.5"
|
"utf-8-validate": "6.0.6"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "3.940.0",
|
"@aws-sdk/client-s3": "3.958.0",
|
||||||
"@aws-sdk/lib-storage": "3.940.0",
|
"@aws-sdk/lib-storage": "3.958.0",
|
||||||
"@discordapp/twemoji": "16.0.1",
|
"@discordapp/twemoji": "16.0.1",
|
||||||
"@fastify/accepts": "5.0.3",
|
"@fastify/accepts": "5.0.4",
|
||||||
"@fastify/cookie": "11.0.2",
|
"@fastify/cors": "11.2.0",
|
||||||
"@fastify/cors": "11.1.0",
|
|
||||||
"@fastify/express": "4.0.2",
|
"@fastify/express": "4.0.2",
|
||||||
"@fastify/http-proxy": "11.3.0",
|
"@fastify/http-proxy": "11.4.1",
|
||||||
"@fastify/multipart": "9.3.0",
|
"@fastify/multipart": "9.3.0",
|
||||||
"@fastify/static": "8.3.0",
|
"@fastify/static": "8.3.0",
|
||||||
"@kitajs/html": "4.2.11",
|
"@kitajs/html": "4.2.11",
|
||||||
"@misskey-dev/sharp-read-bmp": "1.2.0",
|
"@misskey-dev/sharp-read-bmp": "1.2.0",
|
||||||
"@misskey-dev/summaly": "5.2.5",
|
"@misskey-dev/summaly": "5.2.5",
|
||||||
"@napi-rs/canvas": "0.1.83",
|
"@napi-rs/canvas": "0.1.87",
|
||||||
"@nestjs/common": "11.1.9",
|
"@nestjs/common": "11.1.10",
|
||||||
"@nestjs/core": "11.1.9",
|
"@nestjs/core": "11.1.10",
|
||||||
"@nestjs/testing": "11.1.9",
|
"@nestjs/testing": "11.1.10",
|
||||||
"@peertube/http-signature": "1.7.0",
|
"@peertube/http-signature": "1.7.0",
|
||||||
"@sentry/node": "10.27.0",
|
"@sentry/node": "10.32.1",
|
||||||
"@sentry/profiling-node": "10.27.0",
|
"@sentry/profiling-node": "10.32.1",
|
||||||
"@simplewebauthn/server": "13.2.2",
|
"@simplewebauthn/server": "13.2.2",
|
||||||
"@sinonjs/fake-timers": "15.0.0",
|
"@sinonjs/fake-timers": "15.1.0",
|
||||||
"@smithy/node-http-handler": "4.4.5",
|
"@smithy/node-http-handler": "4.4.7",
|
||||||
"@swc/cli": "0.7.9",
|
"@swc/cli": "0.7.9",
|
||||||
"@swc/core": "1.15.3",
|
"@swc/core": "1.15.7",
|
||||||
"@twemoji/parser": "16.0.0",
|
"@twemoji/parser": "16.0.0",
|
||||||
"@types/redis-info": "3.0.3",
|
"@types/redis-info": "3.0.3",
|
||||||
"accepts": "1.3.8",
|
"accepts": "1.3.8",
|
||||||
@@ -105,12 +104,11 @@
|
|||||||
"bcryptjs": "3.0.3",
|
"bcryptjs": "3.0.3",
|
||||||
"blurhash": "2.0.5",
|
"blurhash": "2.0.5",
|
||||||
"body-parser": "2.2.1",
|
"body-parser": "2.2.1",
|
||||||
"bullmq": "5.65.0",
|
"bullmq": "5.66.3",
|
||||||
"cacheable-lookup": "7.0.0",
|
"cacheable-lookup": "7.0.0",
|
||||||
"cbor": "10.0.11",
|
|
||||||
"chalk": "5.6.2",
|
"chalk": "5.6.2",
|
||||||
"chalk-template": "1.1.2",
|
"chalk-template": "1.1.2",
|
||||||
"chokidar": "4.0.3",
|
"chokidar": "5.0.0",
|
||||||
"color-convert": "3.1.3",
|
"color-convert": "3.1.3",
|
||||||
"content-disposition": "1.0.1",
|
"content-disposition": "1.0.1",
|
||||||
"date-fns": "4.1.0",
|
"date-fns": "4.1.0",
|
||||||
@@ -118,7 +116,7 @@
|
|||||||
"fastify": "5.6.2",
|
"fastify": "5.6.2",
|
||||||
"fastify-raw-body": "5.0.0",
|
"fastify-raw-body": "5.0.0",
|
||||||
"feed": "5.1.0",
|
"feed": "5.1.0",
|
||||||
"file-type": "21.1.1",
|
"file-type": "21.2.0",
|
||||||
"fluent-ffmpeg": "2.1.3",
|
"fluent-ffmpeg": "2.1.3",
|
||||||
"form-data": "4.0.5",
|
"form-data": "4.0.5",
|
||||||
"got": "14.6.5",
|
"got": "14.6.5",
|
||||||
@@ -131,7 +129,6 @@
|
|||||||
"is-svg": "6.1.0",
|
"is-svg": "6.1.0",
|
||||||
"json5": "2.2.3",
|
"json5": "2.2.3",
|
||||||
"jsonld": "9.0.0",
|
"jsonld": "9.0.0",
|
||||||
"jsrsasign": "11.1.0",
|
|
||||||
"juice": "11.0.3",
|
"juice": "11.0.3",
|
||||||
"meilisearch": "0.54.0",
|
"meilisearch": "0.54.0",
|
||||||
"mfm-js": "0.25.0",
|
"mfm-js": "0.25.0",
|
||||||
@@ -143,9 +140,8 @@
|
|||||||
"nested-property": "4.0.0",
|
"nested-property": "4.0.0",
|
||||||
"node-fetch": "3.3.2",
|
"node-fetch": "3.3.2",
|
||||||
"node-html-parser": "7.0.1",
|
"node-html-parser": "7.0.1",
|
||||||
"nodemailer": "7.0.11",
|
"nodemailer": "7.0.12",
|
||||||
"nsfwjs": "4.2.0",
|
"nsfwjs": "4.2.0",
|
||||||
"oauth": "0.10.2",
|
|
||||||
"oauth2orize": "1.12.0",
|
"oauth2orize": "1.12.0",
|
||||||
"oauth2orize-pkce": "0.1.2",
|
"oauth2orize-pkce": "0.1.2",
|
||||||
"os-utils": "0.0.14",
|
"os-utils": "0.0.14",
|
||||||
@@ -157,7 +153,7 @@
|
|||||||
"qrcode": "1.5.4",
|
"qrcode": "1.5.4",
|
||||||
"random-seed": "0.3.0",
|
"random-seed": "0.3.0",
|
||||||
"ratelimiter": "3.4.1",
|
"ratelimiter": "3.4.1",
|
||||||
"re2": "1.22.3",
|
"re2": "1.23.0",
|
||||||
"redis-info": "3.1.0",
|
"redis-info": "3.1.0",
|
||||||
"reflect-metadata": "0.2.2",
|
"reflect-metadata": "0.2.2",
|
||||||
"rename": "1.0.4",
|
"rename": "1.0.4",
|
||||||
@@ -170,14 +166,12 @@
|
|||||||
"slacc": "0.0.10",
|
"slacc": "0.0.10",
|
||||||
"strict-event-emitter-types": "2.0.0",
|
"strict-event-emitter-types": "2.0.0",
|
||||||
"stringz": "2.1.0",
|
"stringz": "2.1.0",
|
||||||
"systeminformation": "5.27.11",
|
"systeminformation": "5.28.1",
|
||||||
"tinycolor2": "1.6.0",
|
"tinycolor2": "1.6.0",
|
||||||
"tmp": "0.2.5",
|
"tmp": "0.2.5",
|
||||||
"tsc-alias": "1.8.16",
|
"tsc-alias": "1.8.16",
|
||||||
"tsconfig-paths": "4.2.0",
|
"typeorm": "0.3.28",
|
||||||
"typeorm": "0.3.27",
|
"ulid": "3.0.2",
|
||||||
"typescript": "5.9.3",
|
|
||||||
"ulid": "3.0.1",
|
|
||||||
"vary": "1.1.2",
|
"vary": "1.1.2",
|
||||||
"web-push": "3.6.7",
|
"web-push": "3.6.7",
|
||||||
"ws": "8.18.3",
|
"ws": "8.18.3",
|
||||||
@@ -186,8 +180,8 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@jest/globals": "29.7.0",
|
"@jest/globals": "29.7.0",
|
||||||
"@kitajs/ts-html-plugin": "4.1.3",
|
"@kitajs/ts-html-plugin": "4.1.3",
|
||||||
"@nestjs/platform-express": "11.1.9",
|
"@nestjs/platform-express": "11.1.10",
|
||||||
"@sentry/vue": "10.27.0",
|
"@sentry/vue": "10.32.1",
|
||||||
"@simplewebauthn/types": "12.0.0",
|
"@simplewebauthn/types": "12.0.0",
|
||||||
"@swc/jest": "0.2.39",
|
"@swc/jest": "0.2.39",
|
||||||
"@types/accepts": "1.3.7",
|
"@types/accepts": "1.3.7",
|
||||||
@@ -199,22 +193,20 @@
|
|||||||
"@types/http-link-header": "1.0.7",
|
"@types/http-link-header": "1.0.7",
|
||||||
"@types/jest": "29.5.14",
|
"@types/jest": "29.5.14",
|
||||||
"@types/jsonld": "1.5.15",
|
"@types/jsonld": "1.5.15",
|
||||||
"@types/jsrsasign": "10.5.15",
|
|
||||||
"@types/mime-types": "3.0.1",
|
"@types/mime-types": "3.0.1",
|
||||||
"@types/ms": "2.1.0",
|
"@types/ms": "2.1.0",
|
||||||
"@types/node": "24.10.1",
|
"@types/node": "24.10.4",
|
||||||
"@types/nodemailer": "7.0.4",
|
"@types/nodemailer": "7.0.4",
|
||||||
"@types/oauth": "0.9.6",
|
|
||||||
"@types/oauth2orize": "1.11.5",
|
"@types/oauth2orize": "1.11.5",
|
||||||
"@types/oauth2orize-pkce": "0.1.2",
|
"@types/oauth2orize-pkce": "0.1.2",
|
||||||
"@types/pg": "8.15.6",
|
"@types/pg": "8.16.0",
|
||||||
"@types/qrcode": "1.5.6",
|
"@types/qrcode": "1.5.6",
|
||||||
"@types/random-seed": "0.3.5",
|
"@types/random-seed": "0.3.5",
|
||||||
"@types/ratelimiter": "3.4.6",
|
"@types/ratelimiter": "3.4.6",
|
||||||
"@types/rename": "1.0.7",
|
"@types/rename": "1.0.7",
|
||||||
"@types/sanitize-html": "2.16.0",
|
"@types/sanitize-html": "2.16.0",
|
||||||
"@types/semver": "7.7.1",
|
"@types/semver": "7.7.1",
|
||||||
"@types/simple-oauth2": "5.0.7",
|
"@types/simple-oauth2": "5.0.8",
|
||||||
"@types/sinonjs__fake-timers": "15.0.1",
|
"@types/sinonjs__fake-timers": "15.0.1",
|
||||||
"@types/supertest": "6.0.3",
|
"@types/supertest": "6.0.3",
|
||||||
"@types/tinycolor2": "1.4.6",
|
"@types/tinycolor2": "1.4.6",
|
||||||
@@ -222,21 +214,22 @@
|
|||||||
"@types/vary": "1.1.3",
|
"@types/vary": "1.1.3",
|
||||||
"@types/web-push": "3.6.4",
|
"@types/web-push": "3.6.4",
|
||||||
"@types/ws": "8.18.1",
|
"@types/ws": "8.18.1",
|
||||||
"@typescript-eslint/eslint-plugin": "8.48.0",
|
"@typescript-eslint/eslint-plugin": "8.50.1",
|
||||||
"@typescript-eslint/parser": "8.48.0",
|
"@typescript-eslint/parser": "8.50.1",
|
||||||
"aws-sdk-client-mock": "4.1.0",
|
"aws-sdk-client-mock": "4.1.0",
|
||||||
|
"cbor": "10.0.11",
|
||||||
"cross-env": "10.1.0",
|
"cross-env": "10.1.0",
|
||||||
|
"esbuild-plugin-swc": "1.0.1",
|
||||||
"eslint-plugin-import": "2.32.0",
|
"eslint-plugin-import": "2.32.0",
|
||||||
"execa": "9.6.0",
|
"execa": "9.6.1",
|
||||||
"fkill": "10.0.1",
|
"fkill": "10.0.1",
|
||||||
"jest": "29.7.0",
|
"jest": "29.7.0",
|
||||||
"jest-mock": "29.7.0",
|
"jest-mock": "29.7.0",
|
||||||
"jest-util": "29.7.0",
|
|
||||||
"js-yaml": "4.1.1",
|
"js-yaml": "4.1.1",
|
||||||
"nodemon": "3.1.11",
|
"nodemon": "3.1.11",
|
||||||
"pid-port": "2.0.0",
|
"pid-port": "2.0.0",
|
||||||
"simple-oauth2": "5.1.0",
|
"simple-oauth2": "5.1.0",
|
||||||
"supertest": "7.1.4",
|
"supertest": "7.1.4",
|
||||||
"vite": "7.2.4"
|
"vite": "7.3.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import Redis from 'ioredis';
|
import Redis from 'ioredis';
|
||||||
import { loadConfig } from '../built/config.js';
|
import { loadConfig } from '../src-js/config.js';
|
||||||
import { createPostgresDataSource } from '../built/postgres.js';
|
import { createPostgresDataSource } from '../src-js/postgres.js';
|
||||||
|
|
||||||
const config = loadConfig();
|
const config = loadConfig();
|
||||||
|
|
||||||
@@ -16,26 +16,22 @@ async function connectToPostgres() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function connectToRedis(redisOptions) {
|
async function connectToRedis(redisOptions) {
|
||||||
return await new Promise(async (resolve, reject) => {
|
let redis;
|
||||||
const redis = new Redis({
|
try {
|
||||||
|
redis = new Redis({
|
||||||
...redisOptions,
|
...redisOptions,
|
||||||
lazyConnect: true,
|
lazyConnect: true,
|
||||||
reconnectOnError: false,
|
reconnectOnError: false,
|
||||||
showFriendlyErrorStack: true,
|
showFriendlyErrorStack: true,
|
||||||
});
|
});
|
||||||
redis.on('error', e => reject(e));
|
|
||||||
|
|
||||||
try {
|
await Promise.race([
|
||||||
await redis.connect();
|
new Promise((_, reject) => redis.on('error', e => reject(e))),
|
||||||
resolve();
|
redis.connect(),
|
||||||
|
]);
|
||||||
} catch (e) {
|
} finally {
|
||||||
reject(e);
|
redis.disconnect(false);
|
||||||
|
}
|
||||||
} finally {
|
|
||||||
redis.disconnect(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not all of these are defined, the default one gets reused.
|
// If not all of these are defined, the default one gets reused.
|
||||||
@@ -50,7 +46,7 @@ const promises = Array
|
|||||||
]))
|
]))
|
||||||
.map(connectToRedis)
|
.map(connectToRedis)
|
||||||
.concat([
|
.concat([
|
||||||
connectToPostgres()
|
connectToPostgres(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { writeFileSync, existsSync } from 'node:fs';
|
||||||
import { execa } from 'execa';
|
import { execa } from 'execa';
|
||||||
import { writeFileSync, existsSync } from "node:fs";
|
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
if (!process.argv.includes('--no-build')) {
|
if (!process.argv.includes('--no-build')) {
|
||||||
@@ -19,10 +19,10 @@ async function main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @type {import('../src/config.js')} */
|
/** @type {import('../src/config.js')} */
|
||||||
const { loadConfig } = await import('../built/config.js');
|
const { loadConfig } = await import('../src-js/config.js');
|
||||||
|
|
||||||
/** @type {import('../src/server/api/openapi/gen-spec.js')} */
|
/** @type {import('../src/server/api/openapi/gen-spec.js')} */
|
||||||
const { genOpenapiSpec } = await import('../built/server/api/openapi/gen-spec.js');
|
const { genOpenapiSpec } = await import('../src-js/server/api/openapi/gen-spec.js');
|
||||||
|
|
||||||
const config = loadConfig();
|
const config = loadConfig();
|
||||||
const spec = genOpenapiSpec(config, true);
|
const spec = genOpenapiSpec(config, true);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import { execa } from 'execa';
|
|||||||
});
|
});
|
||||||
}, 3000);
|
}, 3000);
|
||||||
|
|
||||||
execa('tsc', ['-w', '-p', 'tsconfig.json'], {
|
execa('tsgo', ['-w', '-p', 'tsconfig.json'], {
|
||||||
stdout: process.stdout,
|
stdout: process.stdout,
|
||||||
stderr: process.stderr,
|
stderr: process.stderr,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as fs from 'node:fs';
|
import * as fs from 'node:fs';
|
||||||
import { fileURLToPath } from 'node:url';
|
|
||||||
import { dirname } from 'node:path';
|
|
||||||
import * as os from 'node:os';
|
import * as os from 'node:os';
|
||||||
import cluster from 'node:cluster';
|
import cluster from 'node:cluster';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
@@ -17,20 +15,15 @@ import { showMachineInfo } from '@/misc/show-machine-info.js';
|
|||||||
import { envOption } from '@/env.js';
|
import { envOption } from '@/env.js';
|
||||||
import { jobQueue, server } from './common.js';
|
import { jobQueue, server } from './common.js';
|
||||||
|
|
||||||
const _filename = fileURLToPath(import.meta.url);
|
|
||||||
const _dirname = dirname(_filename);
|
|
||||||
|
|
||||||
const meta = JSON.parse(fs.readFileSync(`${_dirname}/../../../../built/meta.json`, 'utf-8'));
|
|
||||||
|
|
||||||
const logger = new Logger('core', 'cyan');
|
const logger = new Logger('core', 'cyan');
|
||||||
const bootLogger = logger.createSubLogger('boot', 'magenta');
|
const bootLogger = logger.createSubLogger('boot', 'magenta');
|
||||||
|
|
||||||
const themeColor = chalk.hex('#86b300');
|
const themeColor = chalk.hex('#86b300');
|
||||||
|
|
||||||
function greet() {
|
function greet(props: { version: string }) {
|
||||||
if (!envOption.quiet) {
|
if (!envOption.quiet) {
|
||||||
//#region Misskey logo
|
//#region Misskey logo
|
||||||
const v = `v${meta.version}`;
|
const v = `v${props.version}`;
|
||||||
console.log(themeColor(' _____ _ _ '));
|
console.log(themeColor(' _____ _ _ '));
|
||||||
console.log(themeColor(' | |_|___ ___| |_ ___ _ _ '));
|
console.log(themeColor(' | |_|___ ___| |_ ___ _ _ '));
|
||||||
console.log(themeColor(' | | | | |_ -|_ -| \'_| -_| | |'));
|
console.log(themeColor(' | | | | |_ -|_ -| \'_| -_| | |'));
|
||||||
@@ -46,7 +39,7 @@ function greet() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bootLogger.info('Welcome to Misskey!');
|
bootLogger.info('Welcome to Misskey!');
|
||||||
bootLogger.info(`Misskey v${meta.version}`, null, true);
|
bootLogger.info(`Misskey v${props.version}`, null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -57,15 +50,15 @@ export async function masterMain() {
|
|||||||
|
|
||||||
// initialize app
|
// initialize app
|
||||||
try {
|
try {
|
||||||
greet();
|
config = loadConfigBoot();
|
||||||
|
greet({ version: config.version });
|
||||||
showEnvironment();
|
showEnvironment();
|
||||||
await showMachineInfo(bootLogger);
|
await showMachineInfo(bootLogger);
|
||||||
showNodejsVersion();
|
showNodejsVersion();
|
||||||
config = loadConfigBoot();
|
|
||||||
//await connectDb();
|
//await connectDb();
|
||||||
if (config.pidFile) fs.writeFileSync(config.pidFile, process.pid.toString());
|
if (config.pidFile) fs.writeFileSync(config.pidFile, process.pid.toString());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
bootLogger.error('Fatal error occurred during initialization', null, true);
|
bootLogger.error('Fatal error occurred during initialization: ' + e, null, true);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ type Source = {
|
|||||||
socket?: string;
|
socket?: string;
|
||||||
trustProxy?: FastifyServerOptions['trustProxy'];
|
trustProxy?: FastifyServerOptions['trustProxy'];
|
||||||
chmodSocket?: string;
|
chmodSocket?: string;
|
||||||
|
enableIpRateLimit?: boolean;
|
||||||
disableHsts?: boolean;
|
disableHsts?: boolean;
|
||||||
db: {
|
db: {
|
||||||
host: string;
|
host: string;
|
||||||
@@ -120,8 +121,9 @@ export type Config = {
|
|||||||
url: string;
|
url: string;
|
||||||
port: number;
|
port: number;
|
||||||
socket: string | undefined;
|
socket: string | undefined;
|
||||||
trustProxy: FastifyServerOptions['trustProxy'];
|
trustProxy: NonNullable<FastifyServerOptions['trustProxy']>;
|
||||||
chmodSocket: string | undefined;
|
chmodSocket: string | undefined;
|
||||||
|
enableIpRateLimit: boolean;
|
||||||
disableHsts: boolean | undefined;
|
disableHsts: boolean | undefined;
|
||||||
db: {
|
db: {
|
||||||
host: string;
|
host: string;
|
||||||
@@ -217,24 +219,42 @@ export type FulltextSearchProvider = 'sqlLike' | 'sqlPgroonga' | 'meilisearch';
|
|||||||
const _filename = fileURLToPath(import.meta.url);
|
const _filename = fileURLToPath(import.meta.url);
|
||||||
const _dirname = dirname(_filename);
|
const _dirname = dirname(_filename);
|
||||||
|
|
||||||
const compiledConfigFilePathForTest = resolve(_dirname, '../../../built/._config_.json');
|
/** Path of repository root directory */
|
||||||
|
let rootDir = _dirname;
|
||||||
|
// 見つかるまで上に遡る
|
||||||
|
while (!fs.existsSync(resolve(rootDir, 'packages'))) {
|
||||||
|
const parentDir = dirname(rootDir);
|
||||||
|
if (parentDir === rootDir) {
|
||||||
|
throw new Error('Cannot find root directory');
|
||||||
|
}
|
||||||
|
rootDir = parentDir;
|
||||||
|
}
|
||||||
|
|
||||||
export const compiledConfigFilePath = fs.existsSync(compiledConfigFilePathForTest) ? compiledConfigFilePathForTest : resolve(_dirname, '../../../built/.config.json');
|
/** Path of configuration directory */
|
||||||
|
const configDir = resolve(rootDir, '.config');
|
||||||
|
/** Path of built directory */
|
||||||
|
const projectBuiltDir = resolve(rootDir, 'built');
|
||||||
|
|
||||||
|
const compiledConfigFilePathForTest = resolve(projectBuiltDir, '._config_.json');
|
||||||
|
|
||||||
|
export const compiledConfigFilePath = fs.existsSync(compiledConfigFilePathForTest)
|
||||||
|
? compiledConfigFilePathForTest
|
||||||
|
: resolve(projectBuiltDir, '.config.json');
|
||||||
|
|
||||||
export function loadConfig(): Config {
|
export function loadConfig(): Config {
|
||||||
if (!fs.existsSync(compiledConfigFilePath)) {
|
if (!fs.existsSync(compiledConfigFilePath)) {
|
||||||
throw new Error('Compiled configuration file not found. Try running \'pnpm compile-config\'.');
|
throw new Error('Compiled configuration file not found. Try running \'pnpm compile-config\'.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const meta = JSON.parse(fs.readFileSync(`${_dirname}/../../../built/meta.json`, 'utf-8'));
|
const meta = JSON.parse(fs.readFileSync(resolve(projectBuiltDir, 'meta.json'), 'utf-8'));
|
||||||
|
|
||||||
const frontendManifestExists = fs.existsSync(_dirname + '/../../../built/_frontend_vite_/manifest.json');
|
const frontendManifestExists = fs.existsSync(resolve(projectBuiltDir, '_frontend_vite_/manifest.json'));
|
||||||
const frontendEmbedManifestExists = fs.existsSync(_dirname + '/../../../built/_frontend_embed_vite_/manifest.json');
|
const frontendEmbedManifestExists = fs.existsSync(resolve(projectBuiltDir, '_frontend_embed_vite_/manifest.json'));
|
||||||
const frontendManifest = frontendManifestExists ?
|
const frontendManifest = frontendManifestExists ?
|
||||||
JSON.parse(fs.readFileSync(`${_dirname}/../../../built/_frontend_vite_/manifest.json`, 'utf-8'))
|
JSON.parse(fs.readFileSync(resolve(projectBuiltDir, '_frontend_vite_/manifest.json'), 'utf-8'))
|
||||||
: { 'src/_boot_.ts': { file: null } };
|
: { 'src/_boot_.ts': { file: null } };
|
||||||
const frontendEmbedManifest = frontendEmbedManifestExists ?
|
const frontendEmbedManifest = frontendEmbedManifestExists ?
|
||||||
JSON.parse(fs.readFileSync(`${_dirname}/../../../built/_frontend_embed_vite_/manifest.json`, 'utf-8'))
|
JSON.parse(fs.readFileSync(resolve(projectBuiltDir, '_frontend_embed_vite_/manifest.json'), 'utf-8'))
|
||||||
: { 'src/boot.ts': { file: null } };
|
: { 'src/boot.ts': { file: null } };
|
||||||
|
|
||||||
const config = JSON.parse(fs.readFileSync(compiledConfigFilePath, 'utf-8')) as Source;
|
const config = JSON.parse(fs.readFileSync(compiledConfigFilePath, 'utf-8')) as Source;
|
||||||
@@ -263,9 +283,17 @@ export function loadConfig(): Config {
|
|||||||
url: url.origin,
|
url: url.origin,
|
||||||
port: config.port ?? parseInt(process.env.PORT ?? '', 10),
|
port: config.port ?? parseInt(process.env.PORT ?? '', 10),
|
||||||
socket: config.socket,
|
socket: config.socket,
|
||||||
trustProxy: config.trustProxy,
|
trustProxy: config.trustProxy ?? [
|
||||||
|
'10.0.0.0/8',
|
||||||
|
'172.16.0.0/12',
|
||||||
|
'192.168.0.0/16',
|
||||||
|
'127.0.0.1/32',
|
||||||
|
'::1/128',
|
||||||
|
'fc00::/7',
|
||||||
|
],
|
||||||
chmodSocket: config.chmodSocket,
|
chmodSocket: config.chmodSocket,
|
||||||
disableHsts: config.disableHsts,
|
disableHsts: config.disableHsts,
|
||||||
|
enableIpRateLimit: config.enableIpRateLimit ?? true,
|
||||||
host,
|
host,
|
||||||
hostname,
|
hostname,
|
||||||
scheme,
|
scheme,
|
||||||
@@ -324,7 +352,7 @@ export function loadConfig(): Config {
|
|||||||
function tryCreateUrl(url: string) {
|
function tryCreateUrl(url: string) {
|
||||||
try {
|
try {
|
||||||
return new URL(url);
|
return new URL(url);
|
||||||
} catch (e) {
|
} catch (_) {
|
||||||
throw new Error(`url="${url}" is not a valid URL.`);
|
throw new Error(`url="${url}" is not a valid URL.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ export class AccountMoveService {
|
|||||||
*/
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
public async moveFromLocal(src: MiLocalUser, dst: MiLocalUser | MiRemoteUser): Promise<unknown> {
|
public async moveFromLocal(src: MiLocalUser, dst: MiLocalUser | MiRemoteUser): Promise<unknown> {
|
||||||
const srcUri = this.userEntityService.getUserUri(src);
|
const _srcUri = this.userEntityService.getUserUri(src);
|
||||||
const dstUri = this.userEntityService.getUserUri(dst);
|
const dstUri = this.userEntityService.getUserUri(dst);
|
||||||
|
|
||||||
// add movedToUri to indicate that the user has moved
|
// add movedToUri to indicate that the user has moved
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import * as fs from 'node:fs';
|
|||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import { dirname } from 'node:path';
|
import { dirname } from 'node:path';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import si from 'systeminformation';
|
|
||||||
import { Mutex } from 'async-mutex';
|
import { Mutex } from 'async-mutex';
|
||||||
import fetch from 'node-fetch';
|
import fetch from 'node-fetch';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
@@ -84,6 +83,7 @@ export class AiService {
|
|||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async getCpuFlags(): Promise<string[]> {
|
private async getCpuFlags(): Promise<string[]> {
|
||||||
|
const si = await import('systeminformation');
|
||||||
const str = await si.cpuFlags();
|
const str = await si.cpuFlags();
|
||||||
return str.split(/\s+/);
|
return str.split(/\s+/);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ export class AnnouncementService {
|
|||||||
announcementId: announcementId,
|
announcementId: announcementId,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export class AvatarDecorationService implements OnApplicationShutdown {
|
|||||||
const obj = JSON.parse(data);
|
const obj = JSON.parse(data);
|
||||||
|
|
||||||
if (obj.channel === 'internal') {
|
if (obj.channel === 'internal') {
|
||||||
const { type, body } = obj.message as GlobalEvents['internal']['payload'];
|
const { type, body: _ } = obj.message as GlobalEvents['internal']['payload'];
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'avatarDecorationCreated':
|
case 'avatarDecorationCreated':
|
||||||
case 'avatarDecorationUpdated':
|
case 'avatarDecorationUpdated':
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ import { ApLoggerService } from './activitypub/ApLoggerService.js';
|
|||||||
import { ApMfmService } from './activitypub/ApMfmService.js';
|
import { ApMfmService } from './activitypub/ApMfmService.js';
|
||||||
import { ApRendererService } from './activitypub/ApRendererService.js';
|
import { ApRendererService } from './activitypub/ApRendererService.js';
|
||||||
import { ApRequestService } from './activitypub/ApRequestService.js';
|
import { ApRequestService } from './activitypub/ApRequestService.js';
|
||||||
import { ApResolverService } from './activitypub/ApResolverService.js';
|
import { ApResolverService, Resolver } from './activitypub/ApResolverService.js';
|
||||||
import { JsonLdService } from './activitypub/JsonLdService.js';
|
import { JsonLdService } from './activitypub/JsonLdService.js';
|
||||||
import { RemoteLoggerService } from './RemoteLoggerService.js';
|
import { RemoteLoggerService } from './RemoteLoggerService.js';
|
||||||
import { RemoteUserResolveService } from './RemoteUserResolveService.js';
|
import { RemoteUserResolveService } from './RemoteUserResolveService.js';
|
||||||
@@ -447,6 +447,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
|||||||
ApRendererService,
|
ApRendererService,
|
||||||
ApRequestService,
|
ApRequestService,
|
||||||
ApResolverService,
|
ApResolverService,
|
||||||
|
Resolver,
|
||||||
JsonLdService,
|
JsonLdService,
|
||||||
RemoteLoggerService,
|
RemoteLoggerService,
|
||||||
RemoteUserResolveService,
|
RemoteUserResolveService,
|
||||||
@@ -745,6 +746,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
|||||||
ApRendererService,
|
ApRendererService,
|
||||||
ApRequestService,
|
ApRequestService,
|
||||||
ApResolverService,
|
ApResolverService,
|
||||||
|
Resolver,
|
||||||
JsonLdService,
|
JsonLdService,
|
||||||
RemoteLoggerService,
|
RemoteLoggerService,
|
||||||
RemoteUserResolveService,
|
RemoteUserResolveService,
|
||||||
|
|||||||
@@ -366,7 +366,7 @@ export class EmailService {
|
|||||||
valid: true,
|
valid: true,
|
||||||
reason: null,
|
reason: null,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (_) {
|
||||||
return {
|
return {
|
||||||
valid: false,
|
valid: false,
|
||||||
reason: 'network',
|
reason: 'network',
|
||||||
|
|||||||
@@ -484,25 +484,13 @@ export class FileInfoService {
|
|||||||
* Calculate blurhash string of image
|
* Calculate blurhash string of image
|
||||||
*/
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
private getBlurhash(path: string, type: string): Promise<string> {
|
private async getBlurhash(path: string, type: string): Promise<string> {
|
||||||
return new Promise(async (resolve, reject) => {
|
const sharp = await sharpBmp(path, type);
|
||||||
(await sharpBmp(path, type))
|
const { data: buffer, info } = await sharp
|
||||||
.raw()
|
.raw()
|
||||||
.ensureAlpha()
|
.ensureAlpha()
|
||||||
.resize(64, 64, { fit: 'inside' })
|
.resize(64, 64, { fit: 'inside' })
|
||||||
.toBuffer((err, buffer, info) => {
|
.toBuffer({ resolveWithObject: true });
|
||||||
if (err) return reject(err);
|
return blurhash.encode(new Uint8ClampedArray(buffer), info.width, info.height, 5, 5);
|
||||||
|
|
||||||
let hash;
|
|
||||||
|
|
||||||
try {
|
|
||||||
hash = blurhash.encode(new Uint8ClampedArray(buffer), info.width, info.height, 5, 5);
|
|
||||||
} catch (e) {
|
|
||||||
return reject(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(hash);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,11 +38,7 @@ export interface BroadcastTypes {
|
|||||||
emojis: Packed<'EmojiDetailed'>[];
|
emojis: Packed<'EmojiDetailed'>[];
|
||||||
};
|
};
|
||||||
emojiDeleted: {
|
emojiDeleted: {
|
||||||
emojis: {
|
emojis: Packed<'EmojiDetailed'>[];
|
||||||
id?: string;
|
|
||||||
name: string;
|
|
||||||
[other: string]: any;
|
|
||||||
}[];
|
|
||||||
};
|
};
|
||||||
announcementCreated: {
|
announcementCreated: {
|
||||||
announcement: Packed<'Announcement'>;
|
announcement: Packed<'Announcement'>;
|
||||||
|
|||||||
@@ -308,7 +308,7 @@ export class MfmService {
|
|||||||
try {
|
try {
|
||||||
const date = new Date(parseInt(text, 10) * 1000);
|
const date = new Date(parseInt(text, 10) * 1000);
|
||||||
return `<time datetime="${escapeHtml(date.toISOString())}">${escapeHtml(date.toISOString())}</time>`;
|
return `<time datetime="${escapeHtml(date.toISOString())}">${escapeHtml(date.toISOString())}</time>`;
|
||||||
} catch (err) {
|
} catch (_) {
|
||||||
return fnDefault(node);
|
return fnDefault(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -376,7 +376,7 @@ export class MfmService {
|
|||||||
try {
|
try {
|
||||||
const url = new URL(node.props.url);
|
const url = new URL(node.props.url);
|
||||||
return `<a href="${escapeHtml(url.href)}">${toHtml(node.children)}</a>`;
|
return `<a href="${escapeHtml(url.href)}">${toHtml(node.children)}</a>`;
|
||||||
} catch (err) {
|
} catch (_) {
|
||||||
return `[${toHtml(node.children)}](${escapeHtml(node.props.url)})`;
|
return `[${toHtml(node.children)}](${escapeHtml(node.props.url)})`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -390,7 +390,7 @@ export class MfmService {
|
|||||||
try {
|
try {
|
||||||
const url = new URL(href);
|
const url = new URL(href);
|
||||||
return `<a href="${escapeHtml(url.href)}" class="u-url mention">${escapeHtml(acct)}</a>`;
|
return `<a href="${escapeHtml(url.href)}" class="u-url mention">${escapeHtml(acct)}</a>`;
|
||||||
} catch (err) {
|
} catch (_) {
|
||||||
return escapeHtml(acct);
|
return escapeHtml(acct);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -419,7 +419,7 @@ export class MfmService {
|
|||||||
try {
|
try {
|
||||||
const url = new URL(node.props.url);
|
const url = new URL(node.props.url);
|
||||||
return `<a href="${escapeHtml(url.href)}">${escapeHtml(node.props.url)}</a>`;
|
return `<a href="${escapeHtml(url.href)}">${escapeHtml(node.props.url)}</a>`;
|
||||||
} catch (err) {
|
} catch (_) {
|
||||||
return escapeHtml(node.props.url);
|
return escapeHtml(node.props.url);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -187,9 +187,9 @@ export class NoteDraftService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//#region visibleUsers
|
//#region visibleUsers
|
||||||
let visibleUsers: MiUser[] = [];
|
let _visibleUsers: MiUser[] = [];
|
||||||
if (data.visibleUserIds != null && data.visibleUserIds.length > 0) {
|
if (data.visibleUserIds != null && data.visibleUserIds.length > 0) {
|
||||||
visibleUsers = await this.usersRepository.findBy({
|
_visibleUsers = await this.usersRepository.findBy({
|
||||||
id: In(data.visibleUserIds),
|
id: In(data.visibleUserIds),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -314,7 +314,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
|
|||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (_) {
|
||||||
// TODO: log error
|
// TODO: log error
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -190,8 +190,7 @@ export class SearchService {
|
|||||||
return this.searchNoteByMeiliSearch(q, me, opts, pagination);
|
return this.searchNoteByMeiliSearch(q, me, opts, pagination);
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
const _: never = this.provider;
|
||||||
const typeCheck: never = this.provider;
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ export class UserSuspendService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
await this.postSuspend(user).catch(e => {});
|
await this.postSuspend(user).catch(_ => {});
|
||||||
await this.unFollowAll(user).catch(e => {});
|
await this.unFollowAll(user).catch(_ => {});
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ export class UserSuspendService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
await this.postUnsuspend(user).catch(e => {});
|
await this.postUnsuspend(user).catch(_ => {});
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ export class UtilityService {
|
|||||||
try {
|
try {
|
||||||
// TODO: RE2インスタンスをキャッシュ
|
// TODO: RE2インスタンスをキャッシュ
|
||||||
return new RE2(regexp[1], regexp[2]).test(text);
|
return new RE2(regexp[1], regexp[2]).test(text);
|
||||||
} catch (err) {
|
} catch (_) {
|
||||||
// This should never happen due to input sanitisation.
|
// This should never happen due to input sanitisation.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ export class ApInboxService {
|
|||||||
if (isCollectionOrOrderedCollection(activity)) {
|
if (isCollectionOrOrderedCollection(activity)) {
|
||||||
const results = [] as [string, string | void][];
|
const results = [] as [string, string | void][];
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
resolver ??= this.apResolverService.createResolver();
|
resolver ??= await this.apResolverService.createResolver();
|
||||||
|
|
||||||
const items = toArray(isCollection(activity) ? activity.items : activity.orderedItems);
|
const items = toArray(isCollection(activity) ? activity.items : activity.orderedItems);
|
||||||
if (items.length >= resolver.getRecursionLimit()) {
|
if (items.length >= resolver.getRecursionLimit()) {
|
||||||
@@ -221,7 +221,7 @@ export class ApInboxService {
|
|||||||
this.logger.info(`Accept: ${uri}`);
|
this.logger.info(`Accept: ${uri}`);
|
||||||
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
resolver ??= this.apResolverService.createResolver();
|
resolver ??= await this.apResolverService.createResolver();
|
||||||
|
|
||||||
const object = await resolver.resolve(activity.object).catch(err => {
|
const object = await resolver.resolve(activity.object).catch(err => {
|
||||||
this.logger.error(`Resolution failed: ${err}`);
|
this.logger.error(`Resolution failed: ${err}`);
|
||||||
@@ -284,7 +284,7 @@ export class ApInboxService {
|
|||||||
this.logger.info(`Announce: ${uri}`);
|
this.logger.info(`Announce: ${uri}`);
|
||||||
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
resolver ??= this.apResolverService.createResolver();
|
resolver ??= await this.apResolverService.createResolver();
|
||||||
|
|
||||||
if (!activity.object) return 'skip: activity has no object property';
|
if (!activity.object) return 'skip: activity has no object property';
|
||||||
const targetUri = getApId(activity.object);
|
const targetUri = getApId(activity.object);
|
||||||
@@ -406,7 +406,7 @@ export class ApInboxService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
resolver ??= this.apResolverService.createResolver();
|
resolver ??= await this.apResolverService.createResolver();
|
||||||
|
|
||||||
const object = await resolver.resolve(activity.object).catch(e => {
|
const object = await resolver.resolve(activity.object).catch(e => {
|
||||||
this.logger.error(`Resolution failed: ${e}`);
|
this.logger.error(`Resolution failed: ${e}`);
|
||||||
@@ -575,7 +575,7 @@ export class ApInboxService {
|
|||||||
this.logger.info(`Reject: ${uri}`);
|
this.logger.info(`Reject: ${uri}`);
|
||||||
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
resolver ??= this.apResolverService.createResolver();
|
resolver ??= await this.apResolverService.createResolver();
|
||||||
|
|
||||||
const object = await resolver.resolve(activity.object).catch(e => {
|
const object = await resolver.resolve(activity.object).catch(e => {
|
||||||
this.logger.error(`Resolution failed: ${e}`);
|
this.logger.error(`Resolution failed: ${e}`);
|
||||||
@@ -642,7 +642,7 @@ export class ApInboxService {
|
|||||||
this.logger.info(`Undo: ${uri}`);
|
this.logger.info(`Undo: ${uri}`);
|
||||||
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
resolver ??= this.apResolverService.createResolver();
|
resolver ??= await this.apResolverService.createResolver();
|
||||||
|
|
||||||
const object = await resolver.resolve(activity.object).catch(e => {
|
const object = await resolver.resolve(activity.object).catch(e => {
|
||||||
this.logger.error(`Resolution failed: ${e}`);
|
this.logger.error(`Resolution failed: ${e}`);
|
||||||
@@ -774,7 +774,7 @@ export class ApInboxService {
|
|||||||
this.logger.debug('Update');
|
this.logger.debug('Update');
|
||||||
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
resolver ??= this.apResolverService.createResolver();
|
resolver ??= await this.apResolverService.createResolver();
|
||||||
|
|
||||||
const object = await resolver.resolve(activity.object).catch(e => {
|
const object = await resolver.resolve(activity.object).catch(e => {
|
||||||
this.logger.error(`Resolution failed: ${e}`);
|
this.logger.error(`Resolution failed: ${e}`);
|
||||||
|
|||||||
@@ -515,7 +515,7 @@ export class ApRendererService {
|
|||||||
const restPart = maybeUrl.slice(match[0].length);
|
const restPart = maybeUrl.slice(match[0].length);
|
||||||
|
|
||||||
return `<a href="${urlPartParsed.href}" rel="me nofollow noopener" target="_blank">${urlPart}</a>${restPart}`;
|
return `<a href="${urlPartParsed.href}" rel="me nofollow noopener" target="_blank">${urlPart}</a>${restPart}`;
|
||||||
} catch (e) {
|
} catch (_) {
|
||||||
return maybeUrl;
|
return maybeUrl;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ export class ApRequestService {
|
|||||||
return await this.signedGet(href, user, allowSoftfail, false);
|
return await this.signedGet(href, user, allowSoftfail, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (_) {
|
||||||
// something went wrong parsing the HTML, ignore the whole thing
|
// something went wrong parsing the HTML, ignore the whole thing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,17 @@
|
|||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable, Scope } from '@nestjs/common';
|
||||||
import { IsNull, Not } from 'typeorm';
|
import { IsNull, Not } from 'typeorm';
|
||||||
import type { MiLocalUser, MiRemoteUser } from '@/models/User.js';
|
import type { MiLocalUser, MiRemoteUser } from '@/models/User.js';
|
||||||
import type { NotesRepository, PollsRepository, NoteReactionsRepository, UsersRepository, FollowRequestsRepository, MiMeta } from '@/models/_.js';
|
import type {
|
||||||
|
FollowRequestsRepository,
|
||||||
|
MiMeta,
|
||||||
|
NoteReactionsRepository,
|
||||||
|
NotesRepository,
|
||||||
|
PollsRepository,
|
||||||
|
UsersRepository
|
||||||
|
} from '@/models/_.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
@@ -16,26 +23,43 @@ import { LoggerService } from '@/core/LoggerService.js';
|
|||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import { SystemAccountService } from '@/core/SystemAccountService.js';
|
import { SystemAccountService } from '@/core/SystemAccountService.js';
|
||||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||||
|
import type { ICollection, IObject, IOrderedCollection } from './type.js';
|
||||||
import { isCollectionOrOrderedCollection } from './type.js';
|
import { isCollectionOrOrderedCollection } from './type.js';
|
||||||
import { ApDbResolverService } from './ApDbResolverService.js';
|
import { ApDbResolverService } from './ApDbResolverService.js';
|
||||||
import { ApRendererService } from './ApRendererService.js';
|
import { ApRendererService } from './ApRendererService.js';
|
||||||
import { ApRequestService } from './ApRequestService.js';
|
import { ApRequestService } from './ApRequestService.js';
|
||||||
import { FetchAllowSoftFailMask } from './misc/check-against-url.js';
|
import { FetchAllowSoftFailMask } from './misc/check-against-url.js';
|
||||||
import type { IObject, ICollection, IOrderedCollection } from './type.js';
|
import { ModuleRef } from '@nestjs/core';
|
||||||
|
|
||||||
|
@Injectable({ scope: Scope.TRANSIENT })
|
||||||
export class Resolver {
|
export class Resolver {
|
||||||
private history: Set<string>;
|
private history: Set<string>;
|
||||||
private user?: MiLocalUser;
|
private user?: MiLocalUser;
|
||||||
private logger: Logger;
|
private logger: Logger;
|
||||||
|
private recursionLimit = 256;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@Inject(DI.config)
|
||||||
private config: Config,
|
private config: Config,
|
||||||
|
|
||||||
|
@Inject(DI.meta)
|
||||||
private meta: MiMeta,
|
private meta: MiMeta,
|
||||||
|
|
||||||
|
@Inject(DI.usersRepository)
|
||||||
private usersRepository: UsersRepository,
|
private usersRepository: UsersRepository,
|
||||||
|
|
||||||
|
@Inject(DI.notesRepository)
|
||||||
private notesRepository: NotesRepository,
|
private notesRepository: NotesRepository,
|
||||||
|
|
||||||
|
@Inject(DI.pollsRepository)
|
||||||
private pollsRepository: PollsRepository,
|
private pollsRepository: PollsRepository,
|
||||||
|
|
||||||
|
@Inject(DI.noteReactionsRepository)
|
||||||
private noteReactionsRepository: NoteReactionsRepository,
|
private noteReactionsRepository: NoteReactionsRepository,
|
||||||
|
|
||||||
|
@Inject(DI.followRequestsRepository)
|
||||||
private followRequestsRepository: FollowRequestsRepository,
|
private followRequestsRepository: FollowRequestsRepository,
|
||||||
|
|
||||||
private utilityService: UtilityService,
|
private utilityService: UtilityService,
|
||||||
private systemAccountService: SystemAccountService,
|
private systemAccountService: SystemAccountService,
|
||||||
private apRequestService: ApRequestService,
|
private apRequestService: ApRequestService,
|
||||||
@@ -43,7 +67,6 @@ export class Resolver {
|
|||||||
private apRendererService: ApRendererService,
|
private apRendererService: ApRendererService,
|
||||||
private apDbResolverService: ApDbResolverService,
|
private apDbResolverService: ApDbResolverService,
|
||||||
private loggerService: LoggerService,
|
private loggerService: LoggerService,
|
||||||
private recursionLimit = 256,
|
|
||||||
) {
|
) {
|
||||||
this.history = new Set();
|
this.history = new Set();
|
||||||
this.logger = this.loggerService.getLogger('ap-resolve');
|
this.logger = this.loggerService.getLogger('ap-resolve');
|
||||||
@@ -180,54 +203,12 @@ export class Resolver {
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class ApResolverService {
|
export class ApResolverService {
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(DI.config)
|
private moduleRef: ModuleRef,
|
||||||
private config: Config,
|
|
||||||
|
|
||||||
@Inject(DI.meta)
|
|
||||||
private meta: MiMeta,
|
|
||||||
|
|
||||||
@Inject(DI.usersRepository)
|
|
||||||
private usersRepository: UsersRepository,
|
|
||||||
|
|
||||||
@Inject(DI.notesRepository)
|
|
||||||
private notesRepository: NotesRepository,
|
|
||||||
|
|
||||||
@Inject(DI.pollsRepository)
|
|
||||||
private pollsRepository: PollsRepository,
|
|
||||||
|
|
||||||
@Inject(DI.noteReactionsRepository)
|
|
||||||
private noteReactionsRepository: NoteReactionsRepository,
|
|
||||||
|
|
||||||
@Inject(DI.followRequestsRepository)
|
|
||||||
private followRequestsRepository: FollowRequestsRepository,
|
|
||||||
|
|
||||||
private utilityService: UtilityService,
|
|
||||||
private systemAccountService: SystemAccountService,
|
|
||||||
private apRequestService: ApRequestService,
|
|
||||||
private httpRequestService: HttpRequestService,
|
|
||||||
private apRendererService: ApRendererService,
|
|
||||||
private apDbResolverService: ApDbResolverService,
|
|
||||||
private loggerService: LoggerService,
|
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public createResolver(): Resolver {
|
public async createResolver(): Promise<Resolver> {
|
||||||
return new Resolver(
|
return await this.moduleRef.create(Resolver);
|
||||||
this.config,
|
|
||||||
this.meta,
|
|
||||||
this.usersRepository,
|
|
||||||
this.notesRepository,
|
|
||||||
this.pollsRepository,
|
|
||||||
this.noteReactionsRepository,
|
|
||||||
this.followRequestsRepository,
|
|
||||||
this.utilityService,
|
|
||||||
this.systemAccountService,
|
|
||||||
this.apRequestService,
|
|
||||||
this.httpRequestService,
|
|
||||||
this.apRendererService,
|
|
||||||
this.apDbResolverService,
|
|
||||||
this.loggerService,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export class ApImageService {
|
|||||||
throw new Error('actor has been suspended');
|
throw new Error('actor has been suspended');
|
||||||
}
|
}
|
||||||
|
|
||||||
const image = await this.apResolverService.createResolver().resolve(value);
|
const image = await (await this.apResolverService.createResolver()).resolve(value);
|
||||||
|
|
||||||
if (!isDocument(image)) return null;
|
if (!isDocument(image)) return null;
|
||||||
|
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ export class ApNoteService {
|
|||||||
@bindThis
|
@bindThis
|
||||||
public async createNote(value: string | IObject, actor?: MiRemoteUser, resolver?: Resolver, silent = false): Promise<MiNote | null> {
|
public async createNote(value: string | IObject, actor?: MiRemoteUser, resolver?: Resolver, silent = false): Promise<MiNote | null> {
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
if (resolver == null) resolver = this.apResolverService.createResolver();
|
if (resolver == null) resolver = await this.apResolverService.createResolver();
|
||||||
|
|
||||||
const object = await resolver.resolve(value);
|
const object = await resolver.resolve(value);
|
||||||
|
|
||||||
|
|||||||
@@ -310,7 +310,7 @@ export class ApPersonService implements OnModuleInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
if (resolver == null) resolver = this.apResolverService.createResolver();
|
if (resolver == null) resolver = await this.apResolverService.createResolver();
|
||||||
|
|
||||||
const object = await resolver.resolve(uri);
|
const object = await resolver.resolve(uri);
|
||||||
if (object.id == null) throw new Error('invalid object.id: ' + object.id);
|
if (object.id == null) throw new Error('invalid object.id: ' + object.id);
|
||||||
@@ -500,7 +500,7 @@ export class ApPersonService implements OnModuleInit {
|
|||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
if (resolver == null) resolver = this.apResolverService.createResolver();
|
if (resolver == null) resolver = await this.apResolverService.createResolver();
|
||||||
|
|
||||||
const object = hint ?? await resolver.resolve(uri);
|
const object = hint ?? await resolver.resolve(uri);
|
||||||
|
|
||||||
@@ -678,7 +678,7 @@ export class ApPersonService implements OnModuleInit {
|
|||||||
|
|
||||||
// リモートサーバーからフェッチしてきて登録
|
// リモートサーバーからフェッチしてきて登録
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
if (resolver == null) resolver = this.apResolverService.createResolver();
|
if (resolver == null) resolver = await this.apResolverService.createResolver();
|
||||||
return await this.createPerson(uri, resolver);
|
return await this.createPerson(uri, resolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -707,7 +707,7 @@ export class ApPersonService implements OnModuleInit {
|
|||||||
|
|
||||||
this.logger.info(`Updating the featured: ${user.uri}`);
|
this.logger.info(`Updating the featured: ${user.uri}`);
|
||||||
|
|
||||||
const _resolver = resolver ?? this.apResolverService.createResolver();
|
const _resolver = resolver ?? await this.apResolverService.createResolver();
|
||||||
|
|
||||||
// Resolve to (Ordered)Collection Object
|
// Resolve to (Ordered)Collection Object
|
||||||
const collection = await _resolver.resolveCollection(user.featured);
|
const collection = await _resolver.resolveCollection(user.featured);
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export class ApQuestionService {
|
|||||||
@bindThis
|
@bindThis
|
||||||
public async extractPollFromQuestion(source: string | IObject, resolver?: Resolver): Promise<IPoll> {
|
public async extractPollFromQuestion(source: string | IObject, resolver?: Resolver): Promise<IPoll> {
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
if (resolver == null) resolver = this.apResolverService.createResolver();
|
if (resolver == null) resolver = await this.apResolverService.createResolver();
|
||||||
|
|
||||||
const question = await resolver.resolve(source);
|
const question = await resolver.resolve(source);
|
||||||
if (!isQuestion(question)) throw new Error('invalid type');
|
if (!isQuestion(question)) throw new Error('invalid type');
|
||||||
@@ -91,7 +91,7 @@ export class ApQuestionService {
|
|||||||
|
|
||||||
// resolve new Question object
|
// resolve new Question object
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
if (resolver == null) resolver = this.apResolverService.createResolver();
|
if (resolver == null) resolver = await this.apResolverService.createResolver();
|
||||||
const question = await resolver.resolve(value);
|
const question = await resolver.resolve(value);
|
||||||
this.logger.debug(`fetched question: ${JSON.stringify(question, null, 2)}`);
|
this.logger.debug(`fetched question: ${JSON.stringify(question, null, 2)}`);
|
||||||
|
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ export class ChatEntityService {
|
|||||||
const reactions: { reaction: string; }[] = [];
|
const reactions: { reaction: string; }[] = [];
|
||||||
|
|
||||||
for (const record of message.reactions) {
|
for (const record of message.reactions) {
|
||||||
const [userId, reaction] = record.split('/');
|
const [, reaction] = record.split('/');
|
||||||
reactions.push({
|
reactions.push({
|
||||||
reaction,
|
reaction,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { deepClone } from '@/misc/clone.js';
|
|||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { isMimeImage } from '@/misc/is-mime-image.js';
|
import { isMimeImage } from '@/misc/is-mime-image.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
|
import { uniqueByKey } from '@/misc/unique-by-key.js';
|
||||||
import { UtilityService } from '../UtilityService.js';
|
import { UtilityService } from '../UtilityService.js';
|
||||||
import { VideoProcessingService } from '../VideoProcessingService.js';
|
import { VideoProcessingService } from '../VideoProcessingService.js';
|
||||||
import { UserEntityService } from './UserEntityService.js';
|
import { UserEntityService } from './UserEntityService.js';
|
||||||
@@ -226,6 +227,7 @@ export class DriveFileEntityService {
|
|||||||
options?: PackOptions,
|
options?: PackOptions,
|
||||||
hint?: {
|
hint?: {
|
||||||
packedUser?: Packed<'UserLite'>
|
packedUser?: Packed<'UserLite'>
|
||||||
|
packedFolder?: Packed<'DriveFolder'>
|
||||||
},
|
},
|
||||||
): Promise<Packed<'DriveFile'> | null> {
|
): Promise<Packed<'DriveFile'> | null> {
|
||||||
const opts = Object.assign({
|
const opts = Object.assign({
|
||||||
@@ -250,9 +252,9 @@ export class DriveFileEntityService {
|
|||||||
thumbnailUrl: this.getThumbnailUrl(file),
|
thumbnailUrl: this.getThumbnailUrl(file),
|
||||||
comment: file.comment,
|
comment: file.comment,
|
||||||
folderId: file.folderId,
|
folderId: file.folderId,
|
||||||
folder: opts.detail && file.folderId ? this.driveFolderEntityService.pack(file.folderId, {
|
folder: opts.detail && file.folderId ? (hint?.packedFolder ?? this.driveFolderEntityService.pack(file.folderId, {
|
||||||
detail: true,
|
detail: true,
|
||||||
}) : null,
|
})) : null,
|
||||||
userId: file.userId,
|
userId: file.userId,
|
||||||
user: (opts.withUser && file.userId) ? hint?.packedUser ?? this.userEntityService.pack(file.userId) : null,
|
user: (opts.withUser && file.userId) ? hint?.packedUser ?? this.userEntityService.pack(file.userId) : null,
|
||||||
});
|
});
|
||||||
@@ -263,10 +265,41 @@ export class DriveFileEntityService {
|
|||||||
files: MiDriveFile[],
|
files: MiDriveFile[],
|
||||||
options?: PackOptions,
|
options?: PackOptions,
|
||||||
): Promise<Packed<'DriveFile'>[]> {
|
): Promise<Packed<'DriveFile'>[]> {
|
||||||
const _user = files.map(({ user, userId }) => user ?? userId).filter(x => x != null);
|
// -- ユーザ情報の事前取得 --
|
||||||
const _userMap = await this.userEntityService.packMany(_user)
|
|
||||||
.then(users => new Map(users.map(user => [user.id, user])));
|
let userMap: Map<string, Packed<'UserLite'>> | null = null;
|
||||||
const items = await Promise.all(files.map(f => this.packNullable(f, options, f.userId ? { packedUser: _userMap.get(f.userId) } : {})));
|
if (options?.withUser) {
|
||||||
|
const users = files
|
||||||
|
.map(({ user, userId }) => user ?? userId)
|
||||||
|
.filter(x => x != null);
|
||||||
|
|
||||||
|
const uniqueUsers = uniqueByKey(users, (user) => typeof user === 'string' ? user : user.id);
|
||||||
|
const packedUsers = await this.userEntityService.packMany(uniqueUsers);
|
||||||
|
userMap = new Map(packedUsers.map(user => [user.id, user]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- フォルダ情報の事前取得 --
|
||||||
|
|
||||||
|
let folderMap: Map<string, Packed<'DriveFolder'>> | null = null;
|
||||||
|
if (options?.detail) {
|
||||||
|
const folders = files
|
||||||
|
.map(({ folder, folderId }) => folder ?? folderId)
|
||||||
|
.filter(x => x != null);
|
||||||
|
|
||||||
|
const uniqueFolders = uniqueByKey(folders, (folder) => typeof folder === 'string' ? folder : folder.id);
|
||||||
|
const packedFolders = await this.driveFolderEntityService.packMany(uniqueFolders, { detail: true });
|
||||||
|
folderMap = new Map(packedFolders.map(folder => [folder.id, folder]));
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = await Promise.all(files.map(f => this.packNullable(
|
||||||
|
f,
|
||||||
|
options,
|
||||||
|
{
|
||||||
|
packedUser: f.userId ? userMap?.get(f.userId) : undefined,
|
||||||
|
packedFolder: f.folderId ? folderMap?.get(f.folderId) : undefined,
|
||||||
|
},
|
||||||
|
)));
|
||||||
|
|
||||||
return items.filter(x => x != null);
|
return items.filter(x => x != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ import type { } from '@/models/Blocking.js';
|
|||||||
import type { MiDriveFolder } from '@/models/DriveFolder.js';
|
import type { MiDriveFolder } from '@/models/DriveFolder.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
|
import { In } from 'typeorm';
|
||||||
|
import { uniqueByKey } from '@/misc/unique-by-key.js';
|
||||||
|
import { splitIdAndObjects } from '@/misc/split-id-and-objects.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DriveFolderEntityService {
|
export class DriveFolderEntityService {
|
||||||
@@ -32,12 +35,20 @@ export class DriveFolderEntityService {
|
|||||||
options?: {
|
options?: {
|
||||||
detail: boolean
|
detail: boolean
|
||||||
},
|
},
|
||||||
|
hint?: {
|
||||||
|
folderMap?: Map<string, MiDriveFolder>;
|
||||||
|
foldersCountMap?: Map<string, number> | null;
|
||||||
|
filesCountMap?: Map<string, number> | null;
|
||||||
|
parentPacker?: (id: string) => Promise<Packed<'DriveFolder'>>;
|
||||||
|
},
|
||||||
): Promise<Packed<'DriveFolder'>> {
|
): Promise<Packed<'DriveFolder'>> {
|
||||||
const opts = Object.assign({
|
const opts = Object.assign({
|
||||||
detail: false,
|
detail: false,
|
||||||
}, options);
|
}, options);
|
||||||
|
|
||||||
const folder = typeof src === 'object' ? src : await this.driveFoldersRepository.findOneByOrFail({ id: src });
|
const folder = typeof src === 'object'
|
||||||
|
? src
|
||||||
|
: hint?.folderMap?.get(src) ?? await this.driveFoldersRepository.findOneByOrFail({ id: src });
|
||||||
|
|
||||||
return await awaitAll({
|
return await awaitAll({
|
||||||
id: folder.id,
|
id: folder.id,
|
||||||
@@ -46,20 +57,141 @@ export class DriveFolderEntityService {
|
|||||||
parentId: folder.parentId,
|
parentId: folder.parentId,
|
||||||
|
|
||||||
...(opts.detail ? {
|
...(opts.detail ? {
|
||||||
foldersCount: this.driveFoldersRepository.countBy({
|
foldersCount: hint?.foldersCountMap?.get(folder.id)
|
||||||
parentId: folder.id,
|
?? this.driveFoldersRepository.countBy({
|
||||||
}),
|
parentId: folder.id,
|
||||||
filesCount: this.driveFilesRepository.countBy({
|
}),
|
||||||
folderId: folder.id,
|
filesCount: hint?.filesCountMap?.get(folder.id)
|
||||||
}),
|
?? this.driveFilesRepository.countBy({
|
||||||
|
folderId: folder.id,
|
||||||
|
}),
|
||||||
|
|
||||||
...(folder.parentId ? {
|
...(folder.parentId ? {
|
||||||
parent: this.pack(folder.parentId, {
|
parent: hint?.parentPacker
|
||||||
detail: true,
|
? hint.parentPacker(folder.parentId)
|
||||||
}),
|
: this.pack(folder.parentId, { detail: true }, hint),
|
||||||
} : {}),
|
} : {}),
|
||||||
} : {}),
|
} : {}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
public async packMany(
|
||||||
|
src: Array<MiDriveFolder['id'] | MiDriveFolder>,
|
||||||
|
options?: {
|
||||||
|
detail: boolean
|
||||||
|
},
|
||||||
|
): Promise<Array<Packed<'DriveFolder'>>> {
|
||||||
|
/**
|
||||||
|
* 重複を除去しつつ、必要なDriveFolderオブジェクトをすべて取得する
|
||||||
|
*/
|
||||||
|
const collectUniqueObjects = async (src: Array<MiDriveFolder['id'] | MiDriveFolder>) => {
|
||||||
|
const uniqueSrc = uniqueByKey(
|
||||||
|
src,
|
||||||
|
(s) => typeof s === 'string' ? s : s.id,
|
||||||
|
);
|
||||||
|
const { ids, objects } = splitIdAndObjects(uniqueSrc);
|
||||||
|
|
||||||
|
const uniqueObjects = new Map<string, MiDriveFolder>(objects.map(s => [s.id, s]));
|
||||||
|
const needsFetchIds = ids.filter(id => !uniqueObjects.has(id));
|
||||||
|
|
||||||
|
if (needsFetchIds.length > 0) {
|
||||||
|
const fetchedObjects = await this.driveFoldersRepository.find({
|
||||||
|
where: {
|
||||||
|
id: In(needsFetchIds),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
for (const obj of fetchedObjects) {
|
||||||
|
uniqueObjects.set(obj.id, obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return uniqueObjects;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 親フォルダーを再帰的に収集する
|
||||||
|
*/
|
||||||
|
const collectAncestors = async (folderMap: Map<string, MiDriveFolder>) => {
|
||||||
|
for (;;) {
|
||||||
|
const parentIds = new Set<string>();
|
||||||
|
for (const folder of folderMap.values()) {
|
||||||
|
if (folder.parentId != null && !folderMap.has(folder.parentId)) {
|
||||||
|
parentIds.add(folder.parentId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentIds.size === 0) break;
|
||||||
|
|
||||||
|
const fetchedParents = await this.driveFoldersRepository.find({
|
||||||
|
where: {
|
||||||
|
id: In([...parentIds]),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (fetchedParents.length === 0) break;
|
||||||
|
|
||||||
|
for (const parent of fetchedParents) {
|
||||||
|
folderMap.set(parent.id, parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const opts = Object.assign({
|
||||||
|
detail: false,
|
||||||
|
}, options);
|
||||||
|
|
||||||
|
const folderMap = await collectUniqueObjects(src);
|
||||||
|
|
||||||
|
let foldersCountMap: Map<string, number> | null = null;
|
||||||
|
let filesCountMap: Map<string, number> | null = null;
|
||||||
|
if (opts.detail) {
|
||||||
|
await collectAncestors(folderMap);
|
||||||
|
|
||||||
|
const ids = [...folderMap.keys()];
|
||||||
|
if (ids.length > 0) {
|
||||||
|
const folderCounts = await this.driveFoldersRepository.createQueryBuilder('folder')
|
||||||
|
.select('folder.parentId', 'parentId')
|
||||||
|
.addSelect('COUNT(*)', 'count')
|
||||||
|
.where('folder.parentId IN (:...ids)', { ids })
|
||||||
|
.groupBy('folder.parentId')
|
||||||
|
.getRawMany<{ parentId: string; count: string }>();
|
||||||
|
|
||||||
|
const fileCounts = await this.driveFilesRepository.createQueryBuilder('file')
|
||||||
|
.select('file.folderId', 'folderId')
|
||||||
|
.addSelect('COUNT(*)', 'count')
|
||||||
|
.where('file.folderId IN (:...ids)', { ids })
|
||||||
|
.groupBy('file.folderId')
|
||||||
|
.getRawMany<{ folderId: string; count: string }>();
|
||||||
|
|
||||||
|
foldersCountMap = new Map(folderCounts.map(row => [row.parentId, Number(row.count)]));
|
||||||
|
filesCountMap = new Map(fileCounts.map(row => [row.folderId, Number(row.count)]));
|
||||||
|
} else {
|
||||||
|
foldersCountMap = new Map();
|
||||||
|
filesCountMap = new Map();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const packedMap = new Map<string, Promise<Packed<'DriveFolder'>>>();
|
||||||
|
const packFromId = (id: string): Promise<Packed<'DriveFolder'>> => {
|
||||||
|
const cached = packedMap.get(id);
|
||||||
|
if (cached) return cached;
|
||||||
|
|
||||||
|
const folder = folderMap.get(id);
|
||||||
|
if (!folder) {
|
||||||
|
throw new Error(`DriveFolder not found: ${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const packedPromise = this.pack(folder, options, {
|
||||||
|
folderMap,
|
||||||
|
foldersCountMap,
|
||||||
|
filesCountMap,
|
||||||
|
parentPacker: packFromId,
|
||||||
|
});
|
||||||
|
packedMap.set(id, packedPromise);
|
||||||
|
|
||||||
|
return packedPromise;
|
||||||
|
};
|
||||||
|
|
||||||
|
return Promise.all(src.map(s => packFromId(typeof s === 'string' ? s : s.id)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export class EmojiEntityService {
|
|||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public packSimpleMany(
|
public packSimpleMany(
|
||||||
emojis: any[],
|
emojis: (MiEmoji['id'] | MiEmoji)[],
|
||||||
) {
|
) {
|
||||||
return Promise.all(emojis.map(x => this.packSimple(x)));
|
return Promise.all(emojis.map(x => this.packSimple(x)));
|
||||||
}
|
}
|
||||||
@@ -69,7 +69,7 @@ export class EmojiEntityService {
|
|||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public packDetailedMany(
|
public packDetailedMany(
|
||||||
emojis: any[],
|
emojis: (MiEmoji['id'] | MiEmoji)[],
|
||||||
): Promise<Packed<'EmojiDetailed'>[]> {
|
): Promise<Packed<'EmojiDetailed'>[]> {
|
||||||
return Promise.all(emojis.map(x => this.packDetailed(x)));
|
return Promise.all(emojis.map(x => this.packDetailed(x)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,13 +55,13 @@ export class MetaEntityService {
|
|||||||
if (instance.defaultLightTheme) {
|
if (instance.defaultLightTheme) {
|
||||||
try {
|
try {
|
||||||
defaultLightTheme = JSON.stringify(JSON5.parse(instance.defaultLightTheme));
|
defaultLightTheme = JSON.stringify(JSON5.parse(instance.defaultLightTheme));
|
||||||
} catch (e) {
|
} catch (_) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (instance.defaultDarkTheme) {
|
if (instance.defaultDarkTheme) {
|
||||||
try {
|
try {
|
||||||
defaultDarkTheme = JSON.stringify(JSON5.parse(instance.defaultDarkTheme));
|
defaultDarkTheme = JSON.stringify(JSON5.parse(instance.defaultDarkTheme));
|
||||||
} catch (e) {
|
} catch (_) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export class NoteReactionEntityService implements OnModuleInit {
|
|||||||
packedUser?: Packed<'UserLite'>
|
packedUser?: Packed<'UserLite'>
|
||||||
},
|
},
|
||||||
): Promise<Packed<'NoteReaction'>> {
|
): Promise<Packed<'NoteReaction'>> {
|
||||||
const opts = Object.assign({
|
const _opts = Object.assign({
|
||||||
}, options);
|
}, options);
|
||||||
|
|
||||||
const reaction = typeof src === 'object' ? src : await this.noteReactionsRepository.findOneByOrFail({ id: src });
|
const reaction = typeof src === 'object' ? src : await this.noteReactionsRepository.findOneByOrFail({ id: src });
|
||||||
@@ -90,7 +90,7 @@ export class NoteReactionEntityService implements OnModuleInit {
|
|||||||
packedUser?: Packed<'UserLite'>
|
packedUser?: Packed<'UserLite'>
|
||||||
},
|
},
|
||||||
): Promise<Packed<'NoteReactionWithNote'>> {
|
): Promise<Packed<'NoteReactionWithNote'>> {
|
||||||
const opts = Object.assign({
|
const _opts = Object.assign({
|
||||||
}, options);
|
}, options);
|
||||||
|
|
||||||
const reaction = typeof src === 'object' ? src : await this.noteReactionsRepository.findOneByOrFail({ id: src });
|
const reaction = typeof src === 'object' ? src : await this.noteReactionsRepository.findOneByOrFail({ id: src });
|
||||||
|
|||||||
@@ -720,7 +720,7 @@ export class UserEntityService implements OnModuleInit {
|
|||||||
me,
|
me,
|
||||||
{
|
{
|
||||||
...options,
|
...options,
|
||||||
userProfile: profilesMap.get(u.id),
|
userProfile: profilesMap?.get(u.id),
|
||||||
userRelations: userRelations,
|
userRelations: userRelations,
|
||||||
userMemos: userMemos,
|
userMemos: userMemos,
|
||||||
pinNotes: pinNotes,
|
pinNotes: pinNotes,
|
||||||
|
|||||||
@@ -4,13 +4,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import si from 'systeminformation';
|
|
||||||
import Xev from 'xev';
|
import Xev from 'xev';
|
||||||
import * as osUtils from 'os-utils';
|
import * as osUtils from 'os-utils';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import type { OnApplicationShutdown } from '@nestjs/common';
|
|
||||||
import { MiMeta } from '@/models/_.js';
|
import { MiMeta } from '@/models/_.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import type { OnApplicationShutdown } from '@nestjs/common';
|
||||||
|
|
||||||
const ev = new Xev();
|
const ev = new Xev();
|
||||||
|
|
||||||
@@ -97,12 +96,14 @@ function cpuUsage(): Promise<number> {
|
|||||||
|
|
||||||
// MEMORY STAT
|
// MEMORY STAT
|
||||||
async function mem() {
|
async function mem() {
|
||||||
|
const si = await import('systeminformation');
|
||||||
const data = await si.mem();
|
const data = await si.mem();
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NETWORK STAT
|
// NETWORK STAT
|
||||||
async function net() {
|
async function net() {
|
||||||
|
const si = await import('systeminformation');
|
||||||
const iface = await si.networkInterfaceDefault();
|
const iface = await si.networkInterfaceDefault();
|
||||||
const data = await si.networkStats(iface);
|
const data = await si.networkStats(iface);
|
||||||
return data[0];
|
return data[0];
|
||||||
@@ -110,5 +111,6 @@ async function net() {
|
|||||||
|
|
||||||
// FS STAT
|
// FS STAT
|
||||||
async function fs() {
|
async function fs() {
|
||||||
|
const si = await import('systeminformation');
|
||||||
return await si.disksIO().catch(() => ({ rIO_sec: 0, wIO_sec: 0 }));
|
return await si.disksIO().catch(() => ({ rIO_sec: 0, wIO_sec: 0 }));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export async function checkWordMute(note: NoteLike, me: UserLike | null | undefi
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
return new RE2(regexp[1], regexp[2]).test(text);
|
return new RE2(regexp[1], regexp[2]).test(text);
|
||||||
} catch (err) {
|
} catch (_) {
|
||||||
// This should never happen due to input sanitisation.
|
// This should never happen due to input sanitisation.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export function getIpHash(ip: string): string {
|
|||||||
// (this means for IPv4 the entire address is used)
|
// (this means for IPv4 the entire address is used)
|
||||||
const prefix = IPCIDR.createAddress(ip).mask(64);
|
const prefix = IPCIDR.createAddress(ip).mask(64);
|
||||||
return 'ip-' + BigInt('0b' + prefix).toString(36);
|
return 'ip-' + BigInt('0b' + prefix).toString(36);
|
||||||
} catch (e) {
|
} catch (_) {
|
||||||
const prefix = IPCIDR.createAddress(ip.replace(/:[0-9]+$/, '')).mask(64);
|
const prefix = IPCIDR.createAddress(ip.replace(/:[0-9]+$/, '')).mask(64);
|
||||||
return 'ip-' + BigInt('0b' + prefix).toString(36);
|
return 'ip-' + BigInt('0b' + prefix).toString(36);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export class I18n<T extends Record<string, any>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
} catch (e) {
|
} catch (_) {
|
||||||
console.warn(`missing localization '${key}'`);
|
console.warn(`missing localization '${key}'`);
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -262,8 +262,6 @@ type ObjectSchemaTypeDef<p extends Schema> =
|
|||||||
never :
|
never :
|
||||||
any;
|
any;
|
||||||
|
|
||||||
type ObjectSchemaType<p extends Schema> = NullOrUndefined<p, ObjectSchemaTypeDef<p>>;
|
|
||||||
|
|
||||||
export type SchemaTypeDef<p extends Schema> =
|
export type SchemaTypeDef<p extends Schema> =
|
||||||
p['type'] extends 'null' ? null :
|
p['type'] extends 'null' ? null :
|
||||||
p['type'] extends 'integer' ? number :
|
p['type'] extends 'integer' ? number :
|
||||||
|
|||||||
@@ -4,15 +4,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as os from 'node:os';
|
import * as os from 'node:os';
|
||||||
import sysUtils from 'systeminformation';
|
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
|
|
||||||
export async function showMachineInfo(parentLogger: Logger) {
|
export async function showMachineInfo(parentLogger: Logger) {
|
||||||
const logger = parentLogger.createSubLogger('machine');
|
const logger = parentLogger.createSubLogger('machine');
|
||||||
logger.debug(`Hostname: ${os.hostname()}`);
|
logger.debug(`Hostname: ${os.hostname()}`);
|
||||||
logger.debug(`Platform: ${process.platform} Arch: ${process.arch}`);
|
logger.debug(`Platform: ${process.platform} Arch: ${process.arch}`);
|
||||||
const mem = await sysUtils.mem();
|
logger.debug(`CPU: ${os.cpus().length} core MEM: ${(os.totalmem() / 1024 / 1024 / 1024).toFixed(1)}GB (available: ${(os.freemem() / 1024 / 1024 / 1024).toFixed(1)}GB)`);
|
||||||
const totalmem = (mem.total / 1024 / 1024 / 1024).toFixed(1);
|
|
||||||
const availmem = (mem.available / 1024 / 1024 / 1024).toFixed(1);
|
|
||||||
logger.debug(`CPU: ${os.cpus().length} core MEM: ${totalmem}GB (available: ${availmem}GB)`);
|
|
||||||
}
|
}
|
||||||
|
|||||||
27
packages/backend/src/misc/split-id-and-objects.ts
Normal file
27
packages/backend/src/misc/split-id-and-objects.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* idとオブジェクトを分離する
|
||||||
|
* @param input idまたはオブジェクトの配列
|
||||||
|
* @returns idの配列とオブジェクトの配列
|
||||||
|
*/
|
||||||
|
export function splitIdAndObjects<T extends { id: string }>(input: (T | string)[]): { ids: string[]; objects: T[] } {
|
||||||
|
const ids: string[] = [];
|
||||||
|
const objects : T[] = [];
|
||||||
|
|
||||||
|
for (const item of input) {
|
||||||
|
if (typeof item === 'string') {
|
||||||
|
ids.push(item);
|
||||||
|
} else {
|
||||||
|
objects.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
ids,
|
||||||
|
objects,
|
||||||
|
};
|
||||||
|
}
|
||||||
21
packages/backend/src/misc/unique-by-key.ts
Normal file
21
packages/backend/src/misc/unique-by-key.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* itemsの中でkey関数が返す値が重複しないようにした配列を返す
|
||||||
|
* @param items 重複を除去したい配列
|
||||||
|
* @param key 重複判定に使うキーを返す関数
|
||||||
|
* @returns 重複を除去した配列
|
||||||
|
*/
|
||||||
|
export function uniqueByKey<TItem, TKey = string>(items: Iterable<TItem>, key: (item: TItem) => TKey): TItem[] {
|
||||||
|
const map = new Map<TKey, TItem>();
|
||||||
|
for (const item of items) {
|
||||||
|
const k = key(item);
|
||||||
|
if (!map.has(k)) {
|
||||||
|
map.set(k, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [...map.values()];
|
||||||
|
}
|
||||||
@@ -67,7 +67,7 @@ export class MiAbuseReportNotificationRecipient {
|
|||||||
/**
|
/**
|
||||||
* 通知先のユーザ.
|
* 通知先のユーザ.
|
||||||
*/
|
*/
|
||||||
@ManyToOne(type => MiUser, {
|
@ManyToOne(() => MiUser, {
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
})
|
})
|
||||||
@JoinColumn({ name: 'userId', referencedColumnName: 'id', foreignKeyConstraintName: 'FK_abuse_report_notification_recipient_userId1' })
|
@JoinColumn({ name: 'userId', referencedColumnName: 'id', foreignKeyConstraintName: 'FK_abuse_report_notification_recipient_userId1' })
|
||||||
@@ -76,7 +76,7 @@ export class MiAbuseReportNotificationRecipient {
|
|||||||
/**
|
/**
|
||||||
* 通知先のユーザプロフィール.
|
* 通知先のユーザプロフィール.
|
||||||
*/
|
*/
|
||||||
@ManyToOne(type => MiUserProfile, {
|
@ManyToOne(() => MiUserProfile, {
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
})
|
})
|
||||||
@JoinColumn({ name: 'userId', referencedColumnName: 'userId', foreignKeyConstraintName: 'FK_abuse_report_notification_recipient_userId2' })
|
@JoinColumn({ name: 'userId', referencedColumnName: 'userId', foreignKeyConstraintName: 'FK_abuse_report_notification_recipient_userId2' })
|
||||||
@@ -96,7 +96,7 @@ export class MiAbuseReportNotificationRecipient {
|
|||||||
/**
|
/**
|
||||||
* 通知先のシステムWebhook.
|
* 通知先のシステムWebhook.
|
||||||
*/
|
*/
|
||||||
@ManyToOne(type => MiSystemWebhook, {
|
@ManyToOne(() => MiSystemWebhook, {
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
})
|
})
|
||||||
@JoinColumn({ name: 'systemWebhookId', referencedColumnName: 'id', foreignKeyConstraintName: 'FK_abuse_report_notification_recipient_systemWebhookId' })
|
@JoinColumn({ name: 'systemWebhookId', referencedColumnName: 'id', foreignKeyConstraintName: 'FK_abuse_report_notification_recipient_systemWebhookId' })
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export class MiAbuseUserReport {
|
|||||||
@Column(id())
|
@Column(id())
|
||||||
public targetUserId: MiUser['id'];
|
public targetUserId: MiUser['id'];
|
||||||
|
|
||||||
@ManyToOne(type => MiUser, {
|
@ManyToOne(() => MiUser, {
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
})
|
})
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
@@ -28,7 +28,7 @@ export class MiAbuseUserReport {
|
|||||||
@Column(id())
|
@Column(id())
|
||||||
public reporterId: MiUser['id'];
|
public reporterId: MiUser['id'];
|
||||||
|
|
||||||
@ManyToOne(type => MiUser, {
|
@ManyToOne(() => MiUser, {
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
})
|
})
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
@@ -40,7 +40,7 @@ export class MiAbuseUserReport {
|
|||||||
})
|
})
|
||||||
public assigneeId: MiUser['id'] | null;
|
public assigneeId: MiUser['id'] | null;
|
||||||
|
|
||||||
@ManyToOne(type => MiUser, {
|
@ManyToOne(() => MiUser, {
|
||||||
onDelete: 'SET NULL',
|
onDelete: 'SET NULL',
|
||||||
})
|
})
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export class MiAccessToken {
|
|||||||
@Column(id())
|
@Column(id())
|
||||||
public userId: MiUser['id'];
|
public userId: MiUser['id'];
|
||||||
|
|
||||||
@ManyToOne(type => MiUser, {
|
@ManyToOne(() => MiUser, {
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
})
|
})
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
@@ -53,7 +53,7 @@ export class MiAccessToken {
|
|||||||
})
|
})
|
||||||
public appId: MiApp['id'] | null;
|
public appId: MiApp['id'] | null;
|
||||||
|
|
||||||
@ManyToOne(type => MiApp, {
|
@ManyToOne(() => MiApp, {
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
})
|
})
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ export class MiAnnouncement {
|
|||||||
})
|
})
|
||||||
public userId: MiUser['id'] | null;
|
public userId: MiUser['id'] | null;
|
||||||
|
|
||||||
@ManyToOne(type => MiUser, {
|
@ManyToOne(() => MiUser, {
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
})
|
})
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export class MiAnnouncementRead {
|
|||||||
@Column(id())
|
@Column(id())
|
||||||
public userId: MiUser['id'];
|
public userId: MiUser['id'];
|
||||||
|
|
||||||
@ManyToOne(type => MiUser, {
|
@ManyToOne(() => MiUser, {
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
})
|
})
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
@@ -28,7 +28,7 @@ export class MiAnnouncementRead {
|
|||||||
@Column(id())
|
@Column(id())
|
||||||
public announcementId: MiAnnouncement['id'];
|
public announcementId: MiAnnouncement['id'];
|
||||||
|
|
||||||
@ManyToOne(type => MiAnnouncement, {
|
@ManyToOne(() => MiAnnouncement, {
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
})
|
})
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export class MiAntenna {
|
|||||||
})
|
})
|
||||||
public userId: MiUser['id'];
|
public userId: MiUser['id'];
|
||||||
|
|
||||||
@ManyToOne(type => MiUser, {
|
@ManyToOne(() => MiUser, {
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
})
|
})
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
@@ -45,7 +45,7 @@ export class MiAntenna {
|
|||||||
})
|
})
|
||||||
public userListId: MiUserList['id'] | null;
|
public userListId: MiUserList['id'] | null;
|
||||||
|
|
||||||
@ManyToOne(type => MiUserList, {
|
@ManyToOne(() => MiUserList, {
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
})
|
})
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export class MiApp {
|
|||||||
})
|
})
|
||||||
public userId: MiUser['id'] | null;
|
public userId: MiUser['id'] | null;
|
||||||
|
|
||||||
@ManyToOne(type => MiUser, {
|
@ManyToOne(() => MiUser, {
|
||||||
onDelete: 'SET NULL',
|
onDelete: 'SET NULL',
|
||||||
nullable: true,
|
nullable: true,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export class MiAuthSession {
|
|||||||
})
|
})
|
||||||
public userId: MiUser['id'] | null;
|
public userId: MiUser['id'] | null;
|
||||||
|
|
||||||
@ManyToOne(type => MiUser, {
|
@ManyToOne(() => MiUser, {
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
nullable: true,
|
nullable: true,
|
||||||
})
|
})
|
||||||
@@ -35,7 +35,7 @@ export class MiAuthSession {
|
|||||||
@Column(id())
|
@Column(id())
|
||||||
public appId: MiApp['id'];
|
public appId: MiApp['id'];
|
||||||
|
|
||||||
@ManyToOne(type => MiApp, {
|
@ManyToOne(() => MiApp, {
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
})
|
})
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user