@solar-taro/planets 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -0
- package/README.md +11 -0
- package/eslint.config.cjs +22 -0
- package/package.json +11 -0
- package/project.json +47 -0
- package/src/earth/index.ts +2 -0
- package/src/earth/object-storage.service.ts +37 -0
- package/src/earth/service.ts +105 -0
- package/src/index.ts +1 -0
- package/src/mercury/auth.interceptor.ts +67 -0
- package/src/mercury/index.ts +2 -0
- package/src/mercury/model.ts +9 -0
- package/src/mercury/service.ts +75 -0
- package/tsconfig.json +21 -0
- package/tsconfig.lib.json +24 -0
- package/tsconfig.spec.json +28 -0
- package/typedoc.json +7 -0
- package/vite.config.ts +24 -0
package/CHANGELOG.md
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const baseConfig = require('../../eslint.config.cjs');
|
|
2
|
+
|
|
3
|
+
module.exports = [
|
|
4
|
+
...baseConfig,
|
|
5
|
+
{
|
|
6
|
+
files: ['**/*.json'],
|
|
7
|
+
rules: {
|
|
8
|
+
'@nx/dependency-checks': [
|
|
9
|
+
'error',
|
|
10
|
+
{
|
|
11
|
+
ignoredFiles: [
|
|
12
|
+
'{projectRoot}/eslint.config.{js,cjs,mjs}',
|
|
13
|
+
'{projectRoot}/vite.config.{js,ts,mjs,mts}',
|
|
14
|
+
],
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
},
|
|
18
|
+
languageOptions: {
|
|
19
|
+
parser: require('jsonc-eslint-parser'),
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
];
|
package/package.json
ADDED
package/project.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "planets",
|
|
3
|
+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
+
"sourceRoot": "packages/planets/src",
|
|
5
|
+
"projectType": "library",
|
|
6
|
+
"tags": [],
|
|
7
|
+
"targets": {
|
|
8
|
+
"build": {
|
|
9
|
+
"executor": "@nx/js:tsc",
|
|
10
|
+
"outputs": [
|
|
11
|
+
"{options.outputPath}"
|
|
12
|
+
],
|
|
13
|
+
"options": {
|
|
14
|
+
"outputPath": "dist/planets",
|
|
15
|
+
"main": "packages/planets/src/index.ts",
|
|
16
|
+
"tsConfig": "packages/planets/tsconfig.lib.json",
|
|
17
|
+
"assets": [
|
|
18
|
+
"packages/planets/*.md"
|
|
19
|
+
],
|
|
20
|
+
"additionalEntryPoints": [
|
|
21
|
+
"packages/planets/src/earth/index.ts",
|
|
22
|
+
"packages/planets/src/mercury/index.ts"
|
|
23
|
+
],
|
|
24
|
+
"generateExportsField": true
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"postbuild": {
|
|
28
|
+
"executor": "nx:run-commands",
|
|
29
|
+
"dependsOn": [
|
|
30
|
+
"build"
|
|
31
|
+
],
|
|
32
|
+
"options": {
|
|
33
|
+
"commands": [
|
|
34
|
+
"node scripts/postbuild.js planets"
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"release:dev": {
|
|
39
|
+
"executor": "nx:run-commands",
|
|
40
|
+
"options": {
|
|
41
|
+
"commands": [
|
|
42
|
+
"yalc publish dist/planets"
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { HttpClient, HttpContext, HttpResponse } from '@ngify/http';
|
|
2
|
+
import { WX_UPLOAD_FILE_TOKEN } from '@ngify/http-wx';
|
|
3
|
+
import { UploadKeys } from '@solar-kit/planets/earth';
|
|
4
|
+
import { once, overlay, vibrator } from '@solar-taro/core';
|
|
5
|
+
import { catchError } from 'rxjs';
|
|
6
|
+
|
|
7
|
+
export class ObjectStorageService {
|
|
8
|
+
private readonly http = new HttpClient();
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 目前只支持了 qiniu oss
|
|
12
|
+
* @param filePath
|
|
13
|
+
* @param options
|
|
14
|
+
* @returns
|
|
15
|
+
*/
|
|
16
|
+
upload(filePath: string, key: string, options: Pick<UploadKeys, 'host' | 'token'>) {
|
|
17
|
+
return this.http.post<{ hash: string, key: string }>(
|
|
18
|
+
`https://${options.host}`,
|
|
19
|
+
{ key: key, token: options.token },
|
|
20
|
+
{
|
|
21
|
+
context: new HttpContext().set(WX_UPLOAD_FILE_TOKEN, {
|
|
22
|
+
filePath,
|
|
23
|
+
fileName: 'file'
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
).pipe(
|
|
27
|
+
catchError((error: HttpResponse<unknown>) => {
|
|
28
|
+
vibrator.short();
|
|
29
|
+
overlay.tips('操作失败,状态码:' + error.status || '未知');
|
|
30
|
+
|
|
31
|
+
throw error;
|
|
32
|
+
})
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const oss = once(() => new ObjectStorageService());
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { HttpClient, HttpContext, withInterceptors } from '@ngify/http';
|
|
2
|
+
import { Category, Channel, Origin, UploadKeys } from '@solar-kit/planets/earth';
|
|
3
|
+
import { Result } from '@solar-kit/planets/sun';
|
|
4
|
+
import { defineService, overlay } from '@solar-taro/core';
|
|
5
|
+
import { CACHEABLE_TOKEN, useApiInterceptor, useCacheInterceptor } from '@solar-taro/http';
|
|
6
|
+
import { tap } from 'rxjs';
|
|
7
|
+
import { useAuthInterceptor } from '../mercury';
|
|
8
|
+
|
|
9
|
+
export interface EarthConfig {
|
|
10
|
+
/** earth service host */
|
|
11
|
+
url: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const [setupEarth, earthService] = defineService((config: EarthConfig) => new EarthService(config));
|
|
15
|
+
|
|
16
|
+
export class EarthService {
|
|
17
|
+
readonly http = new HttpClient(
|
|
18
|
+
withInterceptors([
|
|
19
|
+
useApiInterceptor(),
|
|
20
|
+
useCacheInterceptor(),
|
|
21
|
+
useAuthInterceptor(),
|
|
22
|
+
])
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
constructor(
|
|
26
|
+
public readonly config: EarthConfig
|
|
27
|
+
) { }
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 发送短信验证码
|
|
31
|
+
* @param cellphone
|
|
32
|
+
* @deprecated 使用小程序来获取手机号
|
|
33
|
+
*/
|
|
34
|
+
sendSmsCode(cellphone: string | number) {
|
|
35
|
+
return this.http.get<Result>(`${this.config.url}/sms/code/${cellphone}`).pipe(
|
|
36
|
+
tap(({ code }) => code === 0 && overlay.success('发送成功'))
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 获得信道
|
|
42
|
+
* @param origin
|
|
43
|
+
*/
|
|
44
|
+
channels(origin: Origin) {
|
|
45
|
+
return this.http.get<Result<Channel[]>>(`${this.config.url}/channel/${origin}`, {
|
|
46
|
+
context: new HttpContext().set(CACHEABLE_TOKEN, true)
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 获得品类
|
|
52
|
+
* @param origin
|
|
53
|
+
*/
|
|
54
|
+
categories(origin: Origin) {
|
|
55
|
+
return this.http.get<Result<Category[]>>(`${this.config.url}/category/${origin}`, {
|
|
56
|
+
context: new HttpContext().set(CACHEABLE_TOKEN, true)
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 加载单位
|
|
62
|
+
*/
|
|
63
|
+
unitCategories() {
|
|
64
|
+
return this.categories(Origin.Unit);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 加载单位
|
|
69
|
+
*/
|
|
70
|
+
unitChannels() {
|
|
71
|
+
return this.channels(Origin.Unit);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 获取 qiniu token
|
|
76
|
+
* @param bucket
|
|
77
|
+
* @deprecated {@link mediaUploadKeys}
|
|
78
|
+
*/
|
|
79
|
+
qiniuToken(bucket: 0 | 1) {
|
|
80
|
+
const url = {
|
|
81
|
+
[0]: `${this.config.url}/res/upload-token`,
|
|
82
|
+
[1]: `${this.config.url}/media/upload-token`,
|
|
83
|
+
}[bucket];
|
|
84
|
+
|
|
85
|
+
return this.http.get<Result<string>>(url);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* 获取上传头像的文件名(key)
|
|
90
|
+
* @deprecated {@link avatarUploadKey}
|
|
91
|
+
*/
|
|
92
|
+
avatarKey() {
|
|
93
|
+
return this.http.get<Result<string>>(`${this.config.url}/avatar/upload-key`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
avatarUploadKey() {
|
|
97
|
+
return this.http.get<Result<UploadKeys>>(`${this.config.url}/qiniu/avatar/upload-key`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
mediaUploadKeys(keySize = 1) {
|
|
101
|
+
return this.http.get<Result<UploadKeys>>(`${this.config.url}/qiniu/media/upload-keys`, {
|
|
102
|
+
params: { keySize }
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default void 0;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { HttpEvent, HttpHandlerFn, HttpInterceptorFn, HttpRequest, HttpResponse } from '@ngify/http';
|
|
2
|
+
import { HttpStatusCode } from '@ngify/http';
|
|
3
|
+
import { Result } from '@solar-kit/planets/sun';
|
|
4
|
+
import { catchError, finalize, Observable, share, switchMap } from 'rxjs';
|
|
5
|
+
import { WxAuth } from './model';
|
|
6
|
+
import { mercuryService } from './service';
|
|
7
|
+
|
|
8
|
+
/** 负责基础业务接口的认证 */
|
|
9
|
+
export function useAuthInterceptor(): HttpInterceptorFn {
|
|
10
|
+
/** 令牌刷新器 */
|
|
11
|
+
let refresher: Observable<Result<WxAuth>> | null = null;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 获取访问令牌
|
|
15
|
+
*/
|
|
16
|
+
function updateToken() {
|
|
17
|
+
refresher = mercuryService().auth().pipe(
|
|
18
|
+
finalize(() => refresher = null),
|
|
19
|
+
share(),
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 等待令牌后再发送请求
|
|
25
|
+
* @param request
|
|
26
|
+
* @param next
|
|
27
|
+
*/
|
|
28
|
+
function waitToken(request: HttpRequest<unknown>, next: HttpHandlerFn) {
|
|
29
|
+
return refresher!.pipe(
|
|
30
|
+
switchMap(({ data }) => (
|
|
31
|
+
next(request.clone({
|
|
32
|
+
headers: request.headers.set('Authorization', 'Bearer ' + data.token.access_token)
|
|
33
|
+
}))
|
|
34
|
+
))
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return (request: HttpRequest<unknown>, next: HttpHandlerFn): Observable<HttpEvent<unknown>> => {
|
|
39
|
+
const tokens = mercuryService().tokens;
|
|
40
|
+
|
|
41
|
+
if (!tokens?.accessToken && !refresher) {
|
|
42
|
+
updateToken();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (refresher) {
|
|
46
|
+
return waitToken(request, next);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
request = request.clone({
|
|
50
|
+
headers: request.headers.set('Authorization', 'Bearer ' + tokens.accessToken)
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return next(request).pipe(
|
|
54
|
+
catchError((error: HttpResponse<unknown>) => {
|
|
55
|
+
if (error.status === HttpStatusCode.Unauthorized) {
|
|
56
|
+
if (!refresher) {
|
|
57
|
+
updateToken();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return waitToken(request, next);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
throw error;
|
|
64
|
+
})
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { HttpClient, HttpResponse, HttpStatusCode, withInterceptors } from '@ngify/http';
|
|
2
|
+
import { Fan } from '@solar-kit/planets/earth';
|
|
3
|
+
import { AuthTokens, Result } from '@solar-kit/planets/sun';
|
|
4
|
+
import { defineService } from '@solar-taro/core';
|
|
5
|
+
import { useApiInterceptor, WxHeader } from '@solar-taro/http';
|
|
6
|
+
import { checkSession, getStorageSync, getUserInfo, login, setStorage } from '@tarojs/taro';
|
|
7
|
+
import { catchError, defer, from, map, Observable, switchMap, tap } from 'rxjs';
|
|
8
|
+
import { WxAuth } from './model';
|
|
9
|
+
|
|
10
|
+
export interface MercuryConfig {
|
|
11
|
+
/** mercury service host */
|
|
12
|
+
url: string;
|
|
13
|
+
app: string;
|
|
14
|
+
fan: Fan;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const TOKEN_STORAGE_KEY = 'auth-token';
|
|
18
|
+
|
|
19
|
+
export const [setupMercury, mercuryService] = defineService((config: MercuryConfig) => new MercuryService(config));
|
|
20
|
+
|
|
21
|
+
export class MercuryService {
|
|
22
|
+
protected http = new HttpClient(
|
|
23
|
+
withInterceptors([
|
|
24
|
+
useApiInterceptor()
|
|
25
|
+
])
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
tokens: AuthTokens = getStorageSync<AuthTokens>(TOKEN_STORAGE_KEY) || {};
|
|
29
|
+
|
|
30
|
+
constructor(
|
|
31
|
+
protected readonly config: MercuryConfig
|
|
32
|
+
) { }
|
|
33
|
+
|
|
34
|
+
auth(relogin = false): Observable<Result<WxAuth>> {
|
|
35
|
+
return defer(() =>
|
|
36
|
+
relogin
|
|
37
|
+
? login()
|
|
38
|
+
: from(checkSession()).pipe(
|
|
39
|
+
map(() => ({ code: null })),
|
|
40
|
+
catchError(() => login()),
|
|
41
|
+
)
|
|
42
|
+
).pipe(
|
|
43
|
+
switchMap(({ code }) =>
|
|
44
|
+
from(getUserInfo()).pipe(
|
|
45
|
+
map(({ encryptedData, iv }) => ({ code, encryptedData, iv }))
|
|
46
|
+
)
|
|
47
|
+
),
|
|
48
|
+
switchMap(({ code, encryptedData, iv }) => {
|
|
49
|
+
return this.http.post<Result<WxAuth>>(`${this.config.url}/oaa/wx/auth`, null, {
|
|
50
|
+
headers: {
|
|
51
|
+
[WxHeader.Code]: code || '',
|
|
52
|
+
[WxHeader.EncryptedData]: encryptedData,
|
|
53
|
+
[WxHeader.Iv]: iv,
|
|
54
|
+
[WxHeader.App]: this.config.app,
|
|
55
|
+
[WxHeader.OpenId]: this.config.fan.openId || '',
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}),
|
|
59
|
+
tap(({ data }) => {
|
|
60
|
+
this.tokens = { accessToken: data.token.access_token };
|
|
61
|
+
setStorage({
|
|
62
|
+
key: TOKEN_STORAGE_KEY,
|
|
63
|
+
data: this.tokens
|
|
64
|
+
});
|
|
65
|
+
}),
|
|
66
|
+
catchError((error: HttpResponse<unknown>) => {
|
|
67
|
+
if (error.status === HttpStatusCode.Unauthorized) {
|
|
68
|
+
return this.auth(true);
|
|
69
|
+
}
|
|
70
|
+
throw error;
|
|
71
|
+
})
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"forceConsistentCasingInFileNames": true,
|
|
5
|
+
"strict": true,
|
|
6
|
+
"noImplicitOverride": true,
|
|
7
|
+
"noImplicitReturns": true,
|
|
8
|
+
"noFallthroughCasesInSwitch": true,
|
|
9
|
+
"noPropertyAccessFromIndexSignature": true
|
|
10
|
+
},
|
|
11
|
+
"files": [],
|
|
12
|
+
"include": [],
|
|
13
|
+
"references": [
|
|
14
|
+
{
|
|
15
|
+
"path": "./tsconfig.lib.json"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"path": "./tsconfig.spec.json"
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "../../dist/out-tsc",
|
|
5
|
+
"declaration": true
|
|
6
|
+
},
|
|
7
|
+
"include": [
|
|
8
|
+
"src/**/*.ts"
|
|
9
|
+
],
|
|
10
|
+
"exclude": [
|
|
11
|
+
"vite.config.ts",
|
|
12
|
+
"vite.config.mts",
|
|
13
|
+
"vitest.config.ts",
|
|
14
|
+
"vitest.config.mts",
|
|
15
|
+
"src/**/*.test.ts",
|
|
16
|
+
"src/**/*.spec.ts",
|
|
17
|
+
"src/**/*.test.tsx",
|
|
18
|
+
"src/**/*.spec.tsx",
|
|
19
|
+
"src/**/*.test.js",
|
|
20
|
+
"src/**/*.spec.js",
|
|
21
|
+
"src/**/*.test.jsx",
|
|
22
|
+
"src/**/*.spec.jsx"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "../../dist/out-tsc",
|
|
5
|
+
"types": [
|
|
6
|
+
"vitest/globals",
|
|
7
|
+
"vitest/importMeta",
|
|
8
|
+
"vite/client",
|
|
9
|
+
"node",
|
|
10
|
+
"vitest"
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
"include": [
|
|
14
|
+
"vite.config.ts",
|
|
15
|
+
"vite.config.mts",
|
|
16
|
+
"vitest.config.ts",
|
|
17
|
+
"vitest.config.mts",
|
|
18
|
+
"src/**/*.test.ts",
|
|
19
|
+
"src/**/*.spec.ts",
|
|
20
|
+
"src/**/*.test.tsx",
|
|
21
|
+
"src/**/*.spec.tsx",
|
|
22
|
+
"src/**/*.test.js",
|
|
23
|
+
"src/**/*.spec.js",
|
|
24
|
+
"src/**/*.test.jsx",
|
|
25
|
+
"src/**/*.spec.jsx",
|
|
26
|
+
"src/**/*.d.ts"
|
|
27
|
+
]
|
|
28
|
+
}
|
package/typedoc.json
ADDED
package/vite.config.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
|
|
2
|
+
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
|
3
|
+
import { defineConfig } from 'vite';
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
root: __dirname,
|
|
7
|
+
cacheDir: '../../node_modules/.vite/planets',
|
|
8
|
+
plugins: [nxViteTsPaths(), nxCopyAssetsPlugin(['*.md'])],
|
|
9
|
+
// Uncomment this if you are using workers.
|
|
10
|
+
// worker: {
|
|
11
|
+
// plugins: [ nxViteTsPaths() ],
|
|
12
|
+
// },
|
|
13
|
+
test: {
|
|
14
|
+
watch: false,
|
|
15
|
+
globals: true,
|
|
16
|
+
environment: 'node',
|
|
17
|
+
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
|
18
|
+
reporters: ['default'],
|
|
19
|
+
coverage: {
|
|
20
|
+
reportsDirectory: '../../coverage/planets',
|
|
21
|
+
provider: 'v8',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
});
|