Merge branch 'develop' into pizzax-indexeddb

This commit is contained in:
tamaina 2022-01-21 21:32:50 +09:00
commit b5a20494f6
447 changed files with 7322 additions and 7809 deletions

View File

@ -17,14 +17,14 @@ jobs:
services: services:
postgres: postgres:
image: postgres:12.2-alpine image: postgres:13
ports: ports:
- 54312:5432 - 54312:5432
env: env:
POSTGRES_DB: test-misskey POSTGRES_DB: test-misskey
POSTGRES_HOST_AUTH_METHOD: trust POSTGRES_HOST_AUTH_METHOD: trust
redis: redis:
image: redis:4.0-alpine image: redis:6
ports: ports:
- 56312:6379 - 56312:6379
@ -51,19 +51,21 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
fail-fast: false
matrix: matrix:
node-version: [16.x] node-version: [16.x]
browser: [chrome]
services: services:
postgres: postgres:
image: postgres:12.2-alpine image: postgres:13
ports: ports:
- 54312:5432 - 54312:5432
env: env:
POSTGRES_DB: test-misskey POSTGRES_DB: test-misskey
POSTGRES_HOST_AUTH_METHOD: trust POSTGRES_HOST_AUTH_METHOD: trust
redis: redis:
image: redis:4.0-alpine image: redis:6
ports: ports:
- 56312:6379 - 56312:6379
@ -71,6 +73,12 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
submodules: true submodules: true
# https://github.com/cypress-io/cypress-docker-images/issues/150
#- name: Install mplayer for FireFox
# run: sudo apt install mplayer -y
# if: ${{ matrix.browser == 'firefox' }}
#- uses: browser-actions/setup-firefox@latest
# if: ${{ matrix.browser == 'firefox' }}
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1 uses: actions/setup-node@v1
with: with:
@ -87,5 +95,24 @@ jobs:
run: cp .github/misskey/test.yml .config run: cp .github/misskey/test.yml .config
- name: Build - name: Build
run: yarn build run: yarn build
- name: Test # https://github.com/cypress-io/cypress/issues/4351#issuecomment-559489091
run: yarn e2e - name: ALSA Env
run: echo -e 'pcm.!default {\n type hw\n card 0\n}\n\nctl.!default {\n type hw\n card 0\n}' > ~/.asoundrc
- name: Cypress run
uses: cypress-io/github-action@v2
with:
install: false
start: npm run start:test
wait-on: 'http://localhost:61812'
headless: false
browser: ${{ matrix.browser }}
- uses: actions/upload-artifact@v2
if: failure()
with:
name: ${{ matrix.browser }}-cypress-screenshots
path: cypress/screenshots
- uses: actions/upload-artifact@v2
if: always()
with:
name: ${{ matrix.browser }}-cypress-videos
path: cypress/videos

View File

@ -15,10 +15,13 @@
- リバーシ機能が削除されました - リバーシ機能が削除されました
- 後日別リポジトリとして復活予定です - 後日別リポジトリとして復活予定です
- Chat UIが削除されました - Chat UIが削除されました
- ートに添付できるファイルの数が16に増えました
- カスタム絵文字にSVGを指定した場合、PNGに変換されて表示されるようになりました
### Improvements ### Improvements
- カスタム絵文字一括編集機能 - カスタム絵文字一括編集機能
- カスタム絵文字一括インポート - カスタム絵文字一括インポート
- 投稿フォームで一時的に投稿するアカウントを切り替えられるように
### Bugfixes ### Bugfixes

View File

@ -41,8 +41,6 @@ describe('After setup instance', () => {
username: 'admin', username: 'admin',
password: 'pass', password: 'pass',
}).its('body').as('admin'); }).its('body').as('admin');
cy.get('@admin');
}); });
afterEach(() => { afterEach(() => {
@ -82,15 +80,11 @@ describe('After user signup', () => {
password: 'pass', password: 'pass',
}).its('body').as('admin'); }).its('body').as('admin');
cy.get('@admin').then(() => { // ユーザー作成
// ユーザー作成 cy.request('POST', '/api/signup', {
cy.request('POST', '/api/signup', { username: 'alice',
username: 'alice', password: 'alice1234',
password: 'alice1234', }).its('body').as('alice');
}).its('body').as('alice');
});
cy.get('@alice');
}); });
afterEach(() => { afterEach(() => {
@ -145,27 +139,21 @@ describe('After user singed in', () => {
password: 'pass', password: 'pass',
}).its('body').as('admin'); }).its('body').as('admin');
cy.get('@admin').then(() => { // ユーザー作成
// ユーザー作成 cy.request('POST', '/api/signup', {
cy.request('POST', '/api/signup', { username: 'alice',
username: 'alice', password: 'alice1234',
password: 'alice1234', }).its('body').as('alice');
}).its('body').as('alice');
});
cy.get('@alice').then(() => { cy.visit('/');
cy.visit('/');
cy.intercept('POST', '/api/signin').as('signin'); cy.intercept('POST', '/api/signin').as('signin');
cy.get('[data-cy-signin]').click(); cy.get('[data-cy-signin]').click();
cy.get('[data-cy-signin-username] input').type('alice'); cy.get('[data-cy-signin-username] input').type('alice');
cy.get('[data-cy-signin-password] input').type('alice1234{enter}'); cy.get('[data-cy-signin-password] input').type('alice1234{enter}');
cy.wait('@signin').as('signedIn'); cy.wait('@signin').as('signedIn');
});
cy.get('@signedIn');
}); });
afterEach(() => { afterEach(() => {

View File

@ -20,7 +20,13 @@ import './commands'
// require('./commands') // require('./commands')
Cypress.on('uncaught:exception', (err, runnable) => { Cypress.on('uncaught:exception', (err, runnable) => {
if (err.message.includes('ResizeObserver loop limit exceeded')) { if ([
return false // Chrome
} 'ResizeObserver loop limit exceeded',
// Firefox
'ResizeObserver loop completed with undelivered notifications',
].some(msg => err.message.includes(msg))) {
return false;
}
}); });

View File

@ -619,8 +619,11 @@ reportAbuse: "通報"
reportAbuseOf: "{name}を通報する" reportAbuseOf: "{name}を通報する"
fillAbuseReportDescription: "通報理由の詳細を記入してください。対象のートがある場合はそのURLも記入してください。" fillAbuseReportDescription: "通報理由の詳細を記入してください。対象のートがある場合はそのURLも記入してください。"
abuseReported: "内容が送信されました。ご報告ありがとうございました。" abuseReported: "内容が送信されました。ご報告ありがとうございました。"
reporter: "通報者"
reporteeOrigin: "通報先" reporteeOrigin: "通報先"
reporterOrigin: "通報元" reporterOrigin: "通報元"
forwardReport: "リモートインスタンスに通報を転送する"
forwardReportIsAnonymous: "リモートインスタンスからはあなたの情報は見れず、匿名のシステムアカウントとして表示されます。"
send: "送信" send: "送信"
abuseMarkAsResolved: "対応済みにする" abuseMarkAsResolved: "対応済みにする"
openInNewTab: "新しいタブで開く" openInNewTab: "新しいタブで開く"
@ -743,6 +746,7 @@ notRecommended: "非推奨"
botProtection: "Botプロテクション" botProtection: "Botプロテクション"
instanceBlocking: "インスタンスブロック" instanceBlocking: "インスタンスブロック"
selectAccount: "アカウントを選択" selectAccount: "アカウントを選択"
switchAccount: "アカウントを切り替え"
enabled: "有効" enabled: "有効"
disabled: "無効" disabled: "無効"
quickAction: "クイックアクション" quickAction: "クイックアクション"

View File

@ -42,12 +42,12 @@
"js-yaml": "4.1.0" "js-yaml": "4.1.0"
}, },
"devDependencies": { "devDependencies": {
"@redocly/openapi-core": "1.0.0-beta.54", "@redocly/openapi-core": "1.0.0-beta.79",
"@types/fluent-ffmpeg": "2.1.17", "@types/fluent-ffmpeg": "2.1.20",
"@typescript-eslint/parser": "5.4.0", "@typescript-eslint/parser": "5.10.0",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"cypress": "9.1.0", "cypress": "9.3.1",
"start-server-and-test": "1.14.0", "start-server-and-test": "1.14.0",
"typescript": "4.5.2" "typescript": "4.5.5"
} }
} }

View File

@ -0,0 +1,13 @@
const { QueryRunner } = require('typeorm');
module.exports = class forwardedReport1637320813000 {
name = 'forwardedReport1637320813000';
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD "forwarded" boolean NOT NULL DEFAULT false`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP COLUMN "forwarded"`);
}
};

View File

@ -0,0 +1,15 @@
const { MigrationInterface, QueryRunner } = require("typeorm");
module.exports = class emojiUrl1642611822809 {
name = 'emojiUrl1642611822809'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "emoji" RENAME COLUMN "url" TO "originalUrl"`);
await queryRunner.query(`ALTER TABLE "emoji" ADD "publicUrl" character varying(512) NOT NULL DEFAULT ''`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "emoji" DROP COLUMN "publicUrl"`);
await queryRunner.query(`ALTER TABLE "emoji" RENAME COLUMN "originalUrl" TO "url"`);
}
}

View File

@ -0,0 +1,13 @@
const { MigrationInterface, QueryRunner } = require("typeorm");
module.exports = class driveFileWebpublicType1642613870898 {
name = 'driveFileWebpublicType1642613870898'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "drive_file" ADD "webpublicType" character varying(128)`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "drive_file" DROP COLUMN "webpublicType"`);
}
}

View File

@ -22,85 +22,78 @@
"@sinonjs/fake-timers": "7.1.2", "@sinonjs/fake-timers": "7.1.2",
"@syuilo/aiscript": "0.11.1", "@syuilo/aiscript": "0.11.1",
"@types/bcryptjs": "2.4.2", "@types/bcryptjs": "2.4.2",
"@types/bull": "3.15.5", "@types/bull": "3.15.7",
"@types/cbor": "6.0.0", "@types/cbor": "6.0.0",
"@types/dateformat": "3.0.1", "@types/dateformat": "3.0.1",
"@types/escape-regexp": "0.0.0", "@types/escape-regexp": "0.0.1",
"@types/glob": "7.2.0", "@types/glob": "7.2.0",
"@types/is-url": "1.2.30", "@types/is-url": "1.2.30",
"@types/js-yaml": "4.0.4", "@types/js-yaml": "4.0.5",
"@types/jsdom": "16.2.13", "@types/jsdom": "16.2.14",
"@types/jsonld": "1.5.6", "@types/jsonld": "1.5.6",
"@types/koa": "2.13.4", "@types/koa": "2.13.4",
"@types/koa-bodyparser": "4.3.3", "@types/koa-bodyparser": "4.3.5",
"@types/koa-cors": "0.0.2", "@types/koa-cors": "0.0.2",
"@types/koa-favicon": "2.0.21", "@types/koa-favicon": "2.0.21",
"@types/koa-logger": "3.1.2", "@types/koa-logger": "3.1.2",
"@types/koa-mount": "4.0.1", "@types/koa-mount": "4.0.1",
"@types/koa-send": "4.1.3", "@types/koa-send": "4.1.3",
"@types/koa-views": "7.0.0", "@types/koa-views": "7.0.0",
"@types/koa__cors": "3.0.3", "@types/koa__cors": "3.1.1",
"@types/koa__multer": "2.0.4", "@types/koa__multer": "2.0.4",
"@types/koa__router": "8.0.8", "@types/koa__router": "8.0.11",
"@types/mocha": "8.2.3", "@types/mocha": "8.2.3",
"@types/node": "16.11.7", "@types/node": "17.0.10",
"@types/node-fetch": "2.5.12", "@types/node-fetch": "3.0.3",
"@types/nodemailer": "6.4.4", "@types/nodemailer": "6.4.4",
"@types/oauth": "0.9.1", "@types/oauth": "0.9.1",
"@types/parse5": "6.0.3", "@types/parse5": "6.0.3",
"@types/portscanner": "2.1.1", "@types/portscanner": "2.1.1",
"@types/pug": "2.0.5", "@types/pug": "2.0.6",
"@types/punycode": "2.1.0", "@types/punycode": "2.1.0",
"@types/qrcode": "1.4.1", "@types/qrcode": "1.4.2",
"@types/random-seed": "0.3.3", "@types/random-seed": "0.3.3",
"@types/ratelimiter": "3.4.2", "@types/ratelimiter": "3.4.3",
"@types/redis": "2.8.32", "@types/redis": "4.0.11",
"@types/rename": "1.0.4", "@types/rename": "1.0.4",
"@types/request-stats": "3.0.0", "@types/request-stats": "3.0.0",
"@types/sanitize-html": "2.5.0", "@types/sanitize-html": "2.6.2",
"@types/seedrandom": "2.4.28", "@types/seedrandom": "2.4.28",
"@types/sharp": "0.29.3", "@types/sharp": "0.29.5",
"@types/sinonjs__fake-timers": "6.0.4", "@types/sinonjs__fake-timers": "6.0.4",
"@types/speakeasy": "2.0.6", "@types/speakeasy": "2.0.7",
"@types/throttle-debounce": "2.1.0", "@types/throttle-debounce": "2.1.0",
"@types/tinycolor2": "1.4.3", "@types/tinycolor2": "1.4.3",
"@types/tmp": "0.2.2", "@types/tmp": "0.2.3",
"@types/uuid": "8.3.1", "@types/uuid": "8.3.4",
"@types/web-push": "3.3.2", "@types/web-push": "3.3.2",
"@types/webpack": "5.28.0", "@types/webpack": "5.28.0",
"@types/webpack-stream": "3.2.12", "@types/webpack-stream": "3.2.12",
"@types/websocket": "1.0.4", "@types/websocket": "1.0.4",
"@types/ws": "8.2.0", "@types/ws": "8.2.2",
"@typescript-eslint/eslint-plugin": "5.3.1", "@typescript-eslint/eslint-plugin": "5.10.0",
"@typescript-eslint/parser": "5.1.0", "@typescript-eslint/parser": "5.10.0",
"abort-controller": "3.0.0", "abort-controller": "3.0.0",
"archiver": "5.3.0", "archiver": "5.3.0",
"autobind-decorator": "2.4.0", "autobind-decorator": "2.4.0",
"autwh": "0.1.0", "autwh": "0.1.0",
"aws-sdk": "2.1013.0", "aws-sdk": "2.1061.0",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"blurhash": "1.1.4", "blurhash": "1.1.4",
"broadcast-channel": "4.5.0", "broadcast-channel": "4.9.0",
"bull": "4.1.0", "bull": "4.2.1",
"cacheable-lookup": "6.0.4", "cacheable-lookup": "6.0.4",
"cafy": "15.2.1", "cafy": "15.2.1",
"cbor": "8.1.0", "cbor": "8.1.0",
"chalk": "4.1.2", "chalk": "4.1.2",
"chart.js": "3.6.0",
"chartjs-adapter-date-fns": "2.0.0",
"chartjs-plugin-zoom": "1.1.1",
"cli-highlight": "2.1.11", "cli-highlight": "2.1.11",
"content-disposition": "0.5.3", "content-disposition": "0.5.4",
"crc-32": "1.2.0", "crc-32": "1.2.0",
"css-loader": "6.5.1",
"cssnano": "5.0.10",
"date-fns": "2.25.0",
"dateformat": "4.5.1", "dateformat": "4.5.1",
"deep-email-validator": "0.1.18", "deep-email-validator": "0.1.21",
"escape-regexp": "0.0.1", "escape-regexp": "0.0.1",
"eslint": "8.2.0", "eslint": "8.7.0",
"eslint-plugin-import": "2.25.3", "eslint-plugin-import": "2.25.4",
"eslint-plugin-vue": "8.0.3",
"eventemitter3": "4.0.7", "eventemitter3": "4.0.7",
"feed": "4.2.2", "feed": "4.2.2",
"file-type": "16.5.3", "file-type": "16.5.3",
@ -108,9 +101,9 @@
"glob": "7.2.0", "glob": "7.2.0",
"got": "11.8.2", "got": "11.8.2",
"hpagent": "0.1.2", "hpagent": "0.1.2",
"http-signature": "1.3.5", "http-signature": "1.3.6",
"ip-cidr": "3.0.4", "ip-cidr": "3.0.4",
"is-svg": "4.3.1", "is-svg": "4.3.2",
"js-yaml": "4.1.0", "js-yaml": "4.1.0",
"jsdom": "16.7.0", "jsdom": "16.7.0",
"json5": "2.2.0", "json5": "2.2.0",
@ -127,30 +120,29 @@
"koa-slow": "2.1.0", "koa-slow": "2.1.0",
"koa-views": "7.0.2", "koa-views": "7.0.2",
"langmap": "0.0.16", "langmap": "0.0.16",
"mfm-js": "0.20.0", "mfm-js": "0.21.0",
"mime-types": "2.1.34", "mime-types": "2.1.34",
"misskey-js": "0.0.12", "misskey-js": "0.0.13",
"mocha": "8.4.0", "mocha": "8.4.0",
"ms": "3.0.0-canary.1", "ms": "3.0.0-canary.1",
"multer": "1.4.3", "multer": "1.4.4",
"nested-property": "4.0.0", "nested-property": "4.0.0",
"node-fetch": "2.6.1", "node-fetch": "2.6.1",
"nodemailer": "6.7.0", "nodemailer": "6.7.2",
"os-utils": "0.0.14", "os-utils": "0.0.14",
"parse5": "6.0.1", "parse5": "6.0.1",
"pg": "8.7.1", "pg": "8.7.1",
"portscanner": "2.2.0", "portscanner": "2.2.0",
"prismjs": "1.25.0",
"private-ip": "2.3.3", "private-ip": "2.3.3",
"probe-image-size": "7.2.1", "probe-image-size": "7.2.2",
"promise-limit": "2.7.0", "promise-limit": "2.7.0",
"pug": "3.0.2", "pug": "3.0.2",
"punycode": "2.1.1", "punycode": "2.1.1",
"pureimage": "0.3.5", "pureimage": "0.3.8",
"qrcode": "1.4.4", "qrcode": "1.5.0",
"random-seed": "0.3.0", "random-seed": "0.3.0",
"ratelimiter": "3.4.1", "ratelimiter": "3.4.1",
"re2": "1.16.0", "re2": "1.17.3",
"redis": "3.1.2", "redis": "3.1.2",
"redis-lock": "0.1.4", "redis-lock": "0.1.4",
"reflect-metadata": "0.1.13", "reflect-metadata": "0.1.13",
@ -159,9 +151,9 @@
"require-all": "3.0.0", "require-all": "3.0.0",
"rndstr": "1.0.0", "rndstr": "1.0.0",
"s-age": "1.1.2", "s-age": "1.1.2",
"sanitize-html": "2.5.3", "sanitize-html": "2.6.1",
"seedrandom": "3.0.5", "seedrandom": "3.0.5",
"sharp": "0.29.2", "sharp": "0.29.3",
"speakeasy": "2.0.0", "speakeasy": "2.0.0",
"strict-event-emitter-types": "2.0.0", "strict-event-emitter-types": "2.0.0",
"stringz": "2.1.0", "stringz": "2.1.0",
@ -175,21 +167,21 @@
"ts-loader": "9.2.6", "ts-loader": "9.2.6",
"ts-node": "10.4.0", "ts-node": "10.4.0",
"tsc-alias": "1.4.1", "tsc-alias": "1.4.1",
"tsconfig-paths": "3.11.0", "tsconfig-paths": "3.12.0",
"twemoji-parser": "13.1.0", "twemoji-parser": "13.1.0",
"typeorm": "0.2.39", "typeorm": "0.2.41",
"typescript": "4.4.4", "typescript": "4.5.5",
"ulid": "2.3.0", "ulid": "2.3.0",
"unzipper": "0.10.11", "unzipper": "0.10.11",
"uuid": "8.3.2", "uuid": "8.3.2",
"web-push": "3.4.5", "web-push": "3.4.5",
"websocket": "1.0.34", "websocket": "1.0.34",
"ws": "8.2.3", "ws": "8.4.2",
"xev": "2.0.1" "xev": "2.0.1"
}, },
"devDependencies": { "devDependencies": {
"@redocly/openapi-core": "1.0.0-beta.54", "@redocly/openapi-core": "1.0.0-beta.79",
"@types/fluent-ffmpeg": "2.1.17", "@types/fluent-ffmpeg": "2.1.20",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"execa": "6.0.0" "execa": "6.0.0"
} }

