ACCESS_TOKEN_URL |
Type : string
|
Default value : 'https://disqus.com/api/oauth/2.0/access_token/'
|
AUTHORIZE_URL |
Type : string
|
Default value : 'https://disqus.com/api/oauth/2.0/authorize'
|
DISQUS_PUBKEY |
Default value : `E8Uh5l5fHZ6gD8U3KycjAIAk46f68Zw7C6eW8WSjZvCLXebZ7p0r1yrYDrLilk2F`
|
getApiURL |
Default value : (resource: string) => `https://disqus.com/api/3.0/${resource}.json`
|
normalizeAxiosError |
Default value : (error: any) => {
return error?.response?.data?.response || error?.response?.data || error?.toJSON() || error?.message || error
}
|
AdminProvider |
Default value : getProviderByTypegooseClass(Admin)
|
DEFAULT_ADMIN_PROFILE |
Default value : Object.freeze<Admin>({
name: '',
slogan: '',
avatar: ''
})
|
AKISMET |
Type : object
|
Default value : {
key: argv.akismet_key || 'your Akismet Key',
blog: argv.akismet_blog || 'your Akismet blog site, e.g. https://surmon.me'
}
|
APP |
Type : object
|
Default value : {
PORT: 8000,
ROOT_PATH,
DEFAULT_CACHE_TTL: 0,
MASTER: 'Surmon',
NAME: 'NodePress',
URL: 'https://api.surmon.me',
ADMIN_EMAIL: argv.admin_email || 'admin email, e.g. [email protected]',
FE_NAME: 'Surmon.me',
FE_URL: 'https://surmon.me',
STATIC_URL: 'https://static.surmon.me'
}
|
argv |
Default value : yargs.argv as Record<string, string | void>
|
AUTH |
Type : object
|
Default value : {
expiresIn: argv.auth_expires_in || 3600,
data: argv.auth_data || { user: 'root' },
jwtSecret: argv.auth_key || 'nodepress',
defaultPassword: argv.auth_default_password || 'root'
}
|
AWS |
Type : object
|
Default value : {
accessKeyId: argv.aws_access_key_id as string,
secretAccessKey: argv.aws_secret_access_key as string,
s3StaticRegion: argv.aws_s3_static_region as string,
s3StaticBucket: argv.aws_s3_static_bucket as string
}
|
BING_INDEXED |
Type : object
|
Default value : {
site: argv.bing_site || 'your bing site url. e.g. https://surmon.me',
apiKey: argv.bing_api_key || 'your bing webmaster api key'
}
|
CROSS_DOMAIN |
Type : object
|
Default value : {
allowedOrigins: ['https://surmon.me', 'https://cdn.surmon.me', 'https://admin.surmon.me'],
allowedReferer: 'surmon.me'
}
|
DB_BACKUP |
Type : object
|
Default value : {
s3Region: argv.db_backup_s3_region as string,
s3Bucket: argv.db_backup_s3_bucket as string,
password: argv.db_backup_file_password as string
}
|
DISQUS |
Type : object
|
Default value : {
// https://disqus.com/api/applications/<app_id> & Keep permissions: <Read, Write, Manage Forums>
adminAccessToken: argv.disqus_admin_access_token || 'Disqus admin access_token',
adminUsername: argv.disqus_admin_username || 'Disqus admin username',
forum: argv.disqus_forum_shortname || 'Disqus forum shortname',
// https://disqus.com/api/applications/
publicKey: argv.disqus_public_key || 'Disqus application public_key',
secretKey: argv.disqus_secret_key || 'Disqus application secret_key'
}
|
Type : object
|
Default value : {
port: 587,
host: argv.email_host || 'your email host, e.g. smtp.qq.com',
account: argv.email_account || 'your email address, e.g. [email protected]',
password: argv.email_password || 'your email password',
from: `"${APP.FE_NAME}" <${argv.email_from || argv.email_account}>`
}
|
Type : object
|
Default value : {
analyticsV4PropertyId: argv.google_analytics_v4_property_id,
jwtServiceAccountCredentials: argv.google_jwt_cred_json ? JSON.parse(argv.google_jwt_cred_json as string) : null
}
|
MONGO_DB |
Type : object
|
Default value : {
uri: argv.db_uri || `mongodb://127.0.0.1:27017/NodePress`
}
|
packageJSON |
Default value : require(path.resolve(ROOT_PATH, 'package.json'))
|
PROJECT |
Type : object
|
Default value : {
name: packageJSON.name,
version: packageJSON.version,
author: packageJSON.author,
homepage: packageJSON.homepage,
documentation: packageJSON.documentation,
repository: packageJSON.repository.url
}
|
REDIS |
Type : object
|
Default value : {
namespace: argv.redis_namespace || 'nodepress',
host: argv.redis_host || 'localhost',
port: argv.redis_port || 6379,
username: argv.redis_username || null,
password: argv.redis_password || null
}
|
ROOT_PATH |
Default value : path.join(__dirname, '..')
|
ANNOUNCEMENT_STATES |
Default value : [PublishState.Draft, PublishState.Published] as const
|
AnnouncementProvider |
Default value : getProviderByTypegooseClass(Announcement)
|
ARTICLE_DEFAULT_META |
Type : ArticleMeta
|
Default value : Object.freeze({
likes: 0,
views: 0,
comments: 0
})
|
ARTICLE_FULL_QUERY_REF_POPULATE |
Type : []
|
Default value : ['categories', 'tags']
|
ARTICLE_HOTTEST_SORT_PARAMS |
Default value : Object.freeze({
'meta.comments': SortType.Desc,
'meta.likes': SortType.Desc
})
|
ARTICLE_LANGUAGES |
Default value : [Language.English, Language.Chinese, Language.Mixed] as const
|
ARTICLE_LIST_QUERY_GUEST_FILTER |
Default value : Object.freeze({
state: PublishState.Published,
public: PublicState.Public
})
|
ARTICLE_LIST_QUERY_PROJECTION |
Type : object
|
Default value : { content: false }
|
ARTICLE_ORIGIN_STATES |
Default value : [OriginState.Original, OriginState.Reprint, OriginState.Hybrid] as const
|
ARTICLE_PUBLIC_STATES |
Default value : [PublicState.Public, PublicState.Secret, PublicState.Reserve] as const
|
ARTICLE_PUBLISH_STATES |
Default value : [PublishState.Draft, PublishState.Published, PublishState.Recycle] as const
|
ArticleProvider |
Default value : getProviderByTypegooseClass(Article)
|
ARTICLE_IDENTIFIER_PREFIX |
Type : string
|
Default value : 'article-'
|
ARTICLE_THREAD_ID_EXTEND_KEY |
Type : string
|
Default value : 'disqus-thread-id'
|
COMMENT_ANONYMOUS_EXTEND_KEY |
Type : string
|
Default value : 'disqus-anonymous'
|
COMMENT_AUTHOR_ID_EXTEND_KEY |
Type : string
|
Default value : 'disqus-author-id'
|
COMMENT_AUTHOR_USERNAME_EXTEND_KEY |
Type : string
|
Default value : 'disqus-author-username'
|
COMMENT_POST_ID_EXTEND_KEY |
Type : string
|
Default value : 'disqus-post-id'
|
COMMENT_THREAD_ID_EXTEND_KEY |
Type : string
|
Default value : 'disqus-thread-id'
|
DISQUS_OAUTH_CALLBACK_URL |
Default value : isProdEnv
? `${APP.URL}/disqus/oauth-callback`
: `http://localhost:8000/disqus/oauth-callback`
|
getIDByThreadIdentifier |
Default value : (id: string) => {
return id === GUESTBOOK_IDENTIFIER ? GUESTBOOK_POST_ID : id.replace(ARTICLE_IDENTIFIER_PREFIX, '')
}
|
getThreadIdentifierById |
Default value : (postId: number) => {
return postId === GUESTBOOK_POST_ID ? GUESTBOOK_IDENTIFIER : `${ARTICLE_IDENTIFIER_PREFIX}${postId}`
}
|
GUESTBOOK_IDENTIFIER |
Type : string
|
Default value : 'guestbook'
|
BACKUP_DIR_PATH |
Default value : path.join(APP.ROOT_PATH, 'dbbackup')
|
BACKUP_FILE_NAME |
Type : string
|
Default value : 'nodepress.zip'
|
logger |
Default value : createLogger({ scope: 'DBBackupService', time: isDevEnv })
|
UP_FAILED_TIMEOUT |
Default value : 1000 * 60 * 5
|
UPLOAD_INTERVAL |
Type : string
|
Default value : '0 0 3 * * *'
|
CACHE_KEY_METADATA |
Type : string
|
Default value : '__appCacheKey__'
|
CACHE_TTL_METADATA |
Type : string
|
Default value : '__appCacheTTL__'
|
GUEST_REQUEST_METADATA |
Type : string
|
Default value : '__appGuestRequestOption__'
|
HTTP_ERROR_CODE |
Type : string
|
Default value : '__appHttpErrorCode__'
|
HTTP_ERROR_MESSAGE |
Type : string
|
Default value : '__appHttpErrorMessage__'
|
HTTP_RESPONSE_TRANSFORM |
Type : string
|
Default value : '__appHttpResponseTransform__'
|
HTTP_RESPONSE_TRANSFORM_TO_PAGINATE |
Type : string
|
Default value : '__appHttpResponseTransformToPaginate__'
|
HTTP_SUCCESS_CODE |
Default value : constants.HTTP_CODE_METADATA
|
HTTP_SUCCESS_MESSAGE |
Type : string
|
Default value : '__appHttpSuccessMessage__'
|
CategoryProvider |
Default value : getProviderByTypegooseClass(Category)
|
COMMENT_GUEST_QUERY_FILTER |
Default value : Object.freeze({
state: CommentState.Published
})
|
COMMENT_STATES |
Default value : [
CommentState.Auditing,
CommentState.Published,
CommentState.Deleted,
CommentState.Spam
] as const
|
CommentProvider |
Default value : getProviderByTypegooseClass(Comment)
|
error |
Default value : (message: ResponseMessage, statusCode?: HttpStatus): MethodDecorator => {
return createDecorator({ errorMessage: message, errorCode: statusCode })
}
|
paginate |
Default value : (): MethodDecorator => {
return createDecorator({ usePaginate: true })
}
|
Responser |
Type : object
|
Default value : { error, success, handle, paginate }
|
success |
Default value : (message: ResponseMessage, statusCode?: HttpStatus): MethodDecorator => {
return createDecorator({
successMessage: message,
successCode: statusCode
})
}
|
parseValue |
Default value : <T>(value: string | null | void) => {
return isNil(value) ? UNDEFINED : (JSON.parse(value) as T)
}
|
stringifyValue |
Default value : (value: unknown) => {
return isNil(value) ? '' : JSON.stringify(value)
}
|
databaseProvider |
Type : object
|
Default value : {
inject: [EmailService],
provide: DB_CONNECTION_TOKEN,
useFactory: async (emailService: EmailService) => {
let reconnectionTask: NodeJS.Timeout | null = null
const RECONNECT_INTERVAL = 6000
const sendAlarmMail = (error: string) => {
emailService.sendMailAs(APP_CONFIG.APP.NAME, {
to: APP_CONFIG.APP.ADMIN_EMAIL,
subject: `MongoDB Error!`,
text: error,
html: `<pre><code>${error}</code></pre>`
})
}
const connection = () => {
return mongoose.connect(APP_CONFIG.MONGO_DB.uri, {})
}
// DeprecationWarning: Mongoose: the `strictQuery` option will be switched back to `false` by default in Mongoose 7.
// Use `mongoose.set('strictQuery', false);` if you want to prepare for this change.
// Or use `mongoose.set('strictQuery', true);` to suppress this warning.
// https://mongoosejs.com/docs/guide.html#strictQuery
mongoose.set('strictQuery', false)
mongoose.connection.on('connecting', () => {
logger.log('connecting...')
})
mongoose.connection.on('open', () => {
logger.success('readied (open).')
if (reconnectionTask) {
clearTimeout(reconnectionTask)
reconnectionTask = null
}
})
mongoose.connection.on('disconnected', () => {
logger.error(`disconnected! retry after ${RECONNECT_INTERVAL / 1000}s`)
reconnectionTask = setTimeout(connection, RECONNECT_INTERVAL)
})
mongoose.connection.on('error', (error) => {
logger.error('error!', error)
mongoose.disconnect()
sendAlarmMail(String(error))
})
return await connection()
}
}
|
logger |
Default value : createLogger({ scope: 'MongoDB', time: isDevEnv })
|
DB_CONNECTION_TOKEN |
Type : string
|
Default value : 'DBConnectionToken'
|
DB_MODEL_TOKEN_SUFFIX |
Type : string
|
Default value : 'ModelToken'
|
decodeToken |
Default value : (token: string): AccessToken | null => {
try {
const result = jwt.verify(token, DISQUS.adminAccessToken)
return (result as any) || null
} catch (error) {
return null
}
}
|
encodeToken |
Default value : (token: AccessToken) => {
return jwt.sign(token, DISQUS.adminAccessToken, {
expiresIn: token.expires_in
})
}
|
TOKEN_COOKIE_KEY |
Type : string
|
Default value : '_disqus'
|
DEFAULT_OPTION |
Type : Option
|
Default value : Object.freeze<Option>({
title: 'NodePress',
sub_title: 'Blog server app',
description: 'RESTful API service for blog',
keywords: [],
statement: '',
site_url: 'https://github.com/surmon-china/nodepress',
site_email: '[email protected]',
friend_links: [
{
name: APP.FE_NAME,
value: APP.FE_URL
}
],
meta: { likes: 0 },
blocklist: {
ips: [],
mails: [],
keywords: []
},
ad_config: ''
})
|
OptionProvider |
Default value : getProviderByTypegooseClass(Option)
|
DEFAULT_OPTIONS |
Type : Required<Pick<PaginateOptions, "page" | "perPage" | "dateSort" | "lean">>
|
Default value : Object.freeze({
page: 1,
perPage: 16,
dateSort: -1,
lean: false
})
|
DEFAULT_STATISTIC |
Default value : Object.freeze({
tags: null,
articles: null,
comments: null,
totalViews: null,
totalLikes: null,
todayViews: null,
averageEmotion: null
})
|
logger |
Default value : createLogger({ scope: 'StatisticService', time: isDevEnv })
|
FEEDBACK_EMOTION_VALUES |
Default value : FEEDBACK_EMOTIONS.map((e) => e.value)
|
FEEDBACK_EMOTIONS |
Default value : Array.from(emotionMap.values())
|
FeedbackProvider |
Default value : getProviderByTypegooseClass(Feedback)
|
environment |
Default value : process.env.NODE_ENV
|
isDevEnv |
Default value : Object.is(environment, 'development')
|
isProdEnv |
Default value : Object.is(environment, 'production')
|
isTestEnv |
Default value : Object.is(environment, 'test')
|
GENERAL_AUTO_INCREMENT_ID_CONFIG |
Type : AutoIncrementIDOptions
|
Default value : {
field: 'id',
startAt: 1,
incrementBy: 1,
trackerCollection: 'identitycounters',
trackerModelName: 'identitycounter'
// https://github.com/typegoose/auto-increment
// https://github.com/typegoose/auto-increment/blob/master/src/autoIncrement.ts
// https://github.com/typegoose/auto-increment/issues/11
// https://github.com/typegoose/auto-increment#overwritemodelname
// field: '_id',
// overwriteModelName: 'modelName',
}
|
getCacheKey |
Default value : (target: any): CacheOptions['key'] => {
return reflector.get(META.CACHE_KEY_METADATA, target)
}
|
getCacheTTL |
Default value : (target: any): CacheOptions['ttl'] => {
return reflector.get(META.CACHE_TTL_METADATA, target)
}
|
getDecoratorCacheKey |
Default value : (key: string) => {
return `decorator:${key}`
}
|
getDisqusCacheKey |
Default value : (key: string) => {
return `disqus:${key}`
}
|
getExtendObject |
Default value : (_extends: KeyValueModel[]): { [key: string]: string } => {
return _extends.length ? _extends.reduce((v, c) => ({ ...v, [c.name]: c.value }), {}) : {}
}
|
getExtendValue |
Default value : (_extends: KeyValueModel[], key: string): string | void => {
return _extends.length ? getExtendObject(_extends)[key] : void 0
}
|
getGuestRequestOptions |
Default value : (target: any): Record<string, GuestRequestOption> => {
return reflector.get(GUEST_REQUEST_METADATA, target)
}
|
getTodayViewsCount |
Default value : async (cache: CacheService) => {
const count = await cache.get<number>(CacheKeys.TodayViewCount)
return count ? Number(count) : 0
}
|
increaseTodayViewsCount |
Default value : async (cache: CacheService) => {
const views = await getTodayViewsCount(cache)
await cache.set(CacheKeys.TodayViewCount, views + 1)
return views + 1
}
|
resetTodayViewsCount |
Default value : (cache: CacheService) => {
return cache.set(CacheKeys.TodayViewCount, 0)
}
|
GUESTBOOK_POST_ID |
Type : number
|
Default value : 0
|
ROOT_COMMENT_PID |
Type : number
|
Default value : 0
|
ROOT_FEEDBACK_TID |
Type : number
|
Default value : 0
|
HTTP_ANONYMOUS_TEXT |
Type : string
|
Default value : 'Who are U?'
|
HTTP_BAD_REQUEST_TEXT_DEFAULT |
Type : string
|
Default value : 'Unknown error'
|
HTTP_DEFAULT_ERROR_TEXT |
Default value : HTTP_DEFAULT_TEXT + HTTP_ERROR_SUFFIX
|
HTTP_DEFAULT_SUCCESS_TEXT |
Default value : HTTP_DEFAULT_TEXT + HTTP_SUCCESS_SUFFIX
|
HTTP_DEFAULT_TEXT |
Type : string
|
Default value : 'request'
|
HTTP_ERROR_SUFFIX |
Type : string
|
Default value : ' failed'
|
HTTP_PARAMS_PERMISSION_ERROR_DEFAULT |
Type : string
|
Default value : 'Permission denied'
|
HTTP_SUCCESS_SUFFIX |
Type : string
|
Default value : ' succeeded'
|
HTTP_UNAUTHORIZED_TEXT_DEFAULT |
Type : string
|
Default value : 'Unauthorized'
|
VALIDATION_ERROR_DEFAULT |
Type : string
|
Default value : 'Invalid params'
|
isNil |
Default value : (value): value is null | void => isNull(value) || isUndefined(value)
|
isNull |
Default value : (value): value is null => value === NULL
|
isUndefined |
Default value : (value): value is void => value === UNDEFINED
|
NULL |
Type : null
|
Default value : null
|
UNDEFINED |
Default value : void 0
|
isUnverifiableMetaType |
Default value : (metatype: any): metatype is undefined => {
const basicTypes = [String, Boolean, Number, Array, Object]
return !metatype || basicTypes.includes(metatype)
}
|
logger |
Default value : createLogger({ scope: 'CacheInterceptor', time: isDevEnv })
|
logger |
Default value : createLogger({ scope: 'LoggingInterceptor', time: isDevEnv })
|
logger |
Default value : createLogger({ scope: 'ArchiveService', time: isDevEnv })
|
logger |
Default value : createLogger({ scope: 'CategoryService', time: isDevEnv })
|
logger |
Default value : createLogger({ scope: 'CommentService', time: isDevEnv })
|
logger |
Default value : createLogger({ scope: 'DisqusPrivateService', time: isDevEnv })
|
logger |
Default value : createLogger({ scope: 'DisqusPublicService', time: isDevEnv })
|
logger |
Default value : createLogger({ scope: 'OptionService', time: isDevEnv })
|
logger |
Default value : createLogger({ scope: 'TagService', time: isDevEnv })
|
logger |
Default value : createLogger({ scope: 'CacheService', time: isDevEnv })
|
logger |
Default value : createLogger({ scope: 'RedisService', time: isDevEnv })
|
logger |
Default value : createLogger({ scope: 'AkismetService', time: isDevEnv })
|
logger |
Default value : createLogger({ scope: 'EmailService', time: isDevEnv })
|
logger |
Default value : createLogger({ scope: 'GoogleAPIService', time: isDevEnv })
|
logger |
Default value : createLogger({ scope: 'IPService', time: isDevEnv })
|
logger |
Default value : createLogger({ scope: 'SeoService', time: isDevEnv })
|
reflector |
Default value : new Reflector()
|
services |
Type : []
|
Default value : [GoogleService, AkismetService, AWSService, EmailService, SeoService, IPService]
|
TagProvider |
Default value : getProviderByTypegooseClass(Tag)
|
VOTE_AUTHOR_TYPES |
Default value : [VoteAuthorType.Anonymous, VoteAuthorType.Guest, VoteAuthorType.Disqus] as const
|
VOTE_TARGETS |
Default value : [VoteTarget.Post, VoteTarget.Comment] as const
|
VOTE_TYPES |
Default value : [VoteType.Upvote, VoteType.Downvote] as const
|
VoteProvider |
Default value : getProviderByTypegooseClass(Vote)
|
voteTypeMap |
Default value : new Map([
[VoteType.Upvote, '+1'],
[VoteType.Downvote, '-1']
])
|