enhance: meta
をSSR HTMLに埋め込む (#13436)
* enhance: `meta`をSSR HTMLに埋め込む
* HTML Metaの有効時間を指定
* 1時間
* MetaEntityService
* JSONをPackするように
* ✌️
---------
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
This commit is contained in:
parent
bf5952fd63
commit
d20542c495
26 changed files with 676 additions and 530 deletions
|
@ -116,6 +116,7 @@ import { FlashEntityService } from './entities/FlashEntityService.js';
|
||||||
import { FlashLikeEntityService } from './entities/FlashLikeEntityService.js';
|
import { FlashLikeEntityService } from './entities/FlashLikeEntityService.js';
|
||||||
import { RoleEntityService } from './entities/RoleEntityService.js';
|
import { RoleEntityService } from './entities/RoleEntityService.js';
|
||||||
import { ReversiGameEntityService } from './entities/ReversiGameEntityService.js';
|
import { ReversiGameEntityService } from './entities/ReversiGameEntityService.js';
|
||||||
|
import { MetaEntityService } from './entities/MetaEntityService.js';
|
||||||
|
|
||||||
import { ApAudienceService } from './activitypub/ApAudienceService.js';
|
import { ApAudienceService } from './activitypub/ApAudienceService.js';
|
||||||
import { ApDbResolverService } from './activitypub/ApDbResolverService.js';
|
import { ApDbResolverService } from './activitypub/ApDbResolverService.js';
|
||||||
|
@ -254,6 +255,7 @@ const $FlashEntityService: Provider = { provide: 'FlashEntityService', useExisti
|
||||||
const $FlashLikeEntityService: Provider = { provide: 'FlashLikeEntityService', useExisting: FlashLikeEntityService };
|
const $FlashLikeEntityService: Provider = { provide: 'FlashLikeEntityService', useExisting: FlashLikeEntityService };
|
||||||
const $RoleEntityService: Provider = { provide: 'RoleEntityService', useExisting: RoleEntityService };
|
const $RoleEntityService: Provider = { provide: 'RoleEntityService', useExisting: RoleEntityService };
|
||||||
const $ReversiGameEntityService: Provider = { provide: 'ReversiGameEntityService', useExisting: ReversiGameEntityService };
|
const $ReversiGameEntityService: Provider = { provide: 'ReversiGameEntityService', useExisting: ReversiGameEntityService };
|
||||||
|
const $MetaEntityService: Provider = { provide: 'MetaEntityService', useExisting: MetaEntityService };
|
||||||
|
|
||||||
const $ApAudienceService: Provider = { provide: 'ApAudienceService', useExisting: ApAudienceService };
|
const $ApAudienceService: Provider = { provide: 'ApAudienceService', useExisting: ApAudienceService };
|
||||||
const $ApDbResolverService: Provider = { provide: 'ApDbResolverService', useExisting: ApDbResolverService };
|
const $ApDbResolverService: Provider = { provide: 'ApDbResolverService', useExisting: ApDbResolverService };
|
||||||
|
@ -393,6 +395,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
FlashLikeEntityService,
|
FlashLikeEntityService,
|
||||||
RoleEntityService,
|
RoleEntityService,
|
||||||
ReversiGameEntityService,
|
ReversiGameEntityService,
|
||||||
|
MetaEntityService,
|
||||||
|
|
||||||
ApAudienceService,
|
ApAudienceService,
|
||||||
ApDbResolverService,
|
ApDbResolverService,
|
||||||
|
@ -528,6 +531,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
$FlashLikeEntityService,
|
$FlashLikeEntityService,
|
||||||
$RoleEntityService,
|
$RoleEntityService,
|
||||||
$ReversiGameEntityService,
|
$ReversiGameEntityService,
|
||||||
|
$MetaEntityService,
|
||||||
|
|
||||||
$ApAudienceService,
|
$ApAudienceService,
|
||||||
$ApDbResolverService,
|
$ApDbResolverService,
|
||||||
|
@ -663,6 +667,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
FlashLikeEntityService,
|
FlashLikeEntityService,
|
||||||
RoleEntityService,
|
RoleEntityService,
|
||||||
ReversiGameEntityService,
|
ReversiGameEntityService,
|
||||||
|
MetaEntityService,
|
||||||
|
|
||||||
ApAudienceService,
|
ApAudienceService,
|
||||||
ApDbResolverService,
|
ApDbResolverService,
|
||||||
|
@ -797,6 +802,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
$FlashLikeEntityService,
|
$FlashLikeEntityService,
|
||||||
$RoleEntityService,
|
$RoleEntityService,
|
||||||
$ReversiGameEntityService,
|
$ReversiGameEntityService,
|
||||||
|
$MetaEntityService,
|
||||||
|
|
||||||
$ApAudienceService,
|
$ApAudienceService,
|
||||||
$ApDbResolverService,
|
$ApDbResolverService,
|
||||||
|
|
154
packages/backend/src/core/entities/MetaEntityService.ts
Normal file
154
packages/backend/src/core/entities/MetaEntityService.ts
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Brackets } from 'typeorm';
|
||||||
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import JSON5 from 'json5';
|
||||||
|
import type { Packed } from '@/misc/json-schema.js';
|
||||||
|
import type { MiMeta } from '@/models/Meta.js';
|
||||||
|
import type { AdsRepository } from '@/models/_.js';
|
||||||
|
import { MAX_NOTE_TEXT_LENGTH } from '@/const.js';
|
||||||
|
import { MetaService } from '@/core/MetaService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
|
import { InstanceActorService } from '@/core/InstanceActorService.js';
|
||||||
|
import type { Config } from '@/config.js';
|
||||||
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class MetaEntityService {
|
||||||
|
constructor(
|
||||||
|
@Inject(DI.config)
|
||||||
|
private config: Config,
|
||||||
|
|
||||||
|
@Inject(DI.adsRepository)
|
||||||
|
private adsRepository: AdsRepository,
|
||||||
|
|
||||||
|
private userEntityService: UserEntityService,
|
||||||
|
private metaService: MetaService,
|
||||||
|
private instanceActorService: InstanceActorService,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async pack(meta?: MiMeta): Promise<Packed<'MetaLite'>> {
|
||||||
|
let instance = meta;
|
||||||
|
|
||||||
|
if (!instance) {
|
||||||
|
instance = await this.metaService.fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
const ads = await this.adsRepository.createQueryBuilder('ads')
|
||||||
|
.where('ads.expiresAt > :now', { now: new Date() })
|
||||||
|
.andWhere('ads.startsAt <= :now', { now: new Date() })
|
||||||
|
.andWhere(new Brackets(qb => {
|
||||||
|
// 曜日のビットフラグを確認する
|
||||||
|
qb.where('ads.dayOfWeek & :dayOfWeek > 0', { dayOfWeek: 1 << new Date().getDay() })
|
||||||
|
.orWhere('ads.dayOfWeek = 0');
|
||||||
|
}))
|
||||||
|
.getMany();
|
||||||
|
|
||||||
|
const packed: Packed<'MetaLite'> = {
|
||||||
|
maintainerName: instance.maintainerName,
|
||||||
|
maintainerEmail: instance.maintainerEmail,
|
||||||
|
|
||||||
|
version: this.config.version,
|
||||||
|
providesTarball: this.config.publishTarballInsteadOfProvideRepositoryUrl,
|
||||||
|
|
||||||
|
name: instance.name,
|
||||||
|
shortName: instance.shortName,
|
||||||
|
uri: this.config.url,
|
||||||
|
description: instance.description,
|
||||||
|
langs: instance.langs,
|
||||||
|
tosUrl: instance.termsOfServiceUrl,
|
||||||
|
repositoryUrl: instance.repositoryUrl,
|
||||||
|
feedbackUrl: instance.feedbackUrl,
|
||||||
|
impressumUrl: instance.impressumUrl,
|
||||||
|
privacyPolicyUrl: instance.privacyPolicyUrl,
|
||||||
|
disableRegistration: instance.disableRegistration,
|
||||||
|
emailRequiredForSignup: instance.emailRequiredForSignup,
|
||||||
|
enableHcaptcha: instance.enableHcaptcha,
|
||||||
|
hcaptchaSiteKey: instance.hcaptchaSiteKey,
|
||||||
|
enableMcaptcha: instance.enableMcaptcha,
|
||||||
|
mcaptchaSiteKey: instance.mcaptchaSitekey,
|
||||||
|
mcaptchaInstanceUrl: instance.mcaptchaInstanceUrl,
|
||||||
|
enableRecaptcha: instance.enableRecaptcha,
|
||||||
|
recaptchaSiteKey: instance.recaptchaSiteKey,
|
||||||
|
enableTurnstile: instance.enableTurnstile,
|
||||||
|
turnstileSiteKey: instance.turnstileSiteKey,
|
||||||
|
swPublickey: instance.swPublicKey,
|
||||||
|
themeColor: instance.themeColor,
|
||||||
|
mascotImageUrl: instance.mascotImageUrl ?? '/assets/ai.png',
|
||||||
|
bannerUrl: instance.bannerUrl,
|
||||||
|
infoImageUrl: instance.infoImageUrl,
|
||||||
|
serverErrorImageUrl: instance.serverErrorImageUrl,
|
||||||
|
notFoundImageUrl: instance.notFoundImageUrl,
|
||||||
|
iconUrl: instance.iconUrl,
|
||||||
|
backgroundImageUrl: instance.backgroundImageUrl,
|
||||||
|
logoImageUrl: instance.logoImageUrl,
|
||||||
|
maxNoteTextLength: MAX_NOTE_TEXT_LENGTH,
|
||||||
|
// クライアントの手間を減らすためあらかじめJSONに変換しておく
|
||||||
|
defaultLightTheme: instance.defaultLightTheme ? JSON.stringify(JSON5.parse(instance.defaultLightTheme)) : null,
|
||||||
|
defaultDarkTheme: instance.defaultDarkTheme ? JSON.stringify(JSON5.parse(instance.defaultDarkTheme)) : null,
|
||||||
|
ads: ads.map(ad => ({
|
||||||
|
id: ad.id,
|
||||||
|
url: ad.url,
|
||||||
|
place: ad.place,
|
||||||
|
ratio: ad.ratio,
|
||||||
|
imageUrl: ad.imageUrl,
|
||||||
|
dayOfWeek: ad.dayOfWeek,
|
||||||
|
})),
|
||||||
|
notesPerOneAd: instance.notesPerOneAd,
|
||||||
|
enableEmail: instance.enableEmail,
|
||||||
|
enableServiceWorker: instance.enableServiceWorker,
|
||||||
|
|
||||||
|
translatorAvailable: instance.deeplAuthKey != null,
|
||||||
|
|
||||||
|
serverRules: instance.serverRules,
|
||||||
|
|
||||||
|
policies: { ...DEFAULT_POLICIES, ...instance.policies },
|
||||||
|
|
||||||
|
mediaProxy: this.config.mediaProxy,
|
||||||
|
};
|
||||||
|
|
||||||
|
return packed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async packDetailed(meta?: MiMeta): Promise<Packed<'MetaDetailed'>> {
|
||||||
|
let instance = meta;
|
||||||
|
|
||||||
|
if (!instance) {
|
||||||
|
instance = await this.metaService.fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
const packed = await this.pack(instance);
|
||||||
|
|
||||||
|
const proxyAccount = instance.proxyAccountId ? await this.userEntityService.pack(instance.proxyAccountId).catch(() => null) : null;
|
||||||
|
|
||||||
|
const packDetailed: Packed<'MetaDetailed'> = {
|
||||||
|
...packed,
|
||||||
|
cacheRemoteFiles: instance.cacheRemoteFiles,
|
||||||
|
cacheRemoteSensitiveFiles: instance.cacheRemoteSensitiveFiles,
|
||||||
|
requireSetup: !await this.instanceActorService.realLocalUsersPresent(),
|
||||||
|
proxyAccountName: proxyAccount ? proxyAccount.username : null,
|
||||||
|
features: {
|
||||||
|
localTimeline: instance.policies.ltlAvailable,
|
||||||
|
globalTimeline: instance.policies.gtlAvailable,
|
||||||
|
registration: !instance.disableRegistration,
|
||||||
|
emailRequiredForSignup: instance.emailRequiredForSignup,
|
||||||
|
hcaptcha: instance.enableHcaptcha,
|
||||||
|
recaptcha: instance.enableRecaptcha,
|
||||||
|
turnstile: instance.enableTurnstile,
|
||||||
|
objectStorage: instance.useObjectStorage,
|
||||||
|
serviceWorker: instance.enableServiceWorker,
|
||||||
|
miauth: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return packDetailed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -50,6 +50,11 @@ import {
|
||||||
} from '@/models/json-schema/role.js';
|
} from '@/models/json-schema/role.js';
|
||||||
import { packedAdSchema } from '@/models/json-schema/ad.js';
|
import { packedAdSchema } from '@/models/json-schema/ad.js';
|
||||||
import { packedReversiGameLiteSchema, packedReversiGameDetailedSchema } from '@/models/json-schema/reversi-game.js';
|
import { packedReversiGameLiteSchema, packedReversiGameDetailedSchema } from '@/models/json-schema/reversi-game.js';
|
||||||
|
import {
|
||||||
|
packedMetaLiteSchema,
|
||||||
|
packedMetaDetailedOnlySchema,
|
||||||
|
packedMetaDetailedSchema,
|
||||||
|
} from '@/models/json-schema/meta.js';
|
||||||
|
|
||||||
export const refs = {
|
export const refs = {
|
||||||
UserLite: packedUserLiteSchema,
|
UserLite: packedUserLiteSchema,
|
||||||
|
@ -99,6 +104,9 @@ export const refs = {
|
||||||
RolePolicies: packedRolePoliciesSchema,
|
RolePolicies: packedRolePoliciesSchema,
|
||||||
ReversiGameLite: packedReversiGameLiteSchema,
|
ReversiGameLite: packedReversiGameLiteSchema,
|
||||||
ReversiGameDetailed: packedReversiGameDetailedSchema,
|
ReversiGameDetailed: packedReversiGameDetailedSchema,
|
||||||
|
MetaLite: packedMetaLiteSchema,
|
||||||
|
MetaDetailedOnly: packedMetaDetailedOnlySchema,
|
||||||
|
MetaDetailed: packedMetaDetailedSchema,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Packed<x extends keyof typeof refs> = SchemaType<typeof refs[x]>;
|
export type Packed<x extends keyof typeof refs> = SchemaType<typeof refs[x]>;
|
||||||
|
|
328
packages/backend/src/models/json-schema/meta.ts
Normal file
328
packages/backend/src/models/json-schema/meta.ts
Normal file
|
@ -0,0 +1,328 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const packedMetaLiteSchema = {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
properties: {
|
||||||
|
maintainerName: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
maintainerEmail: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
version: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
providesTarball: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
shortName: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
uri: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
format: 'url',
|
||||||
|
example: 'https://misskey.example.com',
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
langs: {
|
||||||
|
type: 'array',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
items: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tosUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
repositoryUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
default: 'https://github.com/misskey-dev/misskey',
|
||||||
|
},
|
||||||
|
feedbackUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
default: 'https://github.com/misskey-dev/misskey/issues/new',
|
||||||
|
},
|
||||||
|
defaultDarkTheme: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
defaultLightTheme: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
disableRegistration: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
emailRequiredForSignup: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
enableHcaptcha: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
hcaptchaSiteKey: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
enableMcaptcha: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
mcaptchaSiteKey: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
mcaptchaInstanceUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
enableRecaptcha: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
recaptchaSiteKey: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
enableTurnstile: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
turnstileSiteKey: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
swPublickey: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
mascotImageUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
default: '/assets/ai.png',
|
||||||
|
},
|
||||||
|
bannerUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
serverErrorImageUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
infoImageUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
notFoundImageUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
iconUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
maxNoteTextLength: {
|
||||||
|
type: 'number',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
ads: {
|
||||||
|
type: 'array',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
format: 'id',
|
||||||
|
example: 'xxxxxxxxxx',
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
format: 'url',
|
||||||
|
},
|
||||||
|
place: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
ratio: {
|
||||||
|
type: 'number',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
imageUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
format: 'url',
|
||||||
|
},
|
||||||
|
dayOfWeek: {
|
||||||
|
type: 'integer',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
notesPerOneAd: {
|
||||||
|
type: 'number',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
enableEmail: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
enableServiceWorker: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
translatorAvailable: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
mediaProxy: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
backgroundImageUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
impressumUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
logoImageUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
privacyPolicyUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
serverRules: {
|
||||||
|
type: 'array',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
items: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
themeColor: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
policies: {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
ref: 'RolePolicies',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const packedMetaDetailedOnlySchema = {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
properties: {
|
||||||
|
features: {
|
||||||
|
type: 'object',
|
||||||
|
optional: true, nullable: false,
|
||||||
|
properties: {
|
||||||
|
registration: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
emailRequiredForSignup: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
localTimeline: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
globalTimeline: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
hcaptcha: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
turnstile: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
recaptcha: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
objectStorage: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
serviceWorker: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
miauth: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: true, nullable: false,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
proxyAccountName: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
requireSetup: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
example: false,
|
||||||
|
},
|
||||||
|
cacheRemoteFiles: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
cacheRemoteSensitiveFiles: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const packedMetaDetailedSchema = {
|
||||||
|
type: 'object',
|
||||||
|
allOf: [
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
ref: 'MetaLite',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
ref: 'MetaDetailedOnly',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} as const;
|
|
@ -3,18 +3,9 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { IsNull, LessThanOrEqual, MoreThan, Brackets } from 'typeorm';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
|
||||||
import JSON5 from 'json5';
|
|
||||||
import type { AdsRepository } from '@/models/_.js';
|
|
||||||
import { MAX_NOTE_TEXT_LENGTH } from '@/const.js';
|
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { MetaEntityService } from '@/core/entities/MetaEntityService.js';
|
||||||
import { MetaService } from '@/core/MetaService.js';
|
|
||||||
import { InstanceActorService } from '@/core/InstanceActorService.js';
|
|
||||||
import type { Config } from '@/config.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
|
||||||
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['meta'],
|
tags: ['meta'],
|
||||||
|
@ -23,297 +14,10 @@ export const meta = {
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
optional: false, nullable: false,
|
oneOf: [
|
||||||
properties: {
|
{ type: 'object', ref: 'MetaLite' },
|
||||||
maintainerName: {
|
{ type: 'object', ref: 'MetaDetailed' },
|
||||||
type: 'string',
|
],
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
maintainerEmail: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
version: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
providesTarball: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
name: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
shortName: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
uri: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
format: 'url',
|
|
||||||
example: 'https://misskey.example.com',
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
langs: {
|
|
||||||
type: 'array',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
items: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tosUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
repositoryUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
default: 'https://github.com/misskey-dev/misskey',
|
|
||||||
},
|
|
||||||
feedbackUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
default: 'https://github.com/misskey-dev/misskey/issues/new',
|
|
||||||
},
|
|
||||||
defaultDarkTheme: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
defaultLightTheme: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
disableRegistration: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
cacheRemoteFiles: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
cacheRemoteSensitiveFiles: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
emailRequiredForSignup: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
enableHcaptcha: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
hcaptchaSiteKey: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
enableMcaptcha: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
mcaptchaSiteKey: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
mcaptchaInstanceUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
enableRecaptcha: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
recaptchaSiteKey: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
enableTurnstile: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
turnstileSiteKey: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
swPublickey: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
mascotImageUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
default: '/assets/ai.png',
|
|
||||||
},
|
|
||||||
bannerUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
serverErrorImageUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
infoImageUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
notFoundImageUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
iconUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
maxNoteTextLength: {
|
|
||||||
type: 'number',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
ads: {
|
|
||||||
type: 'array',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
items: {
|
|
||||||
type: 'object',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
properties: {
|
|
||||||
id: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
format: 'id',
|
|
||||||
example: 'xxxxxxxxxx',
|
|
||||||
},
|
|
||||||
url: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
format: 'url',
|
|
||||||
},
|
|
||||||
place: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
ratio: {
|
|
||||||
type: 'number',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
imageUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
format: 'url',
|
|
||||||
},
|
|
||||||
dayOfWeek: {
|
|
||||||
type: 'integer',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
notesPerOneAd: {
|
|
||||||
type: 'number',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
default: 0,
|
|
||||||
},
|
|
||||||
requireSetup: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
example: false,
|
|
||||||
},
|
|
||||||
enableEmail: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
enableServiceWorker: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
translatorAvailable: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
proxyAccountName: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
mediaProxy: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
features: {
|
|
||||||
type: 'object',
|
|
||||||
optional: true, nullable: false,
|
|
||||||
properties: {
|
|
||||||
registration: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
localTimeline: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
globalTimeline: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
hcaptcha: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
recaptcha: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
objectStorage: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
serviceWorker: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
miauth: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: true, nullable: false,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
backgroundImageUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
impressumUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
logoImageUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
privacyPolicyUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
serverRules: {
|
|
||||||
type: 'array',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
items: {
|
|
||||||
type: 'string',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
themeColor: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
policies: {
|
|
||||||
type: 'object',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
ref: 'RolePolicies',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
@ -328,115 +32,10 @@ export const paramDef = {
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(DI.config)
|
private metaEntityService: MetaEntityService,
|
||||||
private config: Config,
|
|
||||||
|
|
||||||
@Inject(DI.adsRepository)
|
|
||||||
private adsRepository: AdsRepository,
|
|
||||||
|
|
||||||
private userEntityService: UserEntityService,
|
|
||||||
private metaService: MetaService,
|
|
||||||
private instanceActorService: InstanceActorService,
|
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const instance = await this.metaService.fetch(true);
|
return ps.detail ? await this.metaEntityService.packDetailed() : await this.metaEntityService.pack();
|
||||||
|
|
||||||
const ads = await this.adsRepository.createQueryBuilder('ads')
|
|
||||||
.where('ads.expiresAt > :now', { now: new Date() })
|
|
||||||
.andWhere('ads.startsAt <= :now', { now: new Date() })
|
|
||||||
.andWhere(new Brackets(qb => {
|
|
||||||
// 曜日のビットフラグを確認する
|
|
||||||
qb.where('ads.dayOfWeek & :dayOfWeek > 0', { dayOfWeek: 1 << new Date().getDay() })
|
|
||||||
.orWhere('ads.dayOfWeek = 0');
|
|
||||||
}))
|
|
||||||
.getMany();
|
|
||||||
|
|
||||||
const response: any = {
|
|
||||||
maintainerName: instance.maintainerName,
|
|
||||||
maintainerEmail: instance.maintainerEmail,
|
|
||||||
|
|
||||||
version: this.config.version,
|
|
||||||
providesTarball: this.config.publishTarballInsteadOfProvideRepositoryUrl,
|
|
||||||
|
|
||||||
name: instance.name,
|
|
||||||
shortName: instance.shortName,
|
|
||||||
uri: this.config.url,
|
|
||||||
description: instance.description,
|
|
||||||
langs: instance.langs,
|
|
||||||
tosUrl: instance.termsOfServiceUrl,
|
|
||||||
repositoryUrl: instance.repositoryUrl,
|
|
||||||
feedbackUrl: instance.feedbackUrl,
|
|
||||||
impressumUrl: instance.impressumUrl,
|
|
||||||
privacyPolicyUrl: instance.privacyPolicyUrl,
|
|
||||||
disableRegistration: instance.disableRegistration,
|
|
||||||
emailRequiredForSignup: instance.emailRequiredForSignup,
|
|
||||||
enableHcaptcha: instance.enableHcaptcha,
|
|
||||||
hcaptchaSiteKey: instance.hcaptchaSiteKey,
|
|
||||||
enableMcaptcha: instance.enableMcaptcha,
|
|
||||||
mcaptchaSiteKey: instance.mcaptchaSitekey,
|
|
||||||
mcaptchaInstanceUrl: instance.mcaptchaInstanceUrl,
|
|
||||||
enableRecaptcha: instance.enableRecaptcha,
|
|
||||||
recaptchaSiteKey: instance.recaptchaSiteKey,
|
|
||||||
enableTurnstile: instance.enableTurnstile,
|
|
||||||
turnstileSiteKey: instance.turnstileSiteKey,
|
|
||||||
swPublickey: instance.swPublicKey,
|
|
||||||
themeColor: instance.themeColor,
|
|
||||||
mascotImageUrl: instance.mascotImageUrl,
|
|
||||||
bannerUrl: instance.bannerUrl,
|
|
||||||
infoImageUrl: instance.infoImageUrl,
|
|
||||||
serverErrorImageUrl: instance.serverErrorImageUrl,
|
|
||||||
notFoundImageUrl: instance.notFoundImageUrl,
|
|
||||||
iconUrl: instance.iconUrl,
|
|
||||||
backgroundImageUrl: instance.backgroundImageUrl,
|
|
||||||
logoImageUrl: instance.logoImageUrl,
|
|
||||||
maxNoteTextLength: MAX_NOTE_TEXT_LENGTH,
|
|
||||||
// クライアントの手間を減らすためあらかじめJSONに変換しておく
|
|
||||||
defaultLightTheme: instance.defaultLightTheme ? JSON.stringify(JSON5.parse(instance.defaultLightTheme)) : null,
|
|
||||||
defaultDarkTheme: instance.defaultDarkTheme ? JSON.stringify(JSON5.parse(instance.defaultDarkTheme)) : null,
|
|
||||||
ads: ads.map(ad => ({
|
|
||||||
id: ad.id,
|
|
||||||
url: ad.url,
|
|
||||||
place: ad.place,
|
|
||||||
ratio: ad.ratio,
|
|
||||||
imageUrl: ad.imageUrl,
|
|
||||||
dayOfWeek: ad.dayOfWeek,
|
|
||||||
})),
|
|
||||||
notesPerOneAd: instance.notesPerOneAd,
|
|
||||||
enableEmail: instance.enableEmail,
|
|
||||||
enableServiceWorker: instance.enableServiceWorker,
|
|
||||||
|
|
||||||
translatorAvailable: instance.deeplAuthKey != null,
|
|
||||||
|
|
||||||
serverRules: instance.serverRules,
|
|
||||||
|
|
||||||
policies: { ...DEFAULT_POLICIES, ...instance.policies },
|
|
||||||
|
|
||||||
mediaProxy: this.config.mediaProxy,
|
|
||||||
|
|
||||||
...(ps.detail ? {
|
|
||||||
cacheRemoteFiles: instance.cacheRemoteFiles,
|
|
||||||
cacheRemoteSensitiveFiles: instance.cacheRemoteSensitiveFiles,
|
|
||||||
requireSetup: !await this.instanceActorService.realLocalUsersPresent(),
|
|
||||||
} : {}),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (ps.detail) {
|
|
||||||
const proxyAccount = instance.proxyAccountId ? await this.userEntityService.pack(instance.proxyAccountId).catch(() => null) : null;
|
|
||||||
|
|
||||||
response.proxyAccountName = proxyAccount ? proxyAccount.username : null;
|
|
||||||
response.features = {
|
|
||||||
registration: !instance.disableRegistration,
|
|
||||||
emailRequiredForSignup: instance.emailRequiredForSignup,
|
|
||||||
hcaptcha: instance.enableHcaptcha,
|
|
||||||
recaptcha: instance.enableRecaptcha,
|
|
||||||
turnstile: instance.enableTurnstile,
|
|
||||||
objectStorage: instance.useObjectStorage,
|
|
||||||
serviceWorker: instance.enableServiceWorker,
|
|
||||||
miauth: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return response;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, Obj
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||||
import { PageEntityService } from '@/core/entities/PageEntityService.js';
|
import { PageEntityService } from '@/core/entities/PageEntityService.js';
|
||||||
|
import { MetaEntityService } from '@/core/entities/MetaEntityService.js';
|
||||||
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
|
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
|
||||||
import { ClipEntityService } from '@/core/entities/ClipEntityService.js';
|
import { ClipEntityService } from '@/core/entities/ClipEntityService.js';
|
||||||
import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js';
|
import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js';
|
||||||
|
@ -93,6 +94,7 @@ export class ClientServerService {
|
||||||
private userEntityService: UserEntityService,
|
private userEntityService: UserEntityService,
|
||||||
private noteEntityService: NoteEntityService,
|
private noteEntityService: NoteEntityService,
|
||||||
private pageEntityService: PageEntityService,
|
private pageEntityService: PageEntityService,
|
||||||
|
private metaEntityService: MetaEntityService,
|
||||||
private galleryPostEntityService: GalleryPostEntityService,
|
private galleryPostEntityService: GalleryPostEntityService,
|
||||||
private clipEntityService: ClipEntityService,
|
private clipEntityService: ClipEntityService,
|
||||||
private channelEntityService: ChannelEntityService,
|
private channelEntityService: ChannelEntityService,
|
||||||
|
@ -173,7 +175,7 @@ export class ClientServerService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private generateCommonPugData(meta: MiMeta) {
|
private async generateCommonPugData(meta: MiMeta) {
|
||||||
return {
|
return {
|
||||||
instanceName: meta.name ?? 'Misskey',
|
instanceName: meta.name ?? 'Misskey',
|
||||||
icon: meta.iconUrl,
|
icon: meta.iconUrl,
|
||||||
|
@ -183,6 +185,8 @@ export class ClientServerService {
|
||||||
infoImageUrl: meta.infoImageUrl ?? 'https://xn--931a.moe/assets/info.jpg',
|
infoImageUrl: meta.infoImageUrl ?? 'https://xn--931a.moe/assets/info.jpg',
|
||||||
notFoundImageUrl: meta.notFoundImageUrl ?? 'https://xn--931a.moe/assets/not-found.jpg',
|
notFoundImageUrl: meta.notFoundImageUrl ?? 'https://xn--931a.moe/assets/not-found.jpg',
|
||||||
instanceUrl: this.config.url,
|
instanceUrl: this.config.url,
|
||||||
|
metaJson: JSON.stringify(await this.metaEntityService.packDetailed(meta)),
|
||||||
|
now: Date.now(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,7 +437,7 @@ export class ClientServerService {
|
||||||
url: this.config.url,
|
url: this.config.url,
|
||||||
title: meta.name ?? 'Misskey',
|
title: meta.name ?? 'Misskey',
|
||||||
desc: meta.description,
|
desc: meta.description,
|
||||||
...this.generateCommonPugData(meta),
|
...await this.generateCommonPugData(meta),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -520,7 +524,7 @@ export class ClientServerService {
|
||||||
user, profile, me,
|
user, profile, me,
|
||||||
avatarUrl: user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user),
|
avatarUrl: user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user),
|
||||||
sub: request.params.sub,
|
sub: request.params.sub,
|
||||||
...this.generateCommonPugData(meta),
|
...await this.generateCommonPugData(meta),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// リモートユーザーなので
|
// リモートユーザーなので
|
||||||
|
@ -570,7 +574,7 @@ export class ClientServerService {
|
||||||
avatarUrl: _note.user.avatarUrl,
|
avatarUrl: _note.user.avatarUrl,
|
||||||
// TODO: Let locale changeable by instance setting
|
// TODO: Let locale changeable by instance setting
|
||||||
summary: getNoteSummary(_note),
|
summary: getNoteSummary(_note),
|
||||||
...this.generateCommonPugData(meta),
|
...await this.generateCommonPugData(meta),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
|
@ -609,7 +613,7 @@ export class ClientServerService {
|
||||||
page: _page,
|
page: _page,
|
||||||
profile,
|
profile,
|
||||||
avatarUrl: _page.user.avatarUrl,
|
avatarUrl: _page.user.avatarUrl,
|
||||||
...this.generateCommonPugData(meta),
|
...await this.generateCommonPugData(meta),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
|
@ -635,7 +639,7 @@ export class ClientServerService {
|
||||||
flash: _flash,
|
flash: _flash,
|
||||||
profile,
|
profile,
|
||||||
avatarUrl: _flash.user.avatarUrl,
|
avatarUrl: _flash.user.avatarUrl,
|
||||||
...this.generateCommonPugData(meta),
|
...await this.generateCommonPugData(meta),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
|
@ -661,7 +665,7 @@ export class ClientServerService {
|
||||||
clip: _clip,
|
clip: _clip,
|
||||||
profile,
|
profile,
|
||||||
avatarUrl: _clip.user.avatarUrl,
|
avatarUrl: _clip.user.avatarUrl,
|
||||||
...this.generateCommonPugData(meta),
|
...await this.generateCommonPugData(meta),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
|
@ -685,7 +689,7 @@ export class ClientServerService {
|
||||||
post: _post,
|
post: _post,
|
||||||
profile,
|
profile,
|
||||||
avatarUrl: _post.user.avatarUrl,
|
avatarUrl: _post.user.avatarUrl,
|
||||||
...this.generateCommonPugData(meta),
|
...await this.generateCommonPugData(meta),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
|
@ -704,7 +708,7 @@ export class ClientServerService {
|
||||||
reply.header('Cache-Control', 'public, max-age=15');
|
reply.header('Cache-Control', 'public, max-age=15');
|
||||||
return await reply.view('channel', {
|
return await reply.view('channel', {
|
||||||
channel: _channel,
|
channel: _channel,
|
||||||
...this.generateCommonPugData(meta),
|
...await this.generateCommonPugData(meta),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
|
@ -723,7 +727,7 @@ export class ClientServerService {
|
||||||
reply.header('Cache-Control', 'public, max-age=3600');
|
reply.header('Cache-Control', 'public, max-age=3600');
|
||||||
return await reply.view('reversi-game', {
|
return await reply.view('reversi-game', {
|
||||||
game: _game,
|
game: _game,
|
||||||
...this.generateCommonPugData(meta),
|
...await this.generateCommonPugData(meta),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
|
|
|
@ -68,6 +68,9 @@ html
|
||||||
var VERSION = "#{version}";
|
var VERSION = "#{version}";
|
||||||
var CLIENT_ENTRY = "#{clientEntry.file}";
|
var CLIENT_ENTRY = "#{clientEntry.file}";
|
||||||
|
|
||||||
|
script(type='application/json' id='misskey_meta' data-generated-at=now)
|
||||||
|
!= metaJson
|
||||||
|
|
||||||
script
|
script
|
||||||
include ../boot.js
|
include ../boot.js
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { alert, confirm, popup, post, toast } from '@/os.js';
|
||||||
import { useStream } from '@/stream.js';
|
import { useStream } from '@/stream.js';
|
||||||
import * as sound from '@/scripts/sound.js';
|
import * as sound from '@/scripts/sound.js';
|
||||||
import { $i, signout, updateAccount } from '@/account.js';
|
import { $i, signout, updateAccount } from '@/account.js';
|
||||||
import { fetchInstance, instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
import { ColdDeviceStorage, defaultStore } from '@/store.js';
|
import { ColdDeviceStorage, defaultStore } from '@/store.js';
|
||||||
import { makeHotkey } from '@/scripts/hotkey.js';
|
import { makeHotkey } from '@/scripts/hotkey.js';
|
||||||
import { reactionPicker } from '@/scripts/reaction-picker.js';
|
import { reactionPicker } from '@/scripts/reaction-picker.js';
|
||||||
|
@ -235,12 +235,10 @@ export async function mainBoot() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchInstance().then(() => {
|
const modifiedVersionMustProminentlyOfferInAgplV3Section13Read = miLocalStorage.getItem('modifiedVersionMustProminentlyOfferInAgplV3Section13Read');
|
||||||
const modifiedVersionMustProminentlyOfferInAgplV3Section13Read = miLocalStorage.getItem('modifiedVersionMustProminentlyOfferInAgplV3Section13Read');
|
if (modifiedVersionMustProminentlyOfferInAgplV3Section13Read !== 'true' && instance.repositoryUrl !== 'https://github.com/misskey-dev/misskey') {
|
||||||
if (modifiedVersionMustProminentlyOfferInAgplV3Section13Read !== 'true' && instance.repositoryUrl !== 'https://github.com/misskey-dev/misskey') {
|
popup(defineAsyncComponent(() => import('@/components/MkSourceCodeAvailablePopup.vue')), {}, {}, 'closed');
|
||||||
popup(defineAsyncComponent(() => import('@/components/MkSourceCodeAvailablePopup.vue')), {}, {}, 'closed');
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if ('Notification' in window) {
|
if ('Notification' in window) {
|
||||||
// 許可を得ていなかったらリクエスト
|
// 許可を得ていなかったらリクエスト
|
||||||
|
|
|
@ -11,13 +11,24 @@ import { DEFAULT_INFO_IMAGE_URL, DEFAULT_NOT_FOUND_IMAGE_URL, DEFAULT_SERVER_ERR
|
||||||
|
|
||||||
// TODO: 他のタブと永続化されたstateを同期
|
// TODO: 他のタブと永続化されたstateを同期
|
||||||
|
|
||||||
const cached = miLocalStorage.getItem('instance');
|
//#region loader
|
||||||
|
const providedMetaEl = document.getElementById('misskey_meta');
|
||||||
|
|
||||||
|
let cachedMeta = miLocalStorage.getItem('instance') ? JSON.parse(miLocalStorage.getItem('instance')!) : null;
|
||||||
|
let cachedAt = miLocalStorage.getItem('instanceCachedAt') ? parseInt(miLocalStorage.getItem('instanceCachedAt')!) : 0;
|
||||||
|
const providedMeta = providedMetaEl && providedMetaEl.textContent ? JSON.parse(providedMetaEl.textContent) : null;
|
||||||
|
const providedAt = providedMetaEl && providedMetaEl.dataset.generatedAt ? parseInt(providedMetaEl.dataset.generatedAt) : 0;
|
||||||
|
if (providedAt > cachedAt) {
|
||||||
|
miLocalStorage.setItem('instance', JSON.stringify(providedMeta));
|
||||||
|
miLocalStorage.setItem('instanceCachedAt', providedAt.toString());
|
||||||
|
cachedMeta = providedMeta;
|
||||||
|
cachedAt = providedAt;
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
// TODO: instanceをリアクティブにするかは再考の余地あり
|
// TODO: instanceをリアクティブにするかは再考の余地あり
|
||||||
|
|
||||||
export const instance: Misskey.entities.MetaResponse = reactive(cached ? JSON.parse(cached) : {
|
export const instance: Misskey.entities.MetaResponse = reactive(cachedMeta ?? {});
|
||||||
// TODO: set default values
|
|
||||||
});
|
|
||||||
|
|
||||||
export const serverErrorImageUrl = computed(() => instance.serverErrorImageUrl ?? DEFAULT_SERVER_ERROR_IMAGE_URL);
|
export const serverErrorImageUrl = computed(() => instance.serverErrorImageUrl ?? DEFAULT_SERVER_ERROR_IMAGE_URL);
|
||||||
|
|
||||||
|
@ -25,7 +36,15 @@ export const infoImageUrl = computed(() => instance.infoImageUrl ?? DEFAULT_INFO
|
||||||
|
|
||||||
export const notFoundImageUrl = computed(() => instance.notFoundImageUrl ?? DEFAULT_NOT_FOUND_IMAGE_URL);
|
export const notFoundImageUrl = computed(() => instance.notFoundImageUrl ?? DEFAULT_NOT_FOUND_IMAGE_URL);
|
||||||
|
|
||||||
export async function fetchInstance() {
|
export async function fetchInstance(force = false): Promise<void> {
|
||||||
|
if (!force) {
|
||||||
|
const cachedAt = miLocalStorage.getItem('instanceCachedAt') ? parseInt(miLocalStorage.getItem('instanceCachedAt')!) : 0;
|
||||||
|
|
||||||
|
if (Date.now() - cachedAt < 1000 * 60 * 60) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const meta = await misskeyApi('meta', {
|
const meta = await misskeyApi('meta', {
|
||||||
detail: false,
|
detail: false,
|
||||||
});
|
});
|
||||||
|
@ -35,4 +54,5 @@ export async function fetchInstance() {
|
||||||
}
|
}
|
||||||
|
|
||||||
miLocalStorage.setItem('instance', JSON.stringify(instance));
|
miLocalStorage.setItem('instance', JSON.stringify(instance));
|
||||||
|
miLocalStorage.setItem('instanceCachedAt', Date.now().toString());
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ type Keys =
|
||||||
'v' |
|
'v' |
|
||||||
'lastVersion' |
|
'lastVersion' |
|
||||||
'instance' |
|
'instance' |
|
||||||
|
'instanceCachedAt' |
|
||||||
'account' |
|
'account' |
|
||||||
'accounts' |
|
'accounts' |
|
||||||
'latestDonationInfoShownAt' |
|
'latestDonationInfoShownAt' |
|
||||||
|
|
|
@ -142,7 +142,7 @@ function save() {
|
||||||
turnstileSiteKey: turnstileSiteKey.value,
|
turnstileSiteKey: turnstileSiteKey.value,
|
||||||
turnstileSecretKey: turnstileSecretKey.value,
|
turnstileSecretKey: turnstileSecretKey.value,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance();
|
fetchInstance(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -169,7 +169,7 @@ function save() {
|
||||||
feedbackUrl: feedbackUrl.value === '' ? null : feedbackUrl.value,
|
feedbackUrl: feedbackUrl.value === '' ? null : feedbackUrl.value,
|
||||||
manifestJsonOverride: manifestJsonOverride.value === '' ? '{}' : JSON.stringify(JSON5.parse(manifestJsonOverride.value)),
|
manifestJsonOverride: manifestJsonOverride.value === '' ? '{}' : JSON.stringify(JSON5.parse(manifestJsonOverride.value)),
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance();
|
fetchInstance(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,7 +124,7 @@ function save() {
|
||||||
smtpUser: smtpUser.value,
|
smtpUser: smtpUser.value,
|
||||||
smtpPass: smtpPass.value,
|
smtpPass: smtpPass.value,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance();
|
fetchInstance(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ function save() {
|
||||||
deeplAuthKey: deeplAuthKey.value,
|
deeplAuthKey: deeplAuthKey.value,
|
||||||
deeplIsPro: deeplIsPro.value,
|
deeplIsPro: deeplIsPro.value,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance();
|
fetchInstance(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ function save() {
|
||||||
silencedHosts: silencedHosts.value.split('\n') || [],
|
silencedHosts: silencedHosts.value.split('\n') || [],
|
||||||
|
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance();
|
fetchInstance(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,7 +110,7 @@ function save() {
|
||||||
hiddenTags: hiddenTags.value.split('\n'),
|
hiddenTags: hiddenTags.value.split('\n'),
|
||||||
preservedUsernames: preservedUsernames.value.split('\n'),
|
preservedUsernames: preservedUsernames.value.split('\n'),
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance();
|
fetchInstance(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -143,7 +143,7 @@ function save() {
|
||||||
objectStorageSetPublicRead: objectStorageSetPublicRead.value,
|
objectStorageSetPublicRead: objectStorageSetPublicRead.value,
|
||||||
objectStorageS3ForcePathStyle: objectStorageS3ForcePathStyle.value,
|
objectStorageS3ForcePathStyle: objectStorageS3ForcePathStyle.value,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance();
|
fetchInstance(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ function save() {
|
||||||
enableChartsForRemoteUser: enableChartsForRemoteUser.value,
|
enableChartsForRemoteUser: enableChartsForRemoteUser.value,
|
||||||
enableChartsForFederatedInstances: enableChartsForFederatedInstances.value,
|
enableChartsForFederatedInstances: enableChartsForFederatedInstances.value,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance();
|
fetchInstance(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ function save() {
|
||||||
os.apiWithDialog('admin/update-meta', {
|
os.apiWithDialog('admin/update-meta', {
|
||||||
proxyAccountId: proxyAccountId.value,
|
proxyAccountId: proxyAccountId.value,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance();
|
fetchInstance(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -196,7 +196,7 @@ async function init() {
|
||||||
enableTruemailApi.value = meta.enableTruemailApi;
|
enableTruemailApi.value = meta.enableTruemailApi;
|
||||||
truemailInstance.value = meta.truemailInstance;
|
truemailInstance.value = meta.truemailInstance;
|
||||||
truemailAuthKey.value = meta.truemailAuthKey;
|
truemailAuthKey.value = meta.truemailAuthKey;
|
||||||
bannedEmailDomains.value = meta.bannedEmailDomains?.join('\n') || "";
|
bannedEmailDomains.value = meta.bannedEmailDomains?.join('\n') || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function save() {
|
function save() {
|
||||||
|
@ -221,7 +221,7 @@ function save() {
|
||||||
truemailAuthKey: truemailAuthKey.value,
|
truemailAuthKey: truemailAuthKey.value,
|
||||||
bannedEmailDomains: bannedEmailDomains.value.split('\n'),
|
bannedEmailDomains: bannedEmailDomains.value.split('\n'),
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance();
|
fetchInstance(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ const save = async () => {
|
||||||
await os.apiWithDialog('admin/update-meta', {
|
await os.apiWithDialog('admin/update-meta', {
|
||||||
serverRules: serverRules.value,
|
serverRules: serverRules.value,
|
||||||
});
|
});
|
||||||
fetchInstance();
|
fetchInstance(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const remove = (index: number): void => {
|
const remove = (index: number): void => {
|
||||||
|
|
|
@ -243,7 +243,7 @@ async function save(): void {
|
||||||
notesPerOneAd: notesPerOneAd.value,
|
notesPerOneAd: notesPerOneAd.value,
|
||||||
});
|
});
|
||||||
|
|
||||||
fetchInstance();
|
fetchInstance(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const headerTabs = computed(() => []);
|
const headerTabs = computed(() => []);
|
||||||
|
|
|
@ -2,14 +2,18 @@ import { unisonReload } from '@/scripts/unison-reload.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { fetchCustomEmojis } from '@/custom-emojis.js';
|
import { fetchCustomEmojis } from '@/custom-emojis.js';
|
||||||
|
import { fetchInstance } from '@/instance.js';
|
||||||
|
|
||||||
export async function clearCache() {
|
export async function clearCache() {
|
||||||
os.waiting();
|
os.waiting();
|
||||||
|
miLocalStorage.removeItem('instance');
|
||||||
|
miLocalStorage.removeItem('instanceCachedAt');
|
||||||
miLocalStorage.removeItem('locale');
|
miLocalStorage.removeItem('locale');
|
||||||
miLocalStorage.removeItem('localeVersion');
|
miLocalStorage.removeItem('localeVersion');
|
||||||
miLocalStorage.removeItem('theme');
|
miLocalStorage.removeItem('theme');
|
||||||
miLocalStorage.removeItem('emojis');
|
miLocalStorage.removeItem('emojis');
|
||||||
miLocalStorage.removeItem('lastEmojisFetchedAt');
|
miLocalStorage.removeItem('lastEmojisFetchedAt');
|
||||||
|
await fetchInstance(true);
|
||||||
await fetchCustomEmojis(true);
|
await fetchCustomEmojis(true);
|
||||||
unisonReload();
|
unisonReload();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1715,7 +1715,10 @@ declare namespace entities {
|
||||||
Role,
|
Role,
|
||||||
RolePolicies,
|
RolePolicies,
|
||||||
ReversiGameLite,
|
ReversiGameLite,
|
||||||
ReversiGameDetailed
|
ReversiGameDetailed,
|
||||||
|
MetaLite,
|
||||||
|
MetaDetailedOnly,
|
||||||
|
MetaDetailed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export { entities }
|
export { entities }
|
||||||
|
@ -2223,6 +2226,15 @@ type MeDetailed = components['schemas']['MeDetailed'];
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type MeDetailedOnly = components['schemas']['MeDetailedOnly'];
|
type MeDetailedOnly = components['schemas']['MeDetailedOnly'];
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
type MetaDetailed = components['schemas']['MetaDetailed'];
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
type MetaDetailedOnly = components['schemas']['MetaDetailedOnly'];
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
type MetaLite = components['schemas']['MetaLite'];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type MetaRequest = operations['meta']['requestBody']['content']['application/json'];
|
type MetaRequest = operations['meta']['requestBody']['content']['application/json'];
|
||||||
|
|
||||||
|
|
|
@ -46,3 +46,6 @@ export type Role = components['schemas']['Role'];
|
||||||
export type RolePolicies = components['schemas']['RolePolicies'];
|
export type RolePolicies = components['schemas']['RolePolicies'];
|
||||||
export type ReversiGameLite = components['schemas']['ReversiGameLite'];
|
export type ReversiGameLite = components['schemas']['ReversiGameLite'];
|
||||||
export type ReversiGameDetailed = components['schemas']['ReversiGameDetailed'];
|
export type ReversiGameDetailed = components['schemas']['ReversiGameDetailed'];
|
||||||
|
export type MetaLite = components['schemas']['MetaLite'];
|
||||||
|
export type MetaDetailedOnly = components['schemas']['MetaDetailedOnly'];
|
||||||
|
export type MetaDetailed = components['schemas']['MetaDetailed'];
|
||||||
|
|
|
@ -4724,6 +4724,96 @@ export type components = {
|
||||||
logs: number[][];
|
logs: number[][];
|
||||||
map: string[];
|
map: string[];
|
||||||
};
|
};
|
||||||
|
MetaLite: {
|
||||||
|
maintainerName: string | null;
|
||||||
|
maintainerEmail: string | null;
|
||||||
|
version: string;
|
||||||
|
providesTarball: boolean;
|
||||||
|
name: string | null;
|
||||||
|
shortName: string | null;
|
||||||
|
/**
|
||||||
|
* Format: url
|
||||||
|
* @example https://misskey.example.com
|
||||||
|
*/
|
||||||
|
uri: string;
|
||||||
|
description: string | null;
|
||||||
|
langs: string[];
|
||||||
|
tosUrl: string | null;
|
||||||
|
/** @default https://github.com/misskey-dev/misskey */
|
||||||
|
repositoryUrl: string | null;
|
||||||
|
/** @default https://github.com/misskey-dev/misskey/issues/new */
|
||||||
|
feedbackUrl: string | null;
|
||||||
|
defaultDarkTheme: string | null;
|
||||||
|
defaultLightTheme: string | null;
|
||||||
|
disableRegistration: boolean;
|
||||||
|
emailRequiredForSignup: boolean;
|
||||||
|
enableHcaptcha: boolean;
|
||||||
|
hcaptchaSiteKey: string | null;
|
||||||
|
enableMcaptcha: boolean;
|
||||||
|
mcaptchaSiteKey: string | null;
|
||||||
|
mcaptchaInstanceUrl: string | null;
|
||||||
|
enableRecaptcha: boolean;
|
||||||
|
recaptchaSiteKey: string | null;
|
||||||
|
enableTurnstile: boolean;
|
||||||
|
turnstileSiteKey: string | null;
|
||||||
|
swPublickey: string | null;
|
||||||
|
/** @default /assets/ai.png */
|
||||||
|
mascotImageUrl: string;
|
||||||
|
bannerUrl: string | null;
|
||||||
|
serverErrorImageUrl: string | null;
|
||||||
|
infoImageUrl: string | null;
|
||||||
|
notFoundImageUrl: string | null;
|
||||||
|
iconUrl: string | null;
|
||||||
|
maxNoteTextLength: number;
|
||||||
|
ads: {
|
||||||
|
/**
|
||||||
|
* Format: id
|
||||||
|
* @example xxxxxxxxxx
|
||||||
|
*/
|
||||||
|
id: string;
|
||||||
|
/** Format: url */
|
||||||
|
url: string;
|
||||||
|
place: string;
|
||||||
|
ratio: number;
|
||||||
|
/** Format: url */
|
||||||
|
imageUrl: string;
|
||||||
|
dayOfWeek: number;
|
||||||
|
}[];
|
||||||
|
/** @default 0 */
|
||||||
|
notesPerOneAd: number;
|
||||||
|
enableEmail: boolean;
|
||||||
|
enableServiceWorker: boolean;
|
||||||
|
translatorAvailable: boolean;
|
||||||
|
mediaProxy: string;
|
||||||
|
backgroundImageUrl: string | null;
|
||||||
|
impressumUrl: string | null;
|
||||||
|
logoImageUrl: string | null;
|
||||||
|
privacyPolicyUrl: string | null;
|
||||||
|
serverRules: string[];
|
||||||
|
themeColor: string | null;
|
||||||
|
policies: components['schemas']['RolePolicies'];
|
||||||
|
};
|
||||||
|
MetaDetailedOnly: {
|
||||||
|
features?: {
|
||||||
|
registration: boolean;
|
||||||
|
emailRequiredForSignup: boolean;
|
||||||
|
localTimeline: boolean;
|
||||||
|
globalTimeline: boolean;
|
||||||
|
hcaptcha: boolean;
|
||||||
|
turnstile: boolean;
|
||||||
|
recaptcha: boolean;
|
||||||
|
objectStorage: boolean;
|
||||||
|
serviceWorker: boolean;
|
||||||
|
/** @default true */
|
||||||
|
miauth?: boolean;
|
||||||
|
};
|
||||||
|
proxyAccountName: string | null;
|
||||||
|
/** @example false */
|
||||||
|
requireSetup: boolean;
|
||||||
|
cacheRemoteFiles: boolean;
|
||||||
|
cacheRemoteSensitiveFiles: boolean;
|
||||||
|
};
|
||||||
|
MetaDetailed: components['schemas']['MetaLite'] & components['schemas']['MetaDetailedOnly'];
|
||||||
};
|
};
|
||||||
responses: never;
|
responses: never;
|
||||||
parameters: never;
|
parameters: never;
|
||||||
|
@ -19448,91 +19538,7 @@ export type operations = {
|
||||||
/** @description OK (with results) */
|
/** @description OK (with results) */
|
||||||
200: {
|
200: {
|
||||||
content: {
|
content: {
|
||||||
'application/json': {
|
'application/json': components['schemas']['MetaLite'] | components['schemas']['MetaDetailed'];
|
||||||
maintainerName: string | null;
|
|
||||||
maintainerEmail: string | null;
|
|
||||||
version: string;
|
|
||||||
providesTarball: boolean;
|
|
||||||
name: string;
|
|
||||||
shortName: string | null;
|
|
||||||
/**
|
|
||||||
* Format: url
|
|
||||||
* @example https://misskey.example.com
|
|
||||||
*/
|
|
||||||
uri: string;
|
|
||||||
description: string | null;
|
|
||||||
langs: string[];
|
|
||||||
tosUrl: string | null;
|
|
||||||
/** @default https://github.com/misskey-dev/misskey */
|
|
||||||
repositoryUrl: string | null;
|
|
||||||
/** @default https://github.com/misskey-dev/misskey/issues/new */
|
|
||||||
feedbackUrl: string | null;
|
|
||||||
defaultDarkTheme: string | null;
|
|
||||||
defaultLightTheme: string | null;
|
|
||||||
disableRegistration: boolean;
|
|
||||||
cacheRemoteFiles: boolean;
|
|
||||||
cacheRemoteSensitiveFiles: boolean;
|
|
||||||
emailRequiredForSignup: boolean;
|
|
||||||
enableHcaptcha: boolean;
|
|
||||||
hcaptchaSiteKey: string | null;
|
|
||||||
enableMcaptcha: boolean;
|
|
||||||
mcaptchaSiteKey: string | null;
|
|
||||||
mcaptchaInstanceUrl: string | null;
|
|
||||||
enableRecaptcha: boolean;
|
|
||||||
recaptchaSiteKey: string | null;
|
|
||||||
enableTurnstile: boolean;
|
|
||||||
turnstileSiteKey: string | null;
|
|
||||||
swPublickey: string | null;
|
|
||||||
/** @default /assets/ai.png */
|
|
||||||
mascotImageUrl: string;
|
|
||||||
bannerUrl: string;
|
|
||||||
serverErrorImageUrl: string | null;
|
|
||||||
infoImageUrl: string | null;
|
|
||||||
notFoundImageUrl: string | null;
|
|
||||||
iconUrl: string | null;
|
|
||||||
maxNoteTextLength: number;
|
|
||||||
ads: {
|
|
||||||
/**
|
|
||||||
* Format: id
|
|
||||||
* @example xxxxxxxxxx
|
|
||||||
*/
|
|
||||||
id: string;
|
|
||||||
/** Format: url */
|
|
||||||
url: string;
|
|
||||||
place: string;
|
|
||||||
ratio: number;
|
|
||||||
/** Format: url */
|
|
||||||
imageUrl: string;
|
|
||||||
dayOfWeek: number;
|
|
||||||
}[];
|
|
||||||
/** @default 0 */
|
|
||||||
notesPerOneAd: number;
|
|
||||||
/** @example false */
|
|
||||||
requireSetup: boolean;
|
|
||||||
enableEmail: boolean;
|
|
||||||
enableServiceWorker: boolean;
|
|
||||||
translatorAvailable: boolean;
|
|
||||||
proxyAccountName: string | null;
|
|
||||||
mediaProxy: string;
|
|
||||||
features?: {
|
|
||||||
registration: boolean;
|
|
||||||
localTimeline: boolean;
|
|
||||||
globalTimeline: boolean;
|
|
||||||
hcaptcha: boolean;
|
|
||||||
recaptcha: boolean;
|
|
||||||
objectStorage: boolean;
|
|
||||||
serviceWorker: boolean;
|
|
||||||
/** @default true */
|
|
||||||
miauth?: boolean;
|
|
||||||
};
|
|
||||||
backgroundImageUrl: string | null;
|
|
||||||
impressumUrl: string | null;
|
|
||||||
logoImageUrl: string | null;
|
|
||||||
privacyPolicyUrl: string | null;
|
|
||||||
serverRules: string[];
|
|
||||||
themeColor: string | null;
|
|
||||||
policies: components['schemas']['RolePolicies'];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/** @description Client error */
|
/** @description Client error */
|
||||||
|
|
Loading…
Reference in a new issue