View File

@ -220,7 +220,9 @@ export async function resetDb() {
WHERE nspname NOT IN ('pg_catalog', 'information_schema') WHERE nspname NOT IN ('pg_catalog', 'information_schema')
AND C.relkind = 'r' AND C.relkind = 'r'
AND nspname !~ '^pg_toast';`); AND nspname !~ '^pg_toast';`);
await Promise.all(tables.map(t => t.table).map(x => conn.query(`DELETE FROM "${x}" CASCADE`))); for (const table of tables) {
await conn.query(`DELETE FROM "${table.table}" CASCADE`);
}
}; };
for (let i = 1; i <= 3; i++) { for (let i = 1; i <= 3; i++) {

View File

@ -62,7 +62,8 @@ export async function populateEmoji(emojiName: string, noteUserHost: string | nu
if (emoji == null) return null; if (emoji == null) return null;
const isLocal = emoji.host == null; const isLocal = emoji.host == null;
const url = isLocal ? emoji.url : `${config.url}/proxy/image.png?${query({ url: emoji.url })}`; const emojiUrl = emoji.publicUrl || emoji.originalUrl; // || emoji.originalUrl してるのは後方互換性のため
const url = isLocal ? emojiUrl : `${config.url}/proxy/image.png?${query({ url: emojiUrl })}`;
return { return {
name: emojiName, name: emojiName,
@ -116,7 +117,7 @@ export async function prefetchEmojis(emojis: { name: string; host: string | null
} }
const _emojis = emojisQuery.length > 0 ? await Emojis.find({ const _emojis = emojisQuery.length > 0 ? await Emojis.find({
where: emojisQuery, where: emojisQuery,
select: ['name', 'host', 'url'], select: ['name', 'host', 'originalUrl', 'publicUrl'],
}) : []; }) : [];
for (const emoji of _emojis) { for (const emoji of _emojis) {
cache.set(`${emoji.name} ${emoji.host}`, emoji); cache.set(`${emoji.name} ${emoji.host}`, emoji);

View File

@ -1,30 +1,44 @@
import { SimpleObj, SimpleSchema } from './simple-schema'; import {
import { packedUserSchema } from '@/models/repositories/user'; packedUserLiteSchema,
import { packedNoteSchema } from '@/models/repositories/note'; packedUserDetailedNotMeOnlySchema,
import { packedUserListSchema } from '@/models/repositories/user-list'; packedMeDetailedOnlySchema,
import { packedAppSchema } from '@/models/repositories/app'; packedUserDetailedNotMeSchema,
import { packedMessagingMessageSchema } from '@/models/repositories/messaging-message'; packedMeDetailedSchema,
import { packedNotificationSchema } from '@/models/repositories/notification'; packedUserDetailedSchema,
import { packedDriveFileSchema } from '@/models/repositories/drive-file'; packedUserSchema,
import { packedDriveFolderSchema } from '@/models/repositories/drive-folder'; } from '@/models/schema/user';
import { packedFollowingSchema } from '@/models/repositories/following'; import { packedNoteSchema } from '@/models/schema/note';
import { packedMutingSchema } from '@/models/repositories/muting'; import { packedUserListSchema } from '@/models/schema/user-list';
import { packedBlockingSchema } from '@/models/repositories/blocking'; import { packedAppSchema } from '@/models/schema/app';
import { packedNoteReactionSchema } from '@/models/repositories/note-reaction'; import { packedMessagingMessageSchema } from '@/models/schema/messaging-message';
import { packedHashtagSchema } from '@/models/repositories/hashtag'; import { packedNotificationSchema } from '@/models/schema/notification';
import { packedPageSchema } from '@/models/repositories/page'; import { packedDriveFileSchema } from '@/models/schema/drive-file';
import { packedUserGroupSchema } from '@/models/repositories/user-group'; import { packedDriveFolderSchema } from '@/models/schema/drive-folder';
import { packedNoteFavoriteSchema } from '@/models/repositories/note-favorite'; import { packedFollowingSchema } from '@/models/schema/following';
import { packedChannelSchema } from '@/models/repositories/channel'; import { packedMutingSchema } from '@/models/schema/muting';
import { packedAntennaSchema } from '@/models/repositories/antenna'; import { packedBlockingSchema } from '@/models/schema/blocking';
import { packedClipSchema } from '@/models/repositories/clip'; import { packedNoteReactionSchema } from '@/models/schema/note-reaction';
import { packedFederationInstanceSchema } from '@/models/repositories/federation-instance'; import { packedHashtagSchema } from '@/models/schema/hashtag';
import { packedQueueCountSchema } from '@/models/repositories/queue'; import { packedPageSchema } from '@/models/schema/page';
import { packedGalleryPostSchema } from '@/models/repositories/gallery-post'; import { packedUserGroupSchema } from '@/models/schema/user-group';
import { packedEmojiSchema } from '@/models/repositories/emoji'; import { packedNoteFavoriteSchema } from '@/models/schema/note-favorite';
import { packedChannelSchema } from '@/models/schema/channel';
import { packedAntennaSchema } from '@/models/schema/antenna';
import { packedClipSchema } from '@/models/schema/clip';
import { packedFederationInstanceSchema } from '@/models/schema/federation-instance';
import { packedQueueCountSchema } from '@/models/schema/queue';
import { packedGalleryPostSchema } from '@/models/schema/gallery-post';
import { packedEmojiSchema } from '@/models/schema/emoji';
export const refs = { export const refs = {
UserLite: packedUserLiteSchema,
UserDetailedNotMeOnly: packedUserDetailedNotMeOnlySchema,
MeDetailedOnly: packedMeDetailedOnlySchema,
UserDetailedNotMe: packedUserDetailedNotMeSchema,
MeDetailed: packedMeDetailedSchema,
UserDetailed: packedUserDetailedSchema,
User: packedUserSchema, User: packedUserSchema,
UserList: packedUserListSchema, UserList: packedUserListSchema,
UserGroup: packedUserGroupSchema, UserGroup: packedUserGroupSchema,
App: packedAppSchema, App: packedAppSchema,
@ -49,12 +63,50 @@ export const refs = {
Emoji: packedEmojiSchema, Emoji: packedEmojiSchema,
}; };
export type Packed<x extends keyof typeof refs> = ObjType<(typeof refs[x])['properties']>; // Packed = SchemaTypeDef<typeof refs[x]>; とすると展開されてマウスホバー時に型表示が使い物にならなくなる
// ObjType<r['properties']>を指定するとなぜか展開されずにPacked<'Hoge'>と表示される
type PackedDef<r extends { properties?: Obj; oneOf?: ReadonlyArray<MinimumSchema>; allOf?: ReadonlyArray<MinimumSchema> }> =
r['allOf'] extends ReadonlyArray<MinimumSchema> ? UnionToIntersection<UnionSchemaType<r['allOf']>> :
r['oneOf'] extends ReadonlyArray<MinimumSchema> ? UnionSchemaType<r['oneOf']> :
r['properties'] extends Obj ? ObjType<r['properties']> :
never;
export type Packed<x extends keyof typeof refs> = PackedDef<typeof refs[x]>;
export interface Schema extends SimpleSchema { type TypeStringef = 'boolean' | 'number' | 'string' | 'array' | 'object' | 'any';
items?: Schema; type StringDefToType<T extends TypeStringef> =
properties?: Obj; T extends 'boolean' ? boolean :
ref?: keyof typeof refs; T extends 'number' ? number :
T extends 'string' ? string | Date :
T extends 'array' ? ReadonlyArray<any> :
T extends 'object' ? Record<string, any> :
any;
// https://swagger.io/specification/?sbsearch=optional#schema-object
type OfSchema = {
readonly anyOf?: ReadonlyArray<MinimumSchema>;
readonly oneOf?: ReadonlyArray<MinimumSchema>;
readonly allOf?: ReadonlyArray<MinimumSchema>;
}
export interface MinimumSchema extends OfSchema {
readonly type?: TypeStringef;
readonly nullable?: boolean;
readonly optional?: boolean;
readonly items?: MinimumSchema;
readonly properties?: Obj;
readonly description?: string;
readonly example?: any;
readonly format?: string;
readonly ref?: keyof typeof refs;
readonly enum?: ReadonlyArray<string>;
readonly default?: (this['type'] extends TypeStringef ? StringDefToType<this['type']> : any) | null;
readonly maxLength?: number;
readonly minLength?: number;
}
export interface Schema extends MinimumSchema {
readonly nullable: boolean;
readonly optional: boolean;
} }
type NonUndefinedPropertyNames<T extends Obj> = { type NonUndefinedPropertyNames<T extends Obj> = {
@ -65,22 +117,13 @@ type UndefinedPropertyNames<T extends Obj> = {
[K in keyof T]: T[K]['optional'] extends true ? K : never [K in keyof T]: T[K]['optional'] extends true ? K : never
}[keyof T]; }[keyof T];
type OnlyRequired<T extends Obj> = Pick<T, NonUndefinedPropertyNames<T>>; export interface Obj { [key: string]: Schema; }
type OnlyOptional<T extends Obj> = Pick<T, UndefinedPropertyNames<T>>;
export interface Obj extends SimpleObj { [key: string]: Schema; }
export type ObjType<s extends Obj> = export type ObjType<s extends Obj> =
{ [P in keyof OnlyOptional<s>]?: SchemaType<s[P]> } & { -readonly [P in UndefinedPropertyNames<s>]?: SchemaType<s[P]> } &
{ [P in keyof OnlyRequired<s>]: SchemaType<s[P]> }; { -readonly [P in NonUndefinedPropertyNames<s>]: SchemaType<s[P]> };
// https://qiita.com/hrsh7th@github/items/84e8968c3601009cdcf2 type NullOrUndefined<p extends MinimumSchema, T> =
type MyType<T extends Schema> = {
0: any;
1: SchemaType<T>;
}[T extends Schema ? 1 : 0];
type NullOrUndefined<p extends Schema, T> =
p['nullable'] extends true p['nullable'] extends true
? p['optional'] extends true ? p['optional'] extends true
? (T | null | undefined) ? (T | null | undefined)
@ -89,15 +132,41 @@ type NullOrUndefined<p extends Schema, T> =
? (T | undefined) ? (T | undefined)
: T; : T;
export type SchemaType<p extends Schema> = // 共用体型を交差型にする型 https://stackoverflow.com/questions/54938141/typescript-convert-union-to-intersection
p['type'] extends 'number' ? NullOrUndefined<p, number> : type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
p['type'] extends 'string' ? NullOrUndefined<p, string> :
p['type'] extends 'boolean' ? NullOrUndefined<p, boolean> : // https://github.com/misskey-dev/misskey/pull/8144#discussion_r785287552
p['type'] extends 'array' ? NullOrUndefined<p, MyType<NonNullable<p['items']>>[]> : // 単純にSchemaTypeDef<X>で判定するだけではダメ
p['type'] extends 'object' ? ( type UnionSchemaType<a extends readonly any[], X extends MinimumSchema = a[number]> = X extends any ? SchemaType<X> : never;
p['ref'] extends keyof typeof refs type ArrayUnion<T> = T extends any ? Array<T> : never;
? NullOrUndefined<p, Packed<p['ref']>>
: NullOrUndefined<p, ObjType<NonNullable<p['properties']>>> export type SchemaTypeDef<p extends MinimumSchema> =
p['type'] extends 'number' ? number :
p['type'] extends 'string' ? (
p['enum'] extends readonly string[] ?
p['enum'][number] :
p['format'] extends 'date-time' ? string : // Dateにする
string
) : ) :
p['type'] extends 'any' ? NullOrUndefined<p, any> : p['type'] extends 'boolean' ? boolean :
p['type'] extends 'object' ? (
p['ref'] extends keyof typeof refs ? Packed<p['ref']> :
p['properties'] extends NonNullable<Obj> ? ObjType<p['properties']> :
p['anyOf'] extends ReadonlyArray<MinimumSchema> ? UnionSchemaType<p['anyOf']> & Partial<UnionToIntersection<UnionSchemaType<p['anyOf']>>> :
p['allOf'] extends ReadonlyArray<MinimumSchema> ? UnionToIntersection<UnionSchemaType<p['allOf']>> :
any
) :
p['type'] extends 'array' ? (
p['items'] extends OfSchema ? (
p['items']['anyOf'] extends ReadonlyArray<MinimumSchema> ? UnionSchemaType<NonNullable<p['items']['anyOf']>>[] :
p['items']['oneOf'] extends ReadonlyArray<MinimumSchema> ? ArrayUnion<UnionSchemaType<NonNullable<p['items']['oneOf']>>> :
p['items']['allOf'] extends ReadonlyArray<MinimumSchema> ? UnionToIntersection<UnionSchemaType<NonNullable<p['items']['allOf']>>>[] :
never
) :
p['items'] extends NonNullable<MinimumSchema> ? SchemaTypeDef<p['items']>[] :
any[]
) :
p['oneOf'] extends ReadonlyArray<MinimumSchema> ? UnionSchemaType<p['oneOf']> :
any; any;
export type SchemaType<p extends MinimumSchema> = NullOrUndefined<p, SchemaTypeDef<p>>;

View File

@ -1,15 +0,0 @@
export interface SimpleSchema {
type: 'boolean' | 'number' | 'string' | 'array' | 'object' | 'any';
nullable: boolean;
optional: boolean;
items?: SimpleSchema;
properties?: SimpleObj;
description?: string;
example?: any;
format?: string;
ref?: string;
enum?: string[];
default?: boolean | null;
}
export interface SimpleObj { [key: string]: SimpleSchema; }

View File

@ -51,6 +51,11 @@ export class AbuseUserReport {
}) })
public resolved: boolean; public resolved: boolean;
@Column('boolean', {
default: false
})
public forwarded: boolean;
@Column('varchar', { @Column('varchar', {
length: 2048, length: 2048,
}) })

View File

@ -101,6 +101,11 @@ export class DriveFile {
}) })
public webpublicUrl: string | null; public webpublicUrl: string | null;
@Column('varchar', {
length: 128, nullable: true,
})
public webpublicType: string | null;
@Index({ unique: true }) @Index({ unique: true })
@Column('varchar', { @Column('varchar', {
length: 256, nullable: true, length: 256, nullable: true,

View File

@ -32,13 +32,19 @@ export class Emoji {
@Column('varchar', { @Column('varchar', {
length: 512, length: 512,
}) })
public url: string; public originalUrl: string;
@Column('varchar', {
length: 512,
})
public publicUrl: string;
@Column('varchar', { @Column('varchar', {
length: 512, nullable: true, length: 512, nullable: true,
}) })
public uri: string | null; public uri: string | null;
// publicUrlの方のtypeが入る
@Column('varchar', { @Column('varchar', {
length: 64, nullable: true, length: 64, nullable: true,
}) })

View File

@ -27,6 +27,7 @@ export class AbuseUserReportRepository extends Repository<AbuseUserReport> {
assignee: report.assigneeId ? Users.pack(report.assignee || report.assigneeId, null, { assignee: report.assigneeId ? Users.pack(report.assignee || report.assigneeId, null, {
detail: true, detail: true,
}) : null, }) : null,
forwarded: report.forwarded,
}); });
} }

View File

@ -31,94 +31,3 @@ export class AntennaRepository extends Repository<Antenna> {
}; };
} }
} }
export const packedAntennaSchema = {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
id: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
},
name: {
type: 'string' as const,
optional: false as const, nullable: false as const,
},
keywords: {
type: 'array' as const,
optional: false as const, nullable: false as const,
items: {
type: 'array' as const,
optional: false as const, nullable: false as const,
items: {
type: 'string' as const,
optional: false as const, nullable: false as const,
},
},
},
excludeKeywords: {
type: 'array' as const,
optional: false as const, nullable: false as const,
items: {
type: 'array' as const,
optional: false as const, nullable: false as const,
items: {
type: 'string' as const,
optional: false as const, nullable: false as const,
},
},
},
src: {
type: 'string' as const,
optional: false as const, nullable: false as const,
enum: ['home', 'all', 'users', 'list', 'group'],
},
userListId: {
type: 'string' as const,
optional: false as const, nullable: true as const,
format: 'id',
},
userGroupId: {
type: 'string' as const,
optional: false as const, nullable: true as const,
format: 'id',
},
users: {
type: 'array' as const,
optional: false as const, nullable: false as const,
items: {
type: 'string' as const,
optional: false as const, nullable: false as const,
},
},
caseSensitive: {
type: 'boolean' as const,
optional: false as const, nullable: false as const,
default: false,
},
notify: {
type: 'boolean' as const,
optional: false as const, nullable: false as const,
},
withReplies: {
type: 'boolean' as const,
optional: false as const, nullable: false as const,
default: false,
},
withFile: {
type: 'boolean' as const,
optional: false as const, nullable: false as const,
},
hasUnreadNote: {
type: 'boolean' as const,
optional: false as const, nullable: false as const,
default: false,
},
},
};

