├── .husky ├── .gitignore └── pre-commit ├── pnpm-workspace.yaml ├── .eslintignore ├── packages ├── logger │ ├── .gitignore │ ├── babel.config.js │ ├── CHANGELOG.md │ ├── src │ │ ├── index.ts │ │ ├── __tests__ │ │ │ ├── setup.ts │ │ │ ├── logger.test.ts │ │ │ └── debug.test.ts │ │ ├── index.browser.ts │ │ ├── platform │ │ │ ├── node.ts │ │ │ ├── index.ts │ │ │ └── browser.ts │ │ ├── types │ │ │ └── index.ts │ │ └── logger │ │ │ ├── debug.ts │ │ │ └── index.ts │ ├── tsconfig.json │ ├── jest.config.js │ └── package.json ├── markdown-renderer │ ├── src │ │ ├── index.ts │ │ ├── mermaid │ │ │ ├── index.license │ │ │ ├── murmurhash3_gc.license │ │ │ ├── index.js │ │ │ └── murmurhash3_gc.js │ │ └── markdown.ts │ ├── .gitignore │ ├── CHANGELOG.md │ ├── tsconfig.json │ ├── vite.config.ts │ ├── README.md │ └── package.json ├── admin-api │ ├── .gitignore │ ├── babel.config.js │ ├── jest.config.js │ ├── src │ │ ├── url.ts │ │ ├── __tests__ │ │ │ └── AuthorizedClient.test.ts │ │ ├── clients │ │ │ ├── MigrationClient.ts │ │ │ ├── InstallationClient.ts │ │ │ ├── StatisticClient.ts │ │ │ ├── MailClient.ts │ │ │ ├── LogClient.ts │ │ │ ├── index.ts │ │ │ ├── TagClient.ts │ │ │ ├── UserClient.ts │ │ │ ├── LinkClient.ts │ │ │ ├── StaticStorageClient.ts │ │ │ ├── JournalClient.ts │ │ │ ├── OptionClient.ts │ │ │ ├── PhotoClient.ts │ │ │ ├── SheetClient.ts │ │ │ ├── ActuatorClient.ts │ │ │ ├── MenuClient.ts │ │ │ ├── CategoryClient.ts │ │ │ ├── PostCommentClient.ts │ │ │ ├── SheetCommentClient.ts │ │ │ ├── PostClient.ts │ │ │ ├── JournalCommentClient.ts │ │ │ ├── BackupClient.ts │ │ │ ├── CommentClient.ts │ │ │ └── AttachmentClient.ts │ │ ├── index.ts │ │ ├── AuthorizedClient.ts │ │ └── AdminApiClient.ts │ ├── tsconfig.json │ ├── CHANGELOG.md │ ├── package.json │ └── README.md ├── content-api │ ├── .gitignore │ ├── jest.config.js │ ├── babel.config.js │ ├── src │ │ ├── index.ts │ │ ├── url.ts │ │ ├── clients │ │ │ ├── UserClient.ts │ │ │ ├── index.ts │ │ │ ├── StatisticClient.ts │ │ │ ├── LinkClient.ts │ │ │ ├── PhotoClient.ts │ │ │ ├── ArchiveClient.ts │ │ │ ├── MenuClient.ts │ │ │ ├── TagClient.ts │ │ │ ├── CategoryClient.ts │ │ │ ├── JournalClient.ts │ │ │ ├── SheetClient.ts │ │ │ ├── OptionClient.ts │ │ │ ├── ThemeClient.ts │ │ │ ├── PostClient.ts │ │ │ └── CommentClient.ts │ │ ├── ContentApiClient.ts │ │ └── types │ │ │ └── index.ts │ ├── tsconfig.json │ ├── CHANGELOG.md │ ├── package.json │ └── README.md ├── rest-api-client │ ├── .gitignore │ ├── src │ │ ├── http │ │ │ ├── index.ts │ │ │ ├── InterceptorManager.ts │ │ │ ├── AxiosClient.ts │ │ │ └── MockClient.ts │ │ ├── logger.ts │ │ ├── __tests__ │ │ │ ├── setup.ts │ │ │ └── HaloResponseHandler.test.ts │ │ ├── types │ │ │ ├── CredentialsInterface.ts │ │ │ ├── index.ts │ │ │ ├── auth.ts │ │ │ └── HttpClientInterface.ts │ │ ├── index.ts │ │ ├── index.browser.ts │ │ ├── platform │ │ │ ├── UnsupportedPlatformError.ts │ │ │ ├── browser.ts │ │ │ ├── index.ts │ │ │ └── node.ts │ │ ├── HaloResponseHandler.ts │ │ ├── error │ │ │ └── HaloRestAPIError.ts │ │ ├── HaloRestAPIClient.ts │ │ └── HaloRequestConfigBuilder.ts │ ├── babel.config.js │ ├── index.mjs │ ├── jest.config.js │ ├── CHANGELOG.md │ ├── tsconfig.json │ ├── types │ │ └── global │ │ │ └── index.d.ts │ ├── package.json │ └── README.md └── tracker │ ├── rollup.tracker.config.js │ ├── package.json │ ├── public │ └── halo-tracker.js │ └── index.js ├── babel.config.js ├── .prettierrc.js ├── OWNERS ├── .vscode ├── extensions.json └── settings.json ├── netlify.toml ├── .editorconfig ├── .changeset ├── config.json └── README.md ├── .eslintrc.js ├── tsconfig.json ├── .github ├── auto_assign.yml └── workflows │ └── node.js.yml ├── tsconfig.base.json ├── LICENSE ├── .gitignore ├── package.json └── README.md /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'packages/*' 3 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/lib/* 2 | **/node_modules/* 3 | example 4 | -------------------------------------------------------------------------------- /packages/logger/.gitignore: -------------------------------------------------------------------------------- 1 | tsconfig.tsbuildinfo 2 | lib 3 | pnpm-workspace.yaml 4 | -------------------------------------------------------------------------------- /packages/markdown-renderer/src/index.ts: -------------------------------------------------------------------------------- 1 | export { markdownIt } from './markdown' 2 | -------------------------------------------------------------------------------- /packages/admin-api/.gitignore: -------------------------------------------------------------------------------- 1 | tsconfig.tsbuildinfo 2 | lib 3 | pnpm-workspace.yaml 4 | -------------------------------------------------------------------------------- /packages/content-api/.gitignore: -------------------------------------------------------------------------------- 1 | tsconfig.tsbuildinfo 2 | lib 3 | pnpm-workspace.yaml 4 | -------------------------------------------------------------------------------- /packages/rest-api-client/.gitignore: -------------------------------------------------------------------------------- 1 | tsconfig.tsbuildinfo 2 | lib 3 | pnpm-workspace.yaml 4 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['@babel/env', '@babel/typescript'], 3 | } 4 | -------------------------------------------------------------------------------- /packages/markdown-renderer/.gitignore: -------------------------------------------------------------------------------- 1 | tsconfig.tsbuildinfo 2 | lib 3 | pnpm-workspace.yaml 4 | -------------------------------------------------------------------------------- /packages/markdown-renderer/src/mermaid/index.license: -------------------------------------------------------------------------------- 1 | https://github.com/liradb2000/markdown-it-mermaid 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | pnpm lint --fix 5 | 6 | git add . 7 | -------------------------------------------------------------------------------- /packages/rest-api-client/src/http/index.ts: -------------------------------------------------------------------------------- 1 | export { AxiosClient as DefaultHttpClient } from './AxiosClient' 2 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 120, 3 | semi: false, 4 | trailingComma: 'all', 5 | singleQuote: true, 6 | }; 7 | -------------------------------------------------------------------------------- /packages/content-api/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testRegex: '/__tests__/.*\\.test\\.ts$', 3 | testEnvironment: 'node', 4 | } 5 | -------------------------------------------------------------------------------- /packages/logger/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [['@babel/preset-env', { targets: { node: 'current' } }], '@babel/preset-typescript'], 3 | } 4 | -------------------------------------------------------------------------------- /packages/admin-api/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [['@babel/preset-env', { targets: { node: 'current' } }], '@babel/preset-typescript'], 3 | } 4 | -------------------------------------------------------------------------------- /packages/content-api/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [['@babel/preset-env', { targets: { node: 'current' } }], '@babel/preset-typescript'], 3 | } 4 | -------------------------------------------------------------------------------- /packages/rest-api-client/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [['@babel/preset-env', { targets: { node: 'current' } }], '@babel/preset-typescript'], 3 | } 4 | -------------------------------------------------------------------------------- /OWNERS: -------------------------------------------------------------------------------- 1 | reviewers: 2 | - ruibaby 3 | - guqing 4 | - JohnNiang 5 | - lan-yonghui 6 | - wangzhen-fit2cloud 7 | 8 | approvers: 9 | - ruibaby 10 | - guqing 11 | - JohnNiang 12 | -------------------------------------------------------------------------------- /packages/rest-api-client/src/logger.ts: -------------------------------------------------------------------------------- 1 | import * as Logger from '@halo-dev/logger' 2 | 3 | const logger = Logger.createClientLogger('Rest-Api-Client') 4 | 5 | export default logger 6 | -------------------------------------------------------------------------------- /packages/logger/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @halo-dev/logger 2 | 3 | ## 1.1.0 4 | 5 | ### Minor Changes 6 | 7 | - - add an API of updating links in batch #40 @gungnir479 8 | 9 | ## 1.0.0 10 | -------------------------------------------------------------------------------- /packages/content-api/src/index.ts: -------------------------------------------------------------------------------- 1 | export { ContentApiClient } from './ContentApiClient' 2 | export * from '@halo-dev/rest-api-client' 3 | export * from './types' 4 | export * from './clients' 5 | -------------------------------------------------------------------------------- /packages/logger/src/index.ts: -------------------------------------------------------------------------------- 1 | import { injectPlatformDeps } from './platform/' 2 | import * as nodeDeps from './platform/node' 3 | 4 | injectPlatformDeps(nodeDeps) 5 | 6 | export * from './logger/index' 7 | -------------------------------------------------------------------------------- /packages/logger/src/__tests__/setup.ts: -------------------------------------------------------------------------------- 1 | import { injectPlatformDeps } from '../platform' 2 | import * as nodeDeps from '../platform/node' 3 | 4 | beforeEach(() => { 5 | injectPlatformDeps(nodeDeps) 6 | }) 7 | -------------------------------------------------------------------------------- /packages/markdown-renderer/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @halo-dev/markdown-renderer 2 | 3 | ## 1.1.0 4 | 5 | ### Minor Changes 6 | 7 | - - add an API of updating links in batch #40 @gungnir479 8 | 9 | ## 1.0.0 10 | -------------------------------------------------------------------------------- /packages/rest-api-client/src/__tests__/setup.ts: -------------------------------------------------------------------------------- 1 | import { injectPlatformDeps } from '../platform' 2 | import * as nodeDeps from '../platform/node' 3 | 4 | beforeEach(() => { 5 | injectPlatformDeps(nodeDeps) 6 | }) 7 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "oderwat.indent-rainbow", 4 | "esbenp.prettier-vscode", 5 | "editorconfig.editorconfig", 6 | "VisualStudioExptTeam.vscodeintellicode" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /packages/logger/src/index.browser.ts: -------------------------------------------------------------------------------- 1 | import { injectPlatformDeps } from './platform/' 2 | import * as browserDeps from './platform/browser' 3 | 4 | injectPlatformDeps(browserDeps) 5 | 6 | export * from './logger/index' 7 | -------------------------------------------------------------------------------- /packages/logger/src/platform/node.ts: -------------------------------------------------------------------------------- 1 | import util from 'util' 2 | import { EOL } from 'os' 3 | 4 | export const log = (message: unknown, ...args: any[]) => { 5 | process.stderr.write(`${util.format(message, ...args)}${EOL}`) 6 | } 7 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build.environment] 2 | NODE_VERSION = "14" 3 | NPM_FLAGS = "--version" 4 | 5 | [build] 6 | publish = "docs" 7 | command = "npx pnpm install --store=node_modules/.pnpm-store && npx pnpm build && npx pnpm build:docs" 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = false 11 | insert_final_newline = true 12 | -------------------------------------------------------------------------------- /packages/admin-api/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | clearMocks: true, 4 | rootDir: 'src', 5 | testPathIgnorePatterns: ['node_modules', '/__tests__/setup.ts'], 6 | testEnvironment: 'node', 7 | } 8 | -------------------------------------------------------------------------------- /packages/logger/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "lib" 6 | }, 7 | "include": [ 8 | "src" 9 | ], 10 | "exclude": [ 11 | "src/**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /packages/admin-api/src/url.ts: -------------------------------------------------------------------------------- 1 | export const buildPath = (params: { endpointName: string; scope?: number | string }): string => { 2 | const { endpointName, scope } = params 3 | const scopePath = scope !== undefined ? `${scope}` : 'admin' 4 | return `/api/${scopePath}/${endpointName}` 5 | } 6 | -------------------------------------------------------------------------------- /packages/markdown-renderer/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "lib" 6 | }, 7 | "include": [ 8 | "src" 9 | ], 10 | "exclude": [ 11 | "src/**/*.spec.ts", 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /packages/content-api/src/url.ts: -------------------------------------------------------------------------------- 1 | export const buildPath = (params: { endpointName: string; scope?: number | string }): string => { 2 | const { endpointName, scope } = params 3 | const scopePath = scope !== undefined ? `${scope}` : 'content' 4 | return `/api/${scopePath}/${endpointName}` 5 | } 6 | -------------------------------------------------------------------------------- /packages/logger/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | clearMocks: true, 4 | rootDir: 'src', 5 | setupFilesAfterEnv: ['/__tests__/setup.ts'], 6 | testPathIgnorePatterns: ['node_modules', '/__tests__/setup.ts'], 7 | testEnvironment: 'node', 8 | } 9 | -------------------------------------------------------------------------------- /packages/rest-api-client/index.mjs: -------------------------------------------------------------------------------- 1 | import module from "module"; 2 | 3 | const require = module.createRequire(import.meta.url); 4 | 5 | export const { 6 | HaloRestAPIClient, 7 | HaloRestAPIError, 8 | // eslint-disable-next-line @typescript-eslint/no-var-requires 9 | } = require("."); 10 | -------------------------------------------------------------------------------- /packages/rest-api-client/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | clearMocks: true, 4 | rootDir: 'src', 5 | setupFilesAfterEnv: ['/__tests__/setup.ts'], 6 | testPathIgnorePatterns: ['node_modules', '/__tests__/setup.ts'], 7 | testEnvironment: 'node', 8 | } 9 | -------------------------------------------------------------------------------- /packages/admin-api/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "lib", 6 | "typeRoots": [ 7 | "node_modules/@types", 8 | "../../node_modules/@types" 9 | ] 10 | }, 11 | "include": [ 12 | "src" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /packages/content-api/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "lib", 6 | "typeRoots": [ 7 | "node_modules/@types", 8 | "../../node_modules/@types" 9 | ] 10 | }, 11 | "include": [ 12 | "src" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@1.6.3/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "linked": [["@halo-dev/*"]], 6 | "access": "public", 7 | "baseBranch": "master", 8 | "updateInternalDependencies": "patch", 9 | "ignore": [] 10 | } 11 | -------------------------------------------------------------------------------- /packages/rest-api-client/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @halo-dev/rest-api-client 2 | 3 | ## 1.1.0 4 | 5 | ### Minor Changes 6 | 7 | - - add an API of updating links in batch #40 @gungnir479 8 | 9 | ### Patch Changes 10 | 11 | - Updated dependencies 12 | - @halo-dev/logger@1.1.0 13 | 14 | ## 1.0.0 15 | 16 | ### Patch Changes 17 | 18 | - @halo-dev/logger@1.0.0 19 | -------------------------------------------------------------------------------- /packages/admin-api/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @halo-dev/admin-api 2 | 3 | ## 1.1.0 4 | 5 | ### Minor Changes 6 | 7 | - - add an API of updating links in batch #40 @gungnir479 8 | 9 | ### Patch Changes 10 | 11 | - Updated dependencies 12 | - @halo-dev/rest-api-client@1.1.0 13 | 14 | ## 1.0.0 15 | 16 | ### Patch Changes 17 | 18 | - @halo-dev/rest-api-client@1.0.0 19 | -------------------------------------------------------------------------------- /packages/content-api/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @halo-dev/content-api 2 | 3 | ## 1.1.0 4 | 5 | ### Minor Changes 6 | 7 | - - add an API of updating links in batch #40 @gungnir479 8 | 9 | ### Patch Changes 10 | 11 | - Updated dependencies 12 | - @halo-dev/rest-api-client@1.1.0 13 | 14 | ## 1.0.0 15 | 16 | ### Patch Changes 17 | 18 | - @halo-dev/rest-api-client@1.0.0 19 | -------------------------------------------------------------------------------- /packages/rest-api-client/src/types/CredentialsInterface.ts: -------------------------------------------------------------------------------- 1 | export interface Credentials { 2 | username: string 3 | password: string 4 | authcode?: string 5 | } 6 | 7 | export type TokenType = 'admin' | 'api' 8 | 9 | export type AccessToken = { 10 | access_token: string 11 | expired_in: number 12 | refresh_token: string 13 | expired_at: number 14 | } 15 | -------------------------------------------------------------------------------- /packages/rest-api-client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "lib", 6 | "typeRoots": [ 7 | "node_modules/@types", 8 | "types", 9 | "../../node_modules/@types" 10 | ] 11 | }, 12 | "include": [ 13 | "src", 14 | "types" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /packages/logger/src/platform/index.ts: -------------------------------------------------------------------------------- 1 | type PlatformDeps = { 2 | log(...args: any[]): void 3 | } 4 | export const platformDeps: PlatformDeps = { 5 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 6 | log(..._args: any[]) { 7 | throw new Error('not implemented') 8 | }, 9 | } 10 | export const injectPlatformDeps = (deps: Partial) => { 11 | platformDeps.log = deps.log! 12 | } 13 | -------------------------------------------------------------------------------- /packages/admin-api/src/__tests__/AuthorizedClient.test.ts: -------------------------------------------------------------------------------- 1 | import { AuthorizedClient } from '../AuthorizedClient' 2 | 3 | describe('Halo AuthorizedClient test', () => { 4 | it('base test', async () => { 5 | const authorizedClient = new AuthorizedClient('http://localhost:8090') 6 | 7 | const data = await authorizedClient.isInstalled() 8 | console.log('authorizedClient test response:', data) 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /packages/rest-api-client/types/global/index.d.ts: -------------------------------------------------------------------------------- 1 | declare const PACKAGE_VERSION: string 2 | 3 | declare namespace NodeJS { 4 | interface Global { 5 | halo: typeof halo 6 | server: typeof haloServer 7 | } 8 | } 9 | 10 | declare const halo: { 11 | getRequestToken(): string 12 | } 13 | 14 | declare const haloServer: 15 | | { 16 | host: string 17 | protocol: string 18 | } 19 | | undefined 20 | -------------------------------------------------------------------------------- /packages/markdown-renderer/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import path from 'path' 3 | 4 | export default defineConfig({ 5 | build: { 6 | outDir: path.resolve(__dirname, 'lib'), 7 | lib: { 8 | entry: path.resolve(__dirname, 'src/index.ts'), 9 | name: 'markdown-renderer', 10 | fileName: (format) => `markdown-renderer.${format}.js`, 11 | }, 12 | sourcemap: true, 13 | }, 14 | }) 15 | -------------------------------------------------------------------------------- /packages/rest-api-client/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export { CustomizeAuth, DiscriminatedAuth, BasicAuth } from './auth' 2 | 3 | export { AccessToken, TokenType, Credentials } from './CredentialsInterface' 4 | 5 | export { 6 | HttpClient, 7 | ResponseHandler, 8 | RequestConfigBuilder, 9 | HttpResponse, 10 | ProxyConfig, 11 | HttpClientError, 12 | ErrorResponse, 13 | RequestConfig, 14 | HttpMethod, 15 | Params, 16 | } from './HttpClientInterface' 17 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'], 5 | env: { 6 | browser: true, 7 | node: true, 8 | }, 9 | rules: { 10 | '@typescript-eslint/no-explicit-any': ['off'], 11 | '@typescript-eslint/no-non-null-assertion': 'off', 12 | '@typescript-eslint/ban-ts-comment': 'off', 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /packages/content-api/src/clients/UserClient.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@halo-dev/rest-api-client' 2 | import { buildPath } from '../url' 3 | import { Response, User } from '../types' 4 | 5 | export class UserClient { 6 | private client: HttpClient 7 | 8 | constructor(client: HttpClient) { 9 | this.client = client 10 | } 11 | 12 | public getProfile(): Promise> { 13 | const path = buildPath({ 14 | endpointName: 'users/profile', 15 | }) 16 | return this.client.get(path, {}) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /packages/logger/src/platform/browser.ts: -------------------------------------------------------------------------------- 1 | export const log = (...args: any[]) => { 2 | if (args.length > 0) { 3 | const firstArg = String(args[0]) 4 | if (firstArg.includes(':error')) { 5 | console.error(...args) 6 | } else if (firstArg.includes(':warning')) { 7 | console.warn(...args) 8 | } else if (firstArg.includes(':info')) { 9 | console.info(...args) 10 | } else if (firstArg.includes(':debug')) { 11 | console.debug(...args) 12 | } else { 13 | console.debug(...args) 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "compilerOptions": { 4 | "tsBuildInfoFile": "tsconfig.tsbuildinfo" 5 | }, 6 | "include": [], 7 | "exclude": ["node_modules", "lib"], 8 | "references": [ 9 | { 10 | "path": "./packages/logger" 11 | }, 12 | { 13 | "path": "./packages/rest-api-client" 14 | }, 15 | { 16 | "path": "./packages/admin-api" 17 | }, 18 | { 19 | "path": "./packages/content-api" 20 | }, 21 | { 22 | "path": "./packages/markdown-renderer" 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /.github/auto_assign.yml: -------------------------------------------------------------------------------- 1 | # Set to true to add reviewers to pull requests 2 | addReviewers: true 3 | 4 | # Set to true to add assignees to pull requests 5 | addAssignees: true 6 | 7 | # A list of reviewers to be added to pull requests (GitHub user name) 8 | reviewers: 9 | - ruibaby 10 | - JohnNiang 11 | - guqing 12 | - LIlGG 13 | 14 | # A list of keywords to be skipped the process that add reviewers if pull requests include it 15 | skipKeywords: 16 | - wip 17 | 18 | # A number of reviewers added to the pull request 19 | # Set 0 to add all the reviewers (default: 0) 20 | numberOfReviewers: 0 21 | -------------------------------------------------------------------------------- /packages/admin-api/src/clients/MigrationClient.ts: -------------------------------------------------------------------------------- 1 | import { FormData, HttpClient } from '@halo-dev/rest-api-client' 2 | import { buildPath } from '../url' 3 | import { UploadOptions } from '../types' 4 | 5 | export class MigrationClient { 6 | private client: HttpClient 7 | 8 | constructor(client: HttpClient) { 9 | this.client = client 10 | } 11 | 12 | public async migrate(data: unknown, options: UploadOptions): Promise { 13 | const path = buildPath({ 14 | endpointName: 'migrations/halo', 15 | }) 16 | const formData = new FormData() 17 | formData.append('file', data) 18 | await this.client.post(path, formData, { ...options }) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/tracker/rollup.tracker.config.js: -------------------------------------------------------------------------------- 1 | import 'dotenv/config'; 2 | import buble from '@rollup/plugin-buble'; 3 | import replace from '@rollup/plugin-replace'; 4 | import { terser } from 'rollup-plugin-terser'; 5 | 6 | export default { 7 | input: 'index.js', 8 | output: { 9 | file: 'public/halo-tracker.js', 10 | format: 'iife', 11 | }, 12 | plugins: [ 13 | replace({ 14 | '/api/tracker': process.env.COLLECT_API_ENDPOINT || '/apis/api.halo.run/v1alpha1/trackers/counter', 15 | delimiters: ['', ''], 16 | preventAssignment: true, 17 | }), 18 | buble({ objectAssign: true }), 19 | terser({ compress: { evaluate: false } }) 20 | ], 21 | }; 22 | -------------------------------------------------------------------------------- /packages/content-api/src/clients/index.ts: -------------------------------------------------------------------------------- 1 | export { ArchiveClient } from './ArchiveClient' 2 | export { CategoryClient } from './CategoryClient' 3 | export { JournalClient } from './JournalClient' 4 | export { LinkClient } from './LinkClient' 5 | export { MenuClient } from './MenuClient' 6 | export { OptionClient } from './OptionClient' 7 | export { PhotoClient } from './PhotoClient' 8 | export { PostClient } from './PostClient' 9 | export { SheetClient } from './SheetClient' 10 | export { StatisticClient } from './StatisticClient' 11 | export { TagClient } from './TagClient' 12 | export { ThemeClient } from './ThemeClient' 13 | export { UserClient } from './UserClient' 14 | export { CommentClient } from './CommentClient' 15 | -------------------------------------------------------------------------------- /packages/rest-api-client/src/__tests__/HaloResponseHandler.test.ts: -------------------------------------------------------------------------------- 1 | import { HttpResponse } from '../types' 2 | import { HaloResponseHandler } from '../HaloResponseHandler' 3 | 4 | describe('HaloResponseHandler', () => { 5 | describe('handle', () => { 6 | it('should pass', async () => { 7 | const responseHandler = new HaloResponseHandler() 8 | const response: HttpResponse = { 9 | data: { status: 'success', data: null }, 10 | headers: { 11 | hello: 'world', 12 | }, 13 | } 14 | await expect(responseHandler.handle(Promise.resolve(response))).resolves.toStrictEqual({ 15 | status: 'success', 16 | data: null, 17 | }) 18 | }) 19 | }) 20 | }) 21 | -------------------------------------------------------------------------------- /packages/rest-api-client/src/index.ts: -------------------------------------------------------------------------------- 1 | import { injectPlatformDeps } from './platform/' 2 | import * as nodeDeps from './platform/node' 3 | import FormData from 'form-data' 4 | import Axios from 'axios' 5 | 6 | injectPlatformDeps(nodeDeps) 7 | 8 | export { HaloRestAPIClient } from './HaloRestAPIClient' 9 | export { HaloResponseHandler } from './HaloResponseHandler' 10 | export { HaloRequestConfigBuilder } from './HaloRequestConfigBuilder' 11 | export { DefaultHttpClient } from './http' 12 | 13 | export { 14 | CustomizeAuth, 15 | DiscriminatedAuth, 16 | BasicAuth, 17 | AccessToken, 18 | TokenType, 19 | Credentials, 20 | HttpClient, 21 | ResponseHandler, 22 | } from './types' 23 | 24 | export { FormData, Axios } 25 | -------------------------------------------------------------------------------- /packages/rest-api-client/src/index.browser.ts: -------------------------------------------------------------------------------- 1 | import { injectPlatformDeps } from './platform/' 2 | import * as browserDeps from './platform/browser' 3 | import FormData from 'form-data' 4 | import Axios from 'axios' 5 | 6 | injectPlatformDeps(browserDeps) 7 | 8 | export { HaloRestAPIClient } from './HaloRestAPIClient' 9 | export { HaloResponseHandler } from './HaloResponseHandler' 10 | export { HaloRequestConfigBuilder } from './HaloRequestConfigBuilder' 11 | export { DefaultHttpClient } from './http' 12 | 13 | export { 14 | CustomizeAuth, 15 | DiscriminatedAuth, 16 | BasicAuth, 17 | AccessToken, 18 | TokenType, 19 | Credentials, 20 | HttpClient, 21 | ResponseHandler, 22 | } from './types' 23 | 24 | export { FormData, Axios } 25 | -------------------------------------------------------------------------------- /packages/admin-api/src/clients/InstallationClient.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@halo-dev/rest-api-client' 2 | import { buildPath } from '../url' 3 | import { InstallParam, Response } from '../types' 4 | 5 | export class InstallationClient { 6 | private client: HttpClient 7 | 8 | constructor(client: HttpClient) { 9 | this.client = client 10 | } 11 | 12 | /** 13 | * Initializes the blog. 14 | * 15 | * @param params installation parameter 16 | * @returns A response of installation status message. 17 | */ 18 | public install(params: InstallParam): Promise> { 19 | const path = buildPath({ 20 | endpointName: 'installations', 21 | }) 22 | return this.client.post(path, { ...params }) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/admin-api/src/clients/StatisticClient.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@halo-dev/rest-api-client' 2 | import { buildPath } from '../url' 3 | import { Response, Statistic, StatisticWithUser } from '../types' 4 | 5 | export class StatisticClient { 6 | private client: HttpClient 7 | 8 | constructor(client: HttpClient) { 9 | this.client = client 10 | } 11 | 12 | public statistics(): Promise> { 13 | const path = buildPath({ 14 | endpointName: 'statistics', 15 | }) 16 | return this.client.get(path, {}) 17 | } 18 | 19 | public statisticsWithUser(): Promise> { 20 | const path = buildPath({ 21 | endpointName: 'statistics/user', 22 | }) 23 | return this.client.get(path, {}) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/content-api/src/clients/StatisticClient.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@halo-dev/rest-api-client' 2 | import { buildPath } from '../url' 3 | import { Response, Statistic, StatisticWithUser } from '../types' 4 | 5 | export class StatisticClient { 6 | private client: HttpClient 7 | 8 | constructor(client: HttpClient) { 9 | this.client = client 10 | } 11 | 12 | public statistics(): Promise> { 13 | const path = buildPath({ 14 | endpointName: 'statistics', 15 | }) 16 | return this.client.get(path, {}) 17 | } 18 | 19 | public statisticsWithUser(): Promise> { 20 | const path = buildPath({ 21 | endpointName: 'statistics/user', 22 | }) 23 | return this.client.get(path, {}) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/content-api/src/clients/LinkClient.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@halo-dev/rest-api-client' 2 | import { buildPath } from '../url' 3 | import { Link, LinkTeam, Response } from '../types' 4 | 5 | export class LinkClient { 6 | private client: HttpClient 7 | 8 | constructor(client: HttpClient) { 9 | this.client = client 10 | } 11 | 12 | public list(sort?: Array): Promise>> { 13 | const path = buildPath({ 14 | endpointName: 'links', 15 | }) 16 | return this.client.get(path, { sort }) 17 | } 18 | 19 | public listTeams(sort?: Array): Promise>> { 20 | const path = buildPath({ 21 | endpointName: 'links/team_view', 22 | }) 23 | return this.client.get(path, { sort }) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/content-api/src/clients/PhotoClient.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@halo-dev/rest-api-client' 2 | import { buildPath } from '../url' 3 | import { Page, Photo, PhotoQuery, Response } from '../types' 4 | 5 | export class PhotoClient { 6 | private client: HttpClient 7 | 8 | constructor(client: HttpClient) { 9 | this.client = client 10 | } 11 | 12 | public latest(sort: Array): Promise>> { 13 | const path = buildPath({ 14 | endpointName: 'photos/latest', 15 | }) 16 | return this.client.get(path, { sort }) 17 | } 18 | 19 | public list(params: PhotoQuery): Promise> { 20 | const path = buildPath({ 21 | endpointName: 'photos', 22 | }) 23 | return this.client.get(path, { ...params }) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/content-api/src/clients/ArchiveClient.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@halo-dev/rest-api-client' 2 | import { buildPath } from '../url' 3 | import { ArchiveMonth, ArchiveYear, Response } from '../types' 4 | 5 | export class ArchiveClient { 6 | private client: HttpClient 7 | 8 | constructor(client: HttpClient) { 9 | this.client = client 10 | } 11 | 12 | public listYearArchives(): Promise>> { 13 | const path = buildPath({ 14 | endpointName: 'archives/years', 15 | }) 16 | return this.client.get(path, {}) 17 | } 18 | 19 | public listMonthArchives(): Promise>> { 20 | const path = buildPath({ 21 | endpointName: 'archives/years', 22 | }) 23 | return this.client.get(path, {}) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/content-api/src/clients/MenuClient.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@halo-dev/rest-api-client' 2 | import { buildPath } from '../url' 3 | import { Menu, MenuTree, Response } from '../types' 4 | 5 | export class MenuClient { 6 | private client: HttpClient 7 | 8 | constructor(client: HttpClient) { 9 | this.client = client 10 | } 11 | 12 | public list(sort?: Array): Promise>> { 13 | const path = buildPath({ 14 | endpointName: 'menus', 15 | }) 16 | return this.client.get(path, { sort }) 17 | } 18 | 19 | public listAsTreeView(sort?: Array): Promise>> { 20 | const path = buildPath({ 21 | endpointName: 'menus/tree_view', 22 | }) 23 | return this.client.get(path, { sort }) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/admin-api/src/clients/MailClient.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@halo-dev/rest-api-client' 2 | import { buildPath } from '../url' 3 | import { Response } from '../types' 4 | 5 | export class MailClient { 6 | private client: HttpClient 7 | 8 | constructor(client: HttpClient) { 9 | this.client = client 10 | } 11 | 12 | public testSmtpService(params: { content: string; subject: string; to: string }): Promise> { 13 | const path = buildPath({ 14 | endpointName: 'mails/test', 15 | }) 16 | return this.client.post(path, { ...params }) 17 | } 18 | 19 | public testConnect(): Promise> { 20 | const path = buildPath({ 21 | endpointName: 'mails/test/connection', 22 | }) 23 | return this.client.post(path, {}) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2015", 4 | "module": "commonjs", 5 | "lib": [ 6 | "es2015", 7 | "dom" 8 | ], 9 | "allowJs": true, 10 | "noEmitOnError": true, 11 | "declaration": true, 12 | "declarationMap": true, 13 | "sourceMap": true, 14 | "moduleResolution": "node", 15 | "esModuleInterop": true, 16 | "forceConsistentCasingInFileNames": true, 17 | "importHelpers": true, 18 | "composite": true, 19 | "pretty": true, 20 | "strict": true, 21 | "noFallthroughCasesInSwitch": true, 22 | "noImplicitReturns": true, 23 | "noImplicitOverride": true, 24 | "noUnusedParameters": true, 25 | "noUnusedLocals": true, 26 | "preserveWatchOutput": true, 27 | "skipLibCheck": true 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/content-api/src/clients/TagClient.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@halo-dev/rest-api-client' 2 | import { buildPath } from '../url' 3 | import { Page, PageQuery, PostList, Response, Tag } from '../types' 4 | 5 | export class TagClient { 6 | private client: HttpClient 7 | 8 | constructor(client: HttpClient) { 9 | this.client = client 10 | } 11 | 12 | public list(params: { sort: Array; more: boolean }): Promise>> { 13 | const path = buildPath({ 14 | endpointName: 'tags', 15 | }) 16 | return this.client.get(path, { ...params }) 17 | } 18 | 19 | public listPostsBySlug(slug: string, params?: PageQuery): Promise> { 20 | const path = buildPath({ 21 | endpointName: `tags/${slug}/posts`, 22 | }) 23 | return this.client.get(path, { ...params }) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/content-api/src/clients/CategoryClient.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@halo-dev/rest-api-client' 2 | import { buildPath } from '../url' 3 | import { Category, CategoryQuery, Page, PostList, Response } from '../types' 4 | 5 | export class CategoryClient { 6 | private client: HttpClient 7 | 8 | constructor(client: HttpClient) { 9 | this.client = client 10 | } 11 | 12 | public list(params: { sort: Array; more: boolean }): Promise>> { 13 | const path = buildPath({ 14 | endpointName: 'categories', 15 | }) 16 | return this.client.get(path, { ...params }) 17 | } 18 | 19 | public listPostBySlug(params: CategoryQuery): Promise> { 20 | const path = buildPath({ 21 | endpointName: `categories/${params.slug}/posts`, 22 | }) 23 | return this.client.get(path, { ...params }) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/rest-api-client/src/types/auth.ts: -------------------------------------------------------------------------------- 1 | type AdminTokenAuth = { 2 | type: 'adminToken' 3 | adminToken: string 4 | } 5 | 6 | type ApiTokenAuth = { 7 | type: 'apiToken' 8 | apiToken: string | string[] 9 | } 10 | 11 | type PasswordAuth = { 12 | type: 'password' 13 | username: string 14 | password: string 15 | } 16 | 17 | type SessionAuth = { 18 | type: 'session' 19 | } 20 | 21 | type OAuthTokenAuth = { 22 | type: 'oAuthToken' 23 | oAuthToken: string 24 | } 25 | 26 | export type CustomizeAuth = { 27 | type: 'customizeAuth' 28 | authHeader: string 29 | getToken(): string 30 | } 31 | 32 | export type DiscriminatedAuth = 33 | | AdminTokenAuth 34 | | ApiTokenAuth 35 | | PasswordAuth 36 | | SessionAuth 37 | | OAuthTokenAuth 38 | | CustomizeAuth 39 | 40 | export type BasicAuth = { 41 | username: string 42 | password: string 43 | } 44 | 45 | export const SESSION_TOKEN_KEY = '__REQUEST_TOKEN__' 46 | -------------------------------------------------------------------------------- /packages/content-api/src/clients/JournalClient.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@halo-dev/rest-api-client' 2 | import { buildPath } from '../url' 3 | import { Journal, JournalWithCmtCount, Page, Response } from '../types' 4 | 5 | export class JournalClient { 6 | private client: HttpClient 7 | 8 | constructor(client: HttpClient) { 9 | this.client = client 10 | } 11 | 12 | public list(): Promise> { 13 | const path = buildPath({ 14 | endpointName: 'journals', 15 | }) 16 | return this.client.get(path, {}) 17 | } 18 | 19 | public get(journalId: number): Promise> { 20 | const path = buildPath({ 21 | endpointName: `journals/${journalId}`, 22 | }) 23 | return this.client.get(path, {}) 24 | } 25 | 26 | public async like(journalId: number): Promise { 27 | const path = buildPath({ 28 | endpointName: `journals/${journalId}/likes`, 29 | }) 30 | await this.client.post(path, {}) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/rest-api-client/src/platform/UnsupportedPlatformError.ts: -------------------------------------------------------------------------------- 1 | type Platform = 'Browser' | 'Node.js' 2 | 3 | export class UnsupportedPlatformError extends Error { 4 | public platform: Platform 5 | 6 | constructor(platform: Platform) { 7 | const message = `This function is not supported in ${platform} environment` 8 | super(message) 9 | 10 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Custom_Error_Types 11 | // Maintains proper stack trace for where our error was thrown (only available on V8) 12 | if (Error.captureStackTrace) { 13 | Error.captureStackTrace(this, UnsupportedPlatformError) 14 | } 15 | 16 | this.name = 'UnsupportedPlatformError' 17 | this.platform = platform 18 | 19 | // https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work 20 | // Set the prototype explicitly. 21 | Object.setPrototypeOf(this, UnsupportedPlatformError.prototype) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/rest-api-client/src/http/InterceptorManager.ts: -------------------------------------------------------------------------------- 1 | import Axios, { AxiosRequestConfig, AxiosResponse } from 'axios' 2 | import { RejectedFn, ResolvedFn } from '../types/HttpClientInterface' 3 | 4 | export default interface InterceptorManager { 5 | use(resolved: ResolvedFn, rejected?: RejectedFn): number 6 | 7 | eject(id: number): void 8 | } 9 | 10 | export class RequestInterceptor implements InterceptorManager { 11 | use(resolved: ResolvedFn, rejected?: RejectedFn): number { 12 | return Axios.interceptors.request.use(resolved, rejected) 13 | } 14 | 15 | eject(id: number): void { 16 | Axios.interceptors.request.eject(id) 17 | } 18 | } 19 | 20 | export class ResponseInterceptor implements InterceptorManager { 21 | use(resolved: ResolvedFn, rejected?: RejectedFn): number { 22 | return Axios.interceptors.response.use(resolved, rejected) 23 | } 24 | 25 | eject(id: number): void { 26 | Axios.interceptors.response.eject(id) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/content-api/src/clients/SheetClient.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@halo-dev/rest-api-client' 2 | import { buildPath } from '../url' 3 | import { ContentQuery, Page, PageQuery, Response, SheetDetail, SheetList } from '../types' 4 | 5 | export class SheetClient { 6 | private client: HttpClient 7 | 8 | constructor(client: HttpClient) { 9 | this.client = client 10 | } 11 | 12 | public list(params: PageQuery): Promise> { 13 | const path = buildPath({ 14 | endpointName: 'sheets', 15 | }) 16 | return this.client.get(path, { ...params }) 17 | } 18 | 19 | public get(sheetId: number, params?: ContentQuery): Promise> { 20 | const path = buildPath({ 21 | endpointName: `sheets/${sheetId}`, 22 | }) 23 | return this.client.get(path, { ...params }) 24 | } 25 | 26 | public getBySlug(slug: string, params?: ContentQuery): Promise> { 27 | const path = buildPath({ 28 | endpointName: 'sheets/slug', 29 | }) 30 | return this.client.get(path, { slug, ...params }) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: [master] 9 | pull_request: 10 | branches: [master] 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | strategy: 17 | matrix: 18 | node-version: [14.x, 16.x] 19 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 20 | 21 | steps: 22 | - uses: actions/checkout@v2 23 | 24 | - name: Install pnpm 25 | uses: pnpm/action-setup@v2.0.1 26 | with: 27 | version: 7.1.6 28 | 29 | - name: Use Node.js ${{ matrix.node-version }} 30 | uses: actions/setup-node@v2 31 | with: 32 | node-version: ${{ matrix.node-version }} 33 | cache: 'pnpm' 34 | 35 | - run: pnpm install 36 | - run: pnpm lint 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Halo Dev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/content-api/src/clients/OptionClient.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@halo-dev/rest-api-client' 2 | import { buildPath } from '../url' 3 | import { Option, Response } from '../types' 4 | 5 | export class OptionClient { 6 | private client: HttpClient 7 | 8 | constructor(client: HttpClient) { 9 | this.client = client 10 | } 11 | 12 | public list(): Promise>> { 13 | const path = buildPath({ 14 | endpointName: 'options/list_view', 15 | }) 16 | return this.client.get(path, {}) 17 | } 18 | 19 | public listAsMapView(key?: string): Promise>> { 20 | const path = buildPath({ 21 | endpointName: 'options/map_view', 22 | }) 23 | return this.client.get(path, { key }) 24 | } 25 | 26 | public getByKey(key: string): Promise { 27 | const path = buildPath({ 28 | endpointName: `options/keys/${key}`, 29 | }) 30 | return this.client.get(path, { key }) 31 | } 32 | 33 | public comment(): Promise> { 34 | const path = buildPath({ 35 | endpointName: 'options/comment', 36 | }) 37 | return this.client.get(path, {}) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/markdown-renderer/src/mermaid/murmurhash3_gc.license: -------------------------------------------------------------------------------- 1 | License (MIT) 2 | Copyright (c) 2011 Gary Court 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | of the Software, and to permit persons to whom the Software is furnished to do 9 | so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /packages/rest-api-client/src/platform/browser.ts: -------------------------------------------------------------------------------- 1 | import { UnsupportedPlatformError } from './UnsupportedPlatformError' 2 | import { DiscriminatedAuth } from '../types' 3 | 4 | export const readFileFromPath = () => { 5 | throw new UnsupportedPlatformError('Browser') 6 | } 7 | 8 | export const getRequestToken = async () => { 9 | if (typeof halo === 'object' && halo !== null && typeof halo.getRequestToken === 'function') { 10 | return halo.getRequestToken() 11 | } 12 | throw new Error('session authentication must specify a request token') 13 | } 14 | 15 | export const getDefaultAuth = (): DiscriminatedAuth => { 16 | return { 17 | type: 'session', 18 | } 19 | } 20 | 21 | export const buildPlatformDependentConfig = () => { 22 | return {} 23 | } 24 | 25 | export const buildHeaders = () => { 26 | return {} 27 | } 28 | 29 | export const buildFormDataValue = (data: any) => { 30 | return new Blob([data]) 31 | } 32 | 33 | export const buildBaseUrl = (baseUrl?: string) => { 34 | if (typeof baseUrl === 'undefined') { 35 | throw new Error('in browser environment, baseUrl is required') 36 | } 37 | return baseUrl 38 | } 39 | 40 | export const getVersion = () => { 41 | return PACKAGE_VERSION 42 | } 43 | -------------------------------------------------------------------------------- /packages/admin-api/src/clients/LogClient.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@halo-dev/rest-api-client' 2 | import { buildPath } from '../url' 3 | import { Log, Page, Response } from '../types' 4 | 5 | export class LogClient { 6 | private client: HttpClient 7 | 8 | constructor(client: HttpClient) { 9 | this.client = client 10 | } 11 | 12 | /** 13 | * List action logs by params. 14 | * 15 | * @param params 16 | */ 17 | public list(params: { page: number; size: number; sort?: Array }): Promise>> { 18 | const path = buildPath({ 19 | endpointName: 'logs', 20 | }) 21 | return this.client.get(path, { ...params }) 22 | } 23 | 24 | /** 25 | * Clear action logs 26 | */ 27 | public async clear(): Promise { 28 | const path = buildPath({ 29 | endpointName: 'logs/clear', 30 | }) 31 | await this.client.get(path, {}) 32 | } 33 | 34 | /** 35 | * Get latest action logs 36 | * 37 | * @param top the number of logs to get 38 | */ 39 | public latest(top: number): Promise>> { 40 | const path = buildPath({ 41 | endpointName: 'logs/latest', 42 | }) 43 | return this.client.get(path, { top }) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/markdown-renderer/README.md: -------------------------------------------------------------------------------- 1 |

Markdown Renderer

2 | 3 |

4 | 5 | npm version 6 | 7 | 8 | npm 9 | 10 | 11 | node-current 12 | 13 | 14 | NPM 15 | 16 |

17 | 18 | ## Installation 19 | 20 | ```shell 21 | npm install @halo-dev/markdown-renderer --save 22 | ``` 23 | 24 | ## Usage 25 | 26 | ```javascript 27 | import markdownRenderer from '@halo-dev/markdown-renderer' 28 | 29 | const html = markdownRenderer.render('Hello Halo') 30 | ``` 31 | 32 | ### License 33 | 34 | [MIT license](../../LICENSE) 35 | -------------------------------------------------------------------------------- /packages/content-api/src/clients/ThemeClient.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@halo-dev/rest-api-client' 2 | import { buildPath } from '../url' 3 | import { Response, ThemeProperty } from '../types' 4 | 5 | export class ThemeClient { 6 | private client: HttpClient 7 | 8 | constructor(client: HttpClient) { 9 | this.client = client 10 | } 11 | 12 | public getProperty(): Promise> { 13 | const path = buildPath({ 14 | endpointName: 'themes/activation', 15 | }) 16 | return this.client.get(path, {}) 17 | } 18 | 19 | public listSettings(): Promise>> { 20 | const path = buildPath({ 21 | endpointName: 'themes/activation/settings', 22 | }) 23 | return this.client.get(path, {}) 24 | } 25 | 26 | public getPropertyById(themeId: string): Promise> { 27 | const path = buildPath({ 28 | endpointName: `themes/${themeId}`, 29 | }) 30 | return this.client.get(path, {}) 31 | } 32 | 33 | public listSettingsById(themeId: string): Promise>> { 34 | const path = buildPath({ 35 | endpointName: `themes/${themeId}/settings`, 36 | }) 37 | return this.client.get(path, {}) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node template 2 | dist/ 3 | tsconfig.tsbuildinfo 4 | # Logs 5 | logs 6 | *.log 7 | npm-debug.log* 8 | yarn-debug.log* 9 | yarn-error.log* 10 | .tsbuildinfo 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | 24 | # nyc test coverage 25 | .nyc_output 26 | 27 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 28 | .grunt 29 | 30 | # Bower dependency directory (https://bower.io/) 31 | bower_components 32 | 33 | # node-waf configuration 34 | .lock-wscript 35 | 36 | # Compiled binary addons (https://nodejs.org/api/addons.html) 37 | build/Release 38 | 39 | # Dependency directories 40 | node_modules/ 41 | jspm_packages/ 42 | 43 | # Typescript v1 declaration files 44 | typings/ 45 | 46 | # Optional npm cache directory 47 | .npm 48 | 49 | # Optional eslint cache 50 | .eslintcache 51 | 52 | # Optional REPL history 53 | .node_repl_history 54 | 55 | # Output of 'npm pack' 56 | *.tgz 57 | 58 | # Yarn Integrity file 59 | .yarn-integrity 60 | 61 | # IDE 62 | .idea/* 63 | *.iml 64 | *.sublime-* 65 | 66 | # OSX 67 | .DS_Store 68 | 69 | docs 70 | -------------------------------------------------------------------------------- /packages/admin-api/src/clients/index.ts: -------------------------------------------------------------------------------- 1 | export { AttachmentClient } from './AttachmentClient' 2 | export { BackupClient } from './BackupClient' 3 | export { CategoryClient } from './CategoryClient' 4 | export { InstallationClient } from './InstallationClient' 5 | export { JournalCommentClient } from './JournalCommentClient' 6 | export { JournalClient } from './JournalClient' 7 | export { LinkClient } from './LinkClient' 8 | export { LogClient } from './LogClient' 9 | export { MailClient } from './MailClient' 10 | export { MenuClient } from './MenuClient' 11 | export { MigrationClient } from './MigrationClient' 12 | export { OptionClient } from './OptionClient' 13 | export { PhotoClient } from './PhotoClient' 14 | export { PostCommentClient } from './PostCommentClient' 15 | export { PostClient } from './PostClient' 16 | export { SheetCommentClient } from './SheetCommentClient' 17 | export { SheetClient } from './SheetClient' 18 | export { StatisticClient } from './StatisticClient' 19 | export { TagClient } from './TagClient' 20 | export { ThemeClient } from './ThemeClient' 21 | export { UserClient } from './UserClient' 22 | export { StaticStorageClient } from './StaticStorageClient' 23 | export { CommentClient } from './CommentClient' 24 | export { ActuatorClient } from './ActuatorClient' 25 | -------------------------------------------------------------------------------- /packages/rest-api-client/src/HaloResponseHandler.ts: -------------------------------------------------------------------------------- 1 | import { ErrorResponse, HttpClientError, HttpResponse, ResponseHandler } from './types' 2 | import { HaloErrorResponse, HaloRestAPIError } from './error/HaloRestAPIError' 3 | 4 | export class HaloResponseHandler implements ResponseHandler { 5 | handle(response: Promise>): Promise { 6 | return response.then( 7 | (res) => this.handleSuccessResponse(res), 8 | (error) => this.handleErrorResponse(error), 9 | ) 10 | } 11 | 12 | private handleSuccessResponse(response: HttpResponse): T { 13 | return response.data 14 | } 15 | 16 | private handleErrorResponse(error: HttpClientError | HaloErrorResponse>): never { 17 | if (!error.response) { 18 | // FIXME: find a better way to handle this error 19 | if (/MAC address verify failure/.test(error.toString())) { 20 | throw new Error('invalid clientCertAuth setting') 21 | } 22 | throw error 23 | } 24 | const errorResponse = error.response 25 | 26 | const { data, ...rest } = errorResponse 27 | if (typeof data === 'string') { 28 | throw new Error(`${rest.status}: ${rest.statusText}`) 29 | } 30 | throw new HaloRestAPIError({ data, ...rest }) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.quickSuggestions": { 3 | "strings": true 4 | }, 5 | "[javascript]": { 6 | "editor.defaultFormatter": "esbenp.prettier-vscode" 7 | }, 8 | "vetur.format.defaultFormatter.html": "js-beautify-html", 9 | "vetur.format.defaultFormatterOptions": { 10 | "js-beautify-html": { 11 | "wrap_attributes": "force-expand-multiline" 12 | }, 13 | "prettyhtml": { 14 | "printWidth": 100, 15 | "singleQuote": false, 16 | "wrapAttributes": false, 17 | "sortAttributes": false 18 | } 19 | }, 20 | "[vue]": { 21 | "editor.defaultFormatter": "esbenp.prettier-vscode" 22 | }, 23 | "[json]": { 24 | "editor.defaultFormatter": "esbenp.prettier-vscode" 25 | }, 26 | "[jsonc]": { 27 | "editor.defaultFormatter": "esbenp.prettier-vscode" 28 | }, 29 | "[typescript]": { 30 | "editor.defaultFormatter": "esbenp.prettier-vscode" 31 | }, 32 | "editor.suggestSelection": "first", 33 | "[html]": { 34 | "editor.defaultFormatter": "esbenp.prettier-vscode" 35 | }, 36 | "editor.formatOnSave": true, 37 | "[javascriptreact]": { 38 | "editor.defaultFormatter": "esbenp.prettier-vscode" 39 | }, 40 | "[typescriptreact]": { 41 | "editor.defaultFormatter": "esbenp.prettier-vscode" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/tracker/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@halo-dev/tracker", 3 | "version": "0.0.1", 4 | "description": "Halo tracker.", 5 | "main": "lib/index.js", 6 | "module": "./lib/index.js", 7 | "types": "lib/index.d.ts", 8 | "engines": { 9 | "node": ">=12" 10 | }, 11 | "publishConfig": { 12 | "access": "public" 13 | }, 14 | "private": false, 15 | "scripts": { 16 | "build": "rollup -c rollup.tracker.config.js" 17 | }, 18 | "files": [ 19 | "lib" 20 | ], 21 | "repository": { 22 | "type": "git", 23 | "url": "git+https://github.com/halo-dev/js-sdk.git", 24 | "directory": "packages/tracker" 25 | }, 26 | "keywords": [ 27 | "halo", 28 | "halo-sdk", 29 | "halo-tracker" 30 | ], 31 | "maintainers": [ 32 | { 33 | "name": "guqing", 34 | "email": "1484563614@qq.com", 35 | "url": "https://github.com/guqing" 36 | } 37 | ], 38 | "author": "@halo-dev", 39 | "license": "MIT", 40 | "bugs": { 41 | "url": "https://github.com/halo-dev/js-sdk/issues" 42 | }, 43 | "homepage": "https://github.com/halo-dev/js-sdk/tree/master/packages/tracker#readme", 44 | "dependencies": { 45 | "dotenv": "^10.0.0" 46 | }, 47 | "devDependencies": { 48 | "rollup": "^2.70.1", 49 | "rollup-plugin-terser": "^7.0.2", 50 | "@rollup/plugin-buble": "^0.21.3", 51 | "@rollup/plugin-replace": "^4.0.0" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /packages/admin-api/src/clients/TagClient.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@halo-dev/rest-api-client' 2 | import { buildPath } from '../url' 3 | import { Response, Tag, TagParam } from '../types' 4 | 5 | export class TagClient { 6 | private client: HttpClient 7 | 8 | constructor(client: HttpClient) { 9 | this.client = client 10 | } 11 | 12 | public list(params: { sort?: string; more?: boolean }): Promise>> { 13 | const path = buildPath({ 14 | endpointName: 'tags', 15 | }) 16 | return this.client.get(path, { ...params }) 17 | } 18 | 19 | public create(params: TagParam): Promise> { 20 | const path = buildPath({ 21 | endpointName: 'tags', 22 | }) 23 | return this.client.post(path, { ...params }) 24 | } 25 | 26 | public get(tagId: number): Promise> { 27 | const path = buildPath({ 28 | endpointName: `tags/${tagId}`, 29 | }) 30 | return this.client.get(path, {}) 31 | } 32 | 33 | public update(tagId: number, params: TagParam): Promise> { 34 | const path = buildPath({ 35 | endpointName: `tags/${tagId}`, 36 | }) 37 | return this.client.put(path, { ...params }) 38 | } 39 | 40 | public delete(tagId: number): Promise> { 41 | const path = buildPath({ 42 | endpointName: `tags/${tagId}`, 43 | }) 44 | return this.client.delete(path, {}) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/admin-api/src/index.ts: -------------------------------------------------------------------------------- 1 | export { AdminApiClient } from './AdminApiClient' 2 | export { AuthorizedClient } from './AuthorizedClient' 3 | export * from '@halo-dev/rest-api-client' 4 | export * from './clients' 5 | export { 6 | UploadOptions, 7 | Response, 8 | PageQuery, 9 | Page, 10 | UserParam, 11 | User, 12 | InstallParam, 13 | LoginPreCheck, 14 | AccessToken, 15 | AttachmentQuery, 16 | Attachment, 17 | Backup, 18 | PostStatus, 19 | PostEditorType, 20 | BasePostMinimal, 21 | BasePostSimple, 22 | BasePostDetail, 23 | Category, 24 | CategoryTree, 25 | CategoryParam, 26 | CommentStatus, 27 | BaseCommentParam, 28 | BaseComment, 29 | BaseCommentWithParent, 30 | JournalType, 31 | JournalCommentQuery, 32 | Journal, 33 | JournalCommentWithJournal, 34 | JournalQuery, 35 | JournalWithCmtCount, 36 | Link, 37 | LogType, 38 | Log, 39 | Menu, 40 | OptionType, 41 | OptionQuery, 42 | Photo, 43 | PhotoQuery, 44 | PostCommentWithPost, 45 | CommentQuery, 46 | PostQuery, 47 | BaseMetaParam, 48 | BaseMeta, 49 | PostMetaParam, 50 | Tag, 51 | PostParam, 52 | Post, 53 | PostDetail, 54 | SheetCommentWithSheet, 55 | Sheet, 56 | SheetDetail, 57 | IndependentSheet, 58 | SheetParam, 59 | Statistic, 60 | StatisticWithUser, 61 | TagParam, 62 | UpdateStrategy, 63 | Author, 64 | InputType, 65 | DataType, 66 | ThemeProperty, 67 | Item, 68 | Group, 69 | ThemeFile, 70 | MultiFactorAuthParam, 71 | Environment, 72 | StaticFile, 73 | StaticContentParam, 74 | } from './types' 75 | -------------------------------------------------------------------------------- /packages/rest-api-client/src/error/HaloRestAPIError.ts: -------------------------------------------------------------------------------- 1 | import { ErrorResponse } from '../types' 2 | 3 | type SingleErrorResponseData = { 4 | status: string | number 5 | message: string 6 | data?: any 7 | } 8 | 9 | type HaloErrorResponseData = SingleErrorResponseData 10 | 11 | export type HaloErrorResponse = ErrorResponse 12 | 13 | export class HaloRestAPIError extends Error { 14 | status: number | string 15 | data?: any 16 | headers: any 17 | 18 | constructor(error: HaloErrorResponse) { 19 | const { data } = HaloRestAPIError.buildErrorResponseDate(error) 20 | 21 | super(data.message) 22 | 23 | this.name = 'HaloRestAPIError' 24 | this.data = data 25 | this.status = data.status 26 | this.headers = error.headers 27 | this.message = `[${this.status}] ${this.message}` 28 | 29 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Custom_Error_Types 30 | // Maintains proper stack trace for where our error was thrown (only available on V8) 31 | if (Error.captureStackTrace) { 32 | Error.captureStackTrace(this, HaloRestAPIError) 33 | } 34 | 35 | // https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work 36 | // Set the prototype explicitly. 37 | Object.setPrototypeOf(this, HaloRestAPIError.prototype) 38 | } 39 | 40 | private static buildErrorResponseDate(error: HaloErrorResponse): { 41 | data: SingleErrorResponseData 42 | } { 43 | // improvable 44 | return { data: error.data } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/logger/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@halo-dev/logger", 3 | "version": "1.1.0", 4 | "description": "Halo SDK for JavaScript - Logger", 5 | "main": "./lib/index.js", 6 | "module": "./lib/index.js", 7 | "browser": "./lib/index.browser.js", 8 | "engines": { 9 | "node": ">=12.0.0" 10 | }, 11 | "publishConfig": { 12 | "access": "public" 13 | }, 14 | "private": false, 15 | "scripts": { 16 | "dev": "tsc --build --force --watch", 17 | "build": "tsc --build --force", 18 | "test": "jest --rootDir src" 19 | }, 20 | "types": "lib/index.d.ts", 21 | "files": [ 22 | "lib", 23 | "README.md", 24 | "LICENSE" 25 | ], 26 | "repository": { 27 | "type": "git", 28 | "url": "git+https://github.com/halo-dev/js-sdk.git", 29 | "directory": "packages/logger" 30 | }, 31 | "keywords": [ 32 | "halo", 33 | "log", 34 | "logger", 35 | "logging", 36 | "node.js", 37 | "typescript", 38 | "javascript" 39 | ], 40 | "author": "@halo-dev", 41 | "license": "MIT", 42 | "bugs": { 43 | "url": "https://github.com/halo-dev/js-sdk/issues" 44 | }, 45 | "homepage": "https://github.com/halo-dev/js-sdk#readme", 46 | "sideEffects": false, 47 | "dependencies": { 48 | "tslib": "^2.4.0" 49 | }, 50 | "devDependencies": { 51 | "@types/chai": "^4.3.1", 52 | "@types/sinon": "^9.0.11", 53 | "assert": "^1.5.0", 54 | "chai": "^4.3.6", 55 | "sinon": "^9.2.4" 56 | }, 57 | "exports": { 58 | ".": { 59 | "import": "./lib/index.js", 60 | "require": "./lib/index.js" 61 | }, 62 | "./package.json": "./package.json" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /packages/admin-api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@halo-dev/admin-api", 3 | "version": "1.1.0", 4 | "description": "Halo admin api client.", 5 | "main": "lib/index.js", 6 | "module": "./lib/index.js", 7 | "types": "lib/index.d.ts", 8 | "engines": { 9 | "node": ">=12" 10 | }, 11 | "publishConfig": { 12 | "access": "public" 13 | }, 14 | "private": false, 15 | "scripts": { 16 | "dev": "tsc --build --force --watch", 17 | "build": "tsc --build --force", 18 | "test": "jest --rootDir src" 19 | }, 20 | "files": [ 21 | "lib" 22 | ], 23 | "repository": { 24 | "type": "git", 25 | "url": "git+https://github.com/halo-dev/js-sdk.git", 26 | "directory": "packages/admin-api" 27 | }, 28 | "keywords": [ 29 | "halo", 30 | "halo-sdk", 31 | "halo-admin", 32 | "halo-admin-api" 33 | ], 34 | "maintainers": [ 35 | { 36 | "name": "guqing", 37 | "email": "1484563614@qq.com", 38 | "url": "https://github.com/guqing" 39 | }, 40 | { 41 | "name": "ryanwang", 42 | "email": "i@ryanc.cc", 43 | "url": "https://github.com/ruibaby" 44 | } 45 | ], 46 | "author": "@halo-dev", 47 | "license": "MIT", 48 | "bugs": { 49 | "url": "https://github.com/halo-dev/js-sdk/issues" 50 | }, 51 | "homepage": "https://github.com/halo-dev/js-sdk/tree/master/packages/admin-api#readme", 52 | "dependencies": { 53 | "@halo-dev/rest-api-client": "workspace:*", 54 | "tslib": "^2.4.0" 55 | }, 56 | "exports": { 57 | ".": { 58 | "import": "./lib/index.js", 59 | "require": "./lib/index.js" 60 | }, 61 | "./package.json": "./package.json" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /packages/content-api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@halo-dev/content-api", 3 | "version": "1.1.0", 4 | "description": "Halo content api client.", 5 | "main": "lib/index.js", 6 | "module": "./lib/index.js", 7 | "types": "lib/index.d.ts", 8 | "engines": { 9 | "node": ">=12" 10 | }, 11 | "publishConfig": { 12 | "access": "public" 13 | }, 14 | "private": false, 15 | "scripts": { 16 | "dev": "tsc --build --force --watch", 17 | "build": "tsc --build --force", 18 | "test": "echo \"Error: no test specified\"" 19 | }, 20 | "files": [ 21 | "lib" 22 | ], 23 | "repository": { 24 | "type": "git", 25 | "url": "git+https://github.com/halo-dev/js-sdk.git", 26 | "directory": "packages/content-api" 27 | }, 28 | "keywords": [ 29 | "halo", 30 | "halo-sdk", 31 | "halo-content-api" 32 | ], 33 | "maintainers": [ 34 | { 35 | "name": "guqing", 36 | "email": "1484563614@qq.com", 37 | "url": "https://github.com/guqing" 38 | }, 39 | { 40 | "name": "ryanwang", 41 | "email": "i@ryanc.cc", 42 | "url": "https://github.com/ruibaby" 43 | } 44 | ], 45 | "author": "@halo-dev", 46 | "license": "MIT", 47 | "bugs": { 48 | "url": "https://github.com/halo-dev/js-sdk/issues" 49 | }, 50 | "homepage": "https://github.com/halo-dev/js-sdk/tree/master/packages/content-api#readme", 51 | "dependencies": { 52 | "@halo-dev/rest-api-client": "workspace:*", 53 | "tslib": "^2.4.0" 54 | }, 55 | "exports": { 56 | ".": { 57 | "import": "./lib/index.js", 58 | "require": "./lib/index.js" 59 | }, 60 | "./package.json": "./package.json" 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /packages/admin-api/src/clients/UserClient.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@halo-dev/rest-api-client' 2 | import { buildPath } from '../url' 3 | import { MultiFactorAuth, MultiFactorAuthParam, Response, User } from '../types' 4 | 5 | export class UserClient { 6 | private client: HttpClient 7 | 8 | constructor(client: HttpClient) { 9 | this.client = client 10 | } 11 | 12 | /** 13 | * Get user profile 14 | */ 15 | public getProfile(): Promise> { 16 | const path = buildPath({ 17 | endpointName: 'users/profiles', 18 | }) 19 | return this.client.get(path, {}) 20 | } 21 | 22 | /** 23 | * Update user profile 24 | * 25 | * @param user {@link User} 26 | */ 27 | public updateProfile(user: User): Promise> { 28 | const path = buildPath({ 29 | endpointName: 'users/profiles', 30 | }) 31 | return this.client.put(path, user) 32 | } 33 | 34 | public updatePassword(params: { oldPassword: string; newPassword: string }): Promise> { 35 | const path = buildPath({ 36 | endpointName: 'users/profiles/password', 37 | }) 38 | return this.client.put(path, { ...params }) 39 | } 40 | 41 | public generateMFAQrImage(params: MultiFactorAuthParam): Promise> { 42 | const path = buildPath({ 43 | endpointName: 'users/mfa/generate', 44 | }) 45 | return this.client.put(path, { ...params }) 46 | } 47 | 48 | public updateMFAuth(params: MultiFactorAuthParam): Promise> { 49 | const path = buildPath({ 50 | endpointName: 'users/mfa/update', 51 | }) 52 | return this.client.put(path, { ...params }) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /packages/admin-api/src/clients/LinkClient.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@halo-dev/rest-api-client' 2 | import { buildPath } from '../url' 3 | import { Link, Response } from '../types' 4 | 5 | export class LinkClient { 6 | private client: HttpClient 7 | 8 | constructor(client: HttpClient) { 9 | this.client = client 10 | } 11 | 12 | public list(sort?: Array): Promise>> { 13 | const path = buildPath({ 14 | endpointName: 'links', 15 | }) 16 | return this.client.get(path, { sort }) 17 | } 18 | 19 | public create(params: Link): Promise> { 20 | const path = buildPath({ 21 | endpointName: 'links', 22 | }) 23 | return this.client.post(path, { ...params }) 24 | } 25 | 26 | public get(id: number): Promise> { 27 | const path = buildPath({ 28 | endpointName: `links/${id}`, 29 | }) 30 | return this.client.get(path, {}) 31 | } 32 | 33 | public update(linkId: number, params: Link): Promise> { 34 | const path = buildPath({ 35 | endpointName: `links/${linkId}`, 36 | }) 37 | return this.client.put(path, { ...params }) 38 | } 39 | 40 | public updateInBatch(params: Array): Promise>> { 41 | const path = buildPath({ 42 | endpointName: 'links/batch', 43 | }) 44 | return this.client.put(path, [...params]) 45 | } 46 | 47 | public async delete(id: number): Promise { 48 | const path = buildPath({ 49 | endpointName: `links/${id}`, 50 | }) 51 | await this.client.delete(path, {}) 52 | } 53 | 54 | public listTeams(): Promise>> { 55 | const path = buildPath({ 56 | endpointName: 'links/teams', 57 | }) 58 | return this.client.get(path, {}) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /packages/content-api/README.md: -------------------------------------------------------------------------------- 1 |

Content API Client

2 | 3 |

4 | 5 | npm version 6 | 7 | 8 | npm 9 | 10 | 11 | node-current 12 | 13 | 14 | NPM 15 | 16 |

17 | 18 |

JavaScript SDK for Halo's Content API,implemented with TypeScript,encapsulating parameter types and return value types to make the use of API more brief.

19 | 20 | ## Installation 21 | 22 | ```shell 23 | npm install @halo-dev/content-api --save 24 | ``` 25 | 26 | ## Usage 27 | 28 | Here is a simple code for obtaining a list of posts. 29 | 30 | ```javascript 31 | import { ContentApiClient, HaloRestAPIClient } from '@halo-dev/content-api' 32 | 33 | // http request tool for halo rest api. 34 | const haloRestApiClient = new HaloRestAPIClient({ 35 | baseUrl: process.env.HALO_BASE_URL, 36 | auth: { apiToken: process.env.HALO_API_TOKEN }, 37 | }) 38 | 39 | // create contentApiClient by haloRestApiCLient. 40 | const haloContentClient = new ContentApiClient(haloRestApiClient) 41 | 42 | // obtaining a list of articles. 43 | haloContentClient.post.list().then((res) => { 44 | console.log(res) 45 | }) 46 | ``` 47 | 48 | ### License 49 | 50 | [MIT license](../../LICENSE) 51 | -------------------------------------------------------------------------------- /packages/tracker/public/halo-tracker.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";!function(t){var e=t.screen,r=e.width,n=e.height,a=t.navigator.language,o=t.location,i=t.localStorage,c=t.document,u=t.history,l=o.hostname,s=o.pathname,p=o.search,f=c.currentScript;if(f){var h=function(t,e,r){var n=t[e];return function(){for(var e=[],a=arguments.length;a--;)e[a]=arguments[a];return r.apply(null,e),n.apply(t,e)}},d=function(){return i&&i.getItem("haloTracker.disabled")||T&&function(){var e=t.doNotTrack,r=t.navigator,n=t.external,a="msTrackingProtectionEnabled",o=e||r.doNotTrack||r.msDoNotTrack||n&&a in n&&n[a]();return"1"==o||"yes"===o}()||j&&!w.includes(l)},g="data-",v=f.getAttribute.bind(f),m=v(g+"group")||"",k=v(g+"plural"),y=v(g+"name"),S=v(g+"host-url"),b="false"!==v(g+"auto-track"),T=v(g+"do-not-track"),j=v(g+"domains")||"",w=j.split(",").map((function(t){return t.trim()})),E=(S?S.replace(/\/$/,""):f.src.split("/").slice(0,-1).join("/"))+"/apis/api.halo.run/v1alpha1/trackers/counter",N=r+"x"+n,O=""+s+p,x=c.referrer,P=function(t,e){return void 0===t&&(t=O),void 0===e&&(e=x),function(t){if(!d())return fetch(E,{method:"POST",body:JSON.stringify(Object.assign({},t)),headers:{"Content-Type":"application/json"}}).then((function(t){return t.text()})).then((function(t){console.debug("Visit count:",t)}))}((r={group:m,plural:k,name:y,hostname:l,screen:N,language:a,url:O},n={url:t,referrer:e},Object.keys(n).forEach((function(t){void 0!==n[t]&&(r[t]=n[t])})),r));var r,n},V=function(t,e,r){if(r){x=O;var n=r.toString();(O="http"===n.substring(0,4)?"/"+n.split("/").splice(3).join("/"):n)!==x&&P()}};if(!t.haloTracker){var A=function(t){return trackEvent(t)};A.trackView=P,t.haloTracker=A}if(b&&!d()){u.pushState=h(u,"pushState",V),u.replaceState=h(u,"replaceState",V);var C=function(){"complete"===c.readyState&&P()};c.addEventListener("readystatechange",C,!0),C()}}}(window)}(); 2 | -------------------------------------------------------------------------------- /packages/logger/src/types/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * A log function that can be dynamically enabled and redirected. 3 | */ 4 | export interface Debugger { 5 | /** 6 | * True if this logger is active and logging. 7 | */ 8 | enabled: boolean 9 | /** 10 | * Used to cleanup/remove this logger. 11 | */ 12 | destroy: () => boolean 13 | /** 14 | * The current log method. Can be overridden to redirect output. 15 | */ 16 | log: (...args: any[]) => void 17 | /** 18 | * The namespace of this logger. 19 | */ 20 | namespace: string 21 | /** 22 | * Extends this logger with a child namespace. 23 | * Namespaces are separated with a ':' character. 24 | */ 25 | extend: (namespace: string) => Debugger 26 | 27 | /** 28 | * Logs the given arguments to the `log` method. 29 | */ 30 | (...args: any[]): void 31 | } 32 | 33 | /** 34 | * A simple mechanism for enabling logging. 35 | * Intended to mimic the publicly available `debug` package. 36 | */ 37 | export interface Debug { 38 | /** 39 | * The default log method (defaults to console) 40 | */ 41 | log: (...args: any[]) => void 42 | /** 43 | * Enables a particular set of namespaces. 44 | * To enable multiple separate them with commas, e.g. "info,debug". 45 | * Supports wildcards, e.g. "halo:*" 46 | * Supports skip syntax, e.g. "halo:*,-halo:storage:*" will enable 47 | * everything under halo except for things under halo:storage. 48 | */ 49 | enable: (namespaces: string) => void 50 | /** 51 | * Checks if a particular namespace is enabled. 52 | */ 53 | enabled: (namespace: string) => boolean 54 | /** 55 | * Disables all logging, returns what was previously enabled. 56 | */ 57 | disable: () => string 58 | 59 | /** 60 | * Creates a new logger with the given namespace. 61 | */ 62 | (namespace: string): Debugger 63 | } 64 | -------------------------------------------------------------------------------- /packages/rest-api-client/src/platform/index.ts: -------------------------------------------------------------------------------- 1 | import { DiscriminatedAuth } from '../types' 2 | 3 | type PlatformDeps = { 4 | readFileFromPath: (filePath: string) => Promise<{ name: string; data: unknown }> 5 | getRequestToken: () => Promise 6 | getDefaultAuth: () => DiscriminatedAuth 7 | buildPlatformDependentConfig: (params: object) => object 8 | buildHeaders: (params: { userAgent?: string }) => Record 9 | buildFormDataValue: (data: unknown) => unknown 10 | buildBaseUrl: (baseUrl?: string) => string 11 | getVersion: () => string 12 | } 13 | 14 | export const platformDeps: PlatformDeps = { 15 | readFileFromPath: () => { 16 | throw new Error('not implemented') 17 | }, 18 | getRequestToken: () => { 19 | throw new Error('not implemented') 20 | }, 21 | getDefaultAuth: () => { 22 | throw new Error('not implemented') 23 | }, 24 | buildPlatformDependentConfig: () => { 25 | throw new Error('not implemented') 26 | }, 27 | buildHeaders: () => { 28 | throw new Error('not implemented') 29 | }, 30 | buildFormDataValue: () => { 31 | throw new Error('not implemented') 32 | }, 33 | buildBaseUrl: () => { 34 | throw new Error('not implemented') 35 | }, 36 | getVersion: () => { 37 | throw new Error('not implemented') 38 | }, 39 | } 40 | 41 | export const injectPlatformDeps = (deps: Partial) => { 42 | platformDeps.readFileFromPath = deps.readFileFromPath! 43 | platformDeps.getRequestToken = deps.getRequestToken! 44 | platformDeps.getDefaultAuth = deps.getDefaultAuth! 45 | platformDeps.buildPlatformDependentConfig = deps.buildPlatformDependentConfig! 46 | platformDeps.buildHeaders = deps.buildHeaders! 47 | platformDeps.buildFormDataValue = deps.buildFormDataValue! 48 | platformDeps.buildBaseUrl = deps.buildBaseUrl! 49 | platformDeps.getVersion = deps.getVersion! 50 | } 51 | -------------------------------------------------------------------------------- /packages/admin-api/README.md: -------------------------------------------------------------------------------- 1 |

Admin API Client

2 | 3 |

4 | 5 | npm version 6 | 7 | 8 | npm 9 | 10 | 11 | node-current 12 | 13 | 14 | NPM 15 | 16 |

17 | 18 |

JavaScript SDK for Halo's Admin API,implemented with TypeScript,encapsulating parameter types and return value types to make the use of API more brief.

19 | 20 | ## Installation 21 | 22 | ```shell 23 | npm install @halo-dev/admin-api --save 24 | ``` 25 | 26 | ## Usage 27 | 28 | Here is a simple code for obtaining a list of posts. 29 | 30 | ```javascript 31 | import { AdminApiClient, HaloRestAPIClient } from '@halo-dev/admin-api' 32 | 33 | // http request tool for halo rest api. 34 | const haloRestApiClient = new HaloRestAPIClient({ 35 | baseUrl: process.env.HALO_BASE_URL, 36 | }) 37 | 38 | // create adminApiClient by haloRestApiCLient. 39 | const haloAdminClient = new AdminApiClient(haloRestApiClient) 40 | 41 | // obtaining a list of articles. 42 | haloAdminClient.post.list().then((res) => { 43 | console.log(res) 44 | }) 45 | ``` 46 | 47 | You can also view the complete implementation of the halo-admin project: [@halo-dev/halo-admin](https://github.com/halo-dev/halo-admin). 48 | 49 | ### License 50 | 51 | [MIT license](../../LICENSE) 52 | -------------------------------------------------------------------------------- /packages/admin-api/src/clients/StaticStorageClient.ts: -------------------------------------------------------------------------------- 1 | import { FormData, HttpClient } from '@halo-dev/rest-api-client' 2 | import { Response, StaticContentParam, StaticFile, UploadOptions } from '../types' 3 | import { buildPath } from '../url' 4 | 5 | export class StaticStorageClient { 6 | private client: HttpClient 7 | 8 | constructor(client: HttpClient) { 9 | this.client = client 10 | } 11 | 12 | public list(): Promise>> { 13 | const path = buildPath({ 14 | endpointName: `statics`, 15 | }) 16 | return this.client.get(path, {}) 17 | } 18 | 19 | public delete(filePath: string): Promise> { 20 | const path = buildPath({ 21 | endpointName: `statics`, 22 | }) 23 | return this.client.delete(path, { 24 | path: filePath, 25 | }) 26 | } 27 | 28 | public createFolder(basePath: string, folderName: string): Promise> { 29 | const path = buildPath({ 30 | endpointName: `statics?basePath=${basePath}&folderName=${folderName}`, 31 | }) 32 | return this.client.post(path, {}) 33 | } 34 | 35 | public upload(file: File, options: UploadOptions, basePath: string): Promise> { 36 | const path = buildPath({ 37 | endpointName: `statics/upload?basePath=${basePath}`, 38 | }) 39 | const formData = new FormData() 40 | formData.append('file', file) 41 | return this.client.post(path, formData, { ...options }) 42 | } 43 | 44 | public rename(basePath: string, newName: string): Promise> { 45 | const path = buildPath({ 46 | endpointName: `statics/rename?basePath=${basePath}&newName=${newName}`, 47 | }) 48 | return this.client.post(path, {}) 49 | } 50 | 51 | public saveContent(params: StaticContentParam): Promise> { 52 | const path = buildPath({ 53 | endpointName: `statics/files`, 54 | }) 55 | return this.client.put(path, params) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/rest-api-client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@halo-dev/rest-api-client", 3 | "version": "1.1.0", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "description": "Halo REST API client for JavaScript", 8 | "private": false, 9 | "main": "lib/index.js", 10 | "module": "lib/index.js", 11 | "browser": "lib/index.browser.js", 12 | "types": "lib/index.d.ts", 13 | "scripts": { 14 | "dev": "tsc --build --force --watch", 15 | "build": "tsc --build --force", 16 | "test": "jest --rootDir src" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/halo-dev/js-sdk.git", 21 | "directory": "packages/rest-api-client" 22 | }, 23 | "files": [ 24 | "lib", 25 | "index.mjs" 26 | ], 27 | "keywords": [ 28 | "halo", 29 | "rest-api", 30 | "api-client", 31 | "sdk" 32 | ], 33 | "maintainers": [ 34 | { 35 | "name": "guqing", 36 | "email": "1484563614@qq.com", 37 | "url": "https://github.com/guqing" 38 | } 39 | ], 40 | "license": "MIT", 41 | "bugs": { 42 | "url": "https://github.com/halo-dev/js-sdk/issues" 43 | }, 44 | "engines": { 45 | "node": ">=12" 46 | }, 47 | "homepage": "https://github.com/halo-dev/js-sdk/tree/master/packages/rest-api-client#readme", 48 | "dependencies": { 49 | "@halo-dev/logger": "workspace:*", 50 | "axios": "^0.24.0", 51 | "form-data": "^4.0.0", 52 | "js-base64": "^3.7.2", 53 | "qs": "^6.10.3", 54 | "tslib": "^2.4.0" 55 | }, 56 | "devDependencies": { 57 | "@types/qs": "^6.9.7", 58 | "@types/store": "^2.0.2", 59 | "axios-mock-adapter": "^1.20.0" 60 | }, 61 | "exports": { 62 | ".": { 63 | "node": { 64 | "import": "./index.mjs", 65 | "require": "./lib/index.js", 66 | "default": "./lib/index.js" 67 | }, 68 | "browser": "./lib/index.browser.js" 69 | }, 70 | "./package.json": "./package.json" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /packages/markdown-renderer/src/mermaid/index.js: -------------------------------------------------------------------------------- 1 | import Mermaid from 'mermaid' 2 | import Murmur from './murmurhash3_gc.js' 3 | 4 | // const swapObj = (obj) => { 5 | // const result = {}; 6 | // Object.entries(obj).forEach(([key, value]) => { 7 | // result[value] = key; 8 | // }); 9 | // return result; 10 | // }; 11 | 12 | const htmlEntities = (str) => String(str).replace(/&/g, '&').replace(//g, '>') 13 | 14 | const MermaidChart = (code) => { 15 | try { 16 | var needsUniqueId = 'render' + Murmur(code, 42).toString() 17 | Mermaid.mermaidAPI.render(needsUniqueId, code, (sc) => { 18 | code = sc 19 | }) 20 | return `
${code}
` 21 | } catch (err) { 22 | return `
${htmlEntities(err.name)}: ${htmlEntities(err.message)}
` 23 | } 24 | } 25 | 26 | const MermaidPlugIn = (md, opts) => { 27 | Object.assign(MermaidPlugIn.default, opts) 28 | const { token: _token = 'mermaid', ...dictionary } = MermaidPlugIn.default.dictionary 29 | // const dictionary = swapObj(_dictionary); 30 | Mermaid.initialize(MermaidPlugIn.default) 31 | 32 | const defaultRenderer = md.renderer.rules.fence.bind(md.renderer.rules) 33 | 34 | function replacer(_, p1, p2, p3) { 35 | p1 = dictionary[p1] ?? p1 36 | p2 = dictionary[p2] ?? p2 37 | return p2 === '' ? `${p1}\n` : `${p1} ${p2}${p3}` 38 | } 39 | 40 | md.renderer.rules.fence = (tokens, idx, opts, env, self) => { 41 | const token = tokens[idx] 42 | const code = token.content.trim() 43 | if (token.info.trim() === _token) { 44 | return MermaidChart(code.replace(/(.*?)[ \n](.*?)([ \n])/, replacer)) 45 | } 46 | return defaultRenderer(tokens, idx, opts, env, self) 47 | } 48 | } 49 | 50 | MermaidPlugIn.default = { 51 | startOnLoad: false, 52 | securityLevel: 'true', 53 | theme: 'default', 54 | flowchart: { 55 | htmlLabels: false, 56 | useMaxWidth: true, 57 | }, 58 | dictionary: { 59 | token: 'mermaid', 60 | }, 61 | } 62 | 63 | export default MermaidPlugIn 64 | -------------------------------------------------------------------------------- /packages/markdown-renderer/src/markdown.ts: -------------------------------------------------------------------------------- 1 | import escape from 'lodash.escape' 2 | import MarkdownIt from 'markdown-it' 3 | // @ts-ignore 4 | import MarkdownItAbbr from 'markdown-it-abbr' 5 | import MarkdownItAnchor from 'markdown-it-anchor' 6 | // @ts-ignore 7 | import MarkdownItAttrs from 'markdown-it-attrs' 8 | // @ts-ignore 9 | import MarkdownItEmoji from 'markdown-it-emoji' 10 | // @ts-ignore 11 | import MarkdownItFootnote from 'markdown-it-footnote' 12 | // @ts-ignore 13 | import MarkdownItImagesPreview from 'markdown-it-images-preview' 14 | // @ts-ignore 15 | import MarkdownItIns from 'markdown-it-ins' 16 | // @ts-ignore 17 | import MarkdownItKatex from '@iktakahiro/markdown-it-katex' 18 | // @ts-ignore 19 | import MarkdownItMark from 'markdown-it-mark' 20 | // @ts-ignore 21 | import MarkdownItSub from 'markdown-it-sub' 22 | // @ts-ignore 23 | import MarkdownItSup from 'markdown-it-sup' 24 | // @ts-ignore 25 | import MarkdownItTableOfContents from 'markdown-it-table-of-contents' 26 | // @ts-ignore 27 | import MarkdownItTaskLists from 'markdown-it-task-lists' 28 | // @ts-ignore 29 | import MarkdownItMermaid from './mermaid' 30 | 31 | const markdownIt = new MarkdownIt({ 32 | html: true, 33 | xhtmlOut: true, 34 | breaks: true, 35 | linkify: true, 36 | typographer: true, 37 | highlight: (str: string, lang: string) => { 38 | return `
${escape(str)}
` 39 | }, 40 | }) 41 | 42 | markdownIt 43 | .use(MarkdownItMermaid) 44 | .use(MarkdownItAbbr) 45 | .use(MarkdownItAnchor) 46 | .use(MarkdownItAttrs, { 47 | allowedAttributes: ['id', 'class', 'target'], 48 | }) 49 | .use(MarkdownItEmoji) 50 | .use(MarkdownItFootnote) 51 | .use(MarkdownItImagesPreview) 52 | .use(MarkdownItIns) 53 | .use(MarkdownItKatex, { 54 | trust: true, 55 | }) 56 | .use(MarkdownItMark) 57 | .use(MarkdownItSub) 58 | .use(MarkdownItSup) 59 | .use(MarkdownItTableOfContents, { 60 | includeLevel: [1, 2, 3, 4, 5, 6], 61 | markerPattern: /^\[TOC\]/im, 62 | }) 63 | .use(MarkdownItTaskLists) 64 | 65 | export { markdownIt } 66 | -------------------------------------------------------------------------------- /packages/rest-api-client/src/platform/node.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import { promisify } from 'util' 3 | import { basename } from 'path' 4 | import { UnsupportedPlatformError } from './UnsupportedPlatformError' 5 | import https from 'https' 6 | import os from 'os' 7 | // eslint-disable-next-line @typescript-eslint/no-var-requires 8 | const packageJson = require('../../package.json') 9 | 10 | const readFile = promisify(fs.readFile) 11 | 12 | export const readFileFromPath = async (filePath: string) => { 13 | const data = await readFile(filePath) 14 | const name = basename(filePath) 15 | return { data, name } 16 | } 17 | 18 | export const getRequestToken = () => { 19 | throw new UnsupportedPlatformError('Node.js') 20 | } 21 | 22 | export const getDefaultAuth = () => { 23 | throw new UnsupportedPlatformError('Node.js') 24 | } 25 | 26 | export const buildPlatformDependentConfig = (params: { 27 | clientCertAuth?: 28 | | { 29 | pfx: Buffer 30 | password: string 31 | } 32 | | { 33 | pfxFilePath: string 34 | password: string 35 | } 36 | }) => { 37 | const clientCertAuth = params.clientCertAuth 38 | 39 | if (clientCertAuth) { 40 | const pfx = 'pfx' in clientCertAuth ? clientCertAuth.pfx : fs.readFileSync(clientCertAuth.pfxFilePath) 41 | const httpsAgent = new https.Agent({ 42 | pfx, 43 | passphrase: clientCertAuth.password, 44 | }) 45 | return { httpsAgent } 46 | } 47 | return {} 48 | } 49 | 50 | export const buildHeaders = (params: { userAgent?: string }) => { 51 | const { userAgent } = params 52 | return { 53 | 'User-Agent': `Node.js/${process.version}(${os.type()}) ${packageJson.name}@${packageJson.version}${ 54 | userAgent ? ` ${userAgent}` : '' 55 | }`, 56 | } 57 | } 58 | 59 | export const buildFormDataValue = (data: unknown) => { 60 | return data 61 | } 62 | 63 | export const buildBaseUrl = (baseUrl: string | undefined) => { 64 | if (typeof baseUrl === 'undefined') { 65 | throw new Error('in Node.js environment, baseUrl is required') 66 | } 67 | return baseUrl 68 | } 69 | 70 | export const getVersion = () => { 71 | return packageJson.version 72 | } 73 | -------------------------------------------------------------------------------- /packages/admin-api/src/AuthorizedClient.ts: -------------------------------------------------------------------------------- 1 | import { buildPath } from './url' 2 | import { AccessToken, LoginPreCheck, Response } from './types' 3 | import { DefaultHttpClient, HaloRequestConfigBuilder, HaloResponseHandler } from '@halo-dev/rest-api-client' 4 | 5 | export class AuthorizedClient { 6 | private client: DefaultHttpClient 7 | 8 | constructor(baseUrl: string) { 9 | const requestConfigBuilder = new HaloRequestConfigBuilder({ 10 | baseUrl: baseUrl, 11 | }) 12 | const responseHandler = new HaloResponseHandler() 13 | this.client = new DefaultHttpClient({ 14 | responseHandler, 15 | requestConfigBuilder, 16 | }) 17 | } 18 | 19 | public isInstalled(): Promise> { 20 | const path = buildPath({ 21 | endpointName: 'is_installed', 22 | }) 23 | return this.client.get(path, {}) 24 | } 25 | 26 | public sendResetPasswordCode(params: { 27 | username: string 28 | email: string 29 | code?: string 30 | password?: string 31 | }): Promise { 32 | const path = buildPath({ 33 | endpointName: 'password/code', 34 | }) 35 | return this.client.post(path, params) 36 | } 37 | 38 | public resetPassword(params: { username: string; email: string; code?: string; password?: string }): Promise { 39 | const path = buildPath({ 40 | endpointName: 'password/reset', 41 | }) 42 | return this.client.post(path, params) 43 | } 44 | 45 | public refreshToken(refreshToken: string): Promise> { 46 | const path = buildPath({ 47 | endpointName: `refresh/${refreshToken}`, 48 | }) 49 | return this.client.post(path, {}) 50 | } 51 | 52 | public login(params: { username: string; password: string; authcode: boolean }): Promise> { 53 | const path = buildPath({ 54 | endpointName: 'login', 55 | }) 56 | return this.client.post(path, { ...params }) 57 | } 58 | 59 | public needMFACode(params: { username: string; password: string }): Promise> { 60 | const path = buildPath({ 61 | endpointName: 'login/precheck', 62 | }) 63 | return this.client.post(path, { ...params }) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /packages/content-api/src/clients/PostClient.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@halo-dev/rest-api-client' 2 | import { buildPath } from '../url' 3 | import { BasePostSimple, Page, PageQuery, PostDetail, PostList, Response } from '../types' 4 | 5 | export class PostClient { 6 | private client: HttpClient 7 | 8 | constructor(client: HttpClient) { 9 | this.client = client 10 | } 11 | 12 | public list(params: PageQuery, keyword?: string, categoryId?: number): Promise> { 13 | const path = buildPath({ 14 | endpointName: 'posts', 15 | }) 16 | return this.client.get(path, { keyword, categoryId, ...params }) 17 | } 18 | 19 | public search(keyword: string, pageQuery?: PageQuery): Promise> { 20 | const path = buildPath({ 21 | endpointName: 'posts/search', 22 | }) 23 | return this.client.get(path, { keyword, ...pageQuery }) 24 | } 25 | 26 | public get( 27 | postId: number, 28 | params?: { 29 | formatDisabled: boolean 30 | sourceDisabled: boolean 31 | }, 32 | ): Promise> { 33 | const path = buildPath({ 34 | endpointName: `posts/${postId}`, 35 | }) 36 | return this.client.get(path, { ...params }) 37 | } 38 | 39 | public getBySlug( 40 | slug: string, 41 | params: { 42 | formatDisabled: boolean 43 | sourceDisabled: boolean 44 | }, 45 | ): Promise> { 46 | const path = buildPath({ 47 | endpointName: 'posts/slug', 48 | }) 49 | return this.client.get(path, { slug, ...params }) 50 | } 51 | 52 | public getPrevPostById(postId: number): Promise> { 53 | const path = buildPath({ 54 | endpointName: `posts/${postId}/prev`, 55 | }) 56 | return this.client.get(path, {}) 57 | } 58 | 59 | public getNextPostById(postId: number): Promise> { 60 | const path = buildPath({ 61 | endpointName: `posts/${postId}/next`, 62 | }) 63 | return this.client.get(path, {}) 64 | } 65 | 66 | public async like(postId: number): Promise { 67 | const path = buildPath({ 68 | endpointName: `posts/${postId}/likes`, 69 | }) 70 | await this.client.get(path, {}) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@halo-dev/js-sdk", 3 | "version": "0.0.0", 4 | "description": "Packages for Halo JavaScript SDK.", 5 | "private": true, 6 | "scripts": { 7 | "test": "pnpm --filter './packages/**' run test", 8 | "dev": "pnpm --filter './packages/**' run dev --parallel", 9 | "build": "pnpm --filter './packages/**' run build", 10 | "build:docs": "typedoc --excludeExternals --readme README.md --entryPoints packages/admin-api/src packages/content-api/src packages/logger/src packages/rest-api-client/src", 11 | "lint": "eslint .", 12 | "cleanup": "rimraf node_modules docs packages/**/lib packages/**/node_modules", 13 | "changeset": "changeset", 14 | "release": "changeset publish" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/halo-dev/js-sdk.git" 19 | }, 20 | "keywords": [ 21 | "halo", 22 | "halo-sdk" 23 | ], 24 | "maintainers": [ 25 | { 26 | "name": "guqing", 27 | "email": "1484563614@qq.com", 28 | "url": "https://github.com/guqing" 29 | }, 30 | { 31 | "name": "ryanwang", 32 | "email": "i@ryanc.cc", 33 | "url": "https://github.com/ruibaby" 34 | } 35 | ], 36 | "author": "@halo-dev", 37 | "license": "MIT", 38 | "bugs": { 39 | "url": "https://github.com/halo-dev/js-sdk/issues" 40 | }, 41 | "homepage": "https://github.com/halo-dev/js-sdk#readme", 42 | "workspaces": [ 43 | "packages/*" 44 | ], 45 | "devDependencies": { 46 | "@babel/core": "^7.18.2", 47 | "@babel/preset-env": "^7.18.2", 48 | "@babel/preset-typescript": "^7.17.12", 49 | "@changesets/cli": "^2.22.0", 50 | "@types/jest": "^26.0.24", 51 | "@types/node": "^17.0.35", 52 | "@typescript-eslint/eslint-plugin": "^5.26.0", 53 | "@typescript-eslint/parser": "^5.26.0", 54 | "eslint": "^8.16.0", 55 | "eslint-config-prettier": "^8.5.0", 56 | "eslint-plugin-prettier": "^4.0.0", 57 | "husky": "^7.0.4", 58 | "jest": "^26.6.3", 59 | "lint-staged": "^12.4.2", 60 | "prettier": "^2.6.2", 61 | "rimraf": "^3.0.2", 62 | "ts-jest": "^26.5.6", 63 | "typedoc": "^0.22.15", 64 | "typedoc-plugin-missing-exports": "^0.22.6", 65 | "typescript": "^4.7.2" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /packages/admin-api/src/clients/JournalClient.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@halo-dev/rest-api-client' 2 | import { buildPath } from '../url' 3 | import { Journal, JournalParam, JournalQuery, JournalWithCmtCount, Page, Response } from '../types' 4 | 5 | export class JournalClient { 6 | private client: HttpClient 7 | 8 | constructor(client: HttpClient) { 9 | this.client = client 10 | } 11 | 12 | /** 13 | * Lists journals. 14 | * 15 | * @param params parameter for queries 16 | * @returns A page response of journals. 17 | */ 18 | public list(params: JournalQuery): Promise>> { 19 | const path = buildPath({ 20 | endpointName: 'journals', 21 | }) 22 | return this.client.get(path, { ...params }) 23 | } 24 | 25 | /** 26 | * Gets latest journals. 27 | * 28 | * @param top top option for queries 29 | * @returns A response of lastes journals. 30 | */ 31 | public latest(top: number): Promise>> { 32 | const path = buildPath({ 33 | endpointName: 'journals/latest', 34 | }) 35 | return this.client.get(path, { top }) 36 | } 37 | 38 | /** 39 | * Creates a journal. 40 | * 41 | * @param params parameter for creates 42 | * @returns A response of created journal. 43 | */ 44 | public create(params: JournalParam): Promise> { 45 | const path = buildPath({ 46 | endpointName: 'journals', 47 | }) 48 | return this.client.post(path, { ...params }) 49 | } 50 | 51 | /** 52 | * Updates a journal by id. 53 | * 54 | * @param journalId journal id 55 | * @param params parameter for updates 56 | * @returns A response of updated journal. 57 | */ 58 | public update(journalId: number, params: JournalParam): Promise> { 59 | const path = buildPath({ 60 | endpointName: `journals/${journalId}`, 61 | }) 62 | return this.client.put(path, { ...params }) 63 | } 64 | 65 | /** 66 | * Deletes a journal by id. 67 | * @param journalId journal id 68 | */ 69 | public async delete(journalId: number): Promise { 70 | const path = buildPath({ 71 | endpointName: `journals/${journalId}`, 72 | }) 73 | await this.client.delete(path, {}) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /packages/markdown-renderer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@halo-dev/markdown-renderer", 3 | "version": "1.1.0", 4 | "description": "Halo markdown renderer.", 5 | "main": "lib/markdown-renderer.umd.js", 6 | "module": "lib/markdown-renderer.es.js", 7 | "engines": { 8 | "node": ">=12" 9 | }, 10 | "publishConfig": { 11 | "access": "public" 12 | }, 13 | "private": false, 14 | "scripts": { 15 | "dev": "vite build --watch", 16 | "build": "vite build", 17 | "test": "echo \"Error: no test specified\"" 18 | }, 19 | "files": [ 20 | "lib" 21 | ], 22 | "repository": { 23 | "type": "git", 24 | "url": "git+https://github.com/halo-dev/js-sdk.git", 25 | "directory": "packages/markdown-renderer" 26 | }, 27 | "keywords": [ 28 | "halo", 29 | "halo-sdk", 30 | "markdown", 31 | "markdown-it", 32 | "markdown-renderer" 33 | ], 34 | "maintainers": [ 35 | { 36 | "name": "ryanwang", 37 | "email": "i@ryanc.cc", 38 | "url": "https://github.com/ruibaby" 39 | } 40 | ], 41 | "author": "@halo-dev", 42 | "license": "MIT", 43 | "bugs": { 44 | "url": "https://github.com/halo-dev/js-sdk/issues" 45 | }, 46 | "homepage": "https://github.com/halo-dev/js-sdk/tree/master/packages/markdown-renderer#readme", 47 | "dependencies": { 48 | "@iktakahiro/markdown-it-katex": "^4.0.1", 49 | "lodash.escape": "^4.0.1", 50 | "markdown-it": "^12.3.2", 51 | "markdown-it-abbr": "^1.0.4", 52 | "markdown-it-anchor": "^8.6.4", 53 | "markdown-it-attrs": "^4.1.4", 54 | "markdown-it-emoji": "^2.0.2", 55 | "markdown-it-footnote": "^3.0.3", 56 | "markdown-it-images-preview": "^1.0.1", 57 | "markdown-it-ins": "^3.0.1", 58 | "markdown-it-mark": "^3.0.1", 59 | "markdown-it-sub": "^1.0.0", 60 | "markdown-it-sup": "^1.0.0", 61 | "markdown-it-table-of-contents": "^0.6.0", 62 | "markdown-it-task-lists": "^2.1.1", 63 | "mermaid": "^8.14.0" 64 | }, 65 | "devDependencies": { 66 | "@types/lodash.escape": "^4.0.7", 67 | "@types/markdown-it": "^12.2.3", 68 | "vite": "^2.9.9" 69 | }, 70 | "exports": { 71 | ".": { 72 | "import": "./lib/markdown-renderer.es.js", 73 | "require": "./lib/markdown-renderer.umd.js" 74 | }, 75 | "./package.json": "./package.json" 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /packages/markdown-renderer/src/mermaid/murmurhash3_gc.js: -------------------------------------------------------------------------------- 1 | /** 2 | * JS Implementation of MurmurHash3 (r136) (as of May 20, 2011) 3 | * 4 | * Modifed to support non-ascii string by encoding to utf-8 5 | * 6 | * @author Gary Court 7 | * @see http://github.com/garycourt/murmurhash-js 8 | * @author Austin Appleby 9 | * @see http://sites.google.com/site/murmurhash/ 10 | * 11 | * @param {string} str string to hash 12 | * @param {number} seed Positive integer only 13 | * @return {number} 32-bit positive integer hash 14 | */ 15 | 16 | function murmurhash3_32_gc(str, seed) { 17 | // eslint-disable-next-line 18 | var key, remainder, bytes, h1, h1b, c1, c1b, c2, c2b, k1, i 19 | 20 | key = new TextEncoder().encode(str) 21 | 22 | remainder = key.length & 3 // key.length % 4 23 | bytes = key.length - remainder 24 | h1 = seed 25 | c1 = 0xcc9e2d51 26 | c2 = 0x1b873593 27 | i = 0 28 | 29 | while (i < bytes) { 30 | k1 = (key[i] & 0xff) | ((key[++i] & 0xff) << 8) | ((key[++i] & 0xff) << 16) | ((key[++i] & 0xff) << 24) 31 | ++i 32 | 33 | k1 = ((k1 & 0xffff) * c1 + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff 34 | k1 = (k1 << 15) | (k1 >>> 17) 35 | k1 = ((k1 & 0xffff) * c2 + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff 36 | 37 | h1 ^= k1 38 | h1 = (h1 << 13) | (h1 >>> 19) 39 | h1b = ((h1 & 0xffff) * 5 + ((((h1 >>> 16) * 5) & 0xffff) << 16)) & 0xffffffff 40 | h1 = (h1b & 0xffff) + 0x6b64 + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16) 41 | } 42 | 43 | k1 = 0 44 | 45 | switch (remainder) { 46 | case 3: 47 | k1 ^= (key[i + 2] & 0xff) << 16 48 | // eslint-disable-next-line no-fallthrough 49 | case 2: 50 | k1 ^= (key[i + 1] & 0xff) << 8 51 | // eslint-disable-next-line no-fallthrough 52 | case 1: 53 | k1 ^= key[i] & 0xff 54 | 55 | k1 = ((k1 & 0xffff) * c1 + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff 56 | k1 = (k1 << 15) | (k1 >>> 17) 57 | k1 = ((k1 & 0xffff) * c2 + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff 58 | h1 ^= k1 59 | } 60 | 61 | h1 ^= key.length 62 | 63 | h1 ^= h1 >>> 16 64 | h1 = ((h1 & 0xffff) * 0x85ebca6b + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff 65 | h1 ^= h1 >>> 13 66 | h1 = ((h1 & 0xffff) * 0xc2b2ae35 + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16)) & 0xffffffff 67 | h1 ^= h1 >>> 16 68 | 69 | return h1 >>> 0 70 | } 71 | 72 | export default murmurhash3_32_gc 73 | -------------------------------------------------------------------------------- /packages/admin-api/src/clients/OptionClient.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@halo-dev/rest-api-client' 2 | import { buildPath } from '../url' 3 | import { Option, OptionQuery, Response } from '../types' 4 | 5 | export class OptionClient { 6 | private client: HttpClient 7 | 8 | constructor(client: HttpClient) { 9 | this.client = client 10 | } 11 | 12 | public list(): Promise>> { 13 | const path = buildPath({ 14 | endpointName: 'options', 15 | }) 16 | return this.client.get(path, {}) 17 | } 18 | 19 | public create(params: Option): Promise> { 20 | const path = buildPath({ 21 | endpointName: 'options', 22 | }) 23 | return this.client.post(path, { ...params }) 24 | } 25 | 26 | public get(id: number): Promise> { 27 | const path = buildPath({ 28 | endpointName: `options/${id}`, 29 | }) 30 | return this.client.get(path, {}) 31 | } 32 | 33 | public update(optionId: number, params: Option): Promise> { 34 | const path = buildPath({ 35 | endpointName: `options/${optionId}`, 36 | }) 37 | return this.client.put(path, { ...params }) 38 | } 39 | 40 | public async delete(optionId: number): Promise { 41 | const path = buildPath({ 42 | endpointName: `options/${optionId}`, 43 | }) 44 | await this.client.delete(path, {}) 45 | } 46 | 47 | public listAsView(params: OptionQuery): Promise>> { 48 | const path = buildPath({ 49 | endpointName: 'options/list_view', 50 | }) 51 | return this.client.get(path, { ...params }) 52 | } 53 | 54 | public listAsMapView(): Promise>> { 55 | const path = buildPath({ 56 | endpointName: 'options/map_view', 57 | }) 58 | return this.client.get(path, {}) 59 | } 60 | 61 | public listAsMapViewByKeys(params: Array): Promise>> { 62 | const path = buildPath({ 63 | endpointName: 'options/map_view/keys', 64 | }) 65 | return this.client.post(path, params) 66 | } 67 | 68 | public async saveMapView(params: any): Promise { 69 | const path = buildPath({ 70 | endpointName: 'options/map_view/saving', 71 | }) 72 | await this.client.post(path, { ...params }) 73 | } 74 | 75 | public async save(params: Array