Merge remote-tracking branch 'misskey-original/develop' into develop

# Conflicts:
#	locales/index.d.ts
#	locales/ja-JP.yml
#	package.json
#	packages/frontend/src/pages/about.vue
#	packages/frontend/src/scripts/get-note-menu.ts
This commit is contained in:
mattyatea 2024-02-17 13:45:01 +09:00
commit 69c16f036c
34 changed files with 555 additions and 91 deletions

View File

@ -2,6 +2,63 @@
# Misskey configuration
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# ┌──────────────────────────────┐
#───┘ a boring but important thing └────────────────────────────
#
# First of all, let me tell you a story that may possibly be
# boring to you and possibly important to you.
#
# Misskey is licensed under the AGPLv3 license. This license is
# known to be often misunderstood. Please read the following
# instructions carefully and select the appropriate option so
# that you do not negligently cause a license violation.
#
# --------
# Option 1: If you host Misskey AS-IS (without any changes to
# the source code. forks are not included).
#
# Step 1: Congratulations! You don't need to do anything.
# --------
# Option 2: If you have made changes to the source code (forks
# are included) and publish a Git repository of source
# code. There should be no access restrictions on
# this repository. Strictly speaking, it doesn't have
# to be a Git repository, but you'll probably use Git!
#
# Step 1: Build and run the Misskey server first.
# Step 2: Open <https://your.misskey.example/admin/settings> in
# your browser with the administrator account.
# Step 3: Enter the URL of your Git repository in the
# "Repository URL" field.
# --------
# Option 3: If neither of the above applies to you.
# (In this case, the source code should be published
# on the Misskey interface. IT IS NOT ENOUGH TO
# DISCLOSE THE SOURCE CODE WEHN A USER REQUESTS IT BY
# E-MAIL OR OTHER MEANS. If you are not satisfied
# with this, it is recommended that you read the
# license again carefully. Anyway, enabling this
# option will automatically generate and publish a
# tarball at build time, protecting you from
# inadvertent license violations. (There is no legal
# guarantee, of course.) The tarball will generated
# from the root directory of your codebase. So it is
# also recommended to check <built/tarball> directory
# once after building and before activating the server
# to avoid ACCIDENTAL LEAKING OF SENSITIVE INFORMATION.
# To prevent certain files from being included in the
# tarball, add a glob pattern after line 15 in
# <scripts/tarball.mjs>. DO NOT FORGET TO BUILD AFTER
# ENABLING THIS OPTION!)
#
# Step 1: Uncomment the following line.
#
# publishTarballInsteadOfProvideRepositoryUrl: true
# ┌─────┐
#───┘ URL └─────────────────────────────────────────────────────

View File