View File

@ -38,38 +38,3 @@ export class AppRepository extends Repository<App> {
}; };
} }
} }
export const packedAppSchema = {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
id: {
type: 'string' as const,
optional: false as const, nullable: false as const,
},
name: {
type: 'string' as const,
optional: false as const, nullable: false as const,
},
callbackUrl: {
type: 'string' as const,
optional: false as const, nullable: true as const,
},
permission: {
type: 'array' as const,
optional: false as const, nullable: false as const,
items: {
type: 'string' as const,
optional: false as const, nullable: false as const,
},
},
secret: {
type: 'string' as const,
optional: true as const, nullable: false as const,
},
isAuthorized: {
type: 'boolean' as const,
optional: true as const, nullable: false as const,
},
},
};

View File

@ -30,31 +30,3 @@ export class BlockingRepository extends Repository<Blocking> {
return Promise.all(blockings.map(x => this.pack(x, me))); return Promise.all(blockings.map(x => this.pack(x, me)));
} }
} }
export const packedBlockingSchema = {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
id: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
},
blockeeId: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
},
blockee: {
type: 'object' as const,
optional: false as const, nullable: false as const,
ref: 'User' as const,
},
},
};

View File

@ -40,56 +40,3 @@ export class ChannelRepository extends Repository<Channel> {
}; };
} }
} }
export const packedChannelSchema = {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
id: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
},
lastNotedAt: {
type: 'string' as const,
optional: false as const, nullable: true as const,
format: 'date-time',
},
name: {
type: 'string' as const,
optional: false as const, nullable: false as const,
},
description: {
type: 'string' as const,
nullable: true as const, optional: false as const,
},
bannerUrl: {
type: 'string' as const,
format: 'url',
nullable: true as const, optional: false as const,
},
notesCount: {
type: 'number' as const,
nullable: false as const, optional: false as const,
},
usersCount: {
type: 'number' as const,
nullable: false as const, optional: false as const,
},
isFollowing: {
type: 'boolean' as const,
optional: true as const, nullable: false as const,
},
userId: {
type: 'string' as const,
nullable: true as const, optional: false as const,
format: 'id',
},
},
};

View File

@ -29,42 +29,3 @@ export class ClipRepository extends Repository<Clip> {
} }
} }
export const packedClipSchema = {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
id: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
},
userId: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
},
user: {
type: 'object' as const,
ref: 'User' as const,
optional: false as const, nullable: false as const,
},
name: {
type: 'string' as const,
optional: false as const, nullable: false as const,
},
description: {
type: 'string' as const,
optional: false as const, nullable: true as const,
},
isPublic: {
type: 'boolean' as const,
optional: false as const, nullable: false as const,
},
},
};

View File

@ -3,7 +3,7 @@ import { DriveFile } from '@/models/entities/drive-file';
import { Users, DriveFolders } from '../index'; import { Users, DriveFolders } from '../index';
import { User } from '@/models/entities/user'; import { User } from '@/models/entities/user';
import { toPuny } from '@/misc/convert-host'; import { toPuny } from '@/misc/convert-host';
import { awaitAll } from '@/prelude/await-all'; import { awaitAll, Promiseable } from '@/prelude/await-all';
import { Packed } from '@/misc/schema'; import { Packed } from '@/misc/schema';
import config from '@/config/index'; import config from '@/config/index';
import { query, appendQuery } from '@/prelude/url'; import { query, appendQuery } from '@/prelude/url';
@ -126,7 +126,7 @@ export class DriveFileRepository extends Repository<DriveFile> {
const meta = await fetchMeta(); const meta = await fetchMeta();
return await awaitAll({ return await awaitAll<Packed<'DriveFile'>>({
id: file.id, id: file.id,
createdAt: file.createdAt.toISOString(), createdAt: file.createdAt.toISOString(),
name: file.name, name: file.name,
@ -156,112 +156,3 @@ export class DriveFileRepository extends Repository<DriveFile> {
return items.filter(x => x != null); return items.filter(x => x != null);
} }
} }
export const packedDriveFileSchema = {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
id: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
},
name: {
type: 'string' as const,
optional: false as const, nullable: false as const,
example: 'lenna.jpg',
},
type: {
type: 'string' as const,
optional: false as const, nullable: false as const,
example: 'image/jpeg',
},
md5: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'md5',
example: '15eca7fba0480996e2245f5185bf39f2',
},
size: {
type: 'number' as const,
optional: false as const, nullable: false as const,
example: 51469,
},
isSensitive: {
type: 'boolean' as const,
optional: false as const, nullable: false as const,
},
blurhash: {
type: 'string' as const,
optional: false as const, nullable: true as const,
},
properties: {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
width: {
type: 'number' as const,
optional: true as const, nullable: false as const,
example: 1280,
},
height: {
type: 'number' as const,
optional: true as const, nullable: false as const,
example: 720,
},
orientation: {
type: 'number' as const,
optional: true as const, nullable: false as const,
example: 8,
},
avgColor: {
type: 'string' as const,
optional: true as const, nullable: false as const,
example: 'rgb(40,65,87)',
},
},
},
url: {
type: 'string' as const,
optional: false as const, nullable: true as const,
format: 'url',
},
thumbnailUrl: {
type: 'string' as const,
optional: false as const, nullable: true as const,
format: 'url',
},
comment: {
type: 'string' as const,
optional: false as const, nullable: true as const,
},
folderId: {
type: 'string' as const,
optional: false as const, nullable: true as const,
format: 'id',
example: 'xxxxxxxxxx',
},
folder: {
type: 'object' as const,
optional: true as const, nullable: true as const,
ref: 'DriveFolder' as const,
},
userId: {
type: 'string' as const,
optional: false as const, nullable: true as const,
format: 'id',
example: 'xxxxxxxxxx',
},
user: {
type: 'object' as const,
optional: true as const, nullable: true as const,
ref: 'User' as const,
},
},
};

View File

@ -48,44 +48,3 @@ export class DriveFolderRepository extends Repository<DriveFolder> {
}); });
} }
} }
export const packedDriveFolderSchema = {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
id: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
},
name: {
type: 'string' as const,
optional: false as const, nullable: false as const,
},
foldersCount: {
type: 'number' as const,
optional: true as const, nullable: false as const,
},
filesCount: {
type: 'number' as const,
optional: true as const, nullable: false as const,
},
parentId: {
type: 'string' as const,
optional: false as const, nullable: true as const,
format: 'id',
example: 'xxxxxxxxxx',
},
parent: {
type: 'object' as const,
optional: true as const, nullable: true as const,
ref: 'DriveFolder' as const,
},
},
};

View File

@ -15,7 +15,8 @@ export class EmojiRepository extends Repository<Emoji> {
name: emoji.name, name: emoji.name,
category: emoji.category, category: emoji.category,
host: emoji.host, host: emoji.host,
url: emoji.url, // || emoji.originalUrl してるのは後方互換性のため
url: emoji.publicUrl || emoji.originalUrl,
}; };
} }
@ -25,41 +26,3 @@ export class EmojiRepository extends Repository<Emoji> {
return Promise.all(emojis.map(x => this.pack(x))); return Promise.all(emojis.map(x => this.pack(x)));
} }
} }
export const packedEmojiSchema = {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
id: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
example: 'xxxxxxxxxx',
},
aliases: {
type: 'array' as const,
optional: false as const, nullable: false as const,
items: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
},
},
name: {
type: 'string' as const,
optional: false as const, nullable: false as const,
},
category: {
type: 'string' as const,
optional: false as const, nullable: true as const,
},
host: {
type: 'string' as const,
optional: false as const, nullable: true as const,
},
url: {
type: 'string' as const,
optional: false as const, nullable: false as const,
},
},
};

View File

@ -1,106 +1,2 @@
import config from '@/config/index'; import config from '@/config/index';
export const packedFederationInstanceSchema = {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
id: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
},
caughtAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
},
host: {
type: 'string' as const,
optional: false as const, nullable: false as const,
example: 'misskey.example.com',
},
usersCount: {
type: 'number' as const,
optional: false as const, nullable: false as const,
},
notesCount: {
type: 'number' as const,
optional: false as const, nullable: false as const,
},
followingCount: {
type: 'number' as const,
optional: false as const, nullable: false as const,
},
followersCount: {
type: 'number' as const,
optional: false as const, nullable: false as const,
},
driveUsage: {
type: 'number' as const,
optional: false as const, nullable: false as const,
},
driveFiles: {
type: 'number' as const,
optional: false as const, nullable: false as const,
},
latestRequestSentAt: {
type: 'string' as const,
optional: false as const, nullable: true as const,
format: 'date-time',
},
lastCommunicatedAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
},
isNotResponding: {
type: 'boolean' as const,
optional: false as const, nullable: false as const,
},
isSuspended: {
type: 'boolean' as const,
optional: false as const, nullable: false as const,
},
softwareName: {
type: 'string' as const,
optional: false as const, nullable: true as const,
example: 'misskey',
},
softwareVersion: {
type: 'string' as const,
optional: false as const, nullable: true as const,
example: config.version,
},
openRegistrations: {
type: 'boolean' as const,
optional: false as const, nullable: true as const,
example: true,
},
name: {
type: 'string' as const,
optional: false as const, nullable: true as const,
},
description: {
type: 'string' as const,
optional: false as const, nullable: true as const,
},
maintainerName: {
type: 'string' as const,
optional: false as const, nullable: true as const,
},
maintainerEmail: {
type: 'string' as const,
optional: false as const, nullable: true as const,
},
iconUrl: {
type: 'string' as const,
optional: false as const, nullable: true as const,
format: 'url',
},
infoUpdatedAt: {
type: 'string' as const,
optional: false as const, nullable: true as const,
format: 'date-time',
},
},
};

View File

@ -84,41 +84,3 @@ export class FollowingRepository extends Repository<Following> {
return Promise.all(followings.map(x => this.pack(x, me, opts))); return Promise.all(followings.map(x => this.pack(x, me, opts)));
} }
} }
export const packedFollowingSchema = {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
id: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
},
followeeId: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
},
followee: {
type: 'object' as const,
optional: true as const, nullable: false as const,
ref: 'User' as const,
},
followerId: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
},
follower: {
type: 'object' as const,
optional: true as const, nullable: false as const,
ref: 'User' as const,
},
},
};

View File

@ -38,74 +38,3 @@ export class GalleryPostRepository extends Repository<GalleryPost> {
return Promise.all(posts.map(x => this.pack(x, me))); return Promise.all(posts.map(x => this.pack(x, me)));
} }
} }
export const packedGalleryPostSchema = {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
id: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
},
updatedAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
},
title: {
type: 'string' as const,
optional: false as const, nullable: false as const,
},
description: {
type: 'string' as const,
optional: false as const, nullable: true as const,
},
userId: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
},
user: {
type: 'object' as const,
ref: 'User' as const,
optional: false as const, nullable: false as const,
},
fileIds: {
type: 'array' as const,
optional: true as const, nullable: false as const,
items: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
},
},
files: {
type: 'array' as const,
optional: true as const, nullable: false as const,
items: {
type: 'object' as const,
optional: false as const, nullable: false as const,
ref: 'DriveFile' as const,
},
},
tags: {
type: 'array' as const,
optional: true as const, nullable: false as const,
items: {
type: 'string' as const,
optional: false as const, nullable: false as const,
},
},
isSensitive: {
type: 'boolean' as const,
optional: false as const, nullable: false as const,
},
},
};

View File

