Merge branch 'develop' into swn

This commit is contained in:
tamaina 2021-10-09 15:45:41 +09:00
commit 92c3162506
86 changed files with 1610 additions and 1000 deletions

View file

@ -13,9 +13,16 @@
## 12.x.x (unreleased) ## 12.x.x (unreleased)
### Improvements ### Improvements
- アカウント登録にメールアドレスの設定を必須にするオプション
- クライアント: アニメーションを減らす設定をメニューのアニメーションにも適用するように - クライアント: アニメーションを減らす設定をメニューのアニメーションにも適用するように
- クライアント: MFM関数構文のサジェストを実装 - クライアント: MFM関数構文のサジェストを実装
- クライアント: 未読の通知のみ表示する機能
- クライアント: 通知ページで通知の種類によるフィルタ
- ActivityPub: HTML -> MFMの変換を強化 - ActivityPub: HTML -> MFMの変換を強化
- API: i/notifications に unreadOnly オプションを追加
- API: ap系のエンドポイントをログイン必須化+レートリミット追加
- Misskeyのコマンドラインオプションを廃止
- 代わりに環境変数で設定することができます
### Bugfixes ### Bugfixes
- Fix createDeleteAccountJob - Fix createDeleteAccountJob

View file

@ -791,6 +791,14 @@ resolved: "解決済み"
unresolved: "未解決" unresolved: "未解決"
itsOn: "オンになっています" itsOn: "オンになっています"
itsOff: "オフになっています" itsOff: "オフになっています"
emailRequiredForSignup: "アカウント登録にメールアドレスを必須にする"
unread: "未読"
filter: "フィルタ"
_signup:
almostThere: "ほとんど完了です"
emailAddressInfo: "あなたが使っているメールアドレスを入力してください。"
emailSent: "入力されたメールアドレス({email})宛に確認のメールが送信されました。メールに記載されたリンクにアクセスすると、アカウントの作成が完了します。"
_accountDelete: _accountDelete:
accountDelete: "アカウントの削除" accountDelete: "アカウントの削除"

View file

@ -0,0 +1,14 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class emailRequiredForSignup1633068642000 implements MigrationInterface {
name = 'emailRequiredForSignup1633068642000'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "meta" ADD "emailRequiredForSignup" boolean NOT NULL DEFAULT false`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "emailRequiredForSignup"`);
}
}

View file

@ -0,0 +1,16 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class userPending1633071909016 implements MigrationInterface {
name = 'userPending1633071909016'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE "user_pending" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "code" character varying(128) NOT NULL, "username" character varying(128) NOT NULL, "email" character varying(128) NOT NULL, "password" character varying(128) NOT NULL, CONSTRAINT "PK_d4c84e013c98ec02d19b8fbbafa" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_4e5c4c99175638ec0761714ab0" ON "user_pending" ("code") `);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP INDEX "IDX_4e5c4c99175638ec0761714ab0"`);
await queryRunner.query(`DROP TABLE "user_pending"`);
}
}

View file

@ -47,7 +47,7 @@
"@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.4", "@types/bull": "3.15.5",
"@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.0",
@ -63,17 +63,17 @@
"@types/koa-bodyparser": "4.3.3", "@types/koa-bodyparser": "4.3.3",
"@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.1", "@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.0.3",
"@types/koa__multer": "2.0.3", "@types/koa__multer": "2.0.3",
"@types/koa__router": "8.0.8", "@types/koa__router": "8.0.8",
"@types/markdown-it": "12.2.1", "@types/markdown-it": "12.2.3",
"@types/matter-js": "0.17.5", "@types/matter-js": "0.17.5",
"@types/mocha": "8.2.3", "@types/mocha": "8.2.3",
"@types/node": "16.9.6", "@types/node": "16.10.3",
"@types/node-fetch": "2.5.12", "@types/node-fetch": "2.5.12",
"@types/nodemailer": "6.4.4", "@types/nodemailer": "6.4.4",
"@types/nprogress": "0.2.0", "@types/nprogress": "0.2.0",
@ -102,28 +102,27 @@
"@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": "7.4.7", "@types/ws": "8.2.0",
"@typescript-eslint/parser": "4.31.2", "@typescript-eslint/parser": "4.33.0",
"@vue/compiler-sfc": "3.2.19", "@vue/compiler-sfc": "3.2.19",
"abort-controller": "3.0.0", "abort-controller": "3.0.0",
"apexcharts": "3.28.3", "apexcharts": "3.28.3",
"autobind-decorator": "2.4.0", "autobind-decorator": "2.4.0",
"autosize": "4.0.4", "autosize": "4.0.4",
"autwh": "0.1.0", "autwh": "0.1.0",
"aws-sdk": "2.992.0", "aws-sdk": "2.1003.0",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"blurhash": "1.1.4", "blurhash": "1.1.4",
"broadcast-channel": "4.2.0", "broadcast-channel": "4.2.0",
"bull": "3.29.2", "bull": "3.29.2",
"cacheable-lookup": "6.0.1", "cacheable-lookup": "6.0.2",
"cafy": "15.2.1", "cafy": "15.2.1",
"cbor": "8.0.0", "cbor": "8.0.2",
"chalk": "4.1.2", "chalk": "4.1.2",
"chart.js": "2.9.4", "chart.js": "2.9.4",
"cli-highlight": "2.1.11", "cli-highlight": "2.1.11",
"commander": "8.1.0",
"compare-versions": "3.6.0", "compare-versions": "3.6.0",
"concurrently": "6.2.1", "concurrently": "6.3.0",
"content-disposition": "0.5.3", "content-disposition": "0.5.3",
"crc-32": "1.2.0", "crc-32": "1.2.0",
"css-loader": "6.3.0", "css-loader": "6.3.0",
@ -131,18 +130,18 @@
"dateformat": "4.5.1", "dateformat": "4.5.1",
"escape-regexp": "0.0.1", "escape-regexp": "0.0.1",
"eslint": "7.32.0", "eslint": "7.32.0",
"eslint-plugin-vue": "7.18.0", "eslint-plugin-vue": "7.19.1",
"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",
"fluent-ffmpeg": "2.1.2", "fluent-ffmpeg": "2.1.2",
"glob": "7.1.7", "glob": "7.2.0",
"got": "11.8.2", "got": "11.8.2",
"gulp": "4.0.2", "gulp": "4.0.2",
"gulp-cssnano": "2.1.3", "gulp-cssnano": "2.1.3",
"gulp-rename": "2.0.0", "gulp-rename": "2.0.0",
"gulp-replace": "1.1.3", "gulp-replace": "1.1.3",
"gulp-terser": "2.0.1", "gulp-terser": "2.1.0",
"gulp-tslint": "8.1.4", "gulp-tslint": "8.1.4",
"hpagent": "0.1.2", "hpagent": "0.1.2",
"http-signature": "1.3.5", "http-signature": "1.3.5",
@ -157,7 +156,7 @@
"jsonld": "5.2.0", "jsonld": "5.2.0",
"jsrsasign": "8.0.20", "jsrsasign": "8.0.20",
"katex": "0.13.18", "katex": "0.13.18",
"koa": "2.13.1", "koa": "2.13.3",
"koa-bodyparser": "4.3.0", "koa-bodyparser": "4.3.0",
"koa-favicon": "2.1.0", "koa-favicon": "2.1.0",
"koa-json-body": "5.3.0", "koa-json-body": "5.3.0",
@ -170,19 +169,19 @@
"markdown-it": "12.2.0", "markdown-it": "12.2.0",
"markdown-it-anchor": "7.1.0", "markdown-it-anchor": "7.1.0",
"matter-js": "0.17.1", "matter-js": "0.17.1",
"mfm-js": "0.19.0", "mfm-js": "0.20.0",
"misskey-js": "0.0.6", "misskey-js": "0.0.6",
"mocha": "8.4.0", "mocha": "8.4.0",
"ms": "2.1.3", "ms": "2.1.3",
"multer": "1.4.3", "multer": "1.4.3",
"nested-property": "4.0.0", "nested-property": "4.0.0",
"node-fetch": "2.6.1", "node-fetch": "2.6.1",
"nodemailer": "6.6.3", "nodemailer": "6.6.5",
"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",
"postcss": "8.3.7", "postcss": "8.3.9",
"postcss-loader": "6.1.1", "postcss-loader": "6.1.1",
"prismjs": "1.25.0", "prismjs": "1.25.0",
"private-ip": "2.2.1", "private-ip": "2.2.1",
@ -214,7 +213,7 @@
"style-loader": "3.3.0", "style-loader": "3.3.0",
"summaly": "2.4.1", "summaly": "2.4.1",
"syslog-pro": "1.0.0", "syslog-pro": "1.0.0",
"systeminformation": "5.9.3", "systeminformation": "5.9.4",
"syuilo-password-strength": "0.0.1", "syuilo-password-strength": "0.0.1",
"textarea-caret": "3.1.0", "textarea-caret": "3.1.0",
"three": "0.117.1", "three": "0.117.1",
@ -223,12 +222,12 @@
"tmp": "0.2.1", "tmp": "0.2.1",
"ts-loader": "9.2.6", "ts-loader": "9.2.6",
"ts-node": "10.2.1", "ts-node": "10.2.1",
"tsc-alias": "1.3.9", "tsc-alias": "1.3.10",
"tsconfig-paths": "3.11.0", "tsconfig-paths": "3.11.0",
"tslint": "6.1.3", "tslint": "6.1.3",
"tslint-sonarts": "1.9.0", "tslint-sonarts": "1.9.0",
"twemoji-parser": "13.1.0", "twemoji-parser": "13.1.0",
"typeorm": "0.2.37", "typeorm": "0.2.38",
"typescript": "4.4.3", "typescript": "4.4.3",
"ulid": "2.3.0", "ulid": "2.3.0",
"uuid": "8.3.2", "uuid": "8.3.2",
@ -242,17 +241,17 @@
"vue-svg-loader": "0.17.0-beta.2", "vue-svg-loader": "0.17.0-beta.2",
"vuedraggable": "4.0.1", "vuedraggable": "4.0.1",
"web-push": "3.4.5", "web-push": "3.4.5",
"webpack": "5.54.0", "webpack": "5.58.0",
"webpack-cli": "4.8.0", "webpack-cli": "4.9.0",
"websocket": "1.0.34", "websocket": "1.0.34",
"ws": "8.2.2", "ws": "8.2.3",
"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.54",
"@types/fluent-ffmpeg": "2.1.17", "@types/fluent-ffmpeg": "2.1.17",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"cypress": "8.4.1", "cypress": "8.5.0",
"start-server-and-test": "1.14.0" "start-server-and-test": "1.14.0"
} }
} }

View file

@ -1,23 +0,0 @@
import { Command } from 'commander';
import config from '@/config/index';
const program = new Command();
program.version(config.version);
program.option('--no-daemons', 'Disable daemon processes (for debbuging)');
program.option('--disable-clustering', 'Disable clustering');
program.option('--only-server', 'Run server only (without job queue processing)');
program.option('--only-queue', 'Pocessing job queue only (without server)');
program.option('--quiet', 'Suppress all logs');
program.option('--verbose', 'Enable all logs');
program.option('--with-log-time', 'Include timestamp for each logs');
program.option('--slow', 'Delay all requests (for debbuging)');
program.option('--color', 'This option is a dummy for some external program\'s (e.g. forever) issue.');
program.parse(process.argv);
if (process.env.MK_ONLY_QUEUE) program.onlyQueue = true;
if (process.env.NODE_ENV === 'test') program.disableClustering = true;
//if (process.env.NODE_ENV === 'test') program.quiet = true;
if (process.env.NODE_ENV === 'test') program.noDaemons = true;
export { program };

View file