@ -12,14 +12,17 @@
-->
## 202x.x.x (Unreleased)
## 2024.2.0
### Note
- 外部サイトからプラグインをインストールする場合のパスが`/install-extentions`から`/install-extensions`に変わります。現時点では以前のパスも利用できますが、非推奨です。
- 外部サイトからプラグインをインストールする場合のパスが`/install-extentions`から`/install-extensions`に変わります。以前のパスからは自動でリダイレクトされるようになっていますが、新しいパスに変更することをお勧めします。
### General
- Feat: [mCaptcha](https://github.com/mCaptcha/mCaptcha)のサポートを追加
- Feat: Add support for TrueMail
- Feat: AGPLv3ライセンスに誤って違反するのを防止する機能を追加
- 管理者がrepositoryUrlを変更したり、またはソースコードを直接頒布することを選択できるようになります
- 本体のソースコードに改変を加えた際に、ライセンスに基づく適切な案内を表示します
- Enhance: モデレーターはすべてのユーザーのリアクション一覧を見られるように
- Fix: リストライムラインの「リノートを表示」が正しく機能しない問題を修正
- Fix: リモートユーザーのリアクション一覧がすべて見えてしまうのを修正
@ -58,6 +61,8 @@
- センシティブなリアクションを認めていないユーザーにセンシティブなカスタム絵文字をリアクションしようとした場合
- ロールが必要な絵文字をリアクションしようとした場合
- Enhance: ページ遷移時にPlayerを閉じるように
- Enhance: ノートの通報時にリモートのノートであっても自インスタンスにおけるノートのリンクを含むように
- Enhance: オフライン表示のデザインを改善・多言語対応
- Fix: ネイティブモードの絵文字がモノクロにならないように
- Fix: v2023.12.0で追加された「モデレーターがユーザーのアイコンもしくはバナー画像を未設定状態にできる機能」が管理画面上で正しく表示されていない問題を修正
- Fix: AiScriptの`readline`関数が不正な値を返すことがある問題のv2023.12.0時点での修正がPlay以外に適用されていないのを修正
@ -94,9 +99,6 @@
- Fix: コントロールパネル->モデレーション->「誰でも新規登録できるようにする」の初期値をONからOFFに変更 #13122
- Fix: リモートユーザーが復活してもキャッシュにより該当ユーザーのActivityが受け入れられないのを修正 #13273
### Service Worker
- Enhance: オフライン表示のデザインを改善・多言語対応
## 2023.12.2
### General

40
locales/index.d.ts vendored
View File

@ -4176,6 +4176,10 @@ export interface Locale extends ILocale {
* Misskeyは{host}使
*/
"pleaseDonate": ParameterizedString<"host">;
/**
* {anchor}
*/
"correspondingSourceIsAvailable": ParameterizedString<"anchor">;
/**
*
*/
@ -4912,6 +4916,34 @@ export interface Locale extends ILocale {
*
*/
"externalServices": string;
/**
*
*/
"sourceCode": string;
/**
*
*/
"sourceCodeIsNotYetProvided": string;
/**
* URL
*/
"repositoryUrl": string;
/**
* URLを記入しますMisskeyを現状のまま使 https://github.com/misskey-dev/misskey と記入します。
*/
"repositoryUrlDescription": string;
/**
* tarballを提供する必要があります.config/example.ymlを参照してください
*/
"repositoryUrlOrTarballRequired": string;
/**
*
*/
"feedback": string;
/**
* URL
*/
"feedbackUrl": string;
/**
*
*/
@ -7065,6 +7097,14 @@ export interface Locale extends ILocale {
*
*/
"source": string;
/**
*
*/
"original": string;
/**
* {name}Misskeyを改変したバージョンを使用しています
*/
"thisIsModifiedVersion": ParameterizedString<"name">;
/**
*
*/

View File

@ -1040,6 +1040,7 @@ neverShow: "今後表示しない"
remindMeLater: "また後で"
didYouLikeMisskey: "Misskeyを気に入っていただけましたか"
pleaseDonate: "Misskeyは{host}が使用している無料のソフトウェアです。これからも開発を続けられるように、ぜひ寄付をお願いします!"
correspondingSourceIsAvailable: "対応するソースコードは{anchor}から利用可能です。"
roles: "ロール"
role: "ロール"
noRole: "ロールはありません"
@ -1224,6 +1225,13 @@ hideRepliesToOthersInTimelineAll: "TLに現在フォロー中の人全員の返
confirmShowRepliesAll: "この操作は元に戻せません。本当にTLに現在フォロー中の人全員の返信を含めるようにしますか"
confirmHideRepliesAll: "この操作は元に戻せません。本当にTLに現在フォロー中の人全員の返信を含めないようにしますか"
externalServices: "外部サービス"
sourceCode: "ソースコード"
sourceCodeIsNotYetProvided: "ソースコードはまだ提供されていません。この問題の修正について管理者に問い合わせてください。"
repositoryUrl: "リポジトリURL"
repositoryUrlDescription: "ソースコードが公開されているリポジトリがある場合、そのURLを記入します。Misskeyを現状のままソースコードにいかなる変更も加えずに使用している場合は https://github.com/misskey-dev/misskey と記入します。"
repositoryUrlOrTarballRequired: "リポジトリを公開していない場合、代わりにtarballを提供する必要があります。詳細は.config/example.ymlを参照してください。"
feedback: "フィードバック"
feedbackUrl: "フィードバックURL"
impressum: "運営者情報"
impressumUrl: "運営者情報URL"
impressumDescription: "ドイツなどの一部の国と地域では表示が義務付けられています(Impressum)。"
@ -1841,6 +1849,8 @@ _aboutMisskey:
contributors: "コントリビューター"
allContributors: "全てのコントリビューター"
source: "ソースコード"
original: "オリジナル"
thisIsModifiedVersion: "{name}はオリジナルのMisskeyを改変したバージョンを使用しています。"
forksource: "当フォークのソースコード"
translation: "Misskeyを翻訳"
donate: "Misskeyに寄付"

View File

@ -1,6 +1,6 @@
{
"name": "misskey",
"version": "2024.2.0-beta.12-PrisMisskey.1",
"version": "2024.2.0-PrisMisskey.1",
"codename": "nasubi",
"repository": {
"type": "git",

View File

@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class MakeRepositoryUrlNullable1707808106310 {
name = 'MakeRepositoryUrlNullable1707808106310'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "repositoryUrl" DROP NOT NULL`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "repositoryUrl" SET NOT NULL`);
}
}

View File

@ -186,13 +186,12 @@
"@jest/globals": "29.7.0",
"@misskey-dev/eslint-plugin": "1.0.0",
"@nestjs/platform-express": "10.3.1",
"@simplewebauthn/typescript-types": "8.3.4",
"@simplewebauthn/types": "9.0.1",
"@swc/jest": "0.2.31",
"@types/accepts": "1.3.7",
"@types/archiver": "6.0.2",
"@types/bcryptjs": "2.4.6",
"@types/body-parser": "1.19.5",
"@types/cbor": "6.0.0",
"@types/color-convert": "2.0.3",
"@types/content-disposition": "0.5.8",
"@types/fluent-ffmpeg": "2.1.24",
@ -219,7 +218,6 @@
"@types/rename": "1.0.7",
"@types/sanitize-html": "2.9.5",
"@types/semver": "7.5.6",
"@types/sharp": "0.32.0",
"@types/simple-oauth2": "5.0.7",
"@types/sinonjs__fake-timers": "8.1.5",
"@types/tinycolor2": "1.4.6",

View File

@ -57,6 +57,8 @@ type Source = {
scope?: 'local' | 'global' | string[];
};
publishTarballInsteadOfProvideRepositoryUrl?: boolean;
proxy?: string;
proxySmtp?: string;
proxyBypassHosts?: string[];
@ -145,6 +147,7 @@ export type Config = {
signToActivityPubGet: boolean | undefined;
version: string;
publishTarballInsteadOfProvideRepositoryUrl: boolean;
host: string;
hostname: string;
scheme: string;
@ -209,6 +212,7 @@ export function loadConfig(): Config {
return {
version,
publishTarballInsteadOfProvideRepositoryUrl: !!config.publishTarballInsteadOfProvideRepositoryUrl,
url: url.origin,
port: config.port ?? parseInt(process.env.PORT ?? '', 10),
socket: config.socket,

View File

@ -14,9 +14,16 @@ import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
import { StatusError } from '@/misc/status-error.js';
import { bindThis } from '@/decorators.js';
import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js';
import type { IObject } from '@/core/activitypub/type.js';
import type { Response } from 'node-fetch';
import type { URL } from 'node:url';
export type HttpRequestSendOptions = {
throwErrorWhenResponseNotOk: boolean;
validators?: ((res: Response) => void)[];
};
@Injectable()
export class HttpRequestService {
/**
@ -104,6 +111,23 @@ export class HttpRequestService {
}
}
@bindThis
public async getActivityJson(url: string): Promise<IObject> {
const res = await this.send(url, {
method: 'GET',
headers: {
Accept: 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
},
timeout: 5000,
size: 1024 * 256,
}, {
throwErrorWhenResponseNotOk: true,
validators: [validateContentTypeSetAsActivityPub],
});
return await res.json() as IObject;
}
@bindThis
public async getJson<T = unknown>(url: string, accept = 'application/json, */*', headers?: Record<string, string>): Promise<T> {
const res = await this.send(url, {
@ -132,17 +156,20 @@ export class HttpRequestService {
}
@bindThis
public async send(url: string, args: {
public async send(
url: string,
args: {
method?: string,
body?: string,
headers?: Record<string, string>,
timeout?: number,
size?: number,
} = {}, extra: {
throwErrorWhenResponseNotOk: boolean;
} = {
} = {},
extra: HttpRequestSendOptions = {
throwErrorWhenResponseNotOk: true,
}): Promise<Response> {
validators: [],
},
): Promise<Response> {
const timeout = args.timeout ?? 5000;
const controller = new AbortController();
@ -166,6 +193,12 @@ export class HttpRequestService {
throw new StatusError(`${res.status} ${res.statusText}`, res.status, res.statusText);
}
if (res.ok) {
for (const validator of (extra.validators ?? [])) {
validator(res);
}
}
return res;
}
}

View File

@ -26,7 +26,7 @@ import type {
PublicKeyCredentialDescriptorFuture,
PublicKeyCredentialRequestOptionsJSON,
RegistrationResponseJSON,
} from '@simplewebauthn/typescript-types';
} from '@simplewebauthn/types';
@Injectable()
export class WebAuthnService {

View File

@ -14,6 +14,7 @@ import { HttpRequestService } from '@/core/HttpRequestService.js';
import { LoggerService } from '@/core/LoggerService.js';
import { bindThis } from '@/decorators.js';
import type Logger from '@/logger.js';
import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js';
type Request = {
url: string;
@ -70,7 +71,7 @@ export class ApRequestCreator {
url: u.href,
method: 'GET',
headers: this.#objectAssignWithLcKey({
'Accept': 'application/activity+json, application/ld+json',
'Accept': 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
'Date': new Date().toUTCString(),
'Host': new URL(args.url).host,
}, args.additionalHeaders),
@ -195,6 +196,9 @@ export class ApRequestService {
const res = await this.httpRequestService.send(url, {
method: req.request.method,
headers: req.request.headers,
}, {
throwErrorWhenResponseNotOk: true,
validators: [validateContentTypeSetAsActivityPub],
});
return await res.json();

View File

@ -105,7 +105,7 @@ export class Resolver {
const object = (this.user
? await this.apRequestService.signedGet(value, this.user) as IObject
: await this.httpRequestService.getJson(value, 'application/activity+json, application/ld+json')) as IObject;
: await this.httpRequestService.getActivityJson(value)) as IObject;
if (
Array.isArray(object['@context']) ?

View File

@ -8,6 +8,7 @@ import { Injectable } from '@nestjs/common';
import { HttpRequestService } from '@/core/HttpRequestService.js';
import { bindThis } from '@/decorators.js';
import { CONTEXTS } from './misc/contexts.js';
import { validateContentTypeSetAsJsonLD } from './misc/validator.js';
import type { JsonLdDocument } from 'jsonld';
import type { JsonLd, RemoteDocument } from 'jsonld/jsonld-spec.js';
@ -133,7 +134,10 @@ class LdSignature {
},
timeout: this.loderTimeout,
},
{ throwErrorWhenResponseNotOk: false },
{
throwErrorWhenResponseNotOk: false,
validators: [validateContentTypeSetAsJsonLD],
},
).then(res => {
if (!res.ok) {
throw new Error(`${res.status} ${res.statusText}`);

View File

@ -0,0 +1,39 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { Response } from 'node-fetch';
export function validateContentTypeSetAsActivityPub(response: Response): void {
const contentType = (response.headers.get('content-type') ?? '').toLowerCase();
if (contentType === '') {
throw new Error('Validate content type of AP response: No content-type header');
}
if (
contentType.startsWith('application/activity+json') ||
(contentType.startsWith('application/ld+json;') && contentType.includes('https://www.w3.org/ns/activitystreams'))
) {
return;
}
throw new Error('Validate content type of AP response: Content type is not application/activity+json or application/ld+json');
}
const plusJsonSuffixRegex = /(application|text)\/[a-zA-Z0-9\.\-\+]+\+json/;
export function validateContentTypeSetAsJsonLD(response: Response): void {
const contentType = (response.headers.get('content-type') ?? '').toLowerCase();
if (contentType === '') {
throw new Error('Validate content type of JSON LD: No content-type header');
}
if (
contentType.startsWith('application/ld+json') ||
contentType.startsWith('application/json') ||
plusJsonSuffixRegex.test(contentType)
) {
return;
}
throw new Error('Validate content type of JSON LD: Content type is not application/ld+json or application/json');
}

View File

@ -379,9 +379,9 @@ export class MiMeta {
@Column('varchar', {
length: 1024,
default: 'https://github.com/misskey-dev/misskey',
nullable: false,
nullable: true,
})
public repositoryUrl: string;
public repositoryUrl: string | null;
@Column('varchar', {
length: 1024,

View File

@ -22,7 +22,7 @@ import { WebAuthnService } from '@/core/WebAuthnService.js';
import { UserAuthService } from '@/core/UserAuthService.js';
import { RateLimiterService } from './RateLimiterService.js';
import { SigninService } from './SigninService.js';
import type { AuthenticationResponseJSON } from '@simplewebauthn/typescript-types';
import type { AuthenticationResponseJSON } from '@simplewebauthn/types';
import type { FastifyReply, FastifyRequest } from 'fastify';
@Injectable()

View File

@ -429,7 +429,7 @@ export const meta = {
},
repositoryUrl: {
type: 'string',
optional: false, nullable: false,
optional: false, nullable: true,
},
summalyProxy: {
type: 'string',

View File

@ -106,8 +106,8 @@ export const paramDef = {
swPublicKey: { type: 'string', nullable: true },
swPrivateKey: { type: 'string', nullable: true },
tosUrl: { type: 'string', nullable: true },
repositoryUrl: { type: 'string' },
feedbackUrl: { type: 'string' },
repositoryUrl: { type: 'string', nullable: true },
feedbackUrl: { type: 'string', nullable: true },
impressumUrl: { type: 'string', nullable: true },
privacyPolicyUrl: { type: 'string', nullable: true },
useObjectStorage: { type: 'boolean' },
@ -440,7 +440,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
}
if (ps.repositoryUrl !== undefined) {
set.repositoryUrl = ps.repositoryUrl;
set.repositoryUrl = URL.canParse(ps.repositoryUrl!) ? ps.repositoryUrl : null;
}
if (ps.feedbackUrl !== undefined) {

View File

@ -37,6 +37,10 @@ export const meta = {
type: 'string',
optional: false, nullable: false,
},
providesTarball: {
type: 'boolean',
optional: false, nullable: false,
},
name: {
type: 'string',
optional: false, nullable: false,
@ -69,12 +73,12 @@ export const meta = {
},
repositoryUrl: {
type: 'string',
optional: false, nullable: false,
optional: false, nullable: true,
default: 'https://github.com/misskey-dev/misskey',
},
feedbackUrl: {
type: 'string',
optional: false, nullable: false,
optional: false, nullable: true,
default: 'https://github.com/misskey-dev/misskey/issues/new',
},
defaultDarkTheme: {
@ -352,6 +356,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
maintainerEmail: instance.maintainerEmail,
version: this.config.version,
providesTarball: this.config.publishTarballInsteadOfProvideRepositoryUrl,
name: instance.name,
shortName: instance.shortName,

View File

@ -18,7 +18,7 @@ import type {
PublicKeyCredentialCreationOptionsJSON,
PublicKeyCredentialRequestOptionsJSON,
RegistrationResponseJSON,
} from '@simplewebauthn/typescript-types';
} from '@simplewebauthn/types';
import type * as misskey from 'misskey-js';
describe('2要素認証', () => {

View File

@ -0,0 +1,40 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
process.env.NODE_ENV = 'test';
import { validateContentTypeSetAsActivityPub, validateContentTypeSetAsJsonLD } from '@/core/activitypub/misc/validator.js';
import { signup, uploadFile, relativeFetch } from '../utils.js';
import type * as misskey from 'misskey-js';
describe('validateContentTypeSetAsActivityPub/JsonLD (deny case)', () => {
let alice: misskey.entities.SignupResponse;
let aliceUploadedFile: any;
beforeAll(async () => {
alice = await signup({ username: 'alice' });
aliceUploadedFile = await uploadFile(alice);
}, 1000 * 60 * 2);
test('ActivityStreams: ファイルはエラーになる', async () => {
const res = await relativeFetch(aliceUploadedFile.webpublicUrl);
function doValidate() {
validateContentTypeSetAsActivityPub(res);
}
expect(doValidate).toThrow('Content type is not');
});
test('JSON-LD: ファイルはエラーになる', async () => {
const res = await relativeFetch(aliceUploadedFile.webpublicUrl);
function doValidate() {
validateContentTypeSetAsJsonLD(res);
}
expect(doValidate).toThrow('Content type is not');
});
});

View File

@ -203,7 +203,7 @@ describe('ActivityPub', () => {
describe('Renderer', () => {
test('Render an announce with visibility: followers', () => {
rendererService.renderAnnounce(null, {
rendererService.renderAnnounce('https://example.com/notes/00example', {
id: genAidx(Date.now()),
visibility: 'followers',
} as MiNote);

View File

@ -13,10 +13,11 @@ import fetch, { File, RequestInit } from 'node-fetch';
import { DataSource } from 'typeorm';
import { JSDOM } from 'jsdom';
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
import { Packed } from '@/misc/json-schema.js';
import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js';
import { entities } from '../src/postgres.js';
import { loadConfig } from '../src/config.js';
import type * as misskey from 'misskey-js';
import { Packed } from '@/misc/json-schema.js';
export { server as startServer, jobQueue as startJobQueue } from '@/boot/common.js';
@ -124,8 +125,8 @@ function timeoutPromise<T>(p: Promise<T>, timeout: number): Promise<T> {
return Promise.race([
p,
new Promise((reject) => {
setTimeout(() => { reject(new Error('timed out')); }, timeout)
}) as never
setTimeout(() => { reject(new Error('timed out')); }, timeout);
}) as never,
]);
}
@ -327,7 +328,6 @@ export const uploadFile = async (user?: UserToken, { path, name, blob }: UploadO
});
const body = res.status !== 204 ? await res.json() as misskey.Endpoints['drive/files/create']['res'] : null;
return {
status: res.status,
headers: res.headers,
@ -343,7 +343,7 @@ export const uploadUrl = async (user: UserToken, url: string): Promise<Packed<'D
'main',
(msg) => msg.type === 'urlUploadFinished' && msg.body.marker === marker,
(msg) => msg.body.file as Packed<'DriveFile'>,
60 * 1000
60 * 1000,
);
await api('drive/files/upload-from-url', {
@ -439,15 +439,15 @@ export function makeStreamCatcher<T>(
cond: (message: Record<string, any>) => boolean,
extractor: (message: Record<string, any>) => T,
timeout = 60 * 1000): Promise<T> {
let ws: WebSocket
let ws: WebSocket;
const p = new Promise<T>(async (resolve) => {
ws = await connectStream(user, channel, (msg) => {
if (cond(msg)) {
resolve(extractor(msg))
resolve(extractor(msg));
}
});
}).finally(() => {
ws?.close();
ws.close();
});
return timeoutPromise(p, timeout);
@ -476,6 +476,14 @@ export const simpleGet = async (path: string, accept = '*/*', cookie: any = unde
'text/html; charset=utf-8',
];
if (res.ok && (
accept.startsWith('application/activity+json') ||
(accept.startsWith('application/ld+json') && accept.includes('https://www.w3.org/ns/activitystreams'))
)) {
// validateContentTypeSetAsActivityPubのテストを兼ねる
validateContentTypeSetAsActivityPub(res);
}
const body =
jsonTypes.includes(res.headers.get('content-type') ?? '') ? await res.json() :
htmlTypes.includes(res.headers.get('content-type') ?? '') ? new JSDOM(await res.text()) :

View File

@ -11,6 +11,7 @@ import { alert, confirm, popup, post, toast } from '@/os.js';
import { useStream } from '@/stream.js';
import * as sound from '@/scripts/sound.js';
import { $i, signout, updateAccount } from '@/account.js';
import { fetchInstance, instance } from '@/instance.js';
import { ColdDeviceStorage, defaultStore } from '@/store.js';
import { makeHotkey } from '@/scripts/hotkey.js';
import { reactionPicker } from '@/scripts/reaction-picker.js';
@ -234,6 +235,13 @@ export async function mainBoot() {
}
}
fetchInstance().then(() => {
const modifiedVersionMustProminentlyOfferInAgplV3Section13Read = miLocalStorage.getItem('modifiedVersionMustProminentlyOfferInAgplV3Section13Read');
if (modifiedVersionMustProminentlyOfferInAgplV3Section13Read !== 'true' && instance.repositoryUrl !== 'https://github.com/misskey-dev/misskey') {
popup(defineAsyncComponent(() => import('@/components/MkSourceCodeAvailablePopup.vue')), {}, {}, 'closed');
}
});
if ('Notification' in window) {
// 許可を得ていなかったらリクエスト
if (Notification.permission === 'default') {

View File

@ -0,0 +1,112 @@
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<div class="_panel _shadow" :class="$style.root">
<div :class="$style.icon">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-brand-open-source" width="40" height="40" viewBox="0 0 24 24" stroke-width="1" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<path d="M12 3a9 9 0 0 1 3.618 17.243l-2.193 -5.602a3 3 0 1 0 -2.849 0l-2.193 5.603a9 9 0 0 1 3.617 -17.244z"/>
</svg>
</div>
<div :class="$style.main">
<div :class="$style.title">
<I18n :src="i18n.ts.aboutX" tag="span">
<template #x>
{{ instance.name ?? host }}
</template>
</I18n>
</div>
<div :class="$style.text">
<I18n :src="i18n.ts._aboutMisskey.thisIsModifiedVersion" tag="span">
<template #name>
{{ instance.name ?? host }}
</template>
</I18n>
<I18n :src="i18n.ts.correspondingSourceIsAvailable" tag="span">
<template #anchor>
<MkA to="/about-misskey" class="_link">{{ i18n.ts.aboutMisskey }}</MkA>
</template>
</I18n>
</div>
<div class="_buttons">
<MkButton @click="close">{{ i18n.ts.gotIt }}</MkButton>
</div>
</div>
<button class="_button" :class="$style.close" @click="close"><i class="ti ti-x"></i></button>
</div>
</template>
<script lang="ts" setup>
import MkButton from '@/components/MkButton.vue';
import { host } from '@/config.js';
import { i18n } from '@/i18n.js';
import { instance } from '@/instance.js';
import { miLocalStorage } from '@/local-storage.js';
import * as os from '@/os.js';
const emit = defineEmits<{
(ev: 'closed'): void;
}>();
const zIndex = os.claimZIndex('low');
function close() {
miLocalStorage.setItem('modifiedVersionMustProminentlyOfferInAgplV3Section13Read', 'true');
emit('closed');
}
</script>
<style lang="scss" module>
.root {
position: fixed;
z-index: v-bind(zIndex);
bottom: var(--margin);
left: 0;
right: 0;
margin: auto;
box-sizing: border-box;
width: calc(100% - (var(--margin) * 2));
max-width: 500px;
display: flex;
}
.icon {
text-align: center;
padding-top: 25px;
width: 100px;
color: var(--accent);
}
@media (max-width: 500px) {
.icon {
width: 80px;
}
}
@media (max-width: 450px) {
.icon {
width: 70px;
}
}
.main {
padding: 25px 25px 25px 0;
flex: 1;
}
.close {
position: absolute;
top: 8px;
right: 8px;
padding: 8px;
}
.title {
font-weight: bold;
}
.text {
margin: 0.7em 0 1em 0;
}
</style>

View File

@ -12,6 +12,7 @@ type Keys =
'latestDonationInfoShownAt' |
'neverShowDonationInfo' |
'neverShowLocalOnlyInfo' |
'modifiedVersionMustProminentlyOfferInAgplV3Section13Read' |
'lastUsed' |
'lang' |
'drafts' |

View File

@ -31,7 +31,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_gaps_s">
<FormLink to="https://github.com/misskey-dev/misskey" external>
<template #icon><i class="ti ti-code"></i></template>
{{ i18n.ts._aboutMisskey.source }}
{{ i18n.ts._aboutMisskey.source }} ({{ i18n.ts._aboutMisskey.original }})
<template #suffix>GitHub</template>
</FormLink>
<FormLink to="https://crowdin.com/project/misskey" external>
@ -46,6 +46,25 @@ SPDX-License-Identifier: AGPL-3.0-only
</FormLink>
</div>
</FormSection>
<FormSection v-if="instance.repositoryUrl !== 'https://github.com/misskey-dev/misskey'">
<div class="_gaps_s">
<MkInfo>
{{ i18n.tsx._aboutMisskey.thisIsModifiedVersion({ name: instance.name }) }}
</MkInfo>
<FormLink v-if="instance.repositoryUrl" :to="instance.repositoryUrl" external>
<template #icon><i class="ti ti-code"></i></template>
{{ i18n.ts._aboutMisskey.source }}
</FormLink>
<FormLink v-if="instance.providesTarball" :to="`/tarball/misskey-${version}.tar.gz`" external>
<template #icon><i class="ti ti-download"></i></template>
{{ i18n.ts._aboutMisskey.source }}
<template #suffix>Tarball</template>
</FormLink>
<MkInfo v-if="!instance.repositoryUrl && !instance.providesTarball" warn>
{{ i18n.ts.sourceCodeIsNotYetProvided }}
</MkInfo>
</div>
</FormSection>
<FormSection>
<template #label>{{ i18n.ts._aboutMisskey.projectMembers }}</template>
<div :class="$style.contributors">
@ -122,9 +141,10 @@ import { version } from '@/config.js';
import FormLink from '@/components/form/link.vue';
import FormSection from '@/components/form/section.vue';
import MkButton from '@/components/MkButton.vue';
import MkLink from '@/components/MkLink.vue';
import MkInfo from '@/components/MkInfo.vue';
import { physics } from '@/scripts/physics.js';
import { i18n } from '@/i18n.js';
import { instance } from '@/instance.js';
import { defaultStore } from '@/store.js';
import * as os from '@/os.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';

View File

@ -48,17 +48,33 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #value>{{ instance.maintainerEmail }}</template>
</MkKeyValue>
</FormSplit>
<FormLink v-if="instance.impressumUrl" :to="instance.impressumUrl" external>{{ i18n.ts.impressum }}</FormLink>
<FormLink v-if="instance.impressumUrl" :to="instance.impressumUrl" external>
<template #icon><i class="ti ti-user-shield"></i></template>
{{ i18n.ts.impressum }}
</FormLink>
<div class="_gaps_s">
<MkFolder v-if="instance.serverRules.length > 0">
<template #label>{{ i18n.ts.serverRules }}</template>
<template #label>
<i class="ti ti-checkup-list"></i>
{{ i18n.ts.serverRules }}
</template>
<ol class="_gaps_s" :class="$style.rules">
<li v-for="item, index in instance.serverRules" :key="index" :class="$style.rule"><div :class="$style.ruleText" v-html="item"></div></li>
<li v-for="(item, index) in instance.serverRules" :key="index" :class="$style.rule"><div :class="$style.ruleText" v-html="item"></div></li>
</ol>
</MkFolder>
<FormLink v-if="instance.tosUrl" :to="instance.tosUrl" external>{{ i18n.ts.termsOfService }}</FormLink>
<FormLink v-if="instance.privacyPolicyUrl" :to="instance.privacyPolicyUrl" external>{{ i18n.ts.privacyPolicy }}</FormLink>
<FormLink v-if="instance.tosUrl" :to="instance.tosUrl" external>
<template #icon><i class="ti ti-license"></i></template>
{{ i18n.ts.termsOfService }}
</FormLink>
<FormLink v-if="instance.privacyPolicyUrl" :to="instance.privacyPolicyUrl" external>
<template #icon><i class="ti ti-shield-lock"></i></template>
{{ i18n.ts.privacyPolicy }}
</FormLink>
<FormLink v-if="instance.feedbackUrl" :to="instance.feedbackUrl" external>
<template #icon><i class="ti ti-message"></i></template>
{{ i18n.ts.feedback }}
</FormLink>
</div>
</div>
</FormSection>
@ -114,6 +130,7 @@ import FormSuspense from '@/components/form/suspense.vue';
import FormSplit from '@/components/form/split.vue';
import MkFolder from '@/components/MkFolder.vue';
import MkKeyValue from '@/components/MkKeyValue.vue';
import MkInfo from '@/components/MkInfo.vue';
import MkInstanceStats from '@/components/MkInstanceStats.vue';
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
import { misskeyApi } from '@/scripts/misskey-api.js';

View File

@ -76,6 +76,16 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #caption>{{ i18n.ts.instanceDefaultThemeDescription }}</template>
</MkTextarea>
<MkInput v-model="repositoryUrl" type="url">
<template #prefix><i class="ti ti-link"></i></template>
<template #label>{{ i18n.ts.repositoryUrl }}</template>
</MkInput>
<MkInput v-model="feedbackUrl" type="url">
<template #prefix><i class="ti ti-link"></i></template>
<template #label>{{ i18n.ts.feedbackUrl }}</template>
</MkInput>
<MkTextarea v-model="manifestJsonOverride">
<template #label>{{ i18n.ts._serverSettings.manifestJsonOverride }}</template>
</MkTextarea>
@ -120,6 +130,8 @@ const defaultDarkTheme = ref<string | null>(null);
const serverErrorImageUrl = ref<string | null>(null);
const infoImageUrl = ref<string | null>(null);
const notFoundImageUrl = ref<string | null>(null);
const repositoryUrl = ref<string | null>(null);
const feedbackUrl = ref<string | null>(null);
const manifestJsonOverride = ref<string>('{}');
async function init() {
@ -135,6 +147,8 @@ async function init() {
serverErrorImageUrl.value = meta.serverErrorImageUrl;
infoImageUrl.value = meta.infoImageUrl;
notFoundImageUrl.value = meta.notFoundImageUrl;
repositoryUrl.value = meta.repositoryUrl;
feedbackUrl.value = meta.feedbackUrl;
manifestJsonOverride.value = meta.manifestJsonOverride === '' ? '{}' : JSON.stringify(JSON.parse(meta.manifestJsonOverride), null, '\t');
}
@ -151,6 +165,8 @@ function save() {
infoImageUrl: infoImageUrl.value === '' ? null : infoImageUrl.value,
notFoundImageUrl: notFoundImageUrl.value === '' ? null : notFoundImageUrl.value,
serverErrorImageUrl: serverErrorImageUrl.value === '' ? null : serverErrorImageUrl.value,
repositoryUrl: repositoryUrl.value === '' ? null : repositoryUrl.value,
feedbackUrl: feedbackUrl.value === '' ? null : feedbackUrl.value,
manifestJsonOverride: manifestJsonOverride.value === '' ? '{}' : JSON.stringify(JSON5.parse(manifestJsonOverride.value)),
}).then(() => {
fetchInstance();

View File

@ -34,6 +34,16 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkInput>
</FormSplit>
<MkInput v-model="repositoryUrl" type="url">
<template #label>{{ i18n.ts.repositoryUrl }}</template>
<template #prefix><i class="ti ti-link"></i></template>
<template #caption>{{ i18n.ts.repositoryUrlDescription }}</template>
</MkInput>
<MkInfo v-if="!instance.providesTarball && !repositoryUrl" warn>
{{ i18n.ts.repositoryUrlOrTarballRequired }}
</MkInfo>
<MkInput v-model="impressumUrl" type="url">
<template #label>{{ i18n.ts.impressumUrl }}</template>
<template #prefix><i class="ti ti-link"></i></template>
@ -159,7 +169,7 @@ import FormSplit from '@/components/form/split.vue';
import FormSuspense from '@/components/form/suspense.vue';
import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { fetchInstance } from '@/instance.js';
import { fetchInstance, instance } from '@/instance.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import MkButton from '@/components/MkButton.vue';
@ -169,6 +179,7 @@ const shortName = ref<string | null>(null);
const description = ref<string | null>(null);
const maintainerName = ref<string | null>(null);
const maintainerEmail = ref<string | null>(null);
const repositoryUrl = ref<string | null>(null);
const impressumUrl = ref<string | null>(null);
const pinnedUsers = ref<string>('');
const cacheRemoteFiles = ref<boolean>(false);
@ -191,6 +202,7 @@ async function init(): Promise<void> {
description.value = meta.description;
maintainerName.value = meta.maintainerName;
maintainerEmail.value = meta.maintainerEmail;
repositoryUrl.value = meta.repositoryUrl;
impressumUrl.value = meta.impressumUrl;
pinnedUsers.value = meta.pinnedUsers.join('\n');
cacheRemoteFiles.value = meta.cacheRemoteFiles;
@ -214,6 +226,7 @@ async function save(): void {
description: description.value,
maintainerName: maintainerName.value,
maintainerEmail: maintainerEmail.value,
repositoryUrl: repositoryUrl.value,
impressumUrl: impressumUrl.value,
pinnedUsers: pinnedUsers.value.split('\n'),
cacheRemoteFiles: cacheRemoteFiles.value,

View File

@ -1,7 +1,7 @@
{
"type": "module",
"name": "misskey-js",
"version": "2024.2.0-beta.12",
"version": "2024.2.0",
"description": "Misskey SDK for JavaScript",
"types": "./built/dts/index.d.ts",
"exports": {

View File

@ -4845,7 +4845,7 @@ export type operations = {
shortName: string | null;
objectStorageS3ForcePathStyle: boolean;
privacyPolicyUrl: string | null;
repositoryUrl: string;
repositoryUrl: string | null;
summalyProxy: string | null;
themeColor: string | null;
tosUrl: string | null;
@ -8758,8 +8758,8 @@ export type operations = {
swPublicKey?: string | null;
swPrivateKey?: string | null;
tosUrl?: string | null;
repositoryUrl?: string;
feedbackUrl?: string;
repositoryUrl?: string | null;
feedbackUrl?: string | null;
impressumUrl?: string | null;
privacyPolicyUrl?: string | null;
useObjectStorage?: boolean;
@ -19452,6 +19452,7 @@ export type operations = {
maintainerName: string | null;
maintainerEmail: string | null;
version: string;
providesTarball: boolean;
name: string;
shortName: string | null;
/**
@ -19463,9 +19464,9 @@ export type operations = {
langs: string[];
tosUrl: string | null;
/** @default https://github.com/misskey-dev/misskey */
repositoryUrl: string;
repositoryUrl: string | null;
/** @default https://github.com/misskey-dev/misskey/issues/new */
feedbackUrl: string;
feedbackUrl: string | null;
defaultDarkTheme: string | null;
defaultLightTheme: string | null;
disableRegistration: boolean;

View File

@ -514,9 +514,9 @@ importers:
'@nestjs/platform-express':
specifier: 10.3.1
version: 10.3.1(@nestjs/common@10.2.10)(@nestjs/core@10.2.10)
'@simplewebauthn/typescript-types':
specifier: 8.3.4
version: 8.3.4
'@simplewebauthn/types':
specifier: 9.0.1
version: 9.0.1
'@swc/jest':
specifier: 0.2.31
version: 0.2.31(@swc/core@1.3.107)
@ -532,9 +532,6 @@ importers:
'@types/body-parser':
specifier: 1.19.5
version: 1.19.5
'@types/cbor':
specifier: 6.0.0
version: 6.0.0
'@types/color-convert':
specifier: 2.0.3
version: 2.0.3
@ -613,9 +610,6 @@ importers:
'@types/semver':
specifier: 7.5.6
version: 7.5.6
'@types/sharp':
specifier: 0.32.0
version: 0.32.0
'@types/simple-oauth2':
specifier: 5.0.7
version: 5.0.7
@ -5151,11 +5145,9 @@ packages:
/@simplewebauthn/types@9.0.1:
resolution: {integrity: sha512-tGSRP1QvsAvsJmnOlRQyw/mvK9gnPtjEc5fg2+m8n+QUa+D7rvrKkOYyfpy42GTs90X3RDOnqJgfHt+qO67/+w==}
dev: false
/@simplewebauthn/typescript-types@8.3.4:
resolution: {integrity: sha512-38xtca0OqfRVNloKBrFB5LEM6PN5vzFbJG6rAutPVrtGHFYxPdiV3btYWq0eAZAZmP+dqFPYJxJWeJrGfmYHng==}
deprecated: This package has been renamed to @simplewebauthn/types. Please install @simplewebauthn/types instead to ensure you receive future updates.
/@sinclair/typebox@0.24.51:
resolution: {integrity: sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==}
dev: true
/@sinclair/typebox@0.27.8:
@ -7153,13 +7145,6 @@ packages:
'@types/responselike': 1.0.0
dev: false
/@types/cbor@6.0.0:
resolution: {integrity: sha512-mGQ1lbYOwVti5Xlarn1bTeBZqgY0kstsdjnkoEovgohYKdBjGejHyNGXHdMBeqyQazIv32Jjp33+5pBEaSRy2w==}
deprecated: This is a stub types definition. cbor provides its own type definitions, so you do not need this installed.
dependencies:
cbor: 9.0.2
dev: true
/@types/chai-subset@1.3.5:
resolution: {integrity: sha512-c2mPnw+xHtXDoHmdtcCXGwyLMiauiAyxWMzhGpqHC4nqI/Y5G2XhTampslK2rb59kpcuHon03UH8W6iYUzw88A==}
dependencies:
@ -7596,13 +7581,6 @@ packages:
resolution: {integrity: sha512-7TCH7iNsCSNb+aUD9M/36TekrWFSLCjNK8zw/3n5kOtRjbLtDfGYMXTrDnGhSfqXNwpqmt9Vd90w5C/ad1tX6Q==}
dev: true
/@types/sharp@0.32.0:
resolution: {integrity: sha512-OOi3kL+FZDnPhVzsfD37J88FNeZh6gQsGcLc95NbeURRGvmSjeXiDcyWzF2o3yh/gQAUn2uhh/e+CPCa5nwAxw==}
deprecated: This is a stub types definition. sharp provides its own type definitions, so you do not need this installed.
dependencies:
sharp: 0.32.6
dev: true
/@types/simple-oauth2@5.0.7:
resolution: {integrity: sha512-8JbWVJbiTSBQP/7eiyGKyXWAqp3dKQZpaA+pdW16FCi32ujkzRMG8JfjoAzdWt6W8U591ZNdHcPtP2D7ILTKuA==}
dev: true
@ -8729,6 +8707,7 @@ packages:
/b4a@1.6.4:
resolution: {integrity: sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==}
dev: false
/babel-core@7.0.0-bridge.0(@babel/core@7.23.5):
resolution: {integrity: sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==}
@ -9267,6 +9246,7 @@ packages:
engines: {node: '>=16'}
dependencies:
nofilter: 3.1.0
dev: false
/ccount@2.0.1:
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
@ -9602,6 +9582,7 @@ packages:
dependencies:
color-name: 1.1.4
simple-swizzle: 0.2.2
dev: false
/color-support@1.1.3:
resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==}
@ -9616,6 +9597,7 @@ packages:
dependencies:
color-convert: 2.0.1
color-string: 1.9.1
dev: false
/colord@2.9.3:
resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==}
@ -10288,6 +10270,7 @@ packages:
/deep-extend@0.6.0:
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
engines: {node: '>=4.0.0'}
dev: false
/deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
@ -10382,6 +10365,7 @@ packages:
/detect-libc@2.0.2:
resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==}
engines: {node: '>=8'}
dev: false
/detect-newline@3.1.0:
resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==}
@ -11282,6 +11266,7 @@ packages:
/expand-template@2.0.3:
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
engines: {node: '>=6'}
dev: false
/expect@29.7.0:
resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==}
@ -11394,6 +11379,7 @@ packages:
/fast-fifo@1.3.0:
resolution: {integrity: sha512-IgfweLvEpwyA4WgiQe9Nx6VV2QkML2NkvZnk1oKnIzXgXdWxuhF7zw4DvLTPZJn6PIUneiAXPF24QmoEqHTjyw==}
dev: false
/fast-glob@3.3.2:
resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
@ -11991,6 +11977,7 @@ packages:
/github-from-package@0.0.0:
resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
dev: false
/github-slugger@2.0.0:
resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==}
@ -12707,6 +12694,7 @@ packages:
/is-arrayish@0.3.2:
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
dev: false
/is-bigint@1.0.4:
resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
@ -14964,6 +14952,7 @@ packages:
/napi-build-utils@1.0.2:
resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
dev: false
/natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
@ -15044,6 +15033,7 @@ packages:
engines: {node: '>=10'}
dependencies:
semver: 7.5.4
dev: false
/node-abort-controller@3.1.1:
resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==}
@ -15051,6 +15041,7 @@ packages:
/node-addon-api@6.1.0:
resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==}
dev: false
/node-bitmap@0.0.1:
resolution: {integrity: sha512-Jx5lPaaLdIaOsj2mVLWMWulXF6GQVdyLvNSxmiYCvZ8Ma2hfKX0POoR2kgKOqz+oFsRreq0yYZjQ2wjE9VNzCA==}
@ -15191,6 +15182,7 @@ packages:
/nofilter@3.1.0:
resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==}
engines: {node: '>=12.19'}
dev: false
/nopt@1.0.10:
resolution: {integrity: sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==}
@ -16342,6 +16334,7 @@ packages:
simple-get: 4.0.1
tar-fs: 2.1.1
tunnel-agent: 0.6.0
dev: false
/prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
@ -16718,6 +16711,7 @@ packages:
/queue-tick@1.0.1:
resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==}
dev: false
/quick-format-unescaped@4.0.4:
resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==}
@ -16777,6 +16771,7 @@ packages:
ini: 1.3.8
minimist: 1.2.8
strip-json-comments: 2.0.1
dev: false
/rdf-canonize@3.4.0:
resolution: {integrity: sha512-fUeWjrkOO0t1rg7B2fdyDTvngj+9RlUyL92vOdiB7c0FPguWVsniIMjEtHH+meLBO9rzkUlUzBVXgWrjI8P9LA==}
@ -17521,6 +17516,7 @@ packages:
simple-get: 4.0.1
tar-fs: 3.0.4
tunnel-agent: 0.6.0
dev: false
/shebang-command@1.2.0:
resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==}
@ -17570,6 +17566,7 @@ packages:
/simple-concat@1.0.1:
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
dev: false
/simple-get@4.0.1:
resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
@ -17577,6 +17574,7 @@ packages:
decompress-response: 6.0.0
once: 1.4.0
simple-concat: 1.0.1
dev: false
/simple-oauth2@5.0.0:
resolution: {integrity: sha512-8291lo/z5ZdpmiOFzOs1kF3cxn22bMj5FFH+DNUppLJrpoIlM1QnFiE7KpshHu3J3i21TVcx4yW+gXYjdCKDLQ==}
@ -17593,6 +17591,7 @@ packages:
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
dependencies:
is-arrayish: 0.3.2
dev: false
/simple-update-notifier@2.0.0:
resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==}
@ -18019,6 +18018,7 @@ packages:
dependencies:
fast-fifo: 1.3.0
queue-tick: 1.0.1
dev: false
/strict-event-emitter-types@2.0.0:
resolution: {integrity: sha512-Nk/brWYpD85WlOgzw5h173aci0Teyv8YdIAEtV+N88nDB0dLlazZyJMIsN6eo1/AR61l+p6CJTG1JIyFaoNEEA==}
@ -18153,6 +18153,7 @@ packages:
/strip-json-comments@2.0.1:
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
engines: {node: '>=0.10.0'}
dev: false
/strip-json-comments@3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
@ -18268,6 +18269,7 @@ packages:
mkdirp-classic: 0.5.3
pump: 3.0.0
tar-stream: 3.1.6
dev: false
/tar-stream@2.2.0:
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
@ -18285,6 +18287,7 @@ packages:
b4a: 1.6.4
fast-fifo: 1.3.0
streamx: 2.15.0
dev: false
/tar@4.4.19:
resolution: {integrity: sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==}

View File

@ -5,7 +5,9 @@
import * as fs from 'node:fs/promises';
import * as path from 'node:path';
import { fileURLToPath } from 'node:url';
import cssnano from 'cssnano';
import * as yaml from 'js-yaml';
import postcss from 'postcss';
import * as terser from 'terser';
@ -14,8 +16,19 @@ import generateDTS from '../locales/generateDTS.js';
import meta from '../package.json' assert { type: "json" };
import buildTarball from './tarball.mjs';
const configDir = fileURLToPath(new URL('../.config', import.meta.url));
const configPath = process.env.MISSKEY_CONFIG_YML
? path.resolve(configDir, process.env.MISSKEY_CONFIG_YML)
: process.env.NODE_ENV === 'test'
? path.resolve(configDir, 'test.yml')
: path.resolve(configDir, 'default.yml');
let locales = buildLocales();
async function loadConfig() {
return fs.readFile(configPath, 'utf-8').then(data => yaml.load(data)).catch(() => null);
}
async function copyFrontendFonts() {
await fs.cp('./packages/frontend/node_modules/three/examples/fonts', './built/_frontend_dist_/fonts', { dereference: true, recursive: true });
}
@ -78,7 +91,7 @@ async function build() {
copyBackendViews(),
buildBackendScript(),
buildBackendStyle(),
buildTarball(),
loadConfig().then(config => config?.publishTarballInsteadOfProvideRepositoryUrl && buildTarball()),
]);
}