@ -24,39 +24,3 @@ export class HashtagRepository extends Repository<Hashtag> {
return Promise.all(hashtags.map(x => this.pack(x))); return Promise.all(hashtags.map(x => this.pack(x)));
} }
} }
export const packedHashtagSchema = {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
tag: {
type: 'string' as const,
optional: false as const, nullable: false as const,
example: 'misskey',
},
mentionedUsersCount: {
type: 'number' as const,
optional: false as const, nullable: false as const,
},
mentionedLocalUsersCount: {
type: 'number' as const,
optional: false as const, nullable: false as const,
},
mentionedRemoteUsersCount: {
type: 'number' as const,
optional: false as const, nullable: false as const,
},
attachedUsersCount: {
type: 'number' as const,
optional: false as const, nullable: false as const,
},
attachedLocalUsersCount: {
type: 'number' as const,
optional: false as const, nullable: false as const,
},
attachedRemoteUsersCount: {
type: 'number' as const,
optional: false as const, nullable: false as const,
},
},
};

View File

@ -42,78 +42,3 @@ export class MessagingMessageRepository extends Repository<MessagingMessage> {
}; };
} }
} }
export const packedMessagingMessageSchema = {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
id: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
},
userId: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
},
user: {
type: 'object' as const,
ref: 'User' as const,
optional: true as const, nullable: false as const,
},
text: {
type: 'string' as const,
optional: false as const, nullable: true as const,
},
fileId: {
type: 'string' as const,
optional: true as const, nullable: true as const,
format: 'id',
},
file: {
type: 'object' as const,
optional: true as const, nullable: true as const,
ref: 'DriveFile' as const,
},
recipientId: {
type: 'string' as const,
optional: false as const, nullable: true as const,
format: 'id',
},
recipient: {
type: 'object' as const,
optional: true as const, nullable: true as const,
ref: 'User' as const,
},
groupId: {
type: 'string' as const,
optional: false as const, nullable: true as const,
format: 'id',
},
group: {
type: 'object' as const,
optional: true as const, nullable: true as const,
ref: 'UserGroup' as const,
},
isRead: {
type: 'boolean' as const,
optional: true as const, nullable: false as const,
},
reads: {
type: 'array' as const,
optional: true as const, nullable: false as const,
items: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
},
},
},
};

View File

@ -30,31 +30,3 @@ export class MutingRepository extends Repository<Muting> {
return Promise.all(mutings.map(x => this.pack(x, me))); return Promise.all(mutings.map(x => this.pack(x, me)));
} }
} }
export const packedMutingSchema = {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
id: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
},
muteeId: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
},
mutee: {
type: 'object' as const,
optional: false as const, nullable: false as const,
ref: 'User' as const,
},
},
};

View File

@ -26,31 +26,3 @@ export class NoteFavoriteRepository extends Repository<NoteFavorite> {
return Promise.all(favorites.map(x => this.pack(x, me))); return Promise.all(favorites.map(x => this.pack(x, me)));
} }
} }
export const packedNoteFavoriteSchema = {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
id: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
},
note: {
type: 'object' as const,
optional: false as const, nullable: false as const,
ref: 'Note' as const,
},
noteId: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
},
},
};

View File

@ -31,30 +31,3 @@ export class NoteReactionRepository extends Repository<NoteReaction> {
}; };
} }
} }
export const packedNoteReactionSchema = {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
id: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
},
user: {
type: 'object' as const,
optional: false as const, nullable: false as const,
ref: 'User' as const,
},
type: {
type: 'string' as const,
optional: false as const, nullable: false as const,
},
},
};

View File

@ -218,7 +218,7 @@ export class NoteRepository extends Repository<Note> {
const reactionEmojiNames = Object.keys(note.reactions).filter(x => x?.startsWith(':')).map(x => decodeReaction(x).reaction).map(x => x.replace(/:/g, '')); const reactionEmojiNames = Object.keys(note.reactions).filter(x => x?.startsWith(':')).map(x => decodeReaction(x).reaction).map(x => x.replace(/:/g, ''));
const packed = await awaitAll({ const packed: Packed<'Note'> = await awaitAll({
id: note.id, id: note.id,
createdAt: note.createdAt.toISOString(), createdAt: note.createdAt.toISOString(),
userId: note.userId, userId: note.userId,
@ -320,188 +320,3 @@ export class NoteRepository extends Repository<Note> {
}))); })));
} }
} }
export const packedNoteSchema = {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
id: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
},
text: {
type: 'string' as const,
optional: false as const, nullable: true as const,
},
cw: {
type: 'string' as const,
optional: true as const, nullable: true as const,
},
userId: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
},
user: {
type: 'object' as const,
ref: 'User' as const,
optional: false as const, nullable: false as const,
},
replyId: {
type: 'string' as const,
optional: true as const, nullable: true as const,
format: 'id',
example: 'xxxxxxxxxx',
},
renoteId: {
type: 'string' as const,
optional: true as const, nullable: true as const,
format: 'id',
example: 'xxxxxxxxxx',
},
reply: {
type: 'object' as const,
optional: true as const, nullable: true as const,
ref: 'Note' as const,
},
renote: {
type: 'object' as const,
optional: true as const, nullable: true as const,
ref: 'Note' as const,
},
isHidden: {
type: 'boolean' as const,
optional: true as const, nullable: false as const,
},
visibility: {
type: 'string' as const,
optional: false as const, nullable: false as const,
},
mentions: {
type: 'array' as const,
optional: true as const, nullable: false as const,
items: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
},
},
visibleUserIds: {
type: 'array' as const,
optional: true as const, nullable: false as const,
items: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
},
},
fileIds: {
type: 'array' as const,
optional: true as const, nullable: false as const,
items: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
},
},
files: {
type: 'array' as const,
optional: true as const, nullable: false as const,
items: {
type: 'object' as const,
optional: false as const, nullable: false as const,
ref: 'DriveFile' as const,
},
},
tags: {
type: 'array' as const,
optional: true as const, nullable: false as const,
items: {
type: 'string' as const,
optional: false as const, nullable: false as const,
},
},
poll: {
type: 'object' as const,
optional: true as const, nullable: true as const,
},
channelId: {
type: 'string' as const,
optional: true as const, nullable: true as const,
format: 'id',
example: 'xxxxxxxxxx',
},
channel: {
type: 'object' as const,
optional: true as const, nullable: true as const,
items: {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
id: {
type: 'string' as const,
optional: false as const, nullable: false as const,
},
name: {
type: 'string' as const,
optional: false as const, nullable: true as const,
},
},
},
},
localOnly: {
type: 'boolean' as const,
optional: true as const, nullable: false as const,
},
emojis: {
type: 'array' as const,
optional: false as const, nullable: false as const,
items: {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
name: {
type: 'string' as const,
optional: false as const, nullable: false as const,
},
url: {
type: 'string' as const,
optional: false as const, nullable: true as const,
},
},
},
},
reactions: {
type: 'object' as const,
optional: false as const, nullable: false as const,
},
renoteCount: {
type: 'number' as const,
optional: false as const, nullable: false as const,
},
repliesCount: {
type: 'number' as const,
optional: false as const, nullable: false as const,
},
uri: {
type: 'string' as const,
optional: true as const, nullable: false as const,
},
url: {
type: 'string' as const,
optional: true as const, nullable: false as const,
},
myReaction: {
type: 'object' as const,
optional: true as const, nullable: true as const,
},
},
};

View File

@ -107,69 +107,3 @@ export class NotificationRepository extends Repository<Notification> {
}))); })));
} }
} }
export const packedNotificationSchema = {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
id: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
},
isRead: {
type: 'boolean' as const,
optional: false as const, nullable: false as const,
},
type: {
type: 'string' as const,
optional: false as const, nullable: false as const,
enum: [...notificationTypes],
},
user: {
type: 'object' as const,
ref: 'User' as const,
optional: true as const, nullable: true as const,
},
userId: {
type: 'string' as const,
optional: true as const, nullable: true as const,
format: 'id',
},
note: {
type: 'object' as const,
ref: 'Note' as const,
optional: true as const, nullable: true as const,
},
reaction: {
type: 'string' as const,
optional: true as const, nullable: true as const,
},
choice: {
type: 'number' as const,
optional: true as const, nullable: true as const,
},
invitation: {
type: 'object' as const,
optional: true as const, nullable: true as const,
},
body: {
type: 'string' as const,
optional: true as const, nullable: true as const,
},
header: {
type: 'string' as const,
optional: true as const, nullable: true as const,
},
icon: {
type: 'string' as const,
optional: true as const, nullable: true as const,
},
},
};

View File

@ -87,56 +87,3 @@ export class PageRepository extends Repository<Page> {
return Promise.all(pages.map(x => this.pack(x, me))); return Promise.all(pages.map(x => this.pack(x, me)));
} }
} }
export const packedPageSchema = {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
id: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
},
updatedAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
},
title: {
type: 'string' as const,
optional: false as const, nullable: false as const,
},
name: {
type: 'string' as const,
optional: false as const, nullable: false as const,
},
summary: {
type: 'string' as const,
optional: false as const, nullable: true as const,
},
content: {
type: 'array' as const,
optional: false as const, nullable: false as const,
},
variables: {
type: 'array' as const,
optional: false as const, nullable: false as const,
},
userId: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
},
user: {
type: 'object' as const,
ref: 'User' as const,
optional: false as const, nullable: false as const,
},
},
};

View File

@ -1,30 +0,0 @@
export const packedQueueCountSchema = {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
waiting: {
type: 'number' as const,
optional: false as const, nullable: false as const,
},
active: {
type: 'number' as const,
optional: false as const, nullable: false as const,
},
completed: {
type: 'number' as const,
optional: false as const, nullable: false as const,
},
failed: {
type: 'number' as const,
optional: false as const, nullable: false as const,
},
delayed: {
type: 'number' as const,
optional: false as const, nullable: false as const,
},
paused: {
type: 'number' as const,
optional: false as const, nullable: false as const,
},
},
};

View File

@ -23,39 +23,3 @@ export class UserGroupRepository extends Repository<UserGroup> {
}; };
} }
} }
export const packedUserGroupSchema = {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
id: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
},
name: {
type: 'string' as const,
optional: false as const, nullable: false as const,
},
ownerId: {
type: 'string' as const,
nullable: false as const, optional: false as const,
format: 'id',
},
userIds: {
type: 'array' as const,
nullable: false as const, optional: true as const,
items: {
type: 'string' as const,
nullable: false as const, optional: false as const,
format: 'id',
},
},
},
};

View File

@ -22,34 +22,3 @@ export class UserListRepository extends Repository<UserList> {
}; };
} }
} }
export const packedUserListSchema = {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
id: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string' as const,
optional: false as const, nullable: false as const,
format: 'date-time',
},
name: {
type: 'string' as const,
optional: false as const, nullable: false as const,
},
userIds: {
type: 'array' as const,
nullable: false as const, optional: true as const,
items: {
type: 'string' as const,
nullable: false as const, optional: false as const,
format: 'id',
},
},
},
};

View File