@ -3,7 +3,7 @@ import * as chalk from 'chalk';
import Xev from 'xev'; import Xev from 'xev';
import Logger from '@/services/logger'; import Logger from '@/services/logger';
import { program } from '../argv'; import { envOption } from '../env';
// for typeorm // for typeorm
import 'reflect-metadata'; import 'reflect-metadata';
@ -20,7 +20,7 @@ const ev = new Xev();
export default async function() { export default async function() {
process.title = `Misskey (${cluster.isMaster ? 'master' : 'worker'})`; process.title = `Misskey (${cluster.isMaster ? 'master' : 'worker'})`;
if (cluster.isMaster || program.disableClustering) { if (cluster.isMaster || envOption.disableClustering) {
await masterMain(); await masterMain();
if (cluster.isMaster) { if (cluster.isMaster) {
@ -28,7 +28,7 @@ export default async function() {
} }
} }
if (cluster.isWorker || program.disableClustering) { if (cluster.isWorker || envOption.disableClustering) {
await workerMain(); await workerMain();
} }
@ -60,7 +60,7 @@ cluster.on('exit', worker => {
}); });
// Display detail of unhandled promise rejection // Display detail of unhandled promise rejection
if (!program.quiet) { if (!envOption.quiet) {
process.on('unhandledRejection', console.dir); process.on('unhandledRejection', console.dir);
} }

View file

@ -11,7 +11,7 @@ import Logger from '@/services/logger';
import loadConfig from '@/config/load'; import loadConfig from '@/config/load';
import { Config } from '@/config/types'; import { Config } from '@/config/types';
import { lessThan } from '@/prelude/array'; import { lessThan } from '@/prelude/array';
import { program } from '../argv'; import { envOption } from '../env';
import { showMachineInfo } from '@/misc/show-machine-info'; import { showMachineInfo } from '@/misc/show-machine-info';
import { initDb } from '../db/postgre'; import { initDb } from '../db/postgre';
@ -25,7 +25,7 @@ const logger = new Logger('core', 'cyan');
const bootLogger = logger.createSubLogger('boot', 'magenta', false); const bootLogger = logger.createSubLogger('boot', 'magenta', false);
function greet() { function greet() {
if (!program.quiet) { if (!envOption.quiet) {
//#region Misskey logo //#region Misskey logo
const v = `v${meta.version}`; const v = `v${meta.version}`;
console.log(' _____ _ _ '); console.log(' _____ _ _ ');
@ -73,13 +73,13 @@ export async function masterMain() {
bootLogger.succ('Misskey initialized'); bootLogger.succ('Misskey initialized');
if (!program.disableClustering) { if (!envOption.disableClustering) {
await spawnWorkers(config.clusterLimit); await spawnWorkers(config.clusterLimit);
} }
bootLogger.succ(`Now listening on port ${config.port} on ${config.url}`, null, true); bootLogger.succ(`Now listening on port ${config.port} on ${config.url}`, null, true);
if (!program.noDaemons) { if (!envOption.noDaemons) {
require('../daemons/server-stats').default(); require('../daemons/server-stats').default();
require('../daemons/queue-stats').default(); require('../daemons/queue-stats').default();
require('../daemons/janitor').default(); require('../daemons/janitor').default();

View file

@ -1,10 +1,5 @@
<template> <template>
<div class="fdidabkb" :class="{ slim: titleOnly || narrow }" :style="`--height:${height};`" :key="key"> <div class="fdidabkb" :class="{ slim: narrow, thin }" :style="{ background: bg }" @click="onClick">
<transition :name="$store.state.animation ? 'header' : ''" mode="out-in" appear>
<div class="buttons left" v-if="backButton">
<button class="_button button back" @click.stop="$emit('back')" @touchstart="preventDrag" v-tooltip="$ts.goBack"><i class="fas fa-chevron-left"></i></button>
</div>
</transition>
<template v-if="info"> <template v-if="info">
<div class="titleContainer" @click="showTabsPopup"> <div class="titleContainer" @click="showTabsPopup">
<i v-if="info.icon" class="icon" :class="info.icon"></i> <i v-if="info.icon" class="icon" :class="info.icon"></i>
@ -31,20 +26,29 @@
</template> </template>
<div class="buttons right"> <div class="buttons right">
<template v-if="info && info.actions && !narrow"> <template v-if="info && info.actions && !narrow">
<button v-for="action in info.actions" class="_button button" :class="{ highlighted: action.highlighted }" @click.stop="action.handler" @touchstart="preventDrag" v-tooltip="action.text"><i :class="action.icon"></i></button> <template v-for="action in info.actions">
<MkButton class="fullButton" v-if="action.asFullButton" @click.stop="action.handler" primary><i :class="action.icon" style="margin-right: 6px;"></i>{{ action.text }}</MkButton>
<button v-else class="_button button" :class="{ highlighted: action.highlighted }" @click.stop="action.handler" @touchstart="preventDrag" v-tooltip="action.text"><i :class="action.icon"></i></button>
</template>
</template> </template>
<button v-if="shouldShowMenu" class="_button button" @click.stop="showMenu" @touchstart="preventDrag" v-tooltip="$ts.menu"><i class="fas fa-ellipsis-h"></i></button> <button v-if="shouldShowMenu" class="_button button" @click.stop="showMenu" @touchstart="preventDrag" v-tooltip="$ts.menu"><i class="fas fa-ellipsis-h"></i></button>
<button v-if="closeButton" class="_button button" @click.stop="$emit('close')" @touchstart="preventDrag" v-tooltip="$ts.close"><i class="fas fa-times"></i></button>
</div> </div>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import * as tinycolor from 'tinycolor2';
import { popupMenu } from '@client/os'; import { popupMenu } from '@client/os';
import { url } from '@client/config'; import { url } from '@client/config';
import { scrollToTop } from '@client/scripts/scroll';
import MkButton from '@client/components/ui/button.vue';
export default defineComponent({ export default defineComponent({
components: {
MkButton
},
props: { props: {
info: { info: {
required: true required: true
@ -52,28 +56,17 @@ export default defineComponent({
menu: { menu: {
required: false required: false
}, },
backButton: { thin: {
type: Boolean,
required: false, required: false,
default: false, default: false
},
closeButton: {
type: Boolean,
required: false,
default: false,
},
titleOnly: {
type: Boolean,
required: false,
default: false,
}, },
}, },
data() { data() {
return { return {
bg: null,
narrow: false, narrow: false,
height: 0, height: 0,
key: 0,
}; };
}, },
@ -92,19 +85,21 @@ export default defineComponent({
} }
}, },
watch: {
info() {
this.key++;
},
},
mounted() { mounted() {
this.height = this.$el.parentElement.offsetHeight + 'px'; const rawBg = this.info?.bg || 'var(--bg)';
this.narrow = this.titleOnly || this.$el.parentElement.offsetWidth < 500; const bg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg);
bg.setAlpha(0.85);
this.bg = bg.toRgbString();
if (this.$el.parentElement) {
this.narrow = this.$el.parentElement.offsetWidth < 500;
new ResizeObserver((entries, observer) => { new ResizeObserver((entries, observer) => {
this.height = this.$el.parentElement.offsetHeight + 'px'; this.narrow = this.$el.parentElement.offsetWidth < 500;
this.narrow = this.titleOnly || this.$el.parentElement.offsetWidth < 500; }).observe(this.$el.parentElement);
}).observe(this.$el); const currentStickyTop = getComputedStyle(this.$el).getPropertyValue('--stickyTop') || '0px';
this.$el.style.setProperty('--stickyTop', currentStickyTop);
this.$el.parentElement.style.setProperty('--stickyTop', `calc(${currentStickyTop} + ${this.$el.offsetHeight}px)`);
}
}, },
methods: { methods: {
@ -154,6 +149,10 @@ export default defineComponent({
preventDrag(ev) { preventDrag(ev) {
ev.stopPropagation(); ev.stopPropagation();
},
onClick(ev) {
scrollToTop(this.$el, { behavior: 'smooth' });
} }
} }
}); });
@ -161,7 +160,18 @@ export default defineComponent({
<style lang="scss" scoped> <style lang="scss" scoped>
.fdidabkb { .fdidabkb {
--height: 60px;
display: flex; display: flex;
position: sticky;
top: var(--stickyTop, 0);
z-index: 1000;
width: 100%;
-webkit-backdrop-filter: var(--blur, blur(15px));
backdrop-filter: var(--blur, blur(15px));
&.thin {
--height: 50px;
}
&.slim { &.slim {
text-align: center; text-align: center;
@ -210,6 +220,12 @@ export default defineComponent({
color: var(--accent); color: var(--accent);
} }
} }
> .fullButton {
& + .fullButton {
margin-left: 12px;
}
}
} }
> .titleContainer { > .titleContainer {
@ -220,6 +236,7 @@ export default defineComponent({
text-align: left; text-align: left;
font-weight: bold; font-weight: bold;
flex-shrink: 0; flex-shrink: 0;
margin-left: 24px;
> .avatar { > .avatar {
$size: 32px; $size: 32px;

View file

@ -13,6 +13,7 @@ import i18n from './global/i18n';
import loading from './global/loading.vue'; import loading from './global/loading.vue';
import error from './global/error.vue'; import error from './global/error.vue';
import ad from './global/ad.vue'; import ad from './global/ad.vue';
import header from './global/header.vue';
export default function(app: App) { export default function(app: App) {
app.component('I18n', i18n); app.component('I18n', i18n);
@ -28,4 +29,5 @@ export default function(app: App) {
app.component('MkLoading', loading); app.component('MkLoading', loading);
app.component('MkError', error); app.component('MkError', error);
app.component('MkAd', ad); app.component('MkAd', ad);
app.component('MkHeader', header);
} }

View file

@ -2,9 +2,13 @@
<MkModal ref="modal" @click="$emit('click')" @closed="$emit('closed')"> <MkModal ref="modal" @click="$emit('click')" @closed="$emit('closed')">
<div class="hrmcaedk _window _narrow_" :style="{ width: `${width}px`, height: (height ? `min(${height}px, 100%)` : '100%') }"> <div class="hrmcaedk _window _narrow_" :style="{ width: `${width}px`, height: (height ? `min(${height}px, 100%)` : '100%') }">
<div class="header" @contextmenu="onContextmenu"> <div class="header" @contextmenu="onContextmenu">
<span class="title"> <button v-if="history.length > 0" class="_button" @click="back()"><i class="fas fa-arrow-left"></i></button>
<XHeader :info="pageInfo" :back-button="history.length > 0" @back="back()" :close-button="true" @close="$refs.modal.close()"/> <span v-else style="display: inline-block; width: 20px"></span>
<span v-if="pageInfo" class="title">
<i v-if="pageInfo.icon" class="icon" :class="pageInfo.icon"></i>
<span>{{ pageInfo.title }}</span>
</span> </span>
<button class="_button" @click="$refs.modal.close()"><i class="fas fa-times"></i></button>
</div> </div>
<div class="body _flat_"> <div class="body _flat_">
<keep-alive> <keep-alive>
@ -18,7 +22,6 @@
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import MkModal from '@client/components/ui/modal.vue'; import MkModal from '@client/components/ui/modal.vue';
import XHeader from '@client/ui/_common_/header.vue';
import { popout } from '@client/scripts/popout'; import { popout } from '@client/scripts/popout';
import copyToClipboard from '@client/scripts/copy-to-clipboard'; import copyToClipboard from '@client/scripts/copy-to-clipboard';
import { resolve } from '@client/router'; import { resolve } from '@client/router';
@ -29,7 +32,6 @@ import * as os from '@client/os';
export default defineComponent({ export default defineComponent({
components: { components: {
MkModal, MkModal,
XHeader,
}, },
inject: { inject: {
@ -172,19 +174,39 @@ export default defineComponent({
$height-narrow: 42px; $height-narrow: 42px;
display: flex; display: flex;
flex-shrink: 0; flex-shrink: 0;
box-shadow: 0px 1px var(--divider);
> .title {
flex: 1;
height: $height; height: $height;
line-height: $height;
font-weight: bold; font-weight: bold;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
box-shadow: 0px 1px var(--divider);
> button {
height: $height;
width: $height;
&:hover {
color: var(--fgHighlighted);
}
}
@media (max-width: 500px) { @media (max-width: 500px) {
height: $height-narrow; height: $height-narrow;
line-height: $height-narrow;
padding-left: 16px; padding-left: 16px;
> button {
height: $height-narrow;
width: $height-narrow;
}
}
> .title {
flex: 1;
> .icon {
margin-right: 0.5em;
} }
} }
} }

View file

@ -32,7 +32,7 @@ import XModalWindow from '@client/components/ui/modal-window.vue';
import MkSwitch from './form/switch.vue'; import MkSwitch from './form/switch.vue';
import MkInfo from './ui/info.vue'; import MkInfo from './ui/info.vue';
import MkButton from './ui/button.vue'; import MkButton from './ui/button.vue';
import { notificationTypes } from '../../types'; import { notificationTypes } from '@/types';
export default defineComponent({ export default defineComponent({
components: { components: {

View file

@ -27,7 +27,7 @@ import { markNotificationRead } from '@client/scripts/mark-notification-read';
import XNotification from './notification.vue'; import XNotification from './notification.vue';
import XList from './date-separated-list.vue'; import XList from './date-separated-list.vue';
import XNote from './note.vue'; import XNote from './note.vue';
import { notificationTypes } from '../../types'; import { notificationTypes } from '@/types';
import * as os from '@client/os'; import * as os from '@client/os';
import MkButton from '@client/components/ui/button.vue'; import MkButton from '@client/components/ui/button.vue';
@ -49,6 +49,11 @@ export default defineComponent({
required: false, required: false,
default: null, default: null,
}, },
unreadOnly: {
type: Boolean,
required: false,
default: false,
},
}, },
data() { data() {
@ -59,6 +64,7 @@ export default defineComponent({
limit: 10, limit: 10,
params: () => ({ params: () => ({
includeTypes: this.allIncludeTypes || undefined, includeTypes: this.allIncludeTypes || undefined,
unreadOnly: this.unreadOnly,
}) })
}, },
}; };
@ -77,6 +83,11 @@ export default defineComponent({
}, },
deep: true deep: true
}, },
unreadOnly: {
handler() {
this.reload();
},
},
// TODO: vue/vuex $i // TODO: vue/vuex $i
// mutingNotificationTypes // mutingNotificationTypes
'$i.mutingNotificationTypes': { '$i.mutingNotificationTypes': {

View file

@ -3,12 +3,18 @@
:initial-width="500" :initial-width="500"
:initial-height="500" :initial-height="500"
:can-resize="true" :can-resize="true"
:close-button="false" :close-button="true"
:contextmenu="contextmenu" :contextmenu="contextmenu"
@closed="$emit('closed')" @closed="$emit('closed')"
> >
<template #header> <template #header>
<XHeader :info="pageInfo" :back-button="history.length > 0" @back="back()" :close-button="true" @close="close()" :title-only="true"/> <template v-if="pageInfo">
<i v-if="pageInfo.icon" class="icon" :class="pageInfo.icon" style="margin-right: 0.5em;"></i>
<span>{{ pageInfo.title }}</span>
</template>
</template>
<template #headerLeft>
<button v-if="history.length > 0" class="_button" @click="back()"><i class="fas fa-arrow-left"></i></button>
</template> </template>
<div class="yrolvcoq _flat_"> <div class="yrolvcoq _flat_">
<component :is="component" v-bind="props" :ref="changePage"/> <component :is="component" v-bind="props" :ref="changePage"/>
@ -19,7 +25,6 @@
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import XWindow from '@client/components/ui/window.vue'; import XWindow from '@client/components/ui/window.vue';
import XHeader from '@client/ui/_common_/header.vue';
import { popout } from '@client/scripts/popout'; import { popout } from '@client/scripts/popout';
import copyToClipboard from '@client/scripts/copy-to-clipboard'; import copyToClipboard from '@client/scripts/copy-to-clipboard';
import { resolve } from '@client/router'; import { resolve } from '@client/router';
@ -29,7 +34,6 @@ import * as symbols from '@client/symbols';
export default defineComponent({ export default defineComponent({
components: { components: {
XWindow, XWindow,
XHeader,
}, },
inject: { inject: {

View file

@ -9,7 +9,7 @@
<div class="_monolithic_"> <div class="_monolithic_">
<div class="_section"> <div class="_section">
<XSignup :auto-set="autoSet" @signup="onSignup"/> <XSignup :auto-set="autoSet" @signup="onSignup" @signupEmailPending="onSignupEmailPending"/>
</div> </div>
</div> </div>
</XModalWindow> </XModalWindow>
@ -40,6 +40,10 @@ export default defineComponent({
onSignup(res) { onSignup(res) {
this.$emit('done', res); this.$emit('done', res);
this.$refs.dialog.close(); this.$refs.dialog.close();
},
onSignupEmailPending() {
this.$refs.dialog.close();
} }
} }
}); });

View file

@ -10,13 +10,23 @@
<template #prefix>@</template> <template #prefix>@</template>
<template #suffix>@{{ host }}</template> <template #suffix>@{{ host }}</template>
<template #caption> <template #caption>
<span v-if="usernameState == 'wait'" style="color:#999"><i class="fas fa-spinner fa-pulse fa-fw"></i> {{ $ts.checking }}</span> <span v-if="usernameState === 'wait'" style="color:#999"><i class="fas fa-spinner fa-pulse fa-fw"></i> {{ $ts.checking }}</span>
<span v-if="usernameState == 'ok'" style="color: var(--success)"><i class="fas fa-check fa-fw"></i> {{ $ts.available }}</span> <span v-else-if="usernameState === 'ok'" style="color: var(--success)"><i class="fas fa-check fa-fw"></i> {{ $ts.available }}</span>
<span v-if="usernameState == 'unavailable'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.unavailable }}</span> <span v-else-if="usernameState === 'unavailable'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.unavailable }}</span>
<span v-if="usernameState == 'error'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.error }}</span> <span v-else-if="usernameState === 'error'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.error }}</span>
<span v-if="usernameState == 'invalid-format'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.usernameInvalidFormat }}</span> <span v-else-if="usernameState === 'invalid-format'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.usernameInvalidFormat }}</span>
<span v-if="usernameState == 'min-range'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.tooShort }}</span> <span v-else-if="usernameState === 'min-range'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.tooShort }}</span>
<span v-if="usernameState == 'max-range'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.tooLong }}</span> <span v-else-if="usernameState === 'max-range'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.tooLong }}</span>
</template>
</MkInput>
<MkInput v-if="meta.emailRequiredForSignup" class="_formBlock" v-model="email" type="email" :autocomplete="Math.random()" spellcheck="false" required @update:modelValue="onChangeEmail" data-cy-signup-email>
<template #label>{{ $ts.emailAddress }} <div class="_button _help" v-tooltip:dialog="$ts._signup.emailAddressInfo"><i class="far fa-question-circle"></i></div></template>
<template #prefix><i class="fas fa-envelope"></i></template>
<template #caption>
<span v-if="emailState === 'wait'" style="color:#999"><i class="fas fa-spinner fa-pulse fa-fw"></i> {{ $ts.checking }}</span>
<span v-else-if="emailState === 'ok'" style="color: var(--success)"><i class="fas fa-check fa-fw"></i> {{ $ts.available }}</span>
<span v-else-if="emailState === 'unavailable'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.unavailable }}</span>
<span v-else-if="emailState === 'error'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.error }}</span>
</template> </template>
</MkInput> </MkInput>
<MkInput class="_formBlock" v-model="password" type="password" :autocomplete="Math.random()" required @update:modelValue="onChangePassword" data-cy-signup-password> <MkInput class="_formBlock" v-model="password" type="password" :autocomplete="Math.random()" required @update:modelValue="onChangePassword" data-cy-signup-password>
@ -87,8 +97,10 @@ export default defineComponent({
password: '', password: '',
retypedPassword: '', retypedPassword: '',
invitationCode: '', invitationCode: '',
email: '',
url, url,
usernameState: null, usernameState: null,
emailState: null,
passwordStrength: '', passwordStrength: '',
passwordRetypeState: null, passwordRetypeState: null,
submitting: false, submitting: false,
@ -148,6 +160,23 @@ export default defineComponent({
}); });
}, },
onChangeEmail() {
if (this.email == '') {
this.emailState = null;
return;
}
this.emailState = 'wait';
os.api('email-address/available', {
emailAddress: this.email
}).then(result => {
this.emailState = result.available ? 'ok' : 'unavailable';
}).catch(err => {
this.emailState = 'error';
});
},
onChangePassword() { onChangePassword() {
if (this.password == '') { if (this.password == '') {
this.passwordStrength = ''; this.passwordStrength = '';
@ -174,20 +203,30 @@ export default defineComponent({
os.api('signup', { os.api('signup', {
username: this.username, username: this.username,
password: this.password, password: this.password,
emailAddress: this.email,
invitationCode: this.invitationCode, invitationCode: this.invitationCode,
'hcaptcha-response': this.hCaptchaResponse, 'hcaptcha-response': this.hCaptchaResponse,
'g-recaptcha-response': this.reCaptchaResponse, 'g-recaptcha-response': this.reCaptchaResponse,
}).then(() => { }).then(() => {
return os.api('signin', { if (this.meta.emailRequiredForSignup) {
os.dialog({
type: 'success',
title: this.$ts._signup.almostThere,
text: this.$t('_signup.emailSent', { email: this.email }),
});
this.$emit('signupEmailPending');
} else {
os.api('signin', {
username: this.username, username: this.username,
password: this.password password: this.password
}).then(res => { }).then(res => {
this.$emit('signup', res); this.$emit('signup', res);
if (this.autoSet) { if (this.autoSet) {
return login(res.i); login(res.i);
} }
}); });
}
}).catch(() => { }).catch(() => {
this.submitting = false; this.submitting = false;
this.$refs.hcaptcha?.reset?.(); this.$refs.hcaptcha?.reset?.();

View file

@ -27,7 +27,7 @@
<MkAvatar :user="item.user" class="avatar"/><MkUserName :user="item.user"/> <MkAvatar :user="item.user" class="avatar"/><MkUserName :user="item.user"/>
<span v-if="item.indicate" class="indicator"><i class="fas fa-circle"></i></span> <span v-if="item.indicate" class="indicator"><i class="fas fa-circle"></i></span>
</button> </button>
<button v-else @click="clicked(item.action, $event)" :tabindex="i" class="_button item" :class="{ danger: item.danger }"> <button v-else @click="clicked(item.action, $event)" :tabindex="i" class="_button item" :class="{ danger: item.danger, active: item.active }" :disabled="item.active">
<i v-if="item.icon" class="fa-fw" :class="item.icon"></i> <i v-if="item.icon" class="fa-fw" :class="item.icon"></i>
<MkAvatar v-if="item.avatar" :user="item.avatar" class="avatar"/> <MkAvatar v-if="item.avatar" :user="item.avatar" class="avatar"/>
<span>{{ item.text }}</span> <span>{{ item.text }}</span>
@ -170,9 +170,14 @@ export default defineComponent({
left: 0; left: 0;
right: 0; right: 0;
margin: auto; margin: auto;
width: calc(100% - 16px); //width: calc(100% - 16px);
width: 100%;
height: 100%; height: 100%;
border-radius: 6px; //border-radius: 6px;
}
> * {
position: relative;
} }
&.danger { &.danger {
@ -195,7 +200,16 @@ export default defineComponent({
} }
} }
&:hover { &.active {
color: var(--fgOnAccent);
opacity: 1;
&:before {
background: var(--accent);
}
}
&:not(:disabled):hover {
color: var(--accent); color: var(--accent);
text-decoration: none; text-decoration: none;
@ -204,11 +218,6 @@ export default defineComponent({
} }
} }
&:active {
//color: var(--fgOnAccent);
//background: var(--accentDarken);
}
&:not(:active):focus-visible { &:not(:active):focus-visible {
box-shadow: 0 0 0 2px var(--focus) inset; box-shadow: 0 0 0 2px var(--focus) inset;
} }

View file

@ -3,11 +3,16 @@
<div class="ebkgocck" :class="{ front }" v-if="showing"> <div class="ebkgocck" :class="{ front }" v-if="showing">
<div class="body _window _shadow _narrow_" @mousedown="onBodyMousedown" @keydown="onKeydown"> <div class="body _window _shadow _narrow_" @mousedown="onBodyMousedown" @keydown="onKeydown">
<div class="header" :class="{ mini }" @contextmenu.prevent.stop="onContextmenu"> <div class="header" :class="{ mini }" @contextmenu.prevent.stop="onContextmenu">
<button v-if="closeButton" class="_button" @click="close()"><i class="fas fa-times"></i></button> <span class="left">
<slot name="headerLeft"></slot>
</span>
<span class="title" @mousedown.prevent="onHeaderMousedown" @touchstart.prevent="onHeaderMousedown"> <span class="title" @mousedown.prevent="onHeaderMousedown" @touchstart.prevent="onHeaderMousedown">
<slot name="header"></slot> <slot name="header"></slot>
</span> </span>
<span class="right">
<slot name="headerRight"></slot>
<button v-if="closeButton" class="_button" @click="close()"><i class="fas fa-times"></i></button>
</span>
</div> </div>
<div class="body" v-if="padding"> <div class="body" v-if="padding">
<div class="_section"> <div class="_section">
@ -418,6 +423,7 @@ export default defineComponent({
height: var(--height); height: var(--height);
border-bottom: solid 1px var(--divider); border-bottom: solid 1px var(--divider);
> .left, > .right {
> ::v-deep(button) { > ::v-deep(button) {
height: var(--height); height: var(--height);
width: var(--height); width: var(--height);
@ -426,6 +432,7 @@ export default defineComponent({
color: var(--fgHighlighted); color: var(--fgHighlighted);
} }
} }
}
> .title { > .title {
flex: 1; flex: 1;

View file

@ -0,0 +1,34 @@
import { Directive } from 'vue';
export default {
mounted(src, binding, vn) {
const calc = () => {
const height = src.clientHeight;
const width = src.clientWidth;
// 要素が(一時的に)DOMに存在しないときは計算スキップ
if (height === 0) return;
binding.value(width, height);
};
calc();
// Vue3では使えなくなった
// 無くても大丈夫か...
// TODO: ↑大丈夫じゃなかったので解決策を探す
//vn.context.$on('hook:activated', calc);
const ro = new ResizeObserver((entries, observer) => {
calc();
});
ro.observe(src);
src._get_size_ro_ = ro;
},
unmounted(src, binding, vn) {
binding.value(0, 0);
src._get_size_ro_.unobserve(src);
}
} as Directive;

View file

@ -2,6 +2,7 @@ import { App } from 'vue';
import userPreview from './user-preview'; import userPreview from './user-preview';
import size from './size'; import size from './size';
import getSize from './get-size';
import particle from './particle'; import particle from './particle';
import tooltip from './tooltip'; import tooltip from './tooltip';
import hotkey from './hotkey'; import hotkey from './hotkey';
@ -14,6 +15,7 @@ export default function(app: App) {
app.directive('userPreview', userPreview); app.directive('userPreview', userPreview);
app.directive('user-preview', userPreview); app.directive('user-preview', userPreview);
app.directive('size', size); app.directive('size', size);
app.directive('get-size', getSize);
app.directive('particle', particle); app.directive('particle', particle);
app.directive('tooltip', tooltip); app.directive('tooltip', tooltip);
app.directive('hotkey', hotkey); app.directive('hotkey', hotkey);

View file

@ -1,5 +1,7 @@
<template> <template>
<div class="_section"> <div>
<MkHeader :info="header"/>
<div class="_section">
<MkPagination :pagination="pagination" #default="{items}" class="ruryvtyk _content"> <MkPagination :pagination="pagination" #default="{items}" class="ruryvtyk _content">
<section class="_card announcement _gap" v-for="(announcement, i) in items" :key="announcement.id"> <section class="_card announcement _gap" v-for="(announcement, i) in items" :key="announcement.id">
<div class="_title"><span v-if="$i && !announcement.isRead">🆕 </span>{{ announcement.title }}</div> <div class="_title"><span v-if="$i && !announcement.isRead">🆕 </span>{{ announcement.title }}</div>
@ -12,6 +14,7 @@
</div> </div>
</section> </section>
</MkPagination> </MkPagination>
</div>
</div> </div>
</template> </template>
@ -35,6 +38,11 @@ export default defineComponent({
icon: 'fas fa-broadcast-tower', icon: 'fas fa-broadcast-tower',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },
header: {
title: this.$ts.announcements,
icon: 'fas fa-broadcast-tower',
bg: 'var(--bg)',
},
pagination: { pagination: {
endpoint: 'announcements', endpoint: 'announcements',
limit: 10, limit: 10,

View file

@ -89,7 +89,7 @@ export default defineComponent({
}, },
top() { top() {
scroll(this.$el, 0); scroll(this.$el, { top: 0 });
}, },
async timetravel() { async timetravel() {

View file

@ -1,6 +1,9 @@
<template> <template>
<div :class="$style.root"> <div>
<MkHeader :info="header"/>
<div :class="$style.root">
<XCategory v-if="tab === 'category'"/> <XCategory v-if="tab === 'category'"/>
</div>
</div> </div>
</template> </template>
@ -22,6 +25,11 @@ export default defineComponent({
icon: 'fas fa-laugh', icon: 'fas fa-laugh',
bg: 'var(--bg)', bg: 'var(--bg)',
})), })),
header: computed(() => ({
title: this.$ts.customEmojis,
icon: 'fas fa-laugh',
bg: 'var(--bg)',
})),
tab: 'category', tab: 'category',
} }
}, },

View file

@ -1,5 +1,8 @@
<template> <template>
<div class="lznhrdub _root"> <div>
<MkHeader :info="header"/>
<div class="lznhrdub _root">
<div> <div>
<div class="_isolated"> <div class="_isolated">
<MkInput v-model="query" :debounce="true" type="search"> <MkInput v-model="query" :debounce="true" type="search">
@ -68,6 +71,7 @@
</MkFolder> </MkFolder>
</template> </template>
</div> </div>
</div>
</div> </div>
</template> </template>
@ -100,6 +104,10 @@ export default defineComponent({
title: this.$ts.explore, title: this.$ts.explore,
icon: 'fas fa-hashtag' icon: 'fas fa-hashtag'
}, },
header: {
title: this.$ts.explore,
icon: 'fas fa-hashtag'
},
pinnedUsers: { endpoint: 'pinned-users' }, pinnedUsers: { endpoint: 'pinned-users' },
popularUsers: { endpoint: 'users', limit: 10, noPaging: true, params: { popularUsers: { endpoint: 'users', limit: 10, noPaging: true, params: {
state: 'alive', state: 'alive',

View file

@ -1,8 +1,11 @@
<template> <template>
<div class="jmelgwjh"> <div>
<MkHeader :info="header"/>
<div class="jmelgwjh">
<div class="body"> <div class="body">
<XNotes class="notes" :pagination="pagination" :detail="true" :prop="'note'" @before="before()" @after="after()"/> <XNotes class="notes" :pagination="pagination" :detail="true" :prop="'note'" @before="before()" @after="after()"/>
</div> </div>
</div>
</div> </div>
</template> </template>
@ -25,6 +28,11 @@ export default defineComponent({
icon: 'fas fa-star', icon: 'fas fa-star',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },
header: {
title: this.$ts.favorites,
icon: 'fas fa-star',
bg: 'var(--bg)',
},
pagination: { pagination: {
endpoint: 'i/favorites', endpoint: 'i/favorites',
limit: 10, limit: 10,

View file

@ -1,6 +1,9 @@
<template> <template>
<div class="_section"> <div>
<MkHeader :info="header"/>
<div class="_section">
<XNotes class="_content" ref="notes" :pagination="pagination" @before="before" @after="after"/> <XNotes class="_content" ref="notes" :pagination="pagination" @before="before" @after="after"/>
</div>
</div> </div>
</template> </template>
@ -19,12 +22,18 @@ export default defineComponent({
return { return {
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: this.$ts.featured, title: this.$ts.featured,
icon: 'fas fa-fire-alt' icon: 'fas fa-fire-alt',
bg: 'var(--bg)',
},
header: {
title: this.$ts.featured,
icon: 'fas fa-fire-alt',
bg: 'var(--bg)',
}, },
pagination: { pagination: {
endpoint: 'notes/featured', endpoint: 'notes/featured',
limit: 10, limit: 10,
offsetMode: true offsetMode: true,
}, },
}; };
}, },

View file

@ -1,5 +1,7 @@
<template> <template>
<div class="taeiyria"> <div>
<MkHeader :info="header"/>
<div class="taeiyria">
<div class="query"> <div class="query">
<MkInput v-model="host" :debounce="true" class=""> <MkInput v-model="host" :debounce="true" class="">
<template #prefix><i class="fas fa-search"></i></template> <template #prefix><i class="fas fa-search"></i></template>
@ -90,6 +92,7 @@
</MkA> </MkA>
</div> </div>
</MkPagination> </MkPagination>
</div>
</div> </div>
</template> </template>
@ -119,6 +122,11 @@ export default defineComponent({
icon: 'fas fa-globe', icon: 'fas fa-globe',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },
header: {
title: this.$ts.federation,
icon: 'fas fa-globe',
bg: 'var(--bg)',
},
host: '', host: '',
state: 'federating', state: 'federating',
sort: '+pubSub', sort: '+pubSub',

View file

@ -1,6 +1,7 @@
<template> <template>
<div class="uqshojas"> <div>
<MkButton @click="add()" primary style="margin: 0 auto 16px auto;"><i class="fas fa-plus"></i> {{ $ts.add }}</MkButton> <MkHeader :info="header"/>
<div class="uqshojas">
<section class="_card _gap ads" v-for="ad in ads"> <section class="_card _gap ads" v-for="ad in ads">
<div class="_content ad"> <div class="_content ad">
<MkAd v-if="ad.url" :specify="ad"/> <MkAd v-if="ad.url" :specify="ad"/>
@ -38,6 +39,7 @@
</div> </div>
</div> </div>
</section> </section>
</div>
</div> </div>
</template> </template>
@ -67,6 +69,17 @@ export default defineComponent({
icon: 'fas fa-audio-description', icon: 'fas fa-audio-description',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },
header: {
title: this.$ts.ads,
icon: 'fas fa-audio-description',
bg: 'var(--bg)',
actions: [{
asFullButton: true,
icon: 'fas fa-plus',
text: this.$ts.add,
handler: this.add,
}],
},
ads: [], ads: [],
} }
}, },

View file

@ -1,6 +1,8 @@
<template> <template>
<div class="ztgjmzrw"> <div>
<MkButton @click="add()" primary style="margin: 0 auto 16px auto;"><i class="fas fa-plus"></i> {{ $ts.add }}</MkButton> <MkHeader :info="header"/>
<div class="ztgjmzrw">
<section class="_card _gap announcements" v-for="announcement in announcements"> <section class="_card _gap announcements" v-for="announcement in announcements">
<div class="_content announcement"> <div class="_content announcement">
<MkInput v-model="announcement.title"> <MkInput v-model="announcement.title">
@ -19,6 +21,7 @@
</div> </div>
</div> </div>
</section> </section>
</div>
</div> </div>
</template> </template>
@ -46,6 +49,17 @@ export default defineComponent({
icon: 'fas fa-broadcast-tower', icon: 'fas fa-broadcast-tower',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },
header: {
title: this.$ts.announcements,
icon: 'fas fa-broadcast-tower',
bg: 'var(--bg)',
actions: [{
asFullButton: true,
icon: 'fas fa-plus',
text: this.$ts.add,
handler: this.add,
}],
},
announcements: [], announcements: [],
} }
}, },

View file

@ -11,13 +11,13 @@
<div class="_monolithic_"> <div class="_monolithic_">
<div class="yigymqpb _section"> <div class="yigymqpb _section">
<img :src="emoji.url" class="img"/> <img :src="emoji.url" class="img"/>
<MkInput v-model="name"> <MkInput class="_formBlock" v-model="name">
<template #label>{{ $ts.name }}</template> <template #label>{{ $ts.name }}</template>
</MkInput> </MkInput>
<MkInput v-model="category" :datalist="categories"> <MkInput class="_formBlock" v-model="category" :datalist="categories">
<template #label>{{ $ts.category }}</template> <template #label>{{ $ts.category }}</template>
</MkInput> </MkInput>
<MkInput v-model="aliases"> <MkInput class="_formBlock" v-model="aliases">
<template #label>{{ $ts.tags }}</template> <template #label>{{ $ts.tags }}</template>
<template #caption>{{ $ts.setMultipleBySeparatingWithSpace }}</template> <template #caption>{{ $ts.setMultipleBySeparatingWithSpace }}</template>
</MkInput> </MkInput>

View file

@ -1,12 +1,8 @@
<template> <template>
<div class="ogwlenmc"> <div class="ogwlenmc">
<MkTab v-model="tab"> <MkHeader :info="header"/>
<option value="local">{{ $ts.local }}</option>
<option value="remote">{{ $ts.remote }}</option>
</MkTab>
<div class="local" v-if="tab === 'local'"> <div class="local" v-if="tab === 'local'">
<MkButton primary @click="add" style="margin: var(--margin) auto;"><i class="fas fa-plus"></i> {{ $ts.addEmoji }}</MkButton>
<MkInput v-model="query" :debounce="true" type="search" style="margin: var(--margin);"> <MkInput v-model="query" :debounce="true" type="search" style="margin: var(--margin);">
<template #prefix><i class="fas fa-search"></i></template> <template #prefix><i class="fas fa-search"></i></template>
<template #label>{{ $ts.search }}</template> <template #label>{{ $ts.search }}</template>
@ -79,11 +75,27 @@ export default defineComponent({
title: this.$ts.customEmojis, title: this.$ts.customEmojis,
icon: 'fas fa-laugh', icon: 'fas fa-laugh',
bg: 'var(--bg)', bg: 'var(--bg)',
action: {
icon: 'fas fa-plus',
handler: this.add
}
}, },
header: computed(() => ({
title: this.$ts.customEmojis,
icon: 'fas fa-laugh',
bg: 'var(--bg)',
actions: [{
asFullButton: true,
icon: 'fas fa-plus',
text: this.$ts.addEmoji,
handler: this.add,
}],
tabs: [{
active: this.tab === 'local',
title: this.$ts.local,
onClick: () => { this.tab = 'local'; },
}, {
active: this.tab === 'remote',
title: this.$ts.remote,
onClick: () => { this.tab = 'remote'; },
},]
})),
tab: 'local', tab: 'local',
query: null, query: null,
queryRemote: null, queryRemote: null,

View file

@ -79,7 +79,8 @@ export default defineComponent({
setup(props, context) { setup(props, context) {
const indexInfo = { const indexInfo = {
title: i18n.locale.instance, title: i18n.locale.instance,
icon: 'fas fa-cog' icon: 'fas fa-cog',
bg: 'var(--bg)',
}; };
const INFO = ref(indexInfo); const INFO = ref(indexInfo);
const page = ref(props.initialPage); const page = ref(props.initialPage);
@ -126,7 +127,7 @@ export default defineComponent({
pageProps.value = {}; pageProps.value = {};
nextTick(() => { nextTick(() => {
scroll(el.value, 0); scroll(el.value, { top: 0 });
}); });
}, { immediate: true }); }, { immediate: true });
@ -234,7 +235,6 @@ export default defineComponent({
> .main { > .main {
flex: 1; flex: 1;
min-width: 0; min-width: 0;
overflow: auto;
--baseContentWidth: 100%; --baseContentWidth: 100%;
} }
} }

View file

@ -10,6 +10,8 @@
<FormSwitch v-model="enableRegistration">{{ $ts.enableRegistration }}</FormSwitch> <FormSwitch v-model="enableRegistration">{{ $ts.enableRegistration }}</FormSwitch>
<FormSwitch v-model="emailRequiredForSignup">{{ $ts.emailRequiredForSignup }}</FormSwitch>
<FormButton @click="save" primary><i class="fas fa-save"></i> {{ $ts.save }}</FormButton> <FormButton @click="save" primary><i class="fas fa-save"></i> {{ $ts.save }}</FormButton>
</FormSuspense> </FormSuspense>
</FormBase> </FormBase>
@ -50,6 +52,7 @@ export default defineComponent({
enableHcaptcha: false, enableHcaptcha: false,
enableRecaptcha: false, enableRecaptcha: false,
enableRegistration: false, enableRegistration: false,
emailRequiredForSignup: false,
} }
}, },
@ -63,11 +66,13 @@ export default defineComponent({
this.enableHcaptcha = meta.enableHcaptcha; this.enableHcaptcha = meta.enableHcaptcha;
this.enableRecaptcha = meta.enableRecaptcha; this.enableRecaptcha = meta.enableRecaptcha;
this.enableRegistration = !meta.disableRegistration; this.enableRegistration = !meta.disableRegistration;
this.emailRequiredForSignup = meta.emailRequiredForSignup;
}, },
save() { save() {
os.apiWithDialog('admin/update-meta', { os.apiWithDialog('admin/update-meta', {
disableRegistration: !this.enableRegistration, disableRegistration: !this.enableRegistration,
emailRequiredForSignup: this.emailRequiredForSignup,
}).then(() => { }).then(() => {
fetchInstance(); fetchInstance();
}); });

View file

@ -1,9 +1,6 @@
<template> <template>
<div class="lknzcolw"> <div class="lknzcolw">
<div class="actions"> <MkHeader :info="header"/>
<MkButton inline primary @click="addUser()"><i class="fas fa-plus"></i> {{ $ts.addUser }}</MkButton>
<MkButton inline primary @click="lookupUser()"><i class="fas fa-search"></i> {{ $ts.lookup }}</MkButton>
</div>
<div class="users"> <div class="users">
<div class="inputs"> <div class="inputs">
@ -91,10 +88,26 @@ export default defineComponent({
title: this.$ts.users, title: this.$ts.users,
icon: 'fas fa-users', icon: 'fas fa-users',
bg: 'var(--bg)', bg: 'var(--bg)',
action: { },
header: {
title: this.$ts.users,
icon: 'fas fa-users',
bg: 'var(--bg)',
actions: [{
icon: 'fas fa-search', icon: 'fas fa-search',
text: this.$ts.search,
handler: this.searchUser handler: this.searchUser
} }, {
asFullButton: true,
icon: 'fas fa-plus',
text: this.$ts.addUser,
handler: this.addUser
}, {
asFullButton: true,
icon: 'fas fa-search',
text: this.$ts.lookup,
handler: this.lookupUser
}]
}, },
sort: '+createdAt', sort: '+createdAt',
state: 'all', state: 'all',
@ -173,10 +186,6 @@ export default defineComponent({
<style lang="scss" scoped> <style lang="scss" scoped>
.lknzcolw { .lknzcolw {
> .actions {
margin: var(--margin);
}
> .users { > .users {
margin: var(--margin); margin: var(--margin);

View file

@ -1,6 +1,9 @@
<template> <template>
<div class="_section"> <div>
<MkHeader :info="header"/>
<div class="_section">
<XNotes class="_content" :pagination="pagination" @before="before()" @after="after()"/> <XNotes class="_content" :pagination="pagination" @before="before()" @after="after()"/>
</div>
</div> </div>
</template> </template>
@ -19,7 +22,13 @@ export default defineComponent({
return { return {
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: this.$ts.mentions, title: this.$ts.mentions,
icon: 'fas fa-at' icon: 'fas fa-at',
bg: 'var(--bg)',
},
header: {
title: this.$ts.mentions,
icon: 'fas fa-at',
bg: 'var(--bg)',
}, },
pagination: { pagination: {
endpoint: 'notes/mentions', endpoint: 'notes/mentions',

View file

@ -1,6 +1,9 @@
<template> <template>
<div> <div>
<MkHeader :info="header"/>
<div>
<XNotes :pagination="pagination" @before="before()" @after="after()"/> <XNotes :pagination="pagination" @before="before()" @after="after()"/>
</div>
</div> </div>
</template> </template>
@ -19,7 +22,13 @@ export default defineComponent({
return { return {
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: this.$ts.directNotes, title: this.$ts.directNotes,
icon: 'fas fa-envelope' icon: 'fas fa-envelope',
bg: 'var(--bg)',
},
header: {
title: this.$ts.directNotes,
icon: 'fas fa-envelope',
bg: 'var(--bg)',
}, },
pagination: { pagination: {
endpoint: 'notes/mentions', endpoint: 'notes/mentions',

View file

@ -1,5 +1,8 @@
<template> <template>
<div class="yweeujhr _root" v-size="{ max: [400] }"> <div>
<MkHeader :info="header"/>
<div class="yweeujhr _root" v-size="{ max: [400] }">
<MkButton @click="start" primary class="start"><i class="fas fa-plus"></i> {{ $ts.startMessaging }}</MkButton> <MkButton @click="start" primary class="start"><i class="fas fa-plus"></i> {{ $ts.startMessaging }}</MkButton>
<div class="history" v-if="messages.length > 0"> <div class="history" v-if="messages.length > 0">
@ -33,6 +36,7 @@
<div>{{ $ts.noHistory }}</div> <div>{{ $ts.noHistory }}</div>
</div> </div>
<MkLoading v-if="fetching"/> <MkLoading v-if="fetching"/>
</div>
</div> </div>
</template> </template>
@ -56,6 +60,11 @@ export default defineComponent({
icon: 'fas fa-comments', icon: 'fas fa-comments',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },
header: {
title: this.$ts.messaging,
icon: 'fas fa-comments',
bg: 'var(--bg)',
},
fetching: true, fetching: true,
moreFetching: false, moreFetching: false,
messages: [], messages: [],

View file

@ -284,7 +284,7 @@ const Component = defineComponent({
}, },
scrollToBottom() { scrollToBottom() {
scroll(this.$el, this.$el.offsetHeight); scroll(this.$el, { top: this.$el.offsetHeight });
}, },
onIndicatorClick() { onIndicatorClick() {

View file

@ -1,5 +1,7 @@
<template> <template>
<div class="qkcjvfiv"> <div>
<MkHeader :info="header"/>
<div class="qkcjvfiv">
<MkButton @click="create" primary class="add"><i class="fas fa-plus"></i> {{ $ts.createList }}</MkButton> <MkButton @click="create" primary class="add"><i class="fas fa-plus"></i> {{ $ts.createList }}</MkButton>
<MkPagination :pagination="pagination" #default="{items}" class="lists _content" ref="list"> <MkPagination :pagination="pagination" #default="{items}" class="lists _content" ref="list">
@ -8,6 +10,7 @@
<MkAvatars :user-ids="list.userIds"/> <MkAvatars :user-ids="list.userIds"/>
</MkA> </MkA>
</MkPagination> </MkPagination>
</div>
</div> </div>
</template> </template>
@ -31,6 +34,12 @@ export default defineComponent({
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: this.$ts.manageLists, title: this.$ts.manageLists,
icon: 'fas fa-list-ul', icon: 'fas fa-list-ul',
bg: 'var(--bg)',
},
header: {
title: this.$ts.manageLists,
icon: 'fas fa-list-ul',
bg: 'var(--bg)',
action: { action: {
icon: 'fas fa-plus', icon: 'fas fa-plus',
handler: this.create handler: this.create

View file

@ -1,5 +1,7 @@
<template> <template>
<div class="mk-list-page"> <div>
<MkHeader v-if="header" :info="header"/>
<div class="mk-list-page">
<transition name="zoom" mode="out-in"> <transition name="zoom" mode="out-in">
<div v-if="list" class="_section"> <div v-if="list" class="_section">
<div class="_content"> <div class="_content">
@ -29,6 +31,7 @@
</div> </div>
</div> </div>
</transition> </transition>
</div>
</div> </div>
</template> </template>
@ -50,6 +53,10 @@ export default defineComponent({
title: this.list.name, title: this.list.name,
icon: 'fas fa-list-ul', icon: 'fas fa-list-ul',
} : null), } : null),
header: computed(() => this.list ? {
title: this.list.name,
icon: 'fas fa-list-ul',
} : null),
list: null, list: null,
users: [], users: [],
}; };

View file

@ -1,15 +1,19 @@
<template> <template>
<div class="clupoqwt" v-size="{ min: [800] }"> <div>
<XNotifications class="notifications" @before="before" @after="after" page/> <MkHeader :info="header"/>
<div class="clupoqwt" v-size="{ min: [800] }">
<XNotifications class="notifications" @before="before" @after="after" :include-types="includeTypes" :unread-only="tab === 'unread'"/>
</div>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { computed, defineComponent } from 'vue';
import Progress from '@client/scripts/loading'; import Progress from '@client/scripts/loading';
import XNotifications from '@client/components/notifications.vue'; import XNotifications from '@client/components/notifications.vue';
import * as os from '@client/os'; import * as os from '@client/os';
import * as symbols from '@client/symbols'; import * as symbols from '@client/symbols';
import { notificationTypes } from '@/types';
export default defineComponent({ export default defineComponent({
components: { components: {
@ -22,14 +26,35 @@ export default defineComponent({
title: this.$ts.notifications, title: this.$ts.notifications,
icon: 'fas fa-bell', icon: 'fas fa-bell',
bg: 'var(--bg)', bg: 'var(--bg)',
},
tab: 'all',
includeTypes: null,
header: computed(() => ({
title: this.$ts.notifications,
icon: 'fas fa-bell',
bg: 'var(--bg)',
actions: [{ actions: [{
text: this.$ts.filter,
icon: 'fas fa-filter',
highlighted: this.includeTypes != null,
handler: this.setFilter,
}, {
text: this.$ts.markAllAsRead, text: this.$ts.markAllAsRead,
icon: 'fas fa-check', icon: 'fas fa-check',
handler: () => { handler: () => {
os.apiWithDialog('notifications/mark-all-as-read'); os.apiWithDialog('notifications/mark-all-as-read');
}
}]
}, },
}],
tabs: [{
active: this.tab === 'all',
title: this.$ts.all,
onClick: () => { this.tab = 'all'; },
}, {
active: this.tab === 'unread',
title: this.$ts.unread,
onClick: () => { this.tab = 'unread'; },
},]
})),
}; };
}, },
@ -40,6 +65,24 @@ export default defineComponent({
after() { after() {
Progress.done(); Progress.done();
},
setFilter(ev) {
const typeItems = notificationTypes.map(t => ({
text: this.$t(`_notification._types.${t}`),
active: this.includeTypes && this.includeTypes.includes(t),
action: () => {
this.includeTypes = [t];
}
}));
const items = this.includeTypes != null ? [{
icon: 'fas fa-times',
text: this.$ts.clear,
action: () => {
this.includeTypes = null;
}
}, null, ...typeItems] : typeItems;
os.popupMenu(items, ev.currentTarget || ev.target);
} }
} }
}); });

View file

@ -1,5 +1,8 @@
<template> <template>
<div> <div>
<MkHeader :info="header"/>
<!-- TODO: MkHeaderに統合 -->
<MkTab v-model="tab" v-if="$i"> <MkTab v-model="tab" v-if="$i">
<option value="featured"><i class="fas fa-fire-alt"></i> {{ $ts._pages.featured }}</option> <option value="featured"><i class="fas fa-fire-alt"></i> {{ $ts._pages.featured }}</option>
<option value="my"><i class="fas fa-edit"></i> {{ $ts._pages.my }}</option> <option value="my"><i class="fas fa-edit"></i> {{ $ts._pages.my }}</option>
@ -46,11 +49,17 @@ export default defineComponent({
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: this.$ts.pages, title: this.$ts.pages,
icon: 'fas fa-sticky-note', icon: 'fas fa-sticky-note',
bg: 'var(--bg)',
},
header: {
title: this.$ts.pages,
icon: 'fas fa-sticky-note',
bg: 'var(--bg)',
actions: [{ actions: [{
icon: 'fas fa-plus', icon: 'fas fa-plus',
text: this.$ts.create, text: this.$ts.create,
handler: this.create handler: this.create,
}] }],
}, },
tab: 'featured', tab: 'featured',
featuredPagesPagination: { featuredPagesPagination: {

View file

@ -1,8 +1,11 @@
<template> <template>
<div class="_section"> <div>
<MkHeader :info="header"/>
<div class="_section">
<div class="_content"> <div class="_content">
<XNotes ref="notes" :pagination="pagination" @before="before" @after="after"/> <XNotes ref="notes" :pagination="pagination" @before="before" @after="after"/>
</div> </div>
</div>
</div> </div>
</template> </template>
@ -21,7 +24,11 @@ export default defineComponent({
return { return {
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: computed(() => this.$t('searchWith', { q: this.$route.query.q })), title: computed(() => this.$t('searchWith', { q: this.$route.query.q })),
icon: 'fas fa-search' icon: 'fas fa-search',
},
header: {
title: computed(() => this.$t('searchWith', { q: this.$route.query.q })),
icon: 'fas fa-search',
}, },
pagination: { pagination: {
endpoint: 'notes/search', endpoint: 'notes/search',

View file

@ -31,10 +31,10 @@
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import FormSwitch from '@client/components/form/switch.vue'; import FormSwitch from '@client/components/debobigego/switch.vue';
import FormLink from '@client/components/debobigego/link.vue'; import FormLink from '@client/components/debobigego/link.vue';
import FormRadios from '@client/components/form/radios.vue'; import FormRadios from '@client/components/debobigego/radios.vue';
import FormInput from '@client/components/form/input.vue'; import FormInput from '@client/components/debobigego/input.vue';
import FormBase from '@client/components/debobigego/base.vue'; import FormBase from '@client/components/debobigego/base.vue';
import FormGroup from '@client/components/debobigego/group.vue'; import FormGroup from '@client/components/debobigego/group.vue';
import { deckStore } from '@client/ui/deck/deck-store'; import { deckStore } from '@client/ui/deck/deck-store';

View file

@ -39,7 +39,7 @@
</div> </div>
</div> </div>
<div class="main"> <div class="main">
<component :is="component" :key="page" @info="onInfo" v-bind="pageProps"/> <component :is="component" :key="page" v-bind="pageProps"/>
</div> </div>
</div> </div>
</template> </template>
@ -80,9 +80,7 @@ export default defineComponent({
const narrow = ref(false); const narrow = ref(false);
const view = ref(null); const view = ref(null);
const el = ref(null); const el = ref(null);
const onInfo = (viewInfo) => {
INFO.value = viewInfo;
};
const pageProps = ref({}); const pageProps = ref({});
const component = computed(() => { const component = computed(() => {
if (page.value == null) return null; if (page.value == null) return null;
@ -145,7 +143,7 @@ export default defineComponent({
} }
nextTick(() => { nextTick(() => {
scroll(el.value, 0); scroll(el.value, { top: 0 });
}); });
}, { immediate: true }); }, { immediate: true });
@ -175,7 +173,6 @@ export default defineComponent({
narrow, narrow,
view, view,
el, el,
onInfo,
pageProps, pageProps,
component, component,
emailNotConfigured, emailNotConfigured,

View file

@ -15,7 +15,7 @@ import FormButton from '@client/components/debobigego/button.vue';
import FormLink from '@client/components/debobigego/link.vue'; import FormLink from '@client/components/debobigego/link.vue';
import FormBase from '@client/components/debobigego/base.vue'; import FormBase from '@client/components/debobigego/base.vue';
import FormGroup from '@client/components/debobigego/group.vue'; import FormGroup from '@client/components/debobigego/group.vue';
import { notificationTypes } from '../../../types'; import { notificationTypes } from '@/types';
import * as os from '@client/os'; import * as os from '@client/os';
import * as symbols from '@client/symbols'; import * as symbols from '@client/symbols';

View file

@ -77,7 +77,7 @@ export default defineComponent({
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: {
title: this.$ts.profile, title: this.$ts.profile,
icon: 'fas fa-user', icon: 'fas fa-user',
bg: 'var(--bg)' bg: 'var(--bg)',
}, },
host, host,
langs, langs,

View file

@ -0,0 +1,50 @@
<template>
<div>
{{ $ts.processing }}
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import * as os from '@client/os';
import * as symbols from '@client/symbols';
import { login } from '@client/account';
export default defineComponent({
components: {
},
props: {
code: {
type: String,
required: true
}
},
data() {
return {
[symbols.PAGE_INFO]: {
title: this.$ts.signup,
icon: 'fas fa-user'
},
}
},
mounted() {
os.apiWithDialog('signup-pending', {
code: this.code,
}).then(res => {
login(res.i, '/');
});
},
methods: {
}
});
</script>
<style lang="scss" scoped>
</style>

View file

@ -1,5 +1,7 @@
<template> <template>
<div class="cmuxhskf" v-hotkey.global="keymap" v-size="{ min: [800] }"> <div v-hotkey.global="keymap">
<MkHeader :info="header"/>
<div class="cmuxhskf" v-size="{ min: [800] }">
<XTutorial v-if="$store.reactiveState.tutorial.value != -1" class="tutorial _block"/> <XTutorial v-if="$store.reactiveState.tutorial.value != -1" class="tutorial _block"/>
<XPostForm v-if="$store.reactiveState.showFixedPostForm.value" class="post-form _block" fixed/> <XPostForm v-if="$store.reactiveState.showFixedPostForm.value" class="post-form _block" fixed/>
@ -14,6 +16,7 @@
@queue="queueUpdated" @queue="queueUpdated"
/> />
</div> </div>
</div>
</div> </div>
</template> </template>
@ -43,6 +46,11 @@ export default defineComponent({
title: this.$ts.timeline, title: this.$ts.timeline,
icon: this.src === 'local' ? 'fas fa-comments' : this.src === 'social' ? 'fas fa-share-alt' : this.src === 'global' ? 'fas fa-globe' : 'fas fa-home', icon: this.src === 'local' ? 'fas fa-comments' : this.src === 'social' ? 'fas fa-share-alt' : this.src === 'global' ? 'fas fa-globe' : 'fas fa-home',
bg: 'var(--bg)', bg: 'var(--bg)',
})),
header: computed(() => ({
title: this.$ts.timeline,
icon: this.src === 'local' ? 'fas fa-comments' : this.src === 'social' ? 'fas fa-share-alt' : this.src === 'global' ? 'fas fa-globe' : 'fas fa-home',
bg: 'var(--bg)',
actions: [{ actions: [{
icon: 'fas fa-list-ul', icon: 'fas fa-list-ul',
text: this.$ts.lists, text: this.$ts.lists,
@ -129,7 +137,7 @@ export default defineComponent({
}, },
top() { top() {
scroll(this.$el, 0); scroll(this.$el, { top: 0 });
}, },
async chooseList(ev) { async chooseList(ev) {

View file

@ -89,7 +89,7 @@ export default defineComponent({
}, },
top() { top() {
scroll(this.$el, 0); scroll(this.$el, { top: 0 });
}, },
settings() { settings() {

View file

@ -1,5 +1,7 @@
<template> <template>
<transition name="fade" mode="out-in"> <div>
<MkHeader :info="header"/>
<transition name="fade" mode="out-in">
<div class="ftskorzw wide" v-if="user && narrow === false"> <div class="ftskorzw wide" v-if="user && narrow === false">
<MkRemoteCaution v-if="user.host != null" :href="user.url"/> <MkRemoteCaution v-if="user.host != null" :href="user.url"/>
@ -186,7 +188,8 @@
</div> </div>
<MkError v-else-if="error" @retry="fetch()"/> <MkError v-else-if="error" @retry="fetch()"/>
<MkLoading v-else/> <MkLoading v-else/>
</transition> </transition>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -242,6 +245,15 @@ export default defineComponent({
data() { data() {
return { return {
[symbols.PAGE_INFO]: computed(() => this.user ? { [symbols.PAGE_INFO]: computed(() => this.user ? {
icon: 'fas fa-user',
title: this.user.name ? `${this.user.name} (@${this.user.username})` : `@${this.user.username}`,
path: `/@${this.user.username}`,
share: {
title: this.user.name,
},
bg: 'var(--bg)',
} : null),
header: computed(() => this.user ? {
title: this.user.name ? `${this.user.name} (@${this.user.username})` : `@${this.user.username}`, title: this.user.name ? `${this.user.name} (@${this.user.username})` : `@${this.user.username}`,
subtitle: `@${getAcct(this.user)}`, subtitle: `@${getAcct(this.user)}`,
userName: this.user, userName: this.user,

View file

@ -23,6 +23,7 @@ const defaultRoutes = [
{ path: '/@:acct/room', props: true, component: page('room/room') }, { path: '/@:acct/room', props: true, component: page('room/room') },
{ path: '/settings/:page(.*)?', name: 'settings', component: page('settings/index'), props: route => ({ initialPage: route.params.page || null }) }, { path: '/settings/:page(.*)?', name: 'settings', component: page('settings/index'), props: route => ({ initialPage: route.params.page || null }) },
{ path: '/reset-password/:token?', component: page('reset-password'), props: route => ({ token: route.params.token }) }, { path: '/reset-password/:token?', component: page('reset-password'), props: route => ({ token: route.params.token }) },
{ path: '/signup-complete/:code', component: page('signup-complete'), props: route => ({ code: route.params.code }) },
{ path: '/announcements', component: page('announcements') }, { path: '/announcements', component: page('announcements') },
{ path: '/about', component: page('about') }, { path: '/about', component: page('about') },
{ path: '/about-misskey', component: page('about-misskey') }, { path: '/about-misskey', component: page('about-misskey') },

View file

@ -4,7 +4,6 @@ import {
get as iget, get as iget,
set as iset, set as iset,
del as idel, del as idel,
createStore,
} from 'idb-keyval'; } from 'idb-keyval';
const fallbackName = (key: string) => `idbfallback::${key}`; const fallbackName = (key: string) => `idbfallback::${key}`;
@ -13,9 +12,9 @@ let idbAvailable = typeof window !== 'undefined' ? !!window.indexedDB : true;
if (idbAvailable) { if (idbAvailable) {
try { try {
await createStore('keyval-store', 'keyval'); await iset('idb-test', 'test');
} catch (e) { } catch (e) {
console.error('idb open error', e); console.error('idb error', e);
idbAvailable = false; idbAvailable = false;
} }
} }

View file

@ -1,3 +1,5 @@
type ScrollBehavior = 'auto' | 'smooth' | 'instant';
export function getScrollContainer(el: Element | null): Element | null { export function getScrollContainer(el: Element | null): Element | null {
if (el == null || el.tagName === 'BODY') return null; if (el == null || el.tagName === 'BODY') return null;
const overflow = window.getComputedStyle(el).getPropertyValue('overflow'); const overflow = window.getComputedStyle(el).getPropertyValue('overflow');
@ -45,21 +47,25 @@ export function onScrollBottom(el: Element, cb) {
container.addEventListener('scroll', onScroll, { passive: true }); container.addEventListener('scroll', onScroll, { passive: true });
} }
export function scroll(el: Element, top: number) { export function scroll(el: Element, options: {
top?: number;
left?: number;
behavior?: ScrollBehavior;
}) {
const container = getScrollContainer(el); const container = getScrollContainer(el);
if (container == null) { if (container == null) {
window.scroll({ top: top, behavior: 'instant' }); window.scroll(options);
} else { } else {
container.scrollTop = top; container.scroll(options);
} }
} }
export function scrollToTop(el: Element) { export function scrollToTop(el: Element, options: { behavior?: ScrollBehavior; } = {}) {
scroll(el, 0); scroll(el, { top: 0, ...options });
} }
export function scrollToBottom(el: Element) { export function scrollToBottom(el: Element, options: { behavior?: ScrollBehavior; } = {}) {
scroll(el, 99999); // TODO: ちゃんと計算する scroll(el, { top: 99999, ...options }); // TODO: ちゃんと計算する
} }
export function isBottom(el: Element, asobi = 0) { export function isBottom(el: Element, asobi = 0) {

View file

@ -74,7 +74,7 @@
<main class="main" @contextmenu.stop="onContextmenu"> <main class="main" @contextmenu.stop="onContextmenu">
<header class="header"> <header class="header">
<XHeader class="header" :info="pageInfo" :menu="menu" :center="false" :back-button="true" @back="back()" @click="onHeaderClick"/> <MkHeader class="header" :info="pageInfo" :menu="menu" :center="false" @click="onHeaderClick"/>
</header> </header>
<router-view v-slot="{ Component }"> <router-view v-slot="{ Component }">
<transition :name="$store.state.animation ? 'page' : ''" mode="out-in" @enter="onTransition"> <transition :name="$store.state.animation ? 'page' : ''" mode="out-in" @enter="onTransition">
@ -101,7 +101,6 @@ import XSidebar from '@client/ui/_common_/sidebar.vue';
import XWidgets from './widgets.vue'; import XWidgets from './widgets.vue';
import XCommon from '../_common_/common.vue'; import XCommon from '../_common_/common.vue';
import XSide from './side.vue'; import XSide from './side.vue';
import XHeader from '../_common_/header.vue';
import XHeaderClock from './header-clock.vue'; import XHeaderClock from './header-clock.vue';
import * as os from '@client/os'; import * as os from '@client/os';
import { router } from '@client/router'; import { router } from '@client/router';
@ -117,7 +116,6 @@ export default defineComponent({
XSidebar, XSidebar,
XWidgets, XWidgets,
XSide, // NOTE: dynamic importAsyncComponentWrapperref XSide, // NOTE: dynamic importAsyncComponentWrapperref
XHeader,
XHeaderClock, XHeaderClock,
}, },

View file

@ -1,7 +1,7 @@
<template> <template>
<div class="mrajymqm _narrow_" v-if="component"> <div class="mrajymqm _narrow_" v-if="component">
<header class="header" @contextmenu.prevent.stop="onContextmenu"> <header class="header" @contextmenu.prevent.stop="onContextmenu">
<XHeader class="title" :info="pageInfo" :center="false" :back-button="history.length > 0" @back="back()" :close-button="true" @close="close()"/> <MkHeader class="title" :info="pageInfo" :center="false"/>
</header> </header>
<component :is="component" v-bind="props" :ref="changePage" class="body _flat_"/> <component :is="component" v-bind="props" :ref="changePage" class="body _flat_"/>
</div> </div>
@ -9,7 +9,6 @@
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import XHeader from '../_common_/header.vue';
import * as os from '@client/os'; import * as os from '@client/os';
import copyToClipboard from '@client/scripts/copy-to-clipboard'; import copyToClipboard from '@client/scripts/copy-to-clipboard';
import { resolve } from '@client/router'; import { resolve } from '@client/router';
@ -18,7 +17,6 @@ import * as symbols from '@client/symbols';
export default defineComponent({ export default defineComponent({
components: { components: {
XHeader
}, },
provide() { provide() {

View file

@ -1,7 +1,9 @@
<template> <template>
<XColumn v-if="deckStore.state.alwaysShowMainColumn || $route.name !== 'index'" :column="column" :is-stacked="isStacked"> <XColumn v-if="deckStore.state.alwaysShowMainColumn || $route.name !== 'index'" :column="column" :is-stacked="isStacked">
<template #header> <template #header>
<XHeader :info="pageInfo" :back-button="true" @back="back()"/> <template v-if="pageInfo">
{{ pageInfo.title }}
</template>
</template> </template>
<router-view v-slot="{ Component }" class="_flat_"> <router-view v-slot="{ Component }" class="_flat_">
@ -18,7 +20,6 @@
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import XColumn from './column.vue'; import XColumn from './column.vue';
import XNotes from '@client/components/notes.vue'; import XNotes from '@client/components/notes.vue';
import XHeader from '@client/ui/_common_/header.vue';
import { deckStore } from '@client/ui/deck/deck-store'; import { deckStore } from '@client/ui/deck/deck-store';
import * as os from '@client/os'; import * as os from '@client/os';
import * as symbols from '@client/symbols'; import * as symbols from '@client/symbols';
@ -26,7 +27,6 @@ import * as symbols from '@client/symbols';
export default defineComponent({ export default defineComponent({
components: { components: {
XColumn, XColumn,
XHeader,
XNotes XNotes
}, },

View file

@ -29,7 +29,7 @@
<MkAvatar :user="$i" class="avatar"/><MkAcct class="acct" :user="$i"/> <MkAvatar :user="$i" class="avatar"/><MkAcct class="acct" :user="$i"/>
</button> </button>
<div class="post" @click="post"> <div class="post" @click="post">
<MkButton class="button" primary full> <MkButton class="button" primary full rounded>
<i class="fas fa-pencil-alt fa-fw"></i> <i class="fas fa-pencil-alt fa-fw"></i>
</MkButton> </MkButton>
</div> </div>

View file

@ -4,9 +4,10 @@
<header class="header" @contextmenu.prevent.stop="onContextmenu"> <header class="header" @contextmenu.prevent.stop="onContextmenu">
<button class="_button" @click="back()" v-if="history.length > 0"><i class="fas fa-chevron-left"></i></button> <button class="_button" @click="back()" v-if="history.length > 0"><i class="fas fa-chevron-left"></i></button>
<button class="_button" style="pointer-events: none;" v-else><!-- マージンのバランスを取るためのダミー --></button> <button class="_button" style="pointer-events: none;" v-else><!-- マージンのバランスを取るためのダミー --></button>
<XHeader class="title" :info="pageInfo" :back-button="false"/> <span class="title">{{ pageInfo.title }}</span>
<button class="_button" @click="close()"><i class="fas fa-times"></i></button> <button class="_button" @click="close()"><i class="fas fa-times"></i></button>
</header> </header>
<MkHeader class="pageHeader" :info="pageInfo"/>
<component :is="component" v-bind="props" :ref="changePage"/> <component :is="component" v-bind="props" :ref="changePage"/>
</div> </div>
</div> </div>
@ -14,7 +15,6 @@
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import XHeader from './_common_/header.vue';
import * as os from '@client/os'; import * as os from '@client/os';
import copyToClipboard from '@client/scripts/copy-to-clipboard'; import copyToClipboard from '@client/scripts/copy-to-clipboard';
import { resolve } from '@client/router'; import { resolve } from '@client/router';
@ -22,10 +22,6 @@ import { url } from '@client/config';
import * as symbols from '@client/symbols'; import * as symbols from '@client/symbols';
export default defineComponent({ export default defineComponent({
components: {
XHeader
},
provide() { provide() {
return { return {
navHook: (path) => { navHook: (path) => {

View file

@ -1,6 +1,6 @@
<template> <template>
<div class="mk-app" :class="{ wallpaper, isMobile }"> <div class="mk-app" :class="{ wallpaper, isMobile }" :style="`--globalHeaderHeight:${globalHeaderHeight}px`">
<XHeaderMenu v-if="showMenuOnTop"/> <XHeaderMenu v-if="showMenuOnTop" v-get-size="(w, h) => globalHeaderHeight = h"/>
<div class="columns" :class="{ fullView, withGlobalHeader: showMenuOnTop }"> <div class="columns" :class="{ fullView, withGlobalHeader: showMenuOnTop }">
<template v-if="!isMobile"> <template v-if="!isMobile">
@ -13,9 +13,6 @@
</template> </template>
<main class="main" @contextmenu.stop="onContextmenu" :style="{ background: pageInfo?.bg }"> <main class="main" @contextmenu.stop="onContextmenu" :style="{ background: pageInfo?.bg }">
<header class="header" @click="onHeaderClick">
<XHeader :info="pageInfo" :back-button="true" @back="back()"/>
</header>
<div class="content" :class="{ _flat_: !fullView }"> <div class="content" :class="{ _flat_: !fullView }">
<router-view v-slot="{ Component }"> <router-view v-slot="{ Component }">
<transition :name="$store.state.animation ? 'page' : ''" mode="out-in" @enter="onTransition"> <transition :name="$store.state.animation ? 'page' : ''" mode="out-in" @enter="onTransition">
@ -67,7 +64,6 @@ import { StickySidebar } from '@client/scripts/sticky-sidebar';
import XSidebar from './default.sidebar.vue'; import XSidebar from './default.sidebar.vue';
import XDrawerSidebar from '@client/ui/_common_/sidebar.vue'; import XDrawerSidebar from '@client/ui/_common_/sidebar.vue';
import XCommon from './_common_/common.vue'; import XCommon from './_common_/common.vue';
import XHeader from './_common_/header.vue';
import * as os from '@client/os'; import * as os from '@client/os';
import { menuDef } from '@client/menu'; import { menuDef } from '@client/menu';
import * as symbols from '@client/symbols'; import * as symbols from '@client/symbols';
@ -80,7 +76,6 @@ export default defineComponent({
XCommon, XCommon,
XSidebar, XSidebar,
XDrawerSidebar, XDrawerSidebar,
XHeader,
XHeaderMenu: defineAsyncComponent(() => import('./default.header.vue')), XHeaderMenu: defineAsyncComponent(() => import('./default.header.vue')),
XWidgets: defineAsyncComponent(() => import('./default.widgets.vue')), XWidgets: defineAsyncComponent(() => import('./default.widgets.vue')),
}, },
@ -89,6 +84,7 @@ export default defineComponent({
return { return {
pageInfo: null, pageInfo: null,
menuDef: menuDef, menuDef: menuDef,
globalHeaderHeight: 0,
isMobile: window.innerWidth <= MOBILE_THRESHOLD, isMobile: window.innerWidth <= MOBILE_THRESHOLD,
isDesktop: window.innerWidth >= DESKTOP_THRESHOLD, isDesktop: window.innerWidth >= DESKTOP_THRESHOLD,
widgetsShowing: false, widgetsShowing: false,
@ -193,10 +189,6 @@ export default defineComponent({
if (window._scroll) window._scroll(); if (window._scroll) window._scroll();
}, },
onHeaderClick() {
window.scroll({ top: 0, behavior: 'smooth' });
},
onContextmenu(e) { onContextmenu(e) {
const isLink = (el: HTMLElement) => { const isLink = (el: HTMLElement) => {
if (el.tagName === 'A') return true; if (el.tagName === 'A') return true;
@ -257,7 +249,6 @@ export default defineComponent({
} }
.mk-app { .mk-app {
$header-height: 50px;
$ui-font-size: 1em; $ui-font-size: 1em;
$widgets-hide-threshold: 1200px; $widgets-hide-threshold: 1200px;
$nav-icon-only-width: 78px; // TODO: $nav-icon-only-width: 78px; // TODO:
@ -282,10 +273,6 @@ export default defineComponent({
border: none; border: none;
width: 100%; width: 100%;
border-radius: 0; border-radius: 0;
> .header {
width: 100%;
}
} }
} }
} }
@ -325,30 +312,6 @@ export default defineComponent({
border-radius: 0; border-radius: 0;
overflow: clip; overflow: clip;
--margin: 12px; --margin: 12px;
> .header {
position: sticky;
z-index: 1000;
top: var(--globalHeaderHeight, 0px);
height: $header-height;
-webkit-backdrop-filter: var(--blur, blur(32px));
backdrop-filter: var(--blur, blur(32px));
background-color: var(--header);
border-bottom: solid 0.5px var(--divider);
}
> .content {
--stickyTop: calc(var(--globalHeaderHeight, 0px) + #{$header-height});
}
@media (max-width: 850px) {
padding-top: $header-height;
> .header {
position: fixed;
width: calc(100% - #{$nav-icon-only-width});
}
}
} }
> .widgets { > .widgets {
@ -370,12 +333,11 @@ export default defineComponent({
} }
&.withGlobalHeader { &.withGlobalHeader {
--globalHeaderHeight: 60px; // TODO: 60px
> .main { > .main {
margin-top: 0; margin-top: 0;
border: solid 1px var(--divider); border: solid 1px var(--divider);
border-radius: var(--radius); border-radius: var(--radius);
--stickyTop: var(--globalHeaderHeight);
} }
> .widgets { > .widgets {

View file

@ -3,9 +3,6 @@
<XSidebar ref="nav" class="sidebar"/> <XSidebar ref="nav" class="sidebar"/>
<div class="contents" ref="contents" @contextmenu.stop="onContextmenu" :style="{ background: pageInfo?.bg }"> <div class="contents" ref="contents" @contextmenu.stop="onContextmenu" :style="{ background: pageInfo?.bg }">
<header class="header" ref="header" @click="onHeaderClick" :style="{ background: pageInfo?.bg }">
<XHeader :info="pageInfo" :back-button="true" @back="back()"/>
</header>
<main ref="main"> <main ref="main">
<div class="content"> <div class="content">
<router-view v-slot="{ Component }"> <router-view v-slot="{ Component }">
@ -58,7 +55,6 @@ import { instanceName } from '@client/config';
import { StickySidebar } from '@client/scripts/sticky-sidebar'; import { StickySidebar } from '@client/scripts/sticky-sidebar';
import XSidebar from '@client/ui/_common_/sidebar.vue'; import XSidebar from '@client/ui/_common_/sidebar.vue';
import XCommon from './_common_/common.vue'; import XCommon from './_common_/common.vue';
import XHeader from './_common_/header.vue';
import XSide from './default.side.vue'; import XSide from './default.side.vue';
import * as os from '@client/os'; import * as os from '@client/os';
import { menuDef } from '@client/menu'; import { menuDef } from '@client/menu';
@ -70,7 +66,6 @@ export default defineComponent({
components: { components: {
XCommon, XCommon,
XSidebar, XSidebar,
XHeader,
XWidgets: defineAsyncComponent(() => import('./universal.widgets.vue')), XWidgets: defineAsyncComponent(() => import('./universal.widgets.vue')),
XSide, // NOTE: dynamic importAsyncComponentWrapperref XSide, // NOTE: dynamic importAsyncComponentWrapperref
}, },
@ -151,9 +146,6 @@ export default defineComponent({
adjustUI() { adjustUI() {
const navWidth = this.$refs.nav.$el.offsetWidth; const navWidth = this.$refs.nav.$el.offsetWidth;
this.navHidden = navWidth === 0; this.navHidden = navWidth === 0;
if (this.$refs.contents == null) return;
const width = this.$refs.contents.offsetWidth;
if (this.$refs.header) this.$refs.header.style.width = `${width}px`;
}, },
showNav() { showNav() {
@ -183,10 +175,6 @@ export default defineComponent({
if (window._scroll) window._scroll(); if (window._scroll) window._scroll();
}, },
onHeaderClick() {
window.scroll({ top: 0, behavior: 'smooth' });
},
onContextmenu(e) { onContextmenu(e) {
const isLink = (el: HTMLElement) => { const isLink = (el: HTMLElement) => {
if (el.tagName === 'A') return true; if (el.tagName === 'A') return true;
@ -243,7 +231,6 @@ export default defineComponent({
} }
.mk-app { .mk-app {
$header-height: 58px; // TODO:
$ui-font-size: 1em; // TODO: $ui-font-size: 1em; // TODO:
$widgets-hide-threshold: 1090px; $widgets-hide-threshold: 1090px;
@ -263,37 +250,11 @@ export default defineComponent({
> .contents { > .contents {
width: 100%; width: 100%;
min-width: 0; min-width: 0;
--stickyTop: #{$header-height};
padding-top: $header-height;
background: var(--panel); background: var(--panel);
> .header {
position: fixed;
z-index: 1000;
top: 0;
height: $header-height;
width: 100%;
line-height: $header-height;
text-align: center;
font-weight: bold;
//background-color: var(--panel);
-webkit-backdrop-filter: var(--blur, blur(32px));
backdrop-filter: var(--blur, blur(32px));
background-color: var(--header);
border-bottom: solid 0.5px var(--divider);
user-select: none;
}
> main { > main {
min-width: 0; min-width: 0;
> .content {
> * {
// calc(100vh - #{$header-height}) ... https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
min-height: calc((var(--vh, 1vh) * 100) - #{$header-height});
}
}
> .spacer { > .spacer {
height: 82px; height: 82px;

View file

@ -2,7 +2,7 @@
<div class="mk-app"> <div class="mk-app">
<div class="contents"> <div class="contents">
<header class="header"> <header class="header">
<XHeader :info="pageInfo"/> <MkHeader :info="pageInfo"/>
</header> </header>
<main ref="main"> <main ref="main">
<div class="content"> <div class="content">
@ -24,14 +24,12 @@
<script lang="ts"> <script lang="ts">
import { defineComponent, defineAsyncComponent } from 'vue'; import { defineComponent, defineAsyncComponent } from 'vue';
import { host } from '@client/config'; import { host } from '@client/config';
import XHeader from './_common_/header.vue';
import XCommon from './_common_/common.vue'; import XCommon from './_common_/common.vue';
import * as symbols from '@client/symbols'; import * as symbols from '@client/symbols';
export default defineComponent({ export default defineComponent({
components: { components: {
XCommon, XCommon,
XHeader,
}, },
data() { data() {

View file

@ -63,7 +63,7 @@ import { Antenna } from '@/models/entities/antenna';
import { AntennaNote } from '@/models/entities/antenna-note'; import { AntennaNote } from '@/models/entities/antenna-note';
import { PromoNote } from '@/models/entities/promo-note'; import { PromoNote } from '@/models/entities/promo-note';
import { PromoRead } from '@/models/entities/promo-read'; import { PromoRead } from '@/models/entities/promo-read';
import { program } from '../argv'; import { envOption } from '../env';
import { Relay } from '@/models/entities/relay'; import { Relay } from '@/models/entities/relay';
import { MutedNote } from '@/models/entities/muted-note'; import { MutedNote } from '@/models/entities/muted-note';
import { Channel } from '@/models/entities/channel'; import { Channel } from '@/models/entities/channel';
@ -72,6 +72,7 @@ import { ChannelNotePining } from '@/models/entities/channel-note-pining';
import { RegistryItem } from '@/models/entities/registry-item'; import { RegistryItem } from '@/models/entities/registry-item';
import { Ad } from '@/models/entities/ad'; import { Ad } from '@/models/entities/ad';
import { PasswordResetRequest } from '@/models/entities/password-reset-request'; import { PasswordResetRequest } from '@/models/entities/password-reset-request';
import { UserPending } from '@/models/entities/user-pending';
const sqlLogger = dbLogger.createSubLogger('sql', 'white', false); const sqlLogger = dbLogger.createSubLogger('sql', 'white', false);
@ -83,7 +84,7 @@ class MyCustomLogger implements Logger {
} }
public logQuery(query: string, parameters?: any[]) { public logQuery(query: string, parameters?: any[]) {
if (program.verbose) { if (envOption.verbose) {
sqlLogger.info(this.highlight(query)); sqlLogger.info(this.highlight(query));
} }
} }
@ -173,6 +174,7 @@ export const entities = [
RegistryItem, RegistryItem,
Ad, Ad,
PasswordResetRequest, PasswordResetRequest,
UserPending,
...charts as any ...charts as any
]; ];

20
src/env.ts Normal file
View file

@ -0,0 +1,20 @@
const envOption = {
onlyQueue: false,
onlyServer: false,
noDaemons: false,
disableClustering: false,
verbose: false,
withLogTime: false,
quiet: false,
slow: false,
};
for (const key of Object.keys(envOption) as (keyof typeof envOption)[]) {
if (process.env['MK_' + key.replace(/[A-Z]/g, letter => `_${letter}`).toUpperCase()]) envOption[key] = true;
}
if (process.env.NODE_ENV === 'test') envOption.disableClustering = true;
if (process.env.NODE_ENV === 'test') envOption.quiet = true;
if (process.env.NODE_ENV === 'test') envOption.noDaemons = true;
export { envOption };

View file

@ -148,6 +148,11 @@ export class Meta {
@JoinColumn() @JoinColumn()
public proxyAccount: User | null; public proxyAccount: User | null;
@Column('boolean', {
default: false,
})
public emailRequiredForSignup: boolean;
@Column('boolean', { @Column('boolean', {
default: false, default: false,
}) })

View file

@ -5,7 +5,7 @@ import { Note } from './note';
import { FollowRequest } from './follow-request'; import { FollowRequest } from './follow-request';
import { UserGroupInvitation } from './user-group-invitation'; import { UserGroupInvitation } from './user-group-invitation';
import { AccessToken } from './access-token'; import { AccessToken } from './access-token';
import { notificationTypes } from '../../types'; import { notificationTypes } from '@/types';
@Entity() @Entity()
export class Notification { export class Notification {

View file

@ -0,0 +1,32 @@
import { PrimaryColumn, Entity, Index, Column } from 'typeorm';
import { id } from '../id';
@Entity()
export class UserPending {
@PrimaryColumn(id())
public id: string;
@Column('timestamp with time zone')
public createdAt: Date;
@Index({ unique: true })
@Column('varchar', {
length: 128,
})
public code: string;
@Column('varchar', {
length: 128,
})
public username: string;
@Column('varchar', {
length: 128,
})
public email: string;
@Column('varchar', {
length: 128,
})
public password: string;
}

View file

@ -2,7 +2,7 @@ import { Entity, Column, Index, OneToOne, JoinColumn, PrimaryColumn } from 'type
import { id } from '../id'; import { id } from '../id';
import { User } from './user'; import { User } from './user';
import { Page } from './page'; import { Page } from './page';
import { notificationTypes } from '../../types'; import { notificationTypes } from '@/types';
// TODO: このテーブルで管理している情報すべてレジストリで管理するようにしても良いかも // TODO: このテーブルで管理している情報すべてレジストリで管理するようにしても良いかも
// ただ、「emailVerified が true なユーザーを find する」のようなクエリは書けなくなるからウーン // ただ、「emailVerified が true なユーザーを find する」のようなクエリは書けなくなるからウーン

View file

@ -62,6 +62,7 @@ import { ChannelNotePining } from './entities/channel-note-pining';
import { RegistryItem } from './entities/registry-item'; import { RegistryItem } from './entities/registry-item';
import { Ad } from './entities/ad'; import { Ad } from './entities/ad';
import { PasswordResetRequest } from './entities/password-reset-request'; import { PasswordResetRequest } from './entities/password-reset-request';
import { UserPending } from './entities/user-pending';
export const Announcements = getRepository(Announcement); export const Announcements = getRepository(Announcement);
export const AnnouncementReads = getRepository(AnnouncementRead); export const AnnouncementReads = getRepository(AnnouncementRead);
@ -76,6 +77,7 @@ export const PollVotes = getRepository(PollVote);
export const Users = getCustomRepository(UserRepository); export const Users = getCustomRepository(UserRepository);
export const UserProfiles = getRepository(UserProfile); export const UserProfiles = getRepository(UserProfile);
export const UserKeypairs = getRepository(UserKeypair); export const UserKeypairs = getRepository(UserKeypair);
export const UserPendings = getRepository(UserPending);
export const AttestationChallenges = getRepository(AttestationChallenge); export const AttestationChallenges = getRepository(AttestationChallenge);
export const UserSecurityKeys = getRepository(UserSecurityKey); export const UserSecurityKeys = getRepository(UserSecurityKey);
export const UserPublickeys = getRepository(UserPublickey); export const UserPublickeys = getRepository(UserPublickey);

View file

@ -1,7 +1,7 @@
import * as httpSignature from 'http-signature'; import * as httpSignature from 'http-signature';
import config from '@/config/index'; import config from '@/config/index';
import { program } from '../argv'; import { envOption } from '../env';
import processDeliver from './processors/deliver'; import processDeliver from './processors/deliver';
import processInbox from './processors/inbox'; import processInbox from './processors/inbox';
@ -200,7 +200,7 @@ export function createCleanRemoteFilesJob() {
} }
export default function() { export default function() {
if (!program.onlyServer) { if (!envOption.onlyServer) {
deliverQueue.process(config.deliverJobConcurrency || 128, processDeliver); deliverQueue.process(config.deliverJobConcurrency || 128, processDeliver);
inboxQueue.process(config.inboxJobConcurrency || 16, processInbox); inboxQueue.process(config.inboxJobConcurrency || 16, processInbox);
processDb(dbQueue); processDb(dbQueue);

View file

@ -11,12 +11,21 @@ import { UserKeypair } from '@/models/entities/user-keypair';
import { usersChart } from '@/services/chart/index'; import { usersChart } from '@/services/chart/index';
import { UsedUsername } from '@/models/entities/used-username'; import { UsedUsername } from '@/models/entities/used-username';
export async function signup(username: User['username'], password: UserProfile['password'], host: string | null = null) { export async function signup(opts: {
username: User['username'];
password?: string | null;
passwordHash?: UserProfile['password'] | null;
host?: string | null;
}) {
const { username, password, passwordHash, host } = opts;
let hash = passwordHash;
// Validate username // Validate username
if (!Users.validateLocalUsername.ok(username)) { if (!Users.validateLocalUsername.ok(username)) {
throw new Error('INVALID_USERNAME'); throw new Error('INVALID_USERNAME');
} }
if (password != null && passwordHash == null) {
// Validate password // Validate password
if (!Users.validatePassword.ok(password)) { if (!Users.validatePassword.ok(password)) {
throw new Error('INVALID_PASSWORD'); throw new Error('INVALID_PASSWORD');
@ -24,7 +33,8 @@ export async function signup(username: User['username'], password: UserProfile['
// Generate hash of password // Generate hash of password
const salt = await bcrypt.genSalt(8); const salt = await bcrypt.genSalt(8);
const hash = await bcrypt.hash(password, salt); hash = await bcrypt.hash(password, salt);
}
// Generate secret // Generate secret
const secret = generateUserToken(); const secret = generateUserToken();

View file

@ -35,7 +35,10 @@ export default define(meta, async (ps, _me) => {
})) === 0; })) === 0;
if (!noUsers && !me?.isAdmin) throw new Error('access denied'); if (!noUsers && !me?.isAdmin) throw new Error('access denied');
const { account, secret } = await signup(ps.username, ps.password); const { account, secret } = await signup({
username: ps.username,
password: ps.password,
});
const res = await Users.pack(account, account, { const res = await Users.pack(account, account, {
detail: true, detail: true,

View file

@ -93,6 +93,10 @@ export const meta = {
validator: $.optional.bool, validator: $.optional.bool,
}, },
emailRequiredForSignup: {
validator: $.optional.bool,
},
enableHcaptcha: { enableHcaptcha: {
validator: $.optional.bool, validator: $.optional.bool,
}, },
@ -374,6 +378,10 @@ export default define(meta, async (ps, me) => {
set.proxyRemoteFiles = ps.proxyRemoteFiles; set.proxyRemoteFiles = ps.proxyRemoteFiles;
} }
if (ps.emailRequiredForSignup !== undefined) {
set.emailRequiredForSignup = ps.emailRequiredForSignup;
}
if (ps.enableHcaptcha !== undefined) { if (ps.enableHcaptcha !== undefined) {
set.enableHcaptcha = ps.enableHcaptcha; set.enableHcaptcha = ps.enableHcaptcha;
} }

View file

@ -2,11 +2,17 @@ import $ from 'cafy';
import define from '../../define'; import define from '../../define';
import Resolver from '@/remote/activitypub/resolver'; import Resolver from '@/remote/activitypub/resolver';
import { ApiError } from '../../error'; import { ApiError } from '../../error';
import * as ms from 'ms';
export const meta = { export const meta = {
tags: ['federation'], tags: ['federation'],
requireCredential: false as const, requireCredential: true as const,
limit: {
duration: ms('1hour'),
max: 30
},
params: { params: {
uri: { uri: {

View file

@ -11,11 +11,17 @@ import { Note } from '@/models/entities/note';
import { User } from '@/models/entities/user'; import { User } from '@/models/entities/user';
import { fetchMeta } from '@/misc/fetch-meta'; import { fetchMeta } from '@/misc/fetch-meta';
import { isActor, isPost, getApId } from '@/remote/activitypub/type'; import { isActor, isPost, getApId } from '@/remote/activitypub/type';
import * as ms from 'ms';
export const meta = { export const meta = {
tags: ['federation'], tags: ['federation'],
requireCredential: false as const, requireCredential: true as const,
limit: {
duration: ms('1hour'),
max: 30
},
params: { params: {
uri: { uri: {

View file

@ -0,0 +1,37 @@
import $ from 'cafy';
import define from '../../define';
import { UserProfiles } from '@/models/index';
export const meta = {
tags: ['users'],
requireCredential: false as const,
params: {
emailAddress: {
validator: $.str
}
},
res: {
type: 'object' as const,
optional: false as const, nullable: false as const,
properties: {
available: {
type: 'boolean' as const,
optional: false as const, nullable: false as const,
}
}
}
};
export default define(meta, async (ps) => {
const exist = await UserProfiles.count({
emailVerified: true,
email: ps.emailAddress,
});
return {
available: exist === 0
};
});

View file

@ -4,7 +4,7 @@ import { readNotification } from '../../common/read-notification';
import define from '../../define'; import define from '../../define';
import { makePaginationQuery } from '../../common/make-pagination-query'; import { makePaginationQuery } from '../../common/make-pagination-query';
import { Notifications, Followings, Mutings, Users } from '@/models/index'; import { Notifications, Followings, Mutings, Users } from '@/models/index';
import { notificationTypes } from '../../../../types'; import { notificationTypes } from '@/types';
import read from '@/services/note/read'; import read from '@/services/note/read';
export const meta = { export const meta = {
@ -33,6 +33,11 @@ export const meta = {
default: false default: false
}, },
unreadOnly: {
validator: $.optional.bool,
default: false
},
markAsRead: { markAsRead: {
validator: $.optional.bool, validator: $.optional.bool,
default: true default: true
@ -105,6 +110,10 @@ export default define(meta, async (ps, user) => {
query.andWhere(`notification.type NOT IN (:...excludeTypes)`, { excludeTypes: ps.excludeTypes }); query.andWhere(`notification.type NOT IN (:...excludeTypes)`, { excludeTypes: ps.excludeTypes });
} }
if (ps.unreadOnly) {
query.andWhere(`notification.isRead = false`);
}
const notifications = await query.take(ps.limit!).getMany(); const notifications = await query.take(ps.limit!).getMany();
// Mark all as read // Mark all as read

View file

@ -13,7 +13,7 @@ import { ApiError } from '../../error';
import { Users, DriveFiles, UserProfiles, Pages } from '@/models/index'; import { Users, DriveFiles, UserProfiles, Pages } from '@/models/index';
import { User } from '@/models/entities/user'; import { User } from '@/models/entities/user';
import { UserProfile } from '@/models/entities/user-profile'; import { UserProfile } from '@/models/entities/user-profile';
import { notificationTypes } from '../../../../types'; import { notificationTypes } from '@/types';
import { normalizeForSearch } from '@/misc/normalize-for-search'; import { normalizeForSearch } from '@/misc/normalize-for-search';
export const meta = { export const meta = {

View file

@ -104,6 +104,10 @@ export const meta = {
type: 'boolean' as const, type: 'boolean' as const,
optional: false as const, nullable: false as const optional: false as const, nullable: false as const
}, },
emailRequiredForSignup: {
type: 'boolean' as const,
optional: false as const, nullable: false as const
},
enableHcaptcha: { enableHcaptcha: {
type: 'boolean' as const, type: 'boolean' as const,
optional: false as const, nullable: false as const optional: false as const, nullable: false as const
@ -488,6 +492,7 @@ export default define(meta, async (ps, me) => {
disableGlobalTimeline: instance.disableGlobalTimeline, disableGlobalTimeline: instance.disableGlobalTimeline,
driveCapacityPerLocalUserMb: instance.localDriveCapacityMb, driveCapacityPerLocalUserMb: instance.localDriveCapacityMb,
driveCapacityPerRemoteUserMb: instance.remoteDriveCapacityMb, driveCapacityPerRemoteUserMb: instance.remoteDriveCapacityMb,
emailRequiredForSignup: instance.emailRequiredForSignup,
enableHcaptcha: instance.enableHcaptcha, enableHcaptcha: instance.enableHcaptcha,
hcaptchaSiteKey: instance.hcaptchaSiteKey, hcaptchaSiteKey: instance.hcaptchaSiteKey,
enableRecaptcha: instance.enableRecaptcha, enableRecaptcha: instance.enableRecaptcha,
@ -537,6 +542,7 @@ export default define(meta, async (ps, me) => {
registration: !instance.disableRegistration, registration: !instance.disableRegistration,
localTimeLine: !instance.disableLocalTimeline, localTimeLine: !instance.disableLocalTimeline,
globalTimeLine: !instance.disableGlobalTimeline, globalTimeLine: !instance.disableGlobalTimeline,
emailRequiredForSignup: instance.emailRequiredForSignup,
elasticsearch: config.elasticsearch ? true : false, elasticsearch: config.elasticsearch ? true : false,
hcaptcha: instance.enableHcaptcha, hcaptcha: instance.enableHcaptcha,
recaptcha: instance.enableRecaptcha, recaptcha: instance.enableRecaptcha,

View file

@ -12,6 +12,7 @@ import endpoints from './endpoints';
import handler from './api-handler'; import handler from './api-handler';
import signup from './private/signup'; import signup from './private/signup';
import signin from './private/signin'; import signin from './private/signin';
import signupPending from './private/signup-pending';
import discord from './service/discord'; import discord from './service/discord';
import github from './service/github'; import github from './service/github';
import twitter from './service/twitter'; import twitter from './service/twitter';
@ -65,6 +66,7 @@ for (const endpoint of endpoints) {
router.post('/signup', signup); router.post('/signup', signup);
router.post('/signin', signin); router.post('/signin', signin);
router.post('/signup-pending', signupPending);
router.use(discord.routes()); router.use(discord.routes());
router.use(github.routes()); router.use(github.routes());

View file

@ -0,0 +1,35 @@
import * as Koa from 'koa';
import { Users, UserPendings, UserProfiles } from '@/models/index';
import { signup } from '../common/signup';
import signin from '../common/signin';
export default async (ctx: Koa.Context) => {
const body = ctx.request.body;
const code = body['code'];
try {
const pendingUser = await UserPendings.findOneOrFail({ code });
const { account, secret } = await signup({
username: pendingUser.username,
passwordHash: pendingUser.password,
});
UserPendings.delete({
id: pendingUser.id,
});
const profile = await UserProfiles.findOneOrFail(account.id);
await UserProfiles.update({ userId: profile.userId }, {
email: pendingUser.email,
emailVerified: true,
emailVerifyCode: null,
});
signin(ctx, account);
} catch (e) {
ctx.throw(400, e);
}
};

View file

@ -1,8 +1,13 @@
import * as Koa from 'koa'; import * as Koa from 'koa';
import rndstr from 'rndstr';
import * as bcrypt from 'bcryptjs';
import { fetchMeta } from '@/misc/fetch-meta'; import { fetchMeta } from '@/misc/fetch-meta';
import { verifyHcaptcha, verifyRecaptcha } from '@/misc/captcha'; import { verifyHcaptcha, verifyRecaptcha } from '@/misc/captcha';
import { Users, RegistrationTickets } from '@/models/index'; import { Users, RegistrationTickets, UserPendings } from '@/models/index';
import { signup } from '../common/signup'; import { signup } from '../common/signup';
import config from '@/config';
import { sendEmail } from '@/services/send-email';
import { genId } from '@/misc/gen-id';
export default async (ctx: Koa.Context) => { export default async (ctx: Koa.Context) => {
const body = ctx.request.body; const body = ctx.request.body;
@ -29,8 +34,16 @@ export default async (ctx: Koa.Context) => {
const password = body['password']; const password = body['password'];
const host: string | null = process.env.NODE_ENV === 'test' ? (body['host'] || null) : null; const host: string | null = process.env.NODE_ENV === 'test' ? (body['host'] || null) : null;
const invitationCode = body['invitationCode']; const invitationCode = body['invitationCode'];
const emailAddress = body['emailAddress'];
if (instance && instance.disableRegistration) { if (instance.emailRequiredForSignup) {
if (emailAddress == null || typeof emailAddress != 'string') {
ctx.status = 400;
return;
}
}
if (instance.disableRegistration) {
if (invitationCode == null || typeof invitationCode != 'string') { if (invitationCode == null || typeof invitationCode != 'string') {
ctx.status = 400; ctx.status = 400;
return; return;
@ -48,8 +61,34 @@ export default async (ctx: Koa.Context) => {
RegistrationTickets.delete(ticket.id); RegistrationTickets.delete(ticket.id);
} }
if (instance.emailRequiredForSignup) {
const code = rndstr('a-z0-9', 16);
// Generate hash of password
const salt = await bcrypt.genSalt(8);
const hash = await bcrypt.hash(password, salt);
await UserPendings.insert({
id: genId(),
createdAt: new Date(),
code,
email: emailAddress,
username: username,
password: hash,
});
const link = `${config.url}/signup-complete/${code}`;
sendEmail(emailAddress, 'Signup',
`To complete signup, please click this link:<br><a href="${link}">${link}</a>`,
`To complete signup, please click this link: ${link}`);
ctx.status = 204;
} else {
try { try {
const { account, secret } = await signup(username, password, host); const { account, secret } = await signup({
username, password, host
});
const res = await Users.pack(account, account, { const res = await Users.pack(account, account, {
detail: true, detail: true,
@ -62,4 +101,5 @@ export default async (ctx: Koa.Context) => {
} catch (e) { } catch (e) {
ctx.throw(400, e); ctx.throw(400, e);
} }
}
}; };

View file

@ -20,7 +20,7 @@ import config from '@/config/index';
import apiServer from './api/index'; import apiServer from './api/index';
import { sum } from '@/prelude/array'; import { sum } from '@/prelude/array';
import Logger from '@/services/logger'; import Logger from '@/services/logger';
import { program } from '../argv'; import { envOption } from '../env';
import { UserProfiles, Users } from '@/models/index'; import { UserProfiles, Users } from '@/models/index';
import { networkChart } from '@/services/chart/index'; import { networkChart } from '@/services/chart/index';
import { genAvatar } from '@/misc/gen-avatar'; import { genAvatar } from '@/misc/gen-avatar';
@ -40,7 +40,7 @@ if (!['production', 'test'].includes(process.env.NODE_ENV || '')) {
})); }));
// Delay // Delay
if (program.slow) { if (envOption.slow) {
app.use(slow({ app.use(slow({
delay: 3000 delay: 3000
})); }));

View file

@ -68,6 +68,7 @@ const nodeinfo2 = async () => {
disableRegistration: meta.disableRegistration, disableRegistration: meta.disableRegistration,
disableLocalTimeline: meta.disableLocalTimeline, disableLocalTimeline: meta.disableLocalTimeline,
disableGlobalTimeline: meta.disableGlobalTimeline, disableGlobalTimeline: meta.disableGlobalTimeline,
emailRequiredForSignup: meta.emailRequiredForSignup,
enableHcaptcha: meta.enableHcaptcha, enableHcaptcha: meta.enableHcaptcha,
enableRecaptcha: meta.enableRecaptcha, enableRecaptcha: meta.enableRecaptcha,
maxNoteTextLength: meta.maxNoteTextLength, maxNoteTextLength: meta.maxNoteTextLength,

View file

@ -2,7 +2,7 @@ import * as cluster from 'cluster';
import * as os from 'os'; import * as os from 'os';
import * as chalk from 'chalk'; import * as chalk from 'chalk';
import * as dateformat from 'dateformat'; import * as dateformat from 'dateformat';
import { program } from '../argv'; import { envOption } from '../env';
import { getRepository } from 'typeorm'; import { getRepository } from 'typeorm';
import { Log } from '@/models/entities/log'; import { Log } from '@/models/entities/log';
import { genId } from '@/misc/gen-id'; import { genId } from '@/misc/gen-id';
@ -52,7 +52,7 @@ export default class Logger {
} }
private log(level: Level, message: string, data?: Record<string, any> | null, important = false, subDomains: Domain[] = [], store = true): void { private log(level: Level, message: string, data?: Record<string, any> | null, important = false, subDomains: Domain[] = [], store = true): void {
if (program.quiet) return; if (envOption.quiet) return;
if (!this.store) store = false; if (!this.store) store = false;
if (level === 'debug') store = false; if (level === 'debug') store = false;
@ -80,7 +80,7 @@ export default class Logger {
null; null;
let log = `${l} ${worker}\t[${domains.join(' ')}]\t${m}`; let log = `${l} ${worker}\t[${domains.join(' ')}]\t${m}`;
if (program.withLogTime) log = chalk.gray(time) + ' ' + log; if (envOption.withLogTime) log = chalk.gray(time) + ' ' + log;
console.log(important ? chalk.bold(log) : log); console.log(important ? chalk.bold(log) : log);
@ -132,7 +132,7 @@ export default class Logger {
} }
public debug(message: string, data?: Record<string, any> | null, important = false): void { // デバッグ用に使う(開発者に必要だが利用者に不要な情報) public debug(message: string, data?: Record<string, any> | null, important = false): void { // デバッグ用に使う(開発者に必要だが利用者に不要な情報)
if (process.env.NODE_ENV != 'production' || program.verbose) { if (process.env.NODE_ENV != 'production' || envOption.verbose) {
this.log('debug', message, data, important); this.log('debug', message, data, important);
} }
} }

400
yarn.lock
View file

@ -447,10 +447,10 @@
"@types/connect" "*" "@types/connect" "*"
"@types/node" "*" "@types/node" "*"
"@types/bull@3.15.4": "@types/bull@3.15.5":
version "3.15.4" version "3.15.5"
resolved "https://registry.yarnpkg.com/@types/bull/-/bull-3.15.4.tgz#71390e83b6aa41a9106535240ad226c5239615f1" resolved "https://registry.yarnpkg.com/@types/bull/-/bull-3.15.5.tgz#a4459c127c5b10fb847531579a2cd5db35751366"
integrity sha512-vsw4kqsI/SLocfcgTUY2b8POTBUw9AwmTaehvSVnEAbcgJHsPheFMP8WKDFDk2I+aNTLRQX5iP21dPwz3CGLVA== integrity sha512-XgJQWJ03jyKMfdoL8IAIoHIo7JkkL74kcxuujTONkSJswm0giIJ9kuVgDNHS0OvD+OiPNcFmbBl0H3scj2+A8A==
dependencies: dependencies:
"@types/ioredis" "*" "@types/ioredis" "*"
@ -734,10 +734,10 @@
dependencies: dependencies:
"@types/koa" "*" "@types/koa" "*"
"@types/koa-logger@3.1.1": "@types/koa-logger@3.1.2":
version "3.1.1" version "3.1.2"
resolved "https://registry.yarnpkg.com/@types/koa-logger/-/koa-logger-3.1.1.tgz#bf759ba2f25b7562ffa30b09616bb1c1e5070fea" resolved "https://registry.yarnpkg.com/@types/koa-logger/-/koa-logger-3.1.2.tgz#91e890f405ddb0626bc385767e4cc0cd7226d1a8"
integrity sha512-wp2HaskkPugfwgXgNnc+idnReuJZSTTYQbkcxXjsMhp1kTc342PxDzTL9FXDgBfEvgt9NX1CCGjkwPKX2dlEKQ== integrity sha512-sioTA1xlKYiIgryANWPRHBkG3XGbWftw9slWADUPC+qvPIY/yRLSrhvX7zkJwMrntub5dPO0GuAoyGGf0yitfQ==
dependencies: dependencies:
"@types/koa" "*" "@types/koa" "*"
@ -816,14 +816,13 @@
resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-2.1.0.tgz#ea3dd64c4805597311790b61e872cbd1ed2cd806" resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-2.1.0.tgz#ea3dd64c4805597311790b61e872cbd1ed2cd806"
integrity sha512-Q7DYAOi9O/+cLLhdaSvKdaumWyHbm7HAk/bFwwyTuU0arR5yyCeW5GOoqt4tJTpDRxhpx9Q8kQL6vMpuw9hDSw== integrity sha512-Q7DYAOi9O/+cLLhdaSvKdaumWyHbm7HAk/bFwwyTuU0arR5yyCeW5GOoqt4tJTpDRxhpx9Q8kQL6vMpuw9hDSw==
"@types/markdown-it@12.2.1": "@types/markdown-it@12.2.3":
version "12.2.1" version "12.2.3"
resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-12.2.1.tgz#ca36e1edce6f15a770f3e99e68622d1d2e2f0c65" resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-12.2.3.tgz#0d6f6e5e413f8daaa26522904597be3d6cd93b51"
integrity sha512-iij+ilRX/vxtUPCREjn74xzHo/RorHJDwOsJ6X+TgKw7zSvazhVXnDfwlTnyLOMdiVUjtRYU4CrcUZ7Aci4PmQ== integrity sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==
dependencies: dependencies:
"@types/linkify-it" "*" "@types/linkify-it" "*"
"@types/mdurl" "*" "@types/mdurl" "*"
highlight.js "^10.7.2"
"@types/matter-js@0.17.5": "@types/matter-js@0.17.5":
version "0.17.5" version "0.17.5"
@ -863,10 +862,10 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.6.2.tgz#331b7b9f8621c638284787c5559423822fdffc50" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.6.2.tgz#331b7b9f8621c638284787c5559423822fdffc50"
integrity sha512-LSw8TZt12ZudbpHc6EkIyDM3nHVWKYrAvGy6EAJfNfjusbwnThqjqxUKKRwuV3iWYeW/LYMzNgaq3MaLffQ2xA== integrity sha512-LSw8TZt12ZudbpHc6EkIyDM3nHVWKYrAvGy6EAJfNfjusbwnThqjqxUKKRwuV3iWYeW/LYMzNgaq3MaLffQ2xA==
"@types/node@16.9.6": "@types/node@16.10.3":
version "16.9.6" version "16.10.3"
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.9.6.tgz#040a64d7faf9e5d9e940357125f0963012e66f04" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.10.3.tgz#7a8f2838603ea314d1d22bb3171d899e15c57bd5"
integrity sha512-YHUZhBOMTM3mjFkXVcK+WwAcYmyhe1wL4lfqNtzI0b3qAy7yuSetnM7QJazgE5PFmgVTNGiLOgRFfJMqW7XpSQ== integrity sha512-ho3Ruq+fFnBrZhUYI46n/bV2GjwzSkwuT4dTf0GkuNFmnb8nq4ny2z9JEVemFi6bdEJanHLlYfy9c6FN9B9McQ==
"@types/node@^14.11.8", "@types/node@^14.14.31", "@types/node@^14.14.41": "@types/node@^14.11.8", "@types/node@^14.14.31", "@types/node@^14.14.41":
version "14.17.9" version "14.17.9"
@ -880,11 +879,6 @@
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
"@types/normalize-package-data@^2.4.0":
version "2.4.0"
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==
"@types/nprogress@0.2.0": "@types/nprogress@0.2.0":
version "0.2.0" version "0.2.0"
resolved "https://registry.yarnpkg.com/@types/nprogress/-/nprogress-0.2.0.tgz#86c593682d4199212a0509cc3c4d562bbbd6e45f" resolved "https://registry.yarnpkg.com/@types/nprogress/-/nprogress-0.2.0.tgz#86c593682d4199212a0509cc3c4d562bbbd6e45f"
@ -1176,10 +1170,10 @@
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
"@types/ws@7.4.7": "@types/ws@8.2.0":
version "7.4.7" version "8.2.0"
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.2.0.tgz#75faefbe2328f3b833cb8dc640658328990d04f3"
integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== integrity sha512-cyeefcUCgJlEk+hk2h3N+MqKKsPViQgF5boi9TTHSK+PoR9KWBb/C5ccPcDyAqgsbAYHTwulch725DV84+pSpg==
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
@ -1195,48 +1189,48 @@
resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.2.tgz#808c9fa7e4517274ed555fa158f2de4b4f468e71" resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.2.tgz#808c9fa7e4517274ed555fa158f2de4b4f468e71"
integrity sha512-HrCIVMLjE1MOozVoD86622S7aunluLb2PJdPfb3nYiEtohm8mIB/vyv0Fd37AdeMFrTUQXEunw78YloMA3Qilg== integrity sha512-HrCIVMLjE1MOozVoD86622S7aunluLb2PJdPfb3nYiEtohm8mIB/vyv0Fd37AdeMFrTUQXEunw78YloMA3Qilg==
"@typescript-eslint/parser@4.31.2": "@typescript-eslint/parser@4.33.0":
version "4.31.2" version "4.33.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.31.2.tgz#54aa75986e3302d91eff2bbbaa6ecfa8084e9c34" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899"
integrity sha512-EcdO0E7M/sv23S/rLvenHkb58l3XhuSZzKf6DBvLgHqOYdL6YFMYVtreGFWirxaU2mS1GYDby3Lyxco7X5+Vjw== integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==
dependencies: dependencies:
"@typescript-eslint/scope-manager" "4.31.2" "@typescript-eslint/scope-manager" "4.33.0"
"@typescript-eslint/types" "4.31.2" "@typescript-eslint/types" "4.33.0"
"@typescript-eslint/typescript-estree" "4.31.2" "@typescript-eslint/typescript-estree" "4.33.0"
debug "^4.3.1" debug "^4.3.1"
"@typescript-eslint/scope-manager@4.31.2": "@typescript-eslint/scope-manager@4.33.0":
version "4.31.2" version "4.33.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.31.2.tgz#1d528cb3ed3bcd88019c20a57c18b897b073923a" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3"
integrity sha512-2JGwudpFoR/3Czq6mPpE8zBPYdHWFGL6lUNIGolbKQeSNv4EAiHaR5GVDQaLA0FwgcdcMtRk+SBJbFGL7+La5w== integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==
dependencies: dependencies:
"@typescript-eslint/types" "4.31.2" "@typescript-eslint/types" "4.33.0"
"@typescript-eslint/visitor-keys" "4.31.2" "@typescript-eslint/visitor-keys" "4.33.0"
"@typescript-eslint/types@4.31.2": "@typescript-eslint/types@4.33.0":
version "4.31.2" version "4.33.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.31.2.tgz#2aea7177d6d744521a168ed4668eddbd912dfadf" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72"
integrity sha512-kWiTTBCTKEdBGrZKwFvOlGNcAsKGJSBc8xLvSjSppFO88AqGxGNYtF36EuEYG6XZ9vT0xX8RNiHbQUKglbSi1w== integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==
"@typescript-eslint/typescript-estree@4.31.2": "@typescript-eslint/typescript-estree@4.33.0":
version "4.31.2" version "4.33.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.2.tgz#abfd50594d8056b37e7428df3b2d185ef2d0060c" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609"
integrity sha512-ieBq8U9at6PvaC7/Z6oe8D3czeW5d//Fo1xkF/s9394VR0bg/UaMYPdARiWyKX+lLEjY3w/FNZJxitMsiWv+wA== integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==
dependencies: dependencies:
"@typescript-eslint/types" "4.31.2" "@typescript-eslint/types" "4.33.0"
"@typescript-eslint/visitor-keys" "4.31.2" "@typescript-eslint/visitor-keys" "4.33.0"
debug "^4.3.1" debug "^4.3.1"
globby "^11.0.3" globby "^11.0.3"
is-glob "^4.0.1" is-glob "^4.0.1"
semver "^7.3.5" semver "^7.3.5"
tsutils "^3.21.0" tsutils "^3.21.0"
"@typescript-eslint/visitor-keys@4.31.2": "@typescript-eslint/visitor-keys@4.33.0":
version "4.31.2" version "4.33.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.2.tgz#7d5b4a4705db7fe59ecffb273c1d082760f635cc" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd"
integrity sha512-PrBId7EQq2Nibns7dd/ch6S6/M4/iwLM9McbgeEbCXfxdwRUNxJ4UNreJ6Gh3fI2GNKNrWnQxKL7oCPmngKBug== integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==
dependencies: dependencies:
"@typescript-eslint/types" "4.31.2" "@typescript-eslint/types" "4.33.0"
eslint-visitor-keys "^2.0.0" eslint-visitor-keys "^2.0.0"
"@ungap/promise-all-settled@1.1.2": "@ungap/promise-all-settled@1.1.2":
@ -1576,22 +1570,22 @@
"@webassemblyjs/ast" "1.11.1" "@webassemblyjs/ast" "1.11.1"
"@xtuc/long" "4.2.2" "@xtuc/long" "4.2.2"
"@webpack-cli/configtest@^1.0.4": "@webpack-cli/configtest@^1.1.0":
version "1.0.4" version "1.1.0"
resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.0.4.tgz#f03ce6311c0883a83d04569e2c03c6238316d2aa" resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.1.0.tgz#8342bef0badfb7dfd3b576f2574ab80c725be043"
integrity sha512-cs3XLy+UcxiP6bj0A6u7MLLuwdXJ1c3Dtc0RkKg+wiI1g/Ti1om8+/2hc2A2B60NbBNAbMgyBMHvyymWm/j4wQ== integrity sha512-ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg==
"@webpack-cli/info@^1.3.0": "@webpack-cli/info@^1.4.0":
version "1.3.0" version "1.4.0"
resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.3.0.tgz#9d78a31101a960997a4acd41ffd9b9300627fe2b" resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.4.0.tgz#b9179c3227ab09cbbb149aa733475fcf99430223"
integrity sha512-ASiVB3t9LOKHs5DyVUcxpraBXDOKubYu/ihHhU+t1UPpxsivg6Od2E2qU4gJCekfEddzRBzHhzA/Acyw/mlK/w== integrity sha512-F6b+Man0rwE4n0409FyAJHStYA5OIZERxmnUfLVwv0mc0V1wLad3V7jqRlMkgKBeAq07jUvglacNaa6g9lOpuw==
dependencies: dependencies:
envinfo "^7.7.3" envinfo "^7.7.3"
"@webpack-cli/serve@^1.5.2": "@webpack-cli/serve@^1.6.0":
version "1.5.2" version "1.6.0"
resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.5.2.tgz#ea584b637ff63c5a477f6f21604b5a205b72c9ec" resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.6.0.tgz#2c275aa05c895eccebbfc34cfb223c6e8bd591a2"
integrity sha512-vgJ5OLWadI8aKjDlOH3rb+dYyPd2GTZuQC/Tihjct6F9GpXGZINo3Y/IVuZVTM1eDQB+/AOsjPUWH/WySDaXvw== integrity sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA==
"@xtuc/ieee754@^1.2.0": "@xtuc/ieee754@^1.2.0":
version "1.2.0" version "1.2.0"
@ -2094,10 +2088,10 @@ autwh@0.1.0:
dependencies: dependencies:
oauth "0.9.15" oauth "0.9.15"
aws-sdk@2.992.0: aws-sdk@2.1003.0:
version "2.992.0" version "2.1003.0"
resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.992.0.tgz#3d8f663727cf3ea62a794a7499ae001fe6256abb" resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1003.0.tgz#f4ca218f466c524a90370b5604a3ad4cda4c0e08"
integrity sha512-FP/AOu1nxfaPJ6to05eHriBUzvPiNapEwy96sm5GNOL8/T38k9//H6UhxLJ/46CzxFMH/Mo/WFp0qwpS39ev5A== integrity sha512-UEZveI1m7+/YsomU2tVxLMmlo5g3sr3ue+QMJ2UwbrvHZ+O9hr9vVia1lD+L8fYTQenOff95NFc02h3pDE3iDA==
dependencies: dependencies:
buffer "4.9.2" buffer "4.9.2"
events "1.1.1" events "1.1.1"
@ -2503,10 +2497,10 @@ cache-content-type@^1.0.0:
mime-types "^2.1.18" mime-types "^2.1.18"
ylru "^1.2.0" ylru "^1.2.0"
cacheable-lookup@6.0.1: cacheable-lookup@6.0.2:
version "6.0.1" version "6.0.2"
resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-6.0.1.tgz#f32ab50c3212302d9f49aa094c8a7593c162af7c" resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-6.0.2.tgz#8df03d6239c91bb9f6394700d7ba4a100abbad67"
integrity sha512-vaccXt7hUfa5UzrtbdzHTWnL6V6ir39QtLuvGZys32j4HboAeiWVhrcdAm8ecTz1rLubxPhec2n22BBb5/dgVA== integrity sha512-9RJkUl1k/A1dFhaRfrEUdISvvou0WKx8LboMO0j1BpsqgAuolwZgwaEtn0dmFMk5HQxpFtHF1bHCnIQMywUpvw==
cacheable-lookup@^5.0.3: cacheable-lookup@^5.0.3:
version "5.0.3" version "5.0.3"
@ -2619,12 +2613,12 @@ cbor@*:
"@cto.af/textdecoder" "^0.0.0" "@cto.af/textdecoder" "^0.0.0"
nofilter "^2.0.3" nofilter "^2.0.3"
cbor@8.0.0: cbor@8.0.2:
version "8.0.0" version "8.0.2"
resolved "https://registry.yarnpkg.com/cbor/-/cbor-8.0.0.tgz#51657d26a99a6a1866f8c3258e948576eb17d709" resolved "https://registry.yarnpkg.com/cbor/-/cbor-8.0.2.tgz#d0f5088423437efcc160e9304bd0576f45d06abb"
integrity sha512-nMmaLWbj7+bC6MsApKRIig8h+yjgNLhPLXaCelq5+C7mpWsHgIcseZSdvgexSY5uE1Q3m2uPvIDZwSdxdo7qig== integrity sha512-H5WTjQYgyHQI0VrCmbyQBOPy1353MjmUi/r3DbPib4U13vuyqm7es9Mfpe8G58bN/mCdRlJWkiCrPl1uM1wAlg==
dependencies: dependencies:
nofilter "^3.0.2" nofilter "^3.0.3"
chalk@4.0.0: chalk@4.0.0:
version "4.0.0" version "4.0.0"
@ -3068,6 +3062,11 @@ colorette@^1.2.0, colorette@^1.2.1, colorette@^1.2.2:
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w== integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
colorette@^2.0.14:
version "2.0.15"
resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.15.tgz#8e634aa0429b110d24be82eac4d42f5ea65ab2d5"
integrity sha512-lIFQhufWaVvwi4wOlX9Gx5b0Nmw3XAZ8HzHNH9dfxhe+JaKNTmX6QLk4o7UHyI+tUY8ClvyfaHUm5bf61O3psA==
colormin@^1.0.5: colormin@^1.0.5:
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/colormin/-/colormin-1.1.2.tgz#ea2f7420a72b96881a38aae59ec124a6f7298133" resolved "https://registry.yarnpkg.com/colormin/-/colormin-1.1.2.tgz#ea2f7420a72b96881a38aae59ec124a6f7298133"
@ -3094,11 +3093,6 @@ combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
dependencies: dependencies:
delayed-stream "~1.0.0" delayed-stream "~1.0.0"
commander@8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-8.1.0.tgz#db36e3e66edf24ff591d639862c6ab2c52664362"
integrity sha512-mf45ldcuHSYShkplHHGKWb4TrmwQadxOn7v4WuhDJy0ZVoY5JFajaRDKD0PNe5qXzBX0rhovjTnP6Kz9LETcuA==
commander@^2.12.1, commander@^2.19.0, commander@^2.20.0: commander@^2.12.1, commander@^2.19.0, commander@^2.20.0:
version "2.20.3" version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
@ -3165,15 +3159,14 @@ concat-stream@^1.5.2, concat-stream@^1.6.0:
readable-stream "^2.2.2" readable-stream "^2.2.2"
typedarray "^0.0.6" typedarray "^0.0.6"
concurrently@6.2.1: concurrently@6.3.0:
version "6.2.1" version "6.3.0"
resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-6.2.1.tgz#d880fc1d77559084732fa514092a3d5109a0d5bf" resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-6.3.0.tgz#63128cb4a6ed54d3c0ed8528728590a5fe54582a"
integrity sha512-emgwhH+ezkuYKSHZQ+AkgEpoUZZlbpPVYCVv7YZx0r+T7fny1H03r2nYRebpi2DudHR4n1Rgbo2YTxKOxVJ4+g== integrity sha512-k4k1jQGHHKsfbqzkUszVf29qECBrkvBKkcPJEUDTyVR7tZd1G/JOfnst4g1sYbFvJ4UjHZisj1aWQR8yLKpGPw==
dependencies: dependencies:
chalk "^4.1.0" chalk "^4.1.0"
date-fns "^2.16.1" date-fns "^2.16.1"
lodash "^4.17.21" lodash "^4.17.21"
read-pkg "^5.2.0"
rxjs "^6.6.3" rxjs "^6.6.3"
spawn-command "^0.0.2-1" spawn-command "^0.0.2-1"
supports-color "^8.1.0" supports-color "^8.1.0"
@ -3558,10 +3551,10 @@ csstype@^2.6.8:
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.13.tgz#a6893015b90e84dd6e85d0e3b442a1e84f2dbe0f" resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.13.tgz#a6893015b90e84dd6e85d0e3b442a1e84f2dbe0f"
integrity sha512-ul26pfSQTZW8dcOnD2iiJssfXw0gdNVX9IJDH/X3K5DGPfj+fUYe3kB+swUY6BF3oZDxaID3AJt+9/ojSAE05A== integrity sha512-ul26pfSQTZW8dcOnD2iiJssfXw0gdNVX9IJDH/X3K5DGPfj+fUYe3kB+swUY6BF3oZDxaID3AJt+9/ojSAE05A==
cypress@8.4.1: cypress@8.5.0:
version "8.4.1" version "8.5.0"
resolved "https://registry.yarnpkg.com/cypress/-/cypress-8.4.1.tgz#8b5898bf49359cadc28f02ba05d51f63b8e3a717" resolved "https://registry.yarnpkg.com/cypress/-/cypress-8.5.0.tgz#5712ca170913f8344bf167301205c4217c1eb9bd"
integrity sha512-itJXq0Vx3sXCUrDyBi2IUrkxVu/gTTp1VhjB5tzGgkeCR8Ae+/T8WV63rsZ7fS8Tpq7LPPXiyoM/sEdOX7cR6A== integrity sha512-MMkXIS+Ro2KETn4gAlG3tIc/7FiljuuCZP0zpd9QsRG6MZSyZW/l1J3D4iQM6WHsVxuX4rFChn5jPFlC2tNSvQ==
dependencies: dependencies:
"@cypress/request" "^2.88.6" "@cypress/request" "^2.88.6"
"@cypress/xvfb" "^1.2.4" "@cypress/xvfb" "^1.2.4"
@ -3597,6 +3590,7 @@ cypress@8.4.1:
minimist "^1.2.5" minimist "^1.2.5"
ospath "^1.2.2" ospath "^1.2.2"
pretty-bytes "^5.6.0" pretty-bytes "^5.6.0"
proxy-from-env "1.0.0"
ramda "~0.27.1" ramda "~0.27.1"
request-progress "^3.0.0" request-progress "^3.0.0"
supports-color "^8.1.1" supports-color "^8.1.1"
@ -4268,10 +4262,10 @@ escodegen@^2.0.0:
optionalDependencies: optionalDependencies:
source-map "~0.6.1" source-map "~0.6.1"
eslint-plugin-vue@7.18.0: eslint-plugin-vue@7.19.1:
version "7.18.0" version "7.19.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-7.18.0.tgz#02a452142330c7f27c242db21a1b9e25238540f6" resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-7.19.1.tgz#435fb2ce712842a9530b28eacb883680e8eaa4f3"
integrity sha512-ceDXlXYMMPMSXw7tdKUR42w9jlzthJGJ3Kvm3YrZ0zuQfvAySNxe8sm6VHuksBW0+060GzYXhHJG6IHVOfF83Q== integrity sha512-e2pD7nW2sTY04ThH+66BgToNwC4n6dqfNhKE+ypdJFtZgn3Zn+nP8ZEIFPG0PGqCKQ3qxy8dJk1bzUsuQd3ANA==
dependencies: dependencies:
eslint-utils "^2.1.0" eslint-utils "^2.1.0"
natural-compare "^1.4.0" natural-compare "^1.4.0"
@ -5101,10 +5095,10 @@ glob@7.1.6, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
once "^1.3.0" once "^1.3.0"
path-is-absolute "^1.0.0" path-is-absolute "^1.0.0"
glob@7.1.7: glob@7.2.0:
version "7.1.7" version "7.2.0"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
dependencies: dependencies:
fs.realpath "^1.0.0" fs.realpath "^1.0.0"
inflight "^1.0.4" inflight "^1.0.4"
@ -5261,13 +5255,13 @@ gulp-replace@1.1.3:
replacestream "^4.0.3" replacestream "^4.0.3"
yargs-parser ">=5.0.0-security.0" yargs-parser ">=5.0.0-security.0"
gulp-terser@2.0.1: gulp-terser@2.1.0:
version "2.0.1" version "2.1.0"
resolved "https://registry.yarnpkg.com/gulp-terser/-/gulp-terser-2.0.1.tgz#5f8f4fc54588b79519243809cc8eef4936286d0d" resolved "https://registry.yarnpkg.com/gulp-terser/-/gulp-terser-2.1.0.tgz#149b693a1adbde922807b60b844bb7351dafbde1"
integrity sha512-XCrnCXP8ovNpgLK9McJIXlgm0j3W2TsiWu7K9y3m+Sn5XZgUzi6U8MPHtS3NdLMic9poCj695N0ARJ2B6atypw== integrity sha512-lQ3+JUdHDVISAlUIUSZ/G9Dz/rBQHxOiYDQ70IVWFQeh4b33TC1MCIU+K18w07PS3rq/CVc34aQO4SUbdaNMPQ==
dependencies: dependencies:
plugin-error "^1.0.1" plugin-error "^1.0.1"
terser "5.4.0" terser "^5.9.0"
through2 "^4.0.2" through2 "^4.0.2"
vinyl-sourcemaps-apply "^0.2.1" vinyl-sourcemaps-apply "^0.2.1"
@ -5408,11 +5402,6 @@ highlight.js@^10.7.1:
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.2.tgz#89319b861edc66c48854ed1e6da21ea89f847360" resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.2.tgz#89319b861edc66c48854ed1e6da21ea89f847360"
integrity sha512-oFLl873u4usRM9K63j4ME9u3etNF0PLiJhSQ8rdfuL51Wn3zkD6drf9ZW0dOzjnZI22YYG24z30JcmfCZjMgYg== integrity sha512-oFLl873u4usRM9K63j4ME9u3etNF0PLiJhSQ8rdfuL51Wn3zkD6drf9ZW0dOzjnZI22YYG24z30JcmfCZjMgYg==
highlight.js@^10.7.2:
version "10.7.3"
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531"
integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==
homedir-polyfill@^1.0.1: homedir-polyfill@^1.0.1:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8"
@ -6535,6 +6524,14 @@ koa-convert@^1.2.0:
co "^4.6.0" co "^4.6.0"
koa-compose "^3.0.0" koa-compose "^3.0.0"
koa-convert@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/koa-convert/-/koa-convert-2.0.0.tgz#86a0c44d81d40551bae22fee6709904573eea4f5"
integrity sha512-asOvN6bFlSnxewce2e/DK3p4tltyfC4VM7ZwuTuepI7dEQVcvpyFuBcEARu1+Hxg8DIwytce2n7jrZtRlPrARA==
dependencies:
co "^4.6.0"
koa-compose "^4.1.0"
koa-favicon@2.1.0: koa-favicon@2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/koa-favicon/-/koa-favicon-2.1.0.tgz#c430cc594614fb494adcb5ee1196a2f7f53ea442" resolved "https://registry.yarnpkg.com/koa-favicon/-/koa-favicon-2.1.0.tgz#c430cc594614fb494adcb5ee1196a2f7f53ea442"
@ -6627,6 +6624,35 @@ koa@2.13.1:
type-is "^1.6.16" type-is "^1.6.16"
vary "^1.1.2" vary "^1.1.2"
koa@2.13.3:
version "2.13.3"
resolved "https://registry.yarnpkg.com/koa/-/koa-2.13.3.tgz#a62641ba753ec54bee2c6da1a4f294c5fac35407"
integrity sha512-XhXIoR+ylAwqG3HhXwnMPQAM/4xfywz52OvxZNmxmTWGGHsvmBv4NSIhURha6yMuvEex1WdtplUTHnxnKpQiGw==
dependencies:
accepts "^1.3.5"
cache-content-type "^1.0.0"
content-disposition "~0.5.2"
content-type "^1.0.4"
cookies "~0.8.0"
debug "^4.3.2"
delegates "^1.0.0"
depd "^2.0.0"
destroy "^1.0.4"
encodeurl "^1.0.2"
escape-html "^1.0.3"
fresh "~0.5.2"
http-assert "^1.3.0"
http-errors "^1.6.3"
is-generator-function "^1.0.7"
koa-compose "^4.1.0"
koa-convert "^2.0.0"
on-finished "^2.3.0"
only "~0.0.2"
parseurl "^1.3.2"
statuses "^1.5.0"
type-is "^1.6.16"
vary "^1.1.2"
ky-universal@^0.8.2: ky-universal@^0.8.2:
version "0.8.2" version "0.8.2"
resolved "https://registry.yarnpkg.com/ky-universal/-/ky-universal-0.8.2.tgz#edc398d54cf495d7d6830aa1ab69559a3cc7f824" resolved "https://registry.yarnpkg.com/ky-universal/-/ky-universal-0.8.2.tgz#edc398d54cf495d7d6830aa1ab69559a3cc7f824"
@ -7116,10 +7142,10 @@ methods@^1.1.2:
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
mfm-js@0.19.0: mfm-js@0.20.0:
version "0.19.0" version "0.20.0"
resolved "https://registry.yarnpkg.com/mfm-js/-/mfm-js-0.19.0.tgz#77419fb54cb1bcfa49d931467903d6dc6c1815e1" resolved "https://registry.yarnpkg.com/mfm-js/-/mfm-js-0.20.0.tgz#3afdcd7959461fd825aa8af9b9e8a57cdbddc290"
integrity sha512-06uVz9v+ltO9Obt1vWpwfJZEyZloihYuoxud+Rt6R9PW4aUk2/zua8qUeMBDNQkKZ/+IRtRSmmgn2A2GiDSMEg== integrity sha512-1+3tV3nWUKQNh/ztX3wXu5iLBtdsg6q3wUhl+XyOhc2H3sQdG+sih/w2c0nR9TIawjN+Z1/pvgGzxMJHfmKQmA==
dependencies: dependencies:
twemoji-parser "13.1.x" twemoji-parser "13.1.x"
@ -7402,11 +7428,6 @@ nano-time@1.0.0:
dependencies: dependencies:
big-integer "^1.6.16" big-integer "^1.6.16"
nanocolors@^0.1.5:
version "0.1.6"
resolved "https://registry.yarnpkg.com/nanocolors/-/nanocolors-0.1.6.tgz#bc2350d3edfdbfadd7ac018c855ae7c13905a6ad"
integrity sha512-2pvTw6vYRaBLGir2xR7MxaJtyWkrn+C53EpW8yPotG+pdAwBvt0Xwk4VJ6VHLY0aLthVZPvDfm9TdZvrvAm5UQ==
nanoid@3.1.20, nanoid@^3.1.20: nanoid@3.1.20, nanoid@^3.1.20:
version "3.1.20" version "3.1.20"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788"
@ -7417,10 +7438,10 @@ nanoid@^3.1.23:
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81"
integrity sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw== integrity sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==
nanoid@^3.1.25: nanoid@^3.1.28:
version "3.1.25" version "3.1.29"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.29.tgz#214fb2d7a33e1a5bef4757b779dfaeb6a4e5aeb4"
integrity sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q== integrity sha512-dW2pUSGZ8ZnCFIlBIA31SV8huOGCHb6OwzVCc7A69rb/a+SgPBwfmLvK5TKQ3INPbRkcI8a/Owo0XbiTNH19wg==
nanomatch@^1.2.9: nanomatch@^1.2.9:
version "1.2.13" version "1.2.13"
@ -7539,10 +7560,10 @@ node-releases@^1.1.70, node-releases@^1.1.71:
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.71.tgz#cb1334b179896b1c89ecfdd4b725fb7bbdfc7dbb" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.71.tgz#cb1334b179896b1c89ecfdd4b725fb7bbdfc7dbb"
integrity sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg== integrity sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==
nodemailer@6.6.3: nodemailer@6.6.5:
version "6.6.3" version "6.6.5"
resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.6.3.tgz#31fb53dd4d8ae16fc088a65cb9ffa8d928a69b48" resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.6.5.tgz#f9f6953cee5cfe82cbea152eeddacf7a0442049a"
integrity sha512-faZFufgTMrphYoDjvyVpbpJcYzwyFnbAMmQtj1lVBYAUSm3SOy2fIdd9+Mr4UxPosBa0JRw9bJoIwQn+nswiew== integrity sha512-C/v856DBijUzHcHIgGpQoTrfsH3suKIRAGliIzCstatM2cAa+MYX3LuyCrABiO/cdJTxgBBHXxV1ztiqUwst5A==
nofilter@^2.0.3: nofilter@^2.0.3:
version "2.0.3" version "2.0.3"
@ -7551,7 +7572,7 @@ nofilter@^2.0.3:
dependencies: dependencies:
"@cto.af/textdecoder" "^0.0.0" "@cto.af/textdecoder" "^0.0.0"
nofilter@^3.0.2: nofilter@^3.0.3:
version "3.0.3" version "3.0.3"
resolved "https://registry.yarnpkg.com/nofilter/-/nofilter-3.0.3.tgz#3ff3b142efdccb403434ccae4a0c2c835cb9b522" resolved "https://registry.yarnpkg.com/nofilter/-/nofilter-3.0.3.tgz#3ff3b142efdccb403434ccae4a0c2c835cb9b522"
integrity sha512-TN/MCrQmXQk5DyUJ8TGUq1Il8rv4fTsjddLmMopV006QP8DMkglmGgYfQKD5620vXLRXfr8iGI6ZZ4/ZWld2cQ== integrity sha512-TN/MCrQmXQk5DyUJ8TGUq1Il8rv4fTsjddLmMopV006QP8DMkglmGgYfQKD5620vXLRXfr8iGI6ZZ4/ZWld2cQ==
@ -7571,7 +7592,7 @@ nopt@^5.0.0:
dependencies: dependencies:
abbrev "1" abbrev "1"
normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: normalize-package-data@^2.3.2:
version "2.5.0" version "2.5.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
@ -8196,6 +8217,11 @@ pgpass@1.x:
dependencies: dependencies:
split "^1.0.0" split "^1.0.0"
picocolors@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f"
integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==
picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.0.7, picomatch@^2.2.1: picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.0.7, picomatch@^2.2.1:
version "2.2.2" version "2.2.2"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
@ -8755,13 +8781,13 @@ postcss-zindex@^2.0.1:
postcss "^5.0.4" postcss "^5.0.4"
uniqs "^2.0.0" uniqs "^2.0.0"
postcss@8.3.7: postcss@8.3.9:
version "8.3.7" version "8.3.9"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.7.tgz#ec88563588c8da8e58e7226f7633b51ae221eeda" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.9.tgz#98754caa06c4ee9eb59cc48bd073bb6bd3437c31"
integrity sha512-9SaY7nnyQ63/WittqZYAvkkYPyKxchMKH71UDzeTmWuLSvxTRpeEeABZAzlCi55cuGcoFyoV/amX2BdsafQidQ== integrity sha512-f/ZFyAKh9Dnqytx5X62jgjhhzttjZS7hMsohcI7HEI5tjELX/HxCy3EFhsRxyzGvrzFF+82XPvCS8T9TFleVJw==
dependencies: dependencies:
nanocolors "^0.1.5" nanoid "^3.1.28"
nanoid "^3.1.25" picocolors "^0.2.1"
source-map-js "^0.6.2" source-map-js "^0.6.2"
postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.8, postcss@^5.2.16: postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.8, postcss@^5.2.16:
@ -8951,6 +8977,11 @@ proto-list@~1.2.1:
resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=
proxy-from-env@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee"
integrity sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=
ps-tree@1.2.0: ps-tree@1.2.0:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.2.0.tgz#5e7425b89508736cdd4f2224d028f7bb3f722ebd" resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.2.0.tgz#5e7425b89508736cdd4f2224d028f7bb3f722ebd"
@ -9248,16 +9279,6 @@ read-pkg@^1.0.0:
normalize-package-data "^2.3.2" normalize-package-data "^2.3.2"
path-type "^1.0.0" path-type "^1.0.0"
read-pkg@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc"
integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==
dependencies:
"@types/normalize-package-data" "^2.4.0"
normalize-package-data "^2.5.0"
parse-json "^5.0.0"
type-fest "^0.6.0"
readable-stream@1.1.x: readable-stream@1.1.x:
version "1.1.14" version "1.1.14"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
@ -10046,6 +10067,14 @@ source-map-support@~0.5.19:
buffer-from "^1.0.0" buffer-from "^1.0.0"
source-map "^0.6.0" source-map "^0.6.0"
source-map-support@~0.5.20:
version "0.5.20"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9"
integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
source-map-url@^0.4.0: source-map-url@^0.4.0:
version "0.4.0" version "0.4.0"
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
@ -10591,10 +10620,10 @@ syslog-pro@1.0.0:
dependencies: dependencies:
moment "^2.22.2" moment "^2.22.2"
systeminformation@5.9.3: systeminformation@5.9.4:
version "5.9.3" version "5.9.4"
resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.9.3.tgz#d247c3fc27dc51787af28f0b4a0d82f9bce7f88b" resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.9.4.tgz#1f0e29e0aa376dec8f69cc517eeefc5cdcda411a"
integrity sha512-FmifqCPDU5uJZeORt1jCiATBTHwpX7luDzeFo8lojYbEiJk6oR3mtAZBOayCo3iEmgSILzmbcO855OXPHCeU+g== integrity sha512-FOsiTn0CyJZoj9kIhla11ndsMzbbwwuriul81wpqIBt9IpbxHZ6P/oZCphIFgJrwqjTnme0Qp1HDzIkUD9Xr/g==
syuilo-password-strength@0.0.1: syuilo-password-strength@0.0.1:
version "0.0.1" version "0.0.1"
@ -10708,15 +10737,6 @@ terser-webpack-plugin@^5.1.3:
source-map "^0.6.1" source-map "^0.6.1"
terser "^5.7.0" terser "^5.7.0"
terser@5.4.0:
version "5.4.0"
resolved "https://registry.yarnpkg.com/terser/-/terser-5.4.0.tgz#9815c0839072d5c894e22c6fc508fbe9f5e7d7e8"
integrity sha512-3dZunFLbCJis9TAF2VnX+VrQLctRUmt1p3W2kCsJuZE4ZgWqh//+1MZ62EanewrqKoUf4zIaDGZAvml4UDc0OQ==
dependencies:
commander "^2.20.0"
source-map "~0.7.2"
source-map-support "~0.5.19"
terser@^5.5.1: terser@^5.5.1:
version "5.5.1" version "5.5.1"
resolved "https://registry.yarnpkg.com/terser/-/terser-5.5.1.tgz#540caa25139d6f496fdea056e414284886fb2289" resolved "https://registry.yarnpkg.com/terser/-/terser-5.5.1.tgz#540caa25139d6f496fdea056e414284886fb2289"
@ -10735,6 +10755,15 @@ terser@^5.7.0:
source-map "~0.7.2" source-map "~0.7.2"
source-map-support "~0.5.19" source-map-support "~0.5.19"
terser@^5.9.0:
version "5.9.0"
resolved "https://registry.yarnpkg.com/terser/-/terser-5.9.0.tgz#47d6e629a522963240f2b55fcaa3c99083d2c351"
integrity sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ==
dependencies:
commander "^2.20.0"
source-map "~0.7.2"
source-map-support "~0.5.20"
text-table@^0.2.0: text-table@^0.2.0:
version "0.2.0" version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
@ -10961,10 +10990,10 @@ ts-node@10.2.1:
make-error "^1.1.1" make-error "^1.1.1"
yn "3.1.1" yn "3.1.1"
tsc-alias@1.3.9: tsc-alias@1.3.10:
version "1.3.9" version "1.3.10"
resolved "https://registry.yarnpkg.com/tsc-alias/-/tsc-alias-1.3.9.tgz#0c9d1dd571c0a97af8159d20e7cd4ce6aaab1799" resolved "https://registry.yarnpkg.com/tsc-alias/-/tsc-alias-1.3.10.tgz#6ccf81c644092387ab9be3a3a75549a95eeffd80"
integrity sha512-PXNsdsuygWpvQrt41D7CBndJyZ+8Juf2BDvQ1OJNqq0QsMR4i+A4rfniY/NVwb70gW4nMDJBvNxxvzLJjakXtQ== integrity sha512-7SF56qiV7Oh/bON+XjF/uAzEFqbmwCuEIHQyoTyVJAK80WnxaIyhO9TBwD/x8InIMU8lnvExQBOrgKkRPsHH+w==
dependencies: dependencies:
"@jfonx/console-utils" "^1.0.3" "@jfonx/console-utils" "^1.0.3"
"@jfonx/file-utils" "^3.0.1" "@jfonx/file-utils" "^3.0.1"
@ -11100,11 +11129,6 @@ type-fest@^0.21.3:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
type-fest@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b"
integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==
type-is@^1.6.14, type-is@^1.6.16, type-is@^1.6.4: type-is@^1.6.14, type-is@^1.6.16, type-is@^1.6.4:
version "1.6.18" version "1.6.18"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
@ -11140,10 +11164,10 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
typeorm@0.2.37: typeorm@0.2.38:
version "0.2.37" version "0.2.38"
resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.37.tgz#1a5e59216077640694d27c04c99ed3f968d15dc8" resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.38.tgz#2af08079919f6ab04cd17017f9faa2c8d5cd566f"
integrity sha512-7rkW0yCgFC24I5T0f3S/twmLSuccPh1SQmxET/oDWn2sSDVzbyWdnItSdKy27CdJGTlKHYtUVeOcMYw5LRsXVw== integrity sha512-M6Y3KQcAREQcphOVJciywf4mv6+A0I/SeR+lWNjKsjnQ+a3XcMwGYMGL0Jonsx3H0Cqlf/3yYqVki1jIXSK/xg==
dependencies: dependencies:
"@sqltools/formatter" "^1.2.2" "@sqltools/formatter" "^1.2.2"
app-root-path "^3.0.0" app-root-path "^3.0.0"
@ -11615,16 +11639,16 @@ webidl-conversions@^6.1.0:
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514"
integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==
webpack-cli@4.8.0: webpack-cli@4.9.0:
version "4.8.0" version "4.9.0"
resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.8.0.tgz#5fc3c8b9401d3c8a43e2afceacfa8261962338d1" resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.9.0.tgz#dc43e6e0f80dd52e89cbf73d5294bcd7ad6eb343"
integrity sha512-+iBSWsX16uVna5aAYN6/wjhJy1q/GKk4KjKvfg90/6hykCTSgozbfz5iRgDTSJt/LgSbYxdBX3KBHeobIs+ZEw== integrity sha512-n/jZZBMzVEl4PYIBs+auy2WI0WTQ74EnJDiyD98O2JZY6IVIHJNitkYp/uTXOviIOMfgzrNvC9foKv/8o8KSZw==
dependencies: dependencies:
"@discoveryjs/json-ext" "^0.5.0" "@discoveryjs/json-ext" "^0.5.0"
"@webpack-cli/configtest" "^1.0.4" "@webpack-cli/configtest" "^1.1.0"
"@webpack-cli/info" "^1.3.0" "@webpack-cli/info" "^1.4.0"
"@webpack-cli/serve" "^1.5.2" "@webpack-cli/serve" "^1.6.0"
colorette "^1.2.1" colorette "^2.0.14"
commander "^7.0.0" commander "^7.0.0"
execa "^5.0.0" execa "^5.0.0"
fastest-levenshtein "^1.0.12" fastest-levenshtein "^1.0.12"
@ -11655,10 +11679,10 @@ webpack-sources@^3.2.0:
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.0.tgz#b16973bcf844ebcdb3afde32eda1c04d0b90f89d" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.0.tgz#b16973bcf844ebcdb3afde32eda1c04d0b90f89d"
integrity sha512-fahN08Et7P9trej8xz/Z7eRu8ltyiygEo/hnRi9KqBUs80KeDcnf96ZJo++ewWd84fEf3xSX9bp4ZS9hbw0OBw== integrity sha512-fahN08Et7P9trej8xz/Z7eRu8ltyiygEo/hnRi9KqBUs80KeDcnf96ZJo++ewWd84fEf3xSX9bp4ZS9hbw0OBw==
webpack@5.54.0: webpack@5.58.0:
version "5.54.0" version "5.58.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.54.0.tgz#629f0cd14c7a4340af758a3c7cef25c50670ae4d" resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.58.0.tgz#9ec621cf8534f23c25e779e7c35dfde1211d5ccb"
integrity sha512-MAVKJMsIUotOQKzFOmN8ZkmMlj7BOyjDU6t1lomW9dWOme5WTStzGa3HMLdV1KYD1AiFETGsznL4LMSvj4tukw== integrity sha512-xc2k5MLbR1iah24Z5xUm1nBh1PZXEdUnrX6YkTSOScq/VWbl5JCLREXJzGYqEAUbIO8tZI+Dzv82lGtnuUnVCQ==
dependencies: dependencies:
"@types/eslint-scope" "^3.7.0" "@types/eslint-scope" "^3.7.0"
"@types/estree" "^0.0.50" "@types/estree" "^0.0.50"
@ -11857,10 +11881,10 @@ wrappy@1:
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
ws@8.2.2: ws@8.2.3:
version "8.2.2" version "8.2.3"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.2.tgz#ca684330c6dd6076a737250ed81ac1606cb0a63e" resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba"
integrity sha512-Q6B6H2oc8QY3llc3cB8kVmQ6pnJWVQbP7Q5algTcIxx7YEpc0oU4NBVHlztA7Ekzfhw2r0rPducMUiCGWKQRzw== integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==
ws@^7.4.6: ws@^7.4.6:
version "7.5.3" version "7.5.3"