@ -4,11 +4,19 @@ import { User, ILocalUser, IRemoteUser } from '@/models/entities/user';
import { Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles, UserSecurityKeys, UserGroupJoinings, Pages, Announcements, AnnouncementReads, Antennas, AntennaNotes, ChannelFollowings, Instances } from '../index'; import { Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles, UserSecurityKeys, UserGroupJoinings, Pages, Announcements, AnnouncementReads, Antennas, AntennaNotes, ChannelFollowings, Instances } from '../index';
import config from '@/config/index'; import config from '@/config/index';
import { Packed } from '@/misc/schema'; import { Packed } from '@/misc/schema';
import { awaitAll } from '@/prelude/await-all'; import { awaitAll, Promiseable } from '@/prelude/await-all';
import { populateEmojis } from '@/misc/populate-emojis'; import { populateEmojis } from '@/misc/populate-emojis';
import { getAntennas } from '@/misc/antenna-cache'; import { getAntennas } from '@/misc/antenna-cache';
import { USER_ACTIVE_THRESHOLD, USER_ONLINE_THRESHOLD } from '@/const'; import { USER_ACTIVE_THRESHOLD, USER_ONLINE_THRESHOLD } from '@/const';
type IsUserDetailed<Detailed extends boolean> = Detailed extends true ? Packed<'UserDetailed'> : Packed<'UserLite'>;
type IsMeAndIsUserDetailed<ExpectsMe extends boolean | null, Detailed extends boolean> =
Detailed extends true ?
ExpectsMe extends true ? Packed<'MeDetailed'> :
ExpectsMe extends false ? Packed<'UserDetailedNotMe'> :
Packed<'UserDetailed'> :
Packed<'UserLite'>;
@EntityRepository(User) @EntityRepository(User)
export class UserRepository extends Repository<User> { export class UserRepository extends Repository<User> {
public async getRelation(me: User['id'], target: User['id']) { public async getRelation(me: User['id'], target: User['id']) {
@ -144,7 +152,7 @@ export class UserRepository extends Repository<User> {
return count > 0; return count > 0;
} }
public getOnlineStatus(user: User): string { public getOnlineStatus(user: User): 'unknown' | 'online' | 'active' | 'offline' {
if (user.hideOnlineStatus) return 'unknown'; if (user.hideOnlineStatus) return 'unknown';
if (user.lastActiveDate == null) return 'unknown'; if (user.lastActiveDate == null) return 'unknown';
const elapsed = Date.now() - user.lastActiveDate.getTime(); const elapsed = Date.now() - user.lastActiveDate.getTime();
@ -163,14 +171,14 @@ export class UserRepository extends Repository<User> {
} }
} }
public async pack( public async pack<ExpectsMe extends boolean | null = null, D extends boolean = false>(
src: User['id'] | User, src: User['id'] | User,
me?: { id: User['id'] } | null | undefined, me?: { id: User['id'] } | null | undefined,
options?: { options?: {
detail?: boolean, detail?: D,
includeSecrets?: boolean, includeSecrets?: boolean,
} }
): Promise<Packed<'User'>> { ): Promise<IsMeAndIsUserDetailed<ExpectsMe, D>> {
const opts = Object.assign({ const opts = Object.assign({
detail: false, detail: false,
includeSecrets: false, includeSecrets: false,
@ -178,8 +186,9 @@ export class UserRepository extends Repository<User> {
const user = typeof src === 'object' ? src : await this.findOneOrFail(src); const user = typeof src === 'object' ? src : await this.findOneOrFail(src);
const meId = me ? me.id : null; const meId = me ? me.id : null;
const isMe = meId === user.id;
const relation = meId && (meId !== user.id) && opts.detail ? await this.getRelation(meId, user.id) : null; const relation = meId && !isMe && opts.detail ? await this.getRelation(meId, user.id) : null;
const pins = opts.detail ? await UserNotePinings.createQueryBuilder('pin') const pins = opts.detail ? await UserNotePinings.createQueryBuilder('pin')
.where('pin.userId = :userId', { userId: user.id }) .where('pin.userId = :userId', { userId: user.id })
.innerJoinAndSelect('pin.note', 'note') .innerJoinAndSelect('pin.note', 'note')
@ -188,12 +197,12 @@ export class UserRepository extends Repository<User> {
const profile = opts.detail ? await UserProfiles.findOneOrFail(user.id) : null; const profile = opts.detail ? await UserProfiles.findOneOrFail(user.id) : null;
const followingCount = profile == null ? null : const followingCount = profile == null ? null :
(profile.ffVisibility === 'public') || (meId === user.id) ? user.followingCount : (profile.ffVisibility === 'public') || isMe ? user.followingCount :
(profile.ffVisibility === 'followers') && (relation && relation.isFollowing) ? user.followingCount : (profile.ffVisibility === 'followers') && (relation && relation.isFollowing) ? user.followingCount :
null; null;
const followersCount = profile == null ? null : const followersCount = profile == null ? null :
(profile.ffVisibility === 'public') || (meId === user.id) ? user.followersCount : (profile.ffVisibility === 'public') || isMe ? user.followersCount :
(profile.ffVisibility === 'followers') && (relation && relation.isFollowing) ? user.followersCount : (profile.ffVisibility === 'followers') && (relation && relation.isFollowing) ? user.followersCount :
null; null;
@ -227,12 +236,11 @@ export class UserRepository extends Repository<User> {
uri: user.uri, uri: user.uri,
createdAt: user.createdAt.toISOString(), createdAt: user.createdAt.toISOString(),
updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null, updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null,
lastFetchedAt: user.lastFetchedAt?.toISOString(), lastFetchedAt: user.lastFetchedAt ? user.lastFetchedAt.toISOString() : null,
bannerUrl: user.bannerUrl, bannerUrl: user.bannerUrl,
bannerBlurhash: user.bannerBlurhash, bannerBlurhash: user.bannerBlurhash,
bannerColor: null, // 後方互換性のため bannerColor: null, // 後方互換性のため
isLocked: user.isLocked, isLocked: user.isLocked,
isModerator: user.isModerator || falsy,
isSilenced: user.isSilenced || falsy, isSilenced: user.isSilenced || falsy,
isSuspended: user.isSuspended || falsy, isSuspended: user.isSuspended || falsy,
description: profile!.description, description: profile!.description,
@ -260,7 +268,7 @@ export class UserRepository extends Repository<User> {
: false, : false,
} : {}), } : {}),
...(opts.detail && meId === user.id ? { ...(opts.detail && isMe ? {
avatarId: user.avatarId, avatarId: user.avatarId,
bannerId: user.bannerId, bannerId: user.bannerId,
injectFeaturedNote: profile!.injectFeaturedNote, injectFeaturedNote: profile!.injectFeaturedNote,
@ -315,19 +323,19 @@ export class UserRepository extends Repository<User> {
isBlocked: relation.isBlocked, isBlocked: relation.isBlocked,
isMuted: relation.isMuted, isMuted: relation.isMuted,
} : {}), } : {}),
}; } as Promiseable<Packed<'User'>> as Promiseable<IsMeAndIsUserDetailed<ExpectsMe, D>>;
return await awaitAll(packed); return await awaitAll(packed);
} }
public packMany( public packMany<D extends boolean = false>(
users: (User['id'] | User)[], users: (User['id'] | User)[],
me?: { id: User['id'] } | null | undefined, me?: { id: User['id'] } | null | undefined,
options?: { options?: {
detail?: boolean, detail?: D,
includeSecrets?: boolean, includeSecrets?: boolean,
} }
) { ): Promise<IsUserDetailed<D>[]> {
return Promise.all(users.map(u => this.pack(u, me, options))); return Promise.all(users.map(u => this.pack(u, me, options)));
} }
@ -352,313 +360,3 @@ export class UserRepository extends Repository<User> {
public validateBirthday = $.str.match(/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/); public validateBirthday = $.str.match(/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/);
//#endregion //#endregion
} }
export const packedUserSchema = {
type: 'object' as const,
nullable: false as const, optional: false as const,
properties: {
id: {
type: 'string' as const,
nullable: false as const, optional: false as const,
format: 'id',
example: 'xxxxxxxxxx',
},
name: {
type: 'string' as const,
nullable: true as const, optional: false as const,
example: '藍',
},
username: {
type: 'string' as const,
nullable: false as const, optional: false as const,
example: 'ai',
},
host: {
type: 'string' as const,
nullable: true as const, optional: false as const,
example: 'misskey.example.com',
},
avatarUrl: {
type: 'string' as const,
format: 'url',
nullable: true as const, optional: false as const,
},
avatarBlurhash: {
type: 'any' as const,
nullable: true as const, optional: false as const,
},
avatarColor: {
type: 'any' as const,
nullable: true as const, optional: false as const,
default: null,
},
isAdmin: {
type: 'boolean' as const,
nullable: false as const, optional: true as const,
default: false,
},
isModerator: {
type: 'boolean' as const,
nullable: false as const, optional: true as const,
default: false,
},
isBot: {
type: 'boolean' as const,
nullable: false as const, optional: true as const,
},
isCat: {
type: 'boolean' as const,
nullable: false as const, optional: true as const,
},
emojis: {
type: 'array' as const,
nullable: false as const, optional: false as const,
items: {
type: 'object' as const,
nullable: false as const, optional: false as const,
properties: {
name: {
type: 'string' as const,
nullable: false as const, optional: false as const,
},
url: {
type: 'string' as const,
nullable: false as const, optional: false as const,
format: 'url',
},
},
},
},
url: {
type: 'string' as const,
format: 'url',
nullable: true as const, optional: true as const,
},
createdAt: {
type: 'string' as const,
nullable: false as const, optional: true as const,
format: 'date-time',
},
updatedAt: {
type: 'string' as const,
nullable: true as const, optional: true as const,
format: 'date-time',
},
bannerUrl: {
type: 'string' as const,
format: 'url',
nullable: true as const, optional: true as const,
},
bannerBlurhash: {
type: 'any' as const,
nullable: true as const, optional: true as const,
},
bannerColor: {
type: 'any' as const,
nullable: true as const, optional: true as const,
default: null,
},
isLocked: {
type: 'boolean' as const,
nullable: false as const, optional: true as const,
},
isSuspended: {
type: 'boolean' as const,
nullable: false as const, optional: true as const,
example: false,
},
description: {
type: 'string' as const,
nullable: true as const, optional: true as const,
example: 'Hi masters, I am Ai!',
},
location: {
type: 'string' as const,
nullable: true as const, optional: true as const,
},
birthday: {
type: 'string' as const,
nullable: true as const, optional: true as const,
example: '2018-03-12',
},
fields: {
type: 'array' as const,
nullable: false as const, optional: true as const,
items: {
type: 'object' as const,
nullable: false as const, optional: false as const,
properties: {
name: {
type: 'string' as const,
nullable: false as const, optional: false as const,
},
value: {
type: 'string' as const,
nullable: false as const, optional: false as const,
},
},
maxLength: 4,
},
},
followersCount: {
type: 'number' as const,
nullable: false as const, optional: true as const,
},
followingCount: {
type: 'number' as const,
nullable: false as const, optional: true as const,
},
notesCount: {
type: 'number' as const,
nullable: false as const, optional: true as const,
},
pinnedNoteIds: {
type: 'array' as const,
nullable: false as const, optional: true as const,
items: {
type: 'string' as const,
nullable: false as const, optional: false as const,
format: 'id',
},
},
pinnedNotes: {
type: 'array' as const,
nullable: false as const, optional: true as const,
items: {
type: 'object' as const,
nullable: false as const, optional: false as const,
ref: 'Note' as const,
},
},
pinnedPageId: {
type: 'string' as const,
nullable: true as const, optional: true as const,
},
pinnedPage: {
type: 'object' as const,
nullable: true as const, optional: true as const,
ref: 'Page' as const,
},
twoFactorEnabled: {
type: 'boolean' as const,
nullable: false as const, optional: true as const,
default: false,
},
usePasswordLessLogin: {
type: 'boolean' as const,
nullable: false as const, optional: true as const,
default: false,
},
securityKeys: {
type: 'boolean' as const,
nullable: false as const, optional: true as const,
default: false,
},
avatarId: {
type: 'string' as const,
nullable: true as const, optional: true as const,
format: 'id',
},
bannerId: {
type: 'string' as const,
nullable: true as const, optional: true as const,
format: 'id',
},
autoWatch: {
type: 'boolean' as const,
nullable: false as const, optional: true as const,
},
injectFeaturedNote: {
type: 'boolean' as const,
nullable: false as const, optional: true as const,
},
alwaysMarkNsfw: {
type: 'boolean' as const,
nullable: false as const, optional: true as const,
},
carefulBot: {
type: 'boolean' as const,
nullable: false as const, optional: true as const,
},
autoAcceptFollowed: {
type: 'boolean' as const,
nullable: false as const, optional: true as const,
},
hasUnreadSpecifiedNotes: {
type: 'boolean' as const,
nullable: false as const, optional: true as const,
},
hasUnreadMentions: {
type: 'boolean' as const,
nullable: false as const, optional: true as const,
},
hasUnreadAnnouncement: {
type: 'boolean' as const,
nullable: false as const, optional: true as const,
},
hasUnreadAntenna: {
type: 'boolean' as const,
nullable: false as const, optional: true as const,
},
hasUnreadChannel: {
type: 'boolean' as const,
nullable: false as const, optional: true as const,
},
hasUnreadMessagingMessage: {
type: 'boolean' as const,
nullable: false as const, optional: true as const,
},
hasUnreadNotification: {
type: 'boolean' as const,
nullable: false as const, optional: true as const,
},
hasPendingReceivedFollowRequest: {
type: 'boolean' as const,
nullable: false as const, optional: true as const,
},
integrations: {
type: 'object' as const,
nullable: false as const, optional: true as const,
},
mutedWords: {
type: 'array' as const,
nullable: false as const, optional: true as const,
},
mutedInstances: {
type: 'array' as const,
nullable: false as const, optional: true as const,
},
mutingNotificationTypes: {
type: 'array' as const,
nullable: false as const, optional: true as const,
},
isFollowing: {
type: 'boolean' as const,
optional: true as const, nullable: false as const,
},
hasPendingFollowRequestFromYou: {
type: 'boolean' as const,
optional: true as const, nullable: false as const,
},
hasPendingFollowRequestToYou: {
type: 'boolean' as const,
optional: true as const, nullable: false as const,
},
isFollowed: {
type: 'boolean' as const,
optional: true as const, nullable: false as const,
},
isBlocking: {
type: 'boolean' as const,
optional: true as const, nullable: false as const,
},
isBlocked: {
type: 'boolean' as const,
optional: true as const, nullable: false as const,
},
isMuted: {
type: 'boolean' as const,
optional: true as const, nullable: false as const,
},
},
};

View File

@ -0,0 +1,89 @@
export const packedAntennaSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
name: {
type: 'string',
optional: false, nullable: false,
},
keywords: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'string',
optional: false, nullable: false,
},
},
},
excludeKeywords: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'string',
optional: false, nullable: false,
},
},
},
src: {
type: 'string',
optional: false, nullable: false,
enum: ['home', 'all', 'users', 'list', 'group'],
},
userListId: {
type: 'string',
optional: false, nullable: true,
format: 'id',
},
userGroupId: {
type: 'string',
optional: false, nullable: true,
format: 'id',
},
users: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'string',
optional: false, nullable: false,
},
},
caseSensitive: {
type: 'boolean',
optional: false, nullable: false,
default: false,
},
notify: {
type: 'boolean',
optional: false, nullable: false,
},
withReplies: {
type: 'boolean',
optional: false, nullable: false,
default: false,
},
withFile: {
type: 'boolean',
optional: false, nullable: false,
},
hasUnreadNote: {
type: 'boolean',
optional: false, nullable: false,
default: false,
},
},
} as const;

View File

@ -0,0 +1,33 @@
export const packedAppSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
},
name: {
type: 'string',
optional: false, nullable: false,
},
callbackUrl: {
type: 'string',
optional: false, nullable: true,
},
permission: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'string',
optional: false, nullable: false,
},
},
secret: {
type: 'string',
optional: true, nullable: false,
},
isAuthorized: {
type: 'boolean',
optional: true, nullable: false,
},
},
} as const;

View File

@ -0,0 +1,26 @@
export const packedBlockingSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
blockeeId: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
blockee: {
type: 'object',
optional: false, nullable: false,
ref: 'UserDetailed',
},
},
} as const;

View File

@ -0,0 +1,51 @@
export const packedChannelSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
lastNotedAt: {
type: 'string',
optional: false, nullable: true,
format: 'date-time',
},
name: {
type: 'string',
optional: false, nullable: false,
},
description: {
type: 'string',
nullable: true, optional: false,
},
bannerUrl: {
type: 'string',
format: 'url',
nullable: true, optional: false,
},
notesCount: {
type: 'number',
nullable: false, optional: false,
},
usersCount: {
type: 'number',
nullable: false, optional: false,
},
isFollowing: {
type: 'boolean',
optional: true, nullable: false,
},
userId: {
type: 'string',
nullable: true, optional: false,
format: 'id',
},
},
} as const;

View File

@ -0,0 +1,38 @@
export const packedClipSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
userId: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
user: {
type: 'object',
ref: 'UserLite',
optional: false, nullable: false,
},
name: {
type: 'string',
optional: false, nullable: false,
},
description: {
type: 'string',
optional: false, nullable: true,
},
isPublic: {
type: 'boolean',
optional: false, nullable: false,
},
},
} as const;

View File

@ -0,0 +1,107 @@
export const packedDriveFileSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
name: {
type: 'string',
optional: false, nullable: false,
example: 'lenna.jpg',
},
type: {
type: 'string',
optional: false, nullable: false,
example: 'image/jpeg',
},
md5: {
type: 'string',
optional: false, nullable: false,
format: 'md5',
example: '15eca7fba0480996e2245f5185bf39f2',
},
size: {
type: 'number',
optional: false, nullable: false,
example: 51469,
},
isSensitive: {
type: 'boolean',
optional: false, nullable: false,
},
blurhash: {
type: 'string',
optional: false, nullable: true,
},
properties: {
type: 'object',
optional: false, nullable: false,
properties: {
width: {
type: 'number',
optional: true, nullable: false,
example: 1280,
},
height: {
type: 'number',
optional: true, nullable: false,
example: 720,
},
orientation: {
type: 'number',
optional: true, nullable: false,
example: 8,
},
avgColor: {
type: 'string',
optional: true, nullable: false,
example: 'rgb(40,65,87)',
},
},
},
url: {
type: 'string',
optional: false, nullable: true,
format: 'url',
},
thumbnailUrl: {
type: 'string',
optional: false, nullable: true,
format: 'url',
},
comment: {
type: 'string',
optional: false, nullable: true,
},
folderId: {
type: 'string',
optional: false, nullable: true,
format: 'id',
example: 'xxxxxxxxxx',
},
folder: {
type: 'object',
optional: true, nullable: true,
ref: 'DriveFolder',
},
userId: {
type: 'string',
optional: false, nullable: true,
format: 'id',
example: 'xxxxxxxxxx',
},
user: {
type: 'object',
optional: true, nullable: true,
ref: 'UserLite',
},
},
} as const;

View File

@ -0,0 +1,39 @@
export const packedDriveFolderSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
name: {
type: 'string',
optional: false, nullable: false,
},
foldersCount: {
type: 'number',
optional: true, nullable: false,
},
filesCount: {
type: 'number',
optional: true, nullable: false,
},
parentId: {
type: 'string',
optional: false, nullable: true,
format: 'id',
example: 'xxxxxxxxxx',
},
parent: {
type: 'object',
optional: true, nullable: true,
ref: 'DriveFolder',
},
},
} as const;

View File

@ -0,0 +1,36 @@
export const packedEmojiSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
aliases: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
},
name: {
type: 'string',
optional: false, nullable: false,
},
category: {
type: 'string',
optional: false, nullable: true,
},
host: {
type: 'string',
optional: false, nullable: true,
},
url: {
type: 'string',
optional: false, nullable: false,
},
},
} as const;

View File

@ -0,0 +1,105 @@
import config from "@/config";
export const packedFederationInstanceSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
caughtAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
host: {
type: 'string',
optional: false, nullable: false,
example: 'misskey.example.com',
},
usersCount: {
type: 'number',
optional: false, nullable: false,
},
notesCount: {
type: 'number',
optional: false, nullable: false,
},
followingCount: {
type: 'number',
optional: false, nullable: false,
},
followersCount: {
type: 'number',
optional: false, nullable: false,
},
driveUsage: {
type: 'number',
optional: false, nullable: false,
},
driveFiles: {
type: 'number',
optional: false, nullable: false,
},
latestRequestSentAt: {
type: 'string',
optional: false, nullable: true,
format: 'date-time',
},
lastCommunicatedAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
isNotResponding: {
type: 'boolean',
optional: false, nullable: false,
},
isSuspended: {
type: 'boolean',
optional: false, nullable: false,
},
softwareName: {
type: 'string',
optional: false, nullable: true,
example: 'misskey',
},
softwareVersion: {
type: 'string',
optional: false, nullable: true,
example: config.version,
},
openRegistrations: {
type: 'boolean',
optional: false, nullable: true,
example: true,
},
name: {
type: 'string',
optional: false, nullable: true,
},
description: {
type: 'string',
optional: false, nullable: true,
},
maintainerName: {
type: 'string',
optional: false, nullable: true,
},
maintainerEmail: {
type: 'string',
optional: false, nullable: true,
},
iconUrl: {
type: 'string',
optional: false, nullable: true,
format: 'url',
},
infoUpdatedAt: {
type: 'string',
optional: false, nullable: true,
format: 'date-time',
},
},
} as const;

View File

@ -0,0 +1,36 @@
export const packedFollowingSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
followeeId: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
followee: {
type: 'object',
optional: true, nullable: false,
ref: 'UserDetailed',
},
followerId: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
follower: {
type: 'object',
optional: true, nullable: false,
ref: 'UserDetailed',
},
},
} as const;

View File

@ -0,0 +1,69 @@
export const packedGalleryPostSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
updatedAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
title: {
type: 'string',
optional: false, nullable: false,
},
description: {
type: 'string',
optional: false, nullable: true,
},
userId: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
user: {
type: 'object',
ref: 'UserLite',
optional: false, nullable: false,
},
fileIds: {
type: 'array',
optional: true, nullable: false,
items: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
},
files: {
type: 'array',
optional: true, nullable: false,
items: {
type: 'object',
optional: false, nullable: false,
ref: 'DriveFile',
},
},
tags: {
type: 'array',
optional: true, nullable: false,
items: {
type: 'string',
optional: false, nullable: false,
},
},
isSensitive: {
type: 'boolean',
optional: false, nullable: false,
},
},
} as const;

View File

@ -0,0 +1,34 @@
export const packedHashtagSchema = {
type: 'object',
properties: {
tag: {
type: 'string',
optional: false, nullable: false,
example: 'misskey',
},
mentionedUsersCount: {
type: 'number',
optional: false, nullable: false,
},
mentionedLocalUsersCount: {
type: 'number',
optional: false, nullable: false,
},
mentionedRemoteUsersCount: {
type: 'number',
optional: false, nullable: false,
},
attachedUsersCount: {
type: 'number',
optional: false, nullable: false,
},
attachedLocalUsersCount: {
type: 'number',
optional: false, nullable: false,
},
attachedRemoteUsersCount: {
type: 'number',
optional: false, nullable: false,
},
},
} as const;

View File

@ -0,0 +1,73 @@
export const packedMessagingMessageSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
userId: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
user: {
type: 'object',
ref: 'UserLite',
optional: true, nullable: false,
},
text: {
type: 'string',
optional: false, nullable: true,
},
fileId: {
type: 'string',
optional: true, nullable: true,
format: 'id',
},
file: {
type: 'object',
optional: true, nullable: true,
ref: 'DriveFile',
},
recipientId: {
type: 'string',
optional: false, nullable: true,
format: 'id',
},
recipient: {
type: 'object',
optional: true, nullable: true,
ref: 'UserLite',
},
groupId: {
type: 'string',
optional: false, nullable: true,
format: 'id',
},
group: {
type: 'object',
optional: true, nullable: true,
ref: 'UserGroup',
},
isRead: {
type: 'boolean',
optional: true, nullable: false,
},
reads: {
type: 'array',
optional: true, nullable: false,
items: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
},
},
} as const;

View File

@ -0,0 +1,26 @@
export const packedMutingSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
muteeId: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
mutee: {
type: 'object',
optional: false, nullable: false,
ref: 'UserDetailed',
},
},
} as const;

View File

@ -0,0 +1,26 @@
export const packedNoteFavoriteSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
note: {
type: 'object',
optional: false, nullable: false,
ref: 'Note',
},
noteId: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
},
} as const;

View File

@ -0,0 +1,25 @@
export const packedNoteReactionSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
user: {
type: 'object',
optional: false, nullable: false,
ref: 'UserLite',
},
type: {
type: 'string',
optional: false, nullable: false,
},
},
} as const;

View File

@ -0,0 +1,183 @@
export const packedNoteSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
text: {
type: 'string',
optional: false, nullable: true,
},
cw: {
type: 'string',
optional: true, nullable: true,
},
userId: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
user: {
type: 'object',
ref: 'UserLite',
optional: false, nullable: false,
},
replyId: {
type: 'string',
optional: true, nullable: true,
format: 'id',
example: 'xxxxxxxxxx',
},
renoteId: {
type: 'string',
optional: true, nullable: true,
format: 'id',
example: 'xxxxxxxxxx',
},
reply: {
type: 'object',
optional: true, nullable: true,
ref: 'Note',
},
renote: {
type: 'object',
optional: true, nullable: true,
ref: 'Note',
},
isHidden: {
type: 'boolean',
optional: true, nullable: false,
},
visibility: {
type: 'string',
optional: false, nullable: false,
},
mentions: {
type: 'array',
optional: true, nullable: false,
items: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
},
visibleUserIds: {
type: 'array',
optional: true, nullable: false,
items: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
},
fileIds: {
type: 'array',
optional: true, nullable: false,
items: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
},
files: {
type: 'array',
optional: true, nullable: false,
items: {
type: 'object',
optional: false, nullable: false,
ref: 'DriveFile',
},
},
tags: {
type: 'array',
optional: true, nullable: false,
items: {
type: 'string',
optional: false, nullable: false,
},
},
poll: {
type: 'object',
optional: true, nullable: true,
},
channelId: {
type: 'string',
optional: true, nullable: true,
format: 'id',
example: 'xxxxxxxxxx',
},
channel: {
type: 'object',
optional: true, nullable: true,
items: {
type: 'object',
optional: false, nullable: false,
properties: {
id: {
type: 'string',
optional: false, nullable: false,
},
name: {
type: 'string',
optional: false, nullable: true,
},
},
},
},
localOnly: {
type: 'boolean',
optional: true, nullable: false,
},
emojis: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'object',
optional: false, nullable: false,
properties: {
name: {
type: 'string',
optional: false, nullable: false,
},
url: {
type: 'string',
optional: false, nullable: true,
},
},
},
},
reactions: {
type: 'object',
optional: false, nullable: false,
},
renoteCount: {
type: 'number',
optional: false, nullable: false,
},
repliesCount: {
type: 'number',
optional: false, nullable: false,
},
uri: {
type: 'string',
optional: true, nullable: false,
},
url: {
type: 'string',
optional: true, nullable: false,
},
myReaction: {
type: 'object',
optional: true, nullable: true,
},
},
} as const;

View File

@ -0,0 +1,66 @@
import { notificationTypes } from "@/types";
export const packedNotificationSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
isRead: {
type: 'boolean',
optional: false, nullable: false,
},
type: {
type: 'string',
optional: false, nullable: false,
enum: [...notificationTypes],
},
user: {
type: 'object',
ref: 'UserLite',
optional: true, nullable: true,
},
userId: {
type: 'string',
optional: true, nullable: true,
format: 'id',
},
note: {
type: 'object',
ref: 'Note',
optional: true, nullable: true,
},
reaction: {
type: 'string',
optional: true, nullable: true,
},
choice: {
type: 'number',
optional: true, nullable: true,
},
invitation: {
type: 'object',
optional: true, nullable: true,
},
body: {
type: 'string',
optional: true, nullable: true,
},
header: {
type: 'string',
optional: true, nullable: true,
},
icon: {
type: 'string',
optional: true, nullable: true,
},
},
} as const;

View File

@ -0,0 +1,51 @@
export const packedPageSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
updatedAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
title: {
type: 'string',
optional: false, nullable: false,
},
name: {
type: 'string',
optional: false, nullable: false,
},
summary: {
type: 'string',
optional: false, nullable: true,
},
content: {
type: 'array',
optional: false, nullable: false,
},
variables: {
type: 'array',
optional: false, nullable: false,
},
userId: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
user: {
type: 'object',
ref: 'UserLite',
optional: false, nullable: false,
},
},
} as const;

View File

@ -0,0 +1,25 @@
export const packedQueueCountSchema = {
type: 'object',
properties: {
waiting: {
type: 'number',
optional: false, nullable: false,
},
active: {
type: 'number',
optional: false, nullable: false,
},
completed: {
type: 'number',
optional: false, nullable: false,
},
failed: {
type: 'number',
optional: false, nullable: false,
},
delayed: {
type: 'number',
optional: false, nullable: false,
},
},
} as const;

View File

@ -0,0 +1,34 @@
export const packedUserGroupSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
name: {
type: 'string',
optional: false, nullable: false,
},
ownerId: {
type: 'string',
nullable: false, optional: false,
format: 'id',
},
userIds: {
type: 'array',
nullable: false, optional: true,
items: {
type: 'string',
nullable: false, optional: false,
format: 'id',
},
},
},
} as const;

View File

@ -0,0 +1,29 @@
export const packedUserListSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
name: {
type: 'string',
optional: false, nullable: false,
},
userIds: {
type: 'array',
nullable: false, optional: true,
items: {
type: 'string',
nullable: false, optional: false,
format: 'id',
},
},
},
} as const;

View File

@ -0,0 +1,467 @@
export const packedUserLiteSchema = {
type: 'object',
properties: {
id: {
type: 'string',
nullable: false, optional: false,
format: 'id',
example: 'xxxxxxxxxx',
},
name: {
type: 'string',
nullable: true, optional: false,
example: '藍',
},
username: {
type: 'string',
nullable: false, optional: false,
example: 'ai',
},
host: {
type: 'string',
nullable: true, optional: false,
example: 'misskey.example.com',
},
avatarUrl: {
type: 'string',
format: 'url',
nullable: true, optional: false,
},
avatarBlurhash: {
type: 'any',
nullable: true, optional: false,
},
avatarColor: {
type: 'any',
nullable: true, optional: false,
default: null,
},
isAdmin: {
type: 'boolean',
nullable: false, optional: true,
default: false,
},
isModerator: {
type: 'boolean',
nullable: false, optional: true,
default: false,
},
isBot: {
type: 'boolean',
nullable: false, optional: true,
},
isCat: {
type: 'boolean',
nullable: false, optional: true,
},
emojis: {
type: 'array',
nullable: false, optional: false,
items: {
type: 'object',
nullable: false, optional: false,
properties: {
name: {
type: 'string',
nullable: false, optional: false,
},
url: {
type: 'string',
nullable: false, optional: false,
format: 'url',
},
},
},
},
onlineStatus: {
type: 'string',
format: 'url',
nullable: true, optional: false,
enum: ['unknown', 'online', 'active', 'offline'],
},
},
} as const;
export const packedUserDetailedNotMeOnlySchema = {
type: 'object',
properties: {
url: {
type: 'string',
format: 'url',
nullable: true, optional: false,
},
uri: {
type: 'string',
format: 'uri',
nullable: true, optional: false,
},
createdAt: {
type: 'string',
nullable: false, optional: false,
format: 'date-time',
},
updatedAt: {
type: 'string',
nullable: true, optional: false,
format: 'date-time',
},
lastFetchedAt: {
type: 'string',
nullable: true, optional: false,
format: 'date-time',
},
bannerUrl: {
type: 'string',
format: 'url',
nullable: true, optional: false,
},
bannerBlurhash: {
type: 'any',
nullable: true, optional: false,
},
bannerColor: {
type: 'any',
nullable: true, optional: false,
default: null,
},
isLocked: {
type: 'boolean',
nullable: false, optional: false,
},
isSilenced: {
type: 'boolean',
nullable: false, optional: false,
},
isSuspended: {
type: 'boolean',
nullable: false, optional: false,
example: false,
},
description: {
type: 'string',
nullable: true, optional: false,
example: 'Hi masters, I am Ai!',
},
location: {
type: 'string',
nullable: true, optional: false,
},
birthday: {
type: 'string',
nullable: true, optional: false,
example: '2018-03-12',
},
lang: {
type: 'string',
nullable: true, optional: false,
example: 'ja-JP',
},
fields: {
type: 'array',
nullable: false, optional: false,
items: {
type: 'object',
nullable: false, optional: false,
properties: {
name: {
type: 'string',
nullable: false, optional: false,
},
value: {
type: 'string',
nullable: false, optional: false,
},
},
maxLength: 4,
},
},
followersCount: {
type: 'number',
nullable: false, optional: false,
},
followingCount: {
type: 'number',
nullable: false, optional: false,
},
notesCount: {
type: 'number',
nullable: false, optional: false,
},
pinnedNoteIds: {
type: 'array',
nullable: false, optional: false,
items: {
type: 'string',
nullable: false, optional: false,
format: 'id',
},
},
pinnedNotes: {
type: 'array',
nullable: false, optional: false,
items: {
type: 'object',
nullable: false, optional: false,
ref: 'Note',
},
},
pinnedPageId: {
type: 'string',
nullable: true, optional: false,
},
pinnedPage: {
type: 'object',
nullable: true, optional: false,
ref: 'Page',
},
publicReactions: {
type: 'boolean',
nullable: false, optional: false,
},
twoFactorEnabled: {
type: 'boolean',
nullable: false, optional: false,
default: false,
},
usePasswordLessLogin: {
type: 'boolean',
nullable: false, optional: false,
default: false,
},
securityKeys: {
type: 'boolean',
nullable: false, optional: false,
default: false,
},
//#region relations
isFollowing: {
type: 'boolean',
nullable: false, optional: true,
},
isFollowed: {
type: 'boolean',
nullable: false, optional: true,
},
hasPendingFollowRequestFromYou: {
type: 'boolean',
nullable: false, optional: true,
},
hasPendingFollowRequestToYou: {
type: 'boolean',
nullable: false, optional: true,
},
isBlocking: {
type: 'boolean',
nullable: false, optional: true,
},
isBlocked: {
type: 'boolean',
nullable: false, optional: true,
},
isMuted: {
type: 'boolean',
nullable: false, optional: true,
},
//#endregion
},
} as const;
export const packedMeDetailedOnlySchema = {
type: 'object',
properties: {
avatarId: {
type: 'string',
nullable: true, optional: false,
format: 'id',
},
bannerId: {
type: 'string',
nullable: true, optional: false,
format: 'id',
},
injectFeaturedNote: {
type: 'boolean',
nullable: true, optional: false,
},
receiveAnnouncementEmail: {
type: 'boolean',
nullable: true, optional: false,
},
alwaysMarkNsfw: {
type: 'boolean',
nullable: true, optional: false,
},
carefulBot: {
type: 'boolean',
nullable: true, optional: false,
},
autoAcceptFollowed: {
type: 'boolean',
nullable: true, optional: false,
},
noCrawle: {
type: 'boolean',
nullable: true, optional: false,
},
isExplorable: {
type: 'boolean',
nullable: false, optional: false,
},
isDeleted: {
type: 'boolean',
nullable: false, optional: false,
},
hideOnlineStatus: {
type: 'boolean',
nullable: false, optional: false,
},
hasUnreadSpecifiedNotes: {
type: 'boolean',
nullable: false, optional: false,
},
hasUnreadMentions: {
type: 'boolean',
nullable: false, optional: false,
},
hasUnreadAnnouncement: {
type: 'boolean',
nullable: false, optional: false,
},
hasUnreadAntenna: {
type: 'boolean',
nullable: false, optional: false,
},
hasUnreadChannel: {
type: 'boolean',
nullable: false, optional: false,
},
hasUnreadMessagingMessage: {
type: 'boolean',
nullable: false, optional: false,
},
hasUnreadNotification: {
type: 'boolean',
nullable: false, optional: false,
},
hasPendingReceivedFollowRequest: {
type: 'boolean',
nullable: false, optional: false,
},
integrations: {
type: 'object',
nullable: true, optional: false,
},
mutedWords: {
type: 'array',
nullable: false, optional: false,
items: {
type: 'array',
nullable: false, optional: false,
items: {
type: 'string',
nullable: false, optional: false,
},
},
},
mutedInstances: {
type: 'array',
nullable: true, optional: false,
items: {
type: 'string',
nullable: false, optional: false,
},
},
mutingNotificationTypes: {
type: 'array',
nullable: true, optional: false,
items: {
type: 'string',
nullable: false, optional: false,
},
},
emailNotificationTypes: {
type: 'array',
nullable: true, optional: false,
items: {
type: 'string',
nullable: false, optional: false,
},
},
//#region secrets
email: {
type: 'string',
nullable: true, optional: true,
},
emailVerified: {
type: 'boolean',
nullable: true, optional: true,
},
securityKeysList: {
type: 'array',
nullable: false, optional: true,
items: {
type: 'object',
nullable: false, optional: false,
},
},
//#endregion
},
} as const;
export const packedUserDetailedNotMeSchema = {
type: 'object',
allOf: [
{
type: 'object',
ref: 'UserLite',
},
{
type: 'object',
ref: 'UserDetailedNotMeOnly',
},
],
} as const;
export const packedMeDetailedSchema = {
type: 'object',
allOf: [
{
type: 'object',
ref: 'UserLite',
},
{
type: 'object',
ref: 'UserDetailedNotMeOnly',
},
{
type: 'object',
ref: 'MeDetailedOnly',
},
],
} as const;
export const packedUserDetailedSchema = {
oneOf: [
{
type: 'object',
ref: 'UserDetailedNotMe',
},
{
type: 'object',
ref: 'MeDetailed',
},
],
} as const;
export const packedUserSchema = {
oneOf: [
{
type: 'object',
ref: 'UserLite',
},
{
type: 'object',
ref: 'UserDetailed',
},
],
} as const;

View File

@ -1,13 +1,11 @@
type Await<T> = T extends Promise<infer U> ? U : T; export type Promiseable<T> = {
[K in keyof T]: Promise<T[K]> | T[K];
type AwaitAll<T> = {
[P in keyof T]: Await<T[P]>;
}; };
export async function awaitAll<T>(obj: T): Promise<AwaitAll<T>> { export async function awaitAll<T>(obj: Promiseable<T>): Promise<T> {
const target = {} as any; const target = {} as T;
const keys = Object.keys(obj); const keys = Object.keys(obj) as unknown as (keyof T)[];
const values = Object.values(obj); const values = Object.values(obj) as any[];
const resolvedValues = await Promise.all(values.map(value => const resolvedValues = await Promise.all(values.map(value =>
(!value || !value.constructor || value.constructor.name !== 'Object') (!value || !value.constructor || value.constructor.name !== 'Object')

View File

@ -3,7 +3,7 @@ import * as tmp from 'tmp';
import * as fs from 'fs'; import * as fs from 'fs';
import { queueLogger } from '../../logger'; import { queueLogger } from '../../logger';
import addFile from '@/services/drive/add-file'; import { addFile } from '@/services/drive/add-file';
import * as dateFormat from 'dateformat'; import * as dateFormat from 'dateformat';
import { getFullApAccount } from '@/misc/convert-host'; import { getFullApAccount } from '@/misc/convert-host';
import { Users, Blockings } from '@/models/index'; import { Users, Blockings } from '@/models/index';

View File

@ -6,11 +6,12 @@ import { ulid } from 'ulid';
const mime = require('mime-types'); const mime = require('mime-types');
const archiver = require('archiver'); const archiver = require('archiver');
import { queueLogger } from '../../logger'; import { queueLogger } from '../../logger';
import addFile from '@/services/drive/add-file'; import { addFile } from '@/services/drive/add-file';
import * as dateFormat from 'dateformat'; import * as dateFormat from 'dateformat';
import { Users, Emojis } from '@/models/index'; import { Users, Emojis } from '@/models/index';
import { } from '@/queue/types'; import { } from '@/queue/types';
import { downloadUrl } from '@/misc/download-url'; import { downloadUrl } from '@/misc/download-url';
import config from '@/config/index';
const logger = queueLogger.createSubLogger('export-custom-emojis'); const logger = queueLogger.createSubLogger('export-custom-emojis');
@ -52,7 +53,7 @@ export async function exportCustomEmojis(job: Bull.Job, done: () => void): Promi
}); });
}; };
await writeMeta(`{"metaVersion":2,"emojis":[`); await writeMeta(`{"metaVersion":2,"host":"${config.host}","exportedAt":"${new Date().toString()}","emojis":[`);
const customEmojis = await Emojis.find({ const customEmojis = await Emojis.find({
where: { where: {
@ -71,7 +72,7 @@ export async function exportCustomEmojis(job: Bull.Job, done: () => void): Promi
let downloaded = false; let downloaded = false;
try { try {
await downloadUrl(emoji.url, emojiPath); await downloadUrl(emoji.originalUrl, emojiPath);
downloaded = true; downloaded = true;
} catch (e) { // TODO: 何度か再試行 } catch (e) { // TODO: 何度か再試行
logger.error(e); logger.error(e);

View File

@ -3,7 +3,7 @@ import * as tmp from 'tmp';
import * as fs from 'fs'; import * as fs from 'fs';
import { queueLogger } from '../../logger'; import { queueLogger } from '../../logger';
import addFile from '@/services/drive/add-file'; import { addFile } from '@/services/drive/add-file';
import * as dateFormat from 'dateformat'; import * as dateFormat from 'dateformat';
import { getFullApAccount } from '@/misc/convert-host'; import { getFullApAccount } from '@/misc/convert-host';
import { Users, Followings, Mutings } from '@/models/index'; import { Users, Followings, Mutings } from '@/models/index';

View File

@ -3,7 +3,7 @@ import * as tmp from 'tmp';
import * as fs from 'fs'; import * as fs from 'fs';
import { queueLogger } from '../../logger'; import { queueLogger } from '../../logger';
import addFile from '@/services/drive/add-file'; import { addFile } from '@/services/drive/add-file';
import * as dateFormat from 'dateformat'; import * as dateFormat from 'dateformat';
import { getFullApAccount } from '@/misc/convert-host'; import { getFullApAccount } from '@/misc/convert-host';
import { Users, Mutings } from '@/models/index'; import { Users, Mutings } from '@/models/index';

View File

@ -3,7 +3,7 @@ import * as tmp from 'tmp';
import * as fs from 'fs'; import * as fs from 'fs';
import { queueLogger } from '../../logger'; import { queueLogger } from '../../logger';
import addFile from '@/services/drive/add-file'; import { addFile } from '@/services/drive/add-file';
import * as dateFormat from 'dateformat'; import * as dateFormat from 'dateformat';
import { Users, Notes, Polls } from '@/models/index'; import { Users, Notes, Polls } from '@/models/index';
import { MoreThan } from 'typeorm'; import { MoreThan } from 'typeorm';

View File

@ -3,7 +3,7 @@ import * as tmp from 'tmp';
import * as fs from 'fs'; import * as fs from 'fs';
import { queueLogger } from '../../logger'; import { queueLogger } from '../../logger';
import addFile from '@/services/drive/add-file'; import { addFile } from '@/services/drive/add-file';
import * as dateFormat from 'dateformat'; import * as dateFormat from 'dateformat';
import { getFullApAccount } from '@/misc/convert-host'; import { getFullApAccount } from '@/misc/convert-host';
import { Users, UserLists, UserListJoinings } from '@/models/index'; import { Users, UserLists, UserListJoinings } from '@/models/index';

View File

@ -8,7 +8,7 @@ import { queueLogger } from '../../logger';
import { downloadUrl } from '@/misc/download-url'; import { downloadUrl } from '@/misc/download-url';
import { DriveFiles, Emojis } from '@/models/index'; import { DriveFiles, Emojis } from '@/models/index';
import { DbUserImportJobData } from '@/queue/types'; import { DbUserImportJobData } from '@/queue/types';
import addFile from '@/services/drive/add-file'; import { addFile } from '@/services/drive/add-file';
import { genId } from '@/misc/gen-id'; import { genId } from '@/misc/gen-id';
const logger = queueLogger.createSubLogger('import-custom-emojis'); const logger = queueLogger.createSubLogger('import-custom-emojis');
@ -67,8 +67,9 @@ export async function importCustomEmojis(job: Bull.Job<DbUserImportJobData>, don
category: emojiInfo.category, category: emojiInfo.category,
host: null, host: null,
aliases: emojiInfo.aliases, aliases: emojiInfo.aliases,
url: driveFile.url, originalUrl: driveFile.url,
type: driveFile.type, publicUrl: driveFile.webpublicUrl ?? driveFile.url,
type: driveFile.webpublicType ?? driveFile.type,
}).then(x => Emojis.findOneOrFail(x.identifiers[0])); }).then(x => Emojis.findOneOrFail(x.identifiers[0]));
} }

View File

@ -320,14 +320,15 @@ export async function extractEmojis(tags: IObject | IObject[], host: string): Pr
if ((tag.updated != null && exists.updatedAt == null) if ((tag.updated != null && exists.updatedAt == null)
|| (tag.id != null && exists.uri == null) || (tag.id != null && exists.uri == null)
|| (tag.updated != null && exists.updatedAt != null && new Date(tag.updated) > exists.updatedAt) || (tag.updated != null && exists.updatedAt != null && new Date(tag.updated) > exists.updatedAt)
|| (tag.icon!.url !== exists.url) || (tag.icon!.url !== exists.originalUrl)
) { ) {
await Emojis.update({ await Emojis.update({
host, host,
name, name,
}, { }, {
uri: tag.id, uri: tag.id,
url: tag.icon!.url, originalUrl: tag.icon!.url,
publicUrl: tag.icon!.url,
updatedAt: new Date(), updatedAt: new Date(),
}); });
@ -347,7 +348,8 @@ export async function extractEmojis(tags: IObject | IObject[], host: string): Pr
host, host,
name, name,
uri: tag.id, uri: tag.id,
url: tag.icon!.url, originalUrl: tag.icon!.url,
publicUrl: tag.icon!.url,
updatedAt: new Date(), updatedAt: new Date(),
aliases: [], aliases: [],
} as Partial<Emoji>).then(x => Emojis.findOneOrFail(x.identifiers[0])); } as Partial<Emoji>).then(x => Emojis.findOneOrFail(x.identifiers[0]));

View File

@ -9,6 +9,6 @@ export default (emoji: Emoji) => ({
icon: { icon: {
type: 'Image', type: 'Image',
mediaType: emoji.type || 'image/png', mediaType: emoji.type || 'image/png',
url: emoji.url, url: emoji.publicUrl || emoji.originalUrl, // || emoji.originalUrl してるのは後方互換性のため
}, },
}); });

View File

@ -0,0 +1,15 @@
import config from '@/config/index';
import { IObject, IActivity } from '@/remote/activitypub/type';
import { ILocalUser, IRemoteUser } from '@/models/entities/user';
import { getInstanceActor } from '@/services/instance-actor';
// to anonymise reporters, the reporting actor must be a system user
// object has to be a uri or array of uris
export const renderFlag = (user: ILocalUser, object: [string], content: string): IActivity => {
return {
type: 'Flag',
actor: `${config.url}/users/${user.id}`,
content,
object,
};
};

View File

@ -1,5 +1,5 @@
import { performance } from 'perf_hooks'; import { performance } from 'perf_hooks';
import limiter from './limiter'; import { limiter } from './limiter';
import { User } from '@/models/entities/user'; import { User } from '@/models/entities/user';
import endpoints from './endpoints'; import endpoints from './endpoints';
import { ApiError } from './error'; import { ApiError } from './error';

View File

@ -3,7 +3,7 @@ import { dirname } from 'path';
import { Context } from 'cafy'; import { Context } from 'cafy';
import * as path from 'path'; import * as path from 'path';
import * as glob from 'glob'; import * as glob from 'glob';
import { SimpleSchema } from '@/misc/simple-schema'; import { Schema } from '@/misc/schema';
//const _filename = fileURLToPath(import.meta.url); //const _filename = fileURLToPath(import.meta.url);
const _filename = __filename; const _filename = __filename;
@ -18,87 +18,87 @@ export type Param = {
}; };
export interface IEndpointMeta { export interface IEndpointMeta {
stability?: string; //'deprecated' | 'experimental' | 'stable'; readonly stability?: 'deprecated' | 'experimental' | 'stable';
tags?: string[]; readonly tags?: ReadonlyArray<string>;
params?: { readonly params?: {
[key: string]: Param; readonly [key: string]: Param;
}; };
errors?: { readonly errors?: {
[key: string]: { readonly [key: string]: {
message: string; readonly message: string;
code: string; readonly code: string;
id: string; readonly id: string;
}; };
}; };
res?: SimpleSchema; readonly res?: Schema;
/** /**
* *
* false * false
*/ */
requireCredential?: boolean; readonly requireCredential?: boolean;
/** /**
* 使 * 使
*/ */
requireAdmin?: boolean; readonly requireAdmin?: boolean;
/** /**
* 使 * 使
*/ */
requireModerator?: boolean; readonly requireModerator?: boolean;
/** /**
* *
* *
* withCredential false * withCredential false
*/ */
limit?: { readonly limit?: {
/** /**
* *
*/ */
key?: string; readonly key?: string;
/** /**
* (ms) * (ms)
* max * max
*/ */
duration?: number; readonly duration?: number;
/** /**
* durationで指定した期間内にいくつまでリクエストできるのか * durationで指定した期間内にいくつまでリクエストできるのか
* duration * duration
*/ */
max?: number; readonly max?: number;
/** /**
* (ms) * (ms)
*/ */
minInterval?: number; readonly minInterval?: number;
}; };
/** /**
* *
* false * false
*/ */
requireFile?: boolean; readonly requireFile?: boolean;
/** /**
* *
* false * false
*/ */
secure?: boolean; readonly secure?: boolean;
/** /**
* *
* *
*/ */
kind?: string; readonly kind?: string;
} }
export interface IEndpoint { export interface IEndpoint {

View File

@ -7,7 +7,7 @@ import { makePaginationQuery } from '../../common/make-pagination-query';
export const meta = { export const meta = {
tags: ['admin'], tags: ['admin'],
requireCredential: true as const, requireCredential: true,
requireModerator: true, requireModerator: true,
params: { params: {
@ -46,69 +46,74 @@ export const meta = {
]), ]),
default: 'combined', default: 'combined',
}, },
forwarded: {
validator: $.optional.bool,
default: false,
},
}, },
res: { res: {
type: 'array' as const, type: 'array',
optional: false as const, nullable: false as const, optional: false, nullable: false,
items: { items: {
type: 'object' as const, type: 'object',
optional: false as const, nullable: false as const, optional: false, nullable: false,
properties: { properties: {
id: { id: {
type: 'string' as const, type: 'string',
nullable: false as const, optional: false as const, nullable: false, optional: false,
format: 'id', format: 'id',
example: 'xxxxxxxxxx', example: 'xxxxxxxxxx',
}, },
createdAt: { createdAt: {
type: 'string' as const, type: 'string',
nullable: false as const, optional: false as const, nullable: false, optional: false,
format: 'date-time', format: 'date-time',
}, },
comment: { comment: {
type: 'string' as const, type: 'string',
nullable: false as const, optional: false as const, nullable: false, optional: false,
}, },
resolved: { resolved: {
type: 'boolean' as const, type: 'boolean',
nullable: false as const, optional: false as const, nullable: false, optional: false,
example: false, example: false,
}, },
reporterId: { reporterId: {
type: 'string' as const, type: 'string',
nullable: false as const, optional: false as const, nullable: false, optional: false,
format: 'id', format: 'id',
}, },
targetUserId: { targetUserId: {
type: 'string' as const, type: 'string',
nullable: false as const, optional: false as const, nullable: false, optional: false,
format: 'id', format: 'id',
}, },
assigneeId: { assigneeId: {
type: 'string' as const, type: 'string',
nullable: true as const, optional: false as const, nullable: true, optional: false,
format: 'id', format: 'id',
}, },
reporter: { reporter: {
type: 'object' as const, type: 'object',
nullable: false as const, optional: false as const, nullable: false, optional: false,
ref: 'User', ref: 'User',
}, },
targetUser: { targetUser: {
type: 'object' as const, type: 'object',
nullable: false as const, optional: false as const, nullable: false, optional: false,
ref: 'User', ref: 'User',
}, },
assignee: { assignee: {
type: 'object' as const, type: 'object',
nullable: true as const, optional: true as const, nullable: true, optional: true,
ref: 'User', ref: 'User',
}, },
}, },
}, },
}, },
}; } as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => { export default define(meta, async (ps) => {

View File

@ -16,17 +16,17 @@ export const meta = {
}, },
res: { res: {
type: 'object' as const, type: 'object',
optional: false as const, nullable: false as const, optional: false, nullable: false,
ref: 'User', ref: 'User',
properties: { properties: {
token: { token: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: false as const, optional: false, nullable: false,
}, },
}, },
}, },
}; } as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, _me) => { export default define(meta, async (ps, _me) => {

View File

@ -9,7 +9,7 @@ import { ID } from '@/misc/cafy-id';
export const meta = { export const meta = {
tags: ['admin'], tags: ['admin'],
requireCredential: true as const, requireCredential: true,
requireModerator: true, requireModerator: true,
params: { params: {
@ -17,7 +17,7 @@ export const meta = {
validator: $.type(ID), validator: $.type(ID),
}, },
}, },
}; } as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => { export default define(meta, async (ps, me) => {

View File

@ -6,7 +6,7 @@ import { genId } from '@/misc/gen-id';
export const meta = { export const meta = {
tags: ['admin'], tags: ['admin'],
requireCredential: true as const, requireCredential: true,
requireModerator: true, requireModerator: true,
params: { params: {
@ -32,7 +32,7 @@ export const meta = {
validator: $.str.min(1), validator: $.str.min(1),
}, },
}, },
}; } as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => { export default define(meta, async (ps) => {

View File

@ -7,7 +7,7 @@ import { ApiError } from '../../../error';
export const meta = { export const meta = {
tags: ['admin'], tags: ['admin'],
requireCredential: true as const, requireCredential: true,
requireModerator: true, requireModerator: true,
params: { params: {
@ -23,7 +23,7 @@ export const meta = {
id: 'ccac9863-3a03-416e-b899-8a64041118b1', id: 'ccac9863-3a03-416e-b899-8a64041118b1',
}, },
}, },
}; } as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => { export default define(meta, async (ps, me) => {

View File

@ -7,7 +7,7 @@ import { makePaginationQuery } from '../../../common/make-pagination-query';
export const meta = { export const meta = {
tags: ['admin'], tags: ['admin'],
requireCredential: true as const, requireCredential: true,
requireModerator: true, requireModerator: true,
params: { params: {
@ -24,7 +24,7 @@ export const meta = {
validator: $.optional.type(ID), validator: $.optional.type(ID),
}, },
}, },
}; } as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => { export default define(meta, async (ps) => {

View File

@ -7,7 +7,7 @@ import { ApiError } from '../../../error';
export const meta = { export const meta = {
tags: ['admin'], tags: ['admin'],
requireCredential: true as const, requireCredential: true,
requireModerator: true, requireModerator: true,
params: { params: {
@ -44,7 +44,7 @@ export const meta = {
id: 'b7aa1727-1354-47bc-a182-3a9c3973d300', id: 'b7aa1727-1354-47bc-a182-3a9c3973d300',
}, },
}, },
}; } as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => { export default define(meta, async (ps, me) => {

View File

@ -6,7 +6,7 @@ import { genId } from '@/misc/gen-id';
export const meta = { export const meta = {
tags: ['admin'], tags: ['admin'],
requireCredential: true as const, requireCredential: true,
requireModerator: true, requireModerator: true,
params: { params: {
@ -22,40 +22,40 @@ export const meta = {
}, },
res: { res: {
type: 'object' as const, type: 'object',
optional: false as const, nullable: false as const, optional: false, nullable: false,
properties: { properties: {
id: { id: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: false as const, optional: false, nullable: false,
format: 'id', format: 'id',
example: 'xxxxxxxxxx', example: 'xxxxxxxxxx',
}, },
createdAt: { createdAt: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: false as const, optional: false, nullable: false,
format: 'date-time', format: 'date-time',
}, },
updatedAt: { updatedAt: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: true as const, optional: false, nullable: true,
format: 'date-time', format: 'date-time',
}, },
title: { title: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: false as const, optional: false, nullable: false,
}, },
text: { text: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: false as const, optional: false, nullable: false,
}, },
imageUrl: { imageUrl: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: true as const, optional: false, nullable: true,
}, },
}, },
}, },
}; } as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => { export default define(meta, async (ps) => {

View File

@ -7,7 +7,7 @@ import { ApiError } from '../../../error';
export const meta = { export const meta = {
tags: ['admin'], tags: ['admin'],
requireCredential: true as const, requireCredential: true,
requireModerator: true, requireModerator: true,
params: { params: {
@ -23,7 +23,7 @@ export const meta = {
id: 'ecad8040-a276-4e85-bda9-015a708d291e', id: 'ecad8040-a276-4e85-bda9-015a708d291e',
}, },
}, },
}; } as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => { export default define(meta, async (ps, me) => {

View File

@ -7,7 +7,7 @@ import { makePaginationQuery } from '../../../common/make-pagination-query';
export const meta = { export const meta = {
tags: ['admin'], tags: ['admin'],
requireCredential: true as const, requireCredential: true,
requireModerator: true, requireModerator: true,
params: { params: {
@ -26,48 +26,48 @@ export const meta = {
}, },
res: { res: {
type: 'array' as const, type: 'array',
optional: false as const, nullable: false as const, optional: false, nullable: false,
items: { items: {
type: 'object' as const, type: 'object',
optional: false as const, nullable: false as const, optional: false, nullable: false,
properties: { properties: {
id: { id: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: false as const, optional: false, nullable: false,
format: 'id', format: 'id',
example: 'xxxxxxxxxx', example: 'xxxxxxxxxx',
}, },
createdAt: { createdAt: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: false as const, optional: false, nullable: false,
format: 'date-time', format: 'date-time',
}, },
updatedAt: { updatedAt: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: true as const, optional: false, nullable: true,
format: 'date-time', format: 'date-time',
}, },
text: { text: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: false as const, optional: false, nullable: false,
}, },
title: { title: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: false as const, optional: false, nullable: false,
}, },
imageUrl: { imageUrl: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: true as const, optional: false, nullable: true,
}, },
reads: { reads: {
type: 'number' as const, type: 'number',
optional: false as const, nullable: false as const, optional: false, nullable: false,
}, },
}, },
}, },
}, },
}; } as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => { export default define(meta, async (ps) => {

View File

@ -7,7 +7,7 @@ import { ApiError } from '../../../error';
export const meta = { export const meta = {
tags: ['admin'], tags: ['admin'],
requireCredential: true as const, requireCredential: true,
requireModerator: true, requireModerator: true,
params: { params: {
@ -32,7 +32,7 @@ export const meta = {
id: 'd3aae5a7-6372-4cb4-b61c-f511ffc2d7cc', id: 'd3aae5a7-6372-4cb4-b61c-f511ffc2d7cc',
}, },
}, },
}; } as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => { export default define(meta, async (ps, me) => {

View File

@ -7,7 +7,7 @@ import { ID } from '@/misc/cafy-id';
export const meta = { export const meta = {
tags: ['admin'], tags: ['admin'],
requireCredential: true as const, requireCredential: true,
requireModerator: true, requireModerator: true,
params: { params: {
@ -15,7 +15,7 @@ export const meta = {
validator: $.type(ID), validator: $.type(ID),
}, },
}, },
}; } as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => { export default define(meta, async (ps, me) => {

View File

@ -1,14 +0,0 @@
import define from '../../define';
import { Logs } from '@/models/index';
export const meta = {
tags: ['admin'],
requireCredential: true as const,
requireModerator: true,
};
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => {
await Logs.clear(); // TRUNCATE
});

View File

@ -4,9 +4,9 @@ import { createCleanRemoteFilesJob } from '@/queue/index';
export const meta = { export const meta = {
tags: ['admin'], tags: ['admin'],
requireCredential: true as const, requireCredential: true,
requireModerator: true, requireModerator: true,
}; } as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => { export default define(meta, async (ps, me) => {

View File

@ -6,9 +6,9 @@ import { DriveFiles } from '@/models/index';
export const meta = { export const meta = {
tags: ['admin'], tags: ['admin'],
requireCredential: true as const, requireCredential: true,
requireModerator: true, requireModerator: true,
}; } as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => { export default define(meta, async (ps, me) => {

View File

@ -7,7 +7,7 @@ import { ID } from '@/misc/cafy-id';
export const meta = { export const meta = {
tags: ['admin'], tags: ['admin'],
requireCredential: false as const, requireCredential: false,
requireModerator: true, requireModerator: true,
params: { params: {
@ -44,15 +44,15 @@ export const meta = {
}, },
res: { res: {
type: 'array' as const, type: 'array',
optional: false as const, nullable: false as const, optional: false, nullable: false,
items: { items: {
type: 'object' as const, type: 'object',
optional: false as const, nullable: false as const, optional: false, nullable: false,
ref: 'DriveFile', ref: 'DriveFile',
}, },
}, },
}; } as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => { export default define(meta, async (ps, me) => {

View File

@ -7,7 +7,7 @@ import { DriveFiles } from '@/models/index';
export const meta = { export const meta = {
tags: ['admin'], tags: ['admin'],
requireCredential: true as const, requireCredential: true,
requireModerator: true, requireModerator: true,
params: { params: {
@ -29,137 +29,137 @@ export const meta = {
}, },
res: { res: {
type: 'object' as const, type: 'object',
optional: false as const, nullable: false as const, optional: false, nullable: false,
properties: { properties: {
id: { id: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: false as const, optional: false, nullable: false,
format: 'id', format: 'id',
example: 'xxxxxxxxxx', example: 'xxxxxxxxxx',
}, },
createdAt: { createdAt: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: false as const, optional: false, nullable: false,
format: 'date-time', format: 'date-time',
}, },
userId: { userId: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: true as const, optional: false, nullable: true,
format: 'id', format: 'id',
example: 'xxxxxxxxxx', example: 'xxxxxxxxxx',
}, },
userHost: { userHost: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: true as const, optional: false, nullable: true,
}, },
md5: { md5: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: false as const, optional: false, nullable: false,
format: 'md5', format: 'md5',
example: '15eca7fba0480996e2245f5185bf39f2', example: '15eca7fba0480996e2245f5185bf39f2',
}, },
name: { name: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: false as const, optional: false, nullable: false,
example: 'lenna.jpg', example: 'lenna.jpg',
}, },
type: { type: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: false as const, optional: false, nullable: false,
example: 'image/jpeg', example: 'image/jpeg',
}, },
size: { size: {
type: 'number' as const, type: 'number',
optional: false as const, nullable: false as const, optional: false, nullable: false,
example: 51469, example: 51469,
}, },
comment: { comment: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: true as const, optional: false, nullable: true,
}, },
blurhash: { blurhash: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: true as const, optional: false, nullable: true,
}, },
properties: { properties: {
type: 'object' as const, type: 'object',
optional: false as const, nullable: false as const, optional: false, nullable: false,
properties: { properties: {
width: { width: {
type: 'number' as const, type: 'number',
optional: false as const, nullable: false as const, optional: false, nullable: false,
example: 1280, example: 1280,
}, },
height: { height: {
type: 'number' as const, type: 'number',
optional: false as const, nullable: false as const, optional: false, nullable: false,
example: 720, example: 720,
}, },
avgColor: { avgColor: {
type: 'string' as const, type: 'string',
optional: true as const, nullable: false as const, optional: true, nullable: false,
example: 'rgb(40,65,87)', example: 'rgb(40,65,87)',
}, },
}, },
}, },
storedInternal: { storedInternal: {
type: 'boolean' as const, type: 'boolean',
optional: false as const, nullable: true as const, optional: false, nullable: true,
example: true, example: true,
}, },
url: { url: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: true as const, optional: false, nullable: true,
format: 'url', format: 'url',
}, },
thumbnailUrl: { thumbnailUrl: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: true as const, optional: false, nullable: true,
format: 'url', format: 'url',
}, },
webpublicUrl: { webpublicUrl: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: true as const, optional: false, nullable: true,
format: 'url', format: 'url',
}, },
accessKey: { accessKey: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: false as const, optional: false, nullable: false,
}, },
thumbnailAccessKey: { thumbnailAccessKey: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: false as const, optional: false, nullable: false,
}, },
webpublicAccessKey: { webpublicAccessKey: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: false as const, optional: false, nullable: false,
}, },
uri: { uri: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: true as const, optional: false, nullable: true,
}, },
src: { src: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: true as const, optional: false, nullable: true,
}, },
folderId: { folderId: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: true as const, optional: false, nullable: true,
format: 'id', format: 'id',
example: 'xxxxxxxxxx', example: 'xxxxxxxxxx',
}, },
isSensitive: { isSensitive: {
type: 'boolean' as const, type: 'boolean',
optional: false as const, nullable: false as const, optional: false, nullable: false,
}, },
isLink: { isLink: {
type: 'boolean' as const, type: 'boolean',
optional: false as const, nullable: false as const, optional: false, nullable: false,
}, },
}, },
}, },
}; } as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => { export default define(meta, async (ps, me) => {

View File

@ -8,7 +8,7 @@ import { ApiError } from '../../../error';
export const meta = { export const meta = {
tags: ['admin'], tags: ['admin'],
requireCredential: true as const, requireCredential: true,
requireModerator: true, requireModerator: true,
params: { params: {
@ -20,7 +20,7 @@ export const meta = {
validator: $.arr($.str), validator: $.arr($.str),
}, },
}, },
}; } as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => { export default define(meta, async (ps) => {

View File

@ -12,7 +12,7 @@ import { publishBroadcastStream } from '@/services/stream';
export const meta = { export const meta = {
tags: ['admin'], tags: ['admin'],
requireCredential: true as const, requireCredential: true,
requireModerator: true, requireModerator: true,
params: { params: {
@ -28,7 +28,7 @@ export const meta = {
id: 'fc46b5a4-6b92-4c33-ac66-b806659bb5cf', id: 'fc46b5a4-6b92-4c33-ac66-b806659bb5cf',
}, },
}, },
}; } as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => { export default define(meta, async (ps, me) => {
@ -45,8 +45,9 @@ export default define(meta, async (ps, me) => {
category: null, category: null,
host: null, host: null,
aliases: [], aliases: [],
url: file.url, originalUrl: file.url,
type: file.type, publicUrl: file.webpublicUrl ?? file.url,
type: file.webpublicType ?? file.type,
}).then(x => Emojis.findOneOrFail(x.identifiers[0])); }).then(x => Emojis.findOneOrFail(x.identifiers[0]));
await getConnection().queryResultCache!.remove(['meta_emojis']); await getConnection().queryResultCache!.remove(['meta_emojis']);

View File

@ -12,7 +12,7 @@ import { publishBroadcastStream } from '@/services/stream';
export const meta = { export const meta = {
tags: ['admin'], tags: ['admin'],
requireCredential: true as const, requireCredential: true,
requireModerator: true, requireModerator: true,
params: { params: {
@ -30,17 +30,17 @@ export const meta = {
}, },
res: { res: {
type: 'object' as const, type: 'object',
optional: false as const, nullable: false as const, optional: false, nullable: false,
properties: { properties: {
id: { id: {
type: 'string' as const, type: 'string',
optional: false as const, nullable: false as const, optional: false, nullable: false,
format: 'id', format: 'id',
}, },
}, },
}, },
}; } as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => { export default define(meta, async (ps, me) => {
@ -54,7 +54,7 @@ export default define(meta, async (ps, me) => {
try { try {
// Create file // Create file
driveFile = await uploadFromUrl(emoji.url, null, null, null, false, true); driveFile = await uploadFromUrl(emoji.originalUrl, null, null, null, false, true);
} catch (e) { } catch (e) {
throw new ApiError(); throw new ApiError();
} }
@ -65,9 +65,9 @@ export default define(meta, async (ps, me) => {
name: emoji.name, name: emoji.name,
host: null, host: null,
aliases: [], aliases: [],
url: driveFile.url, originalUrl: driveFile.url,
type: driveFile.type, publicUrl: driveFile.webpublicUrl ?? driveFile.url,
fileId: driveFile.id, type: driveFile.webpublicType ?? driveFile.type,
}).then(x => Emojis.findOneOrFail(x.identifiers[0])); }).then(x => Emojis.findOneOrFail(x.identifiers[0]));
await getConnection().queryResultCache!.remove(['meta_emojis']); await getConnection().queryResultCache!.remove(['meta_emojis']);

View File

@ -9,7 +9,7 @@ import { ApiError } from '../../../error';
export const meta = { export const meta = {
tags: ['admin'], tags: ['admin'],
requireCredential: true as const, requireCredential: true,
requireModerator: true, requireModerator: true,
params: { params: {
@ -17,7 +17,7 @@ export const meta = {
validator: $.arr($.type(ID)), validator: $.arr($.type(ID)),
}, },
}, },
}; } as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => { export default define(meta, async (ps, me) => {

View File

@ -9,7 +9,7 @@ import { ApiError } from '../../../error';
export const meta = { export const meta = {
tags: ['admin'], tags: ['admin'],
requireCredential: true as const, requireCredential: true,
requireModerator: true, requireModerator: true,
params: { params: {
@ -25,7 +25,7 @@ export const meta = {
id: 'be83669b-773a-44b7-b1f8-e5e5170ac3c2', id: 'be83669b-773a-44b7-b1f8-e5e5170ac3c2',
}, },
}, },
}; } as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => { export default define(meta, async (ps, me) => {

View File

@ -6,14 +6,14 @@ import { ID } from '@/misc/cafy-id';
export const meta = { export const meta = {
secure: true, secure: true,
requireCredential: true as const, requireCredential: true,
requireModerator: true, requireModerator: true,
params: { params: {
fileId: { fileId: {
validator: $.type(ID), validator: $.type(ID),
}, },
}, },
}; } as const;
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, user) => { export default define(meta, async (ps, user) => {

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