@jolibox/implement 1.1.4-beta.10
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/.eslintrc.js +13 -0
- package/.rush/temp/package-deps_build.json +105 -0
- package/.rush/temp/shrinkwrap-deps.json +79 -0
- package/README.md +1 -0
- package/dist/common/api-factory/index.d.ts +21 -0
- package/dist/common/api-factory/validator/__tests__/validate/any.test.d.ts +1 -0
- package/dist/common/api-factory/validator/__tests__/validate/array.test.d.ts +1 -0
- package/dist/common/api-factory/validator/__tests__/validate/arraybuffer.test.d.ts +1 -0
- package/dist/common/api-factory/validator/__tests__/validate/boolean.test.d.ts +1 -0
- package/dist/common/api-factory/validator/__tests__/validate/enum.test.d.ts +1 -0
- package/dist/common/api-factory/validator/__tests__/validate/function.test.d.ts +1 -0
- package/dist/common/api-factory/validator/__tests__/validate/literal.test.d.ts +1 -0
- package/dist/common/api-factory/validator/__tests__/validate/nullish.test.d.ts +1 -0
- package/dist/common/api-factory/validator/__tests__/validate/number.test.d.ts +1 -0
- package/dist/common/api-factory/validator/__tests__/validate/object.test.d.ts +1 -0
- package/dist/common/api-factory/validator/__tests__/validate/or.test.d.ts +1 -0
- package/dist/common/api-factory/validator/__tests__/validate/record.test.d.ts +1 -0
- package/dist/common/api-factory/validator/__tests__/validate/string.test.d.ts +1 -0
- package/dist/common/api-factory/validator/__tests__/validate/symbol.test.d.ts +1 -0
- package/dist/common/api-factory/validator/__tests__/validate/tuple.test.d.ts +1 -0
- package/dist/common/api-factory/validator/__tests__/validate/type-asserts.test.d.ts +1 -0
- package/dist/common/api-factory/validator/__tests__/validate/utils.test.d.ts +1 -0
- package/dist/common/api-factory/validator/index.d.ts +29 -0
- package/dist/common/api-factory/validator/validate.d.ts +119 -0
- package/dist/common/can-i-use.d.ts +2 -0
- package/dist/common/context/index.d.ts +16 -0
- package/dist/common/context/types.d.ts +5 -0
- package/dist/common/context/url-parse.d.ts +22 -0
- package/dist/common/http/index.d.ts +13 -0
- package/dist/common/http/uuid.d.ts +2 -0
- package/dist/common/http/xua.d.ts +17 -0
- package/dist/common/report/base-tracker.d.ts +13 -0
- package/dist/common/report/create-trace.d.ts +7 -0
- package/dist/common/report/errors/error-types.d.ts +122 -0
- package/dist/common/report/errors/index.d.ts +13 -0
- package/dist/common/report/errors/report/index.d.ts +51 -0
- package/dist/common/report/errors/report/listeners.d.ts +1 -0
- package/dist/common/report/index.d.ts +3 -0
- package/dist/common/report/task-track/index.d.ts +25 -0
- package/dist/common/report/track.d.ts +3 -0
- package/dist/common/report/types.d.ts +75 -0
- package/dist/h5/ads/ads-action-detection.d.ts +6 -0
- package/dist/h5/ads/anti-cheating.d.ts +61 -0
- package/dist/h5/ads/index.d.ts +275 -0
- package/dist/h5/api/base.d.ts +13 -0
- package/dist/h5/api/get-system-info.d.ts +1 -0
- package/dist/h5/api/index.d.ts +4 -0
- package/dist/h5/api/lifecycle.d.ts +1 -0
- package/dist/h5/api/storage.d.ts +27 -0
- package/dist/h5/api/task.d.ts +1 -0
- package/dist/h5/bootstrap/index.d.ts +1 -0
- package/dist/h5/http/index.d.ts +33 -0
- package/dist/h5/http/utils/__tests__/uuid.test.d.ts +1 -0
- package/dist/h5/http/utils/__tests__/xua.test.d.ts +1 -0
- package/dist/h5/http/utils/index.d.ts +14 -0
- package/dist/h5/http/utils/session.d.ts +1 -0
- package/dist/h5/report/errors/index.d.ts +4 -0
- package/dist/h5/report/event-tracker.d.ts +8 -0
- package/dist/h5/report/index.d.ts +10 -0
- package/dist/h5/report/task-tracker.d.ts +18 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +13 -0
- package/dist/index.native.d.ts +2 -0
- package/dist/index.native.js +3 -0
- package/dist/native/api/ads.d.ts +1 -0
- package/dist/native/api/base.d.ts +13 -0
- package/dist/native/api/get-system-info.d.ts +1 -0
- package/dist/native/api/index.d.ts +8 -0
- package/dist/native/api/keyboard.d.ts +9 -0
- package/dist/native/api/lifecycle.d.ts +1 -0
- package/dist/native/api/login.d.ts +1 -0
- package/dist/native/api/request.d.ts +1 -0
- package/dist/native/api/storage.d.ts +25 -0
- package/dist/native/api/task.d.ts +1 -0
- package/dist/native/bootstrap/bridge.d.ts +4 -0
- package/dist/native/bootstrap/index.d.ts +1 -0
- package/dist/native/js-bridge/const.d.ts +5 -0
- package/dist/native/js-bridge/index.d.ts +2 -0
- package/dist/native/js-bridge/invoke.d.ts +21 -0
- package/dist/native/js-bridge/js-bridge.d.ts +6 -0
- package/dist/native/js-bridge/report.d.ts +63 -0
- package/dist/native/js-bridge/subscribe.d.ts +8 -0
- package/dist/native/js-bridge/types.d.ts +14 -0
- package/dist/native/js-bridge/utils.d.ts +17 -0
- package/dist/native/js-core/index.d.ts +3 -0
- package/dist/native/js-core/jolibox-js-core.d.ts +45 -0
- package/dist/native/js-core/message-port.d.ts +12 -0
- package/dist/native/js-core/utils.d.ts +7 -0
- package/dist/native/network/create-fetch.d.ts +27 -0
- package/dist/native/network/index.d.ts +11 -0
- package/dist/native/network/report.d.ts +15 -0
- package/dist/native/network/types.d.ts +61 -0
- package/dist/native/network/utils.d.ts +9 -0
- package/dist/native/report/errors/index.d.ts +4 -0
- package/dist/native/report/index.d.ts +10 -0
- package/dist/native/report/task-tracker.d.ts +24 -0
- package/dist/utils/index.d.ts +0 -0
- package/esbuild.config.js +66 -0
- package/implement.build.log +9 -0
- package/package.json +30 -0
- package/src/common/api-factory/index.ts +188 -0
- package/src/common/api-factory/validator/__tests__/validate/any.test.ts +68 -0
- package/src/common/api-factory/validator/__tests__/validate/array.test.ts +402 -0
- package/src/common/api-factory/validator/__tests__/validate/arraybuffer.test.ts +48 -0
- package/src/common/api-factory/validator/__tests__/validate/boolean.test.ts +27 -0
- package/src/common/api-factory/validator/__tests__/validate/enum.test.ts +106 -0
- package/src/common/api-factory/validator/__tests__/validate/function.test.ts +54 -0
- package/src/common/api-factory/validator/__tests__/validate/literal.test.ts +130 -0
- package/src/common/api-factory/validator/__tests__/validate/nullish.test.ts +41 -0
- package/src/common/api-factory/validator/__tests__/validate/number.test.ts +147 -0
- package/src/common/api-factory/validator/__tests__/validate/object.test.ts +131 -0
- package/src/common/api-factory/validator/__tests__/validate/or.test.ts +96 -0
- package/src/common/api-factory/validator/__tests__/validate/record.test.ts +274 -0
- package/src/common/api-factory/validator/__tests__/validate/string.test.ts +187 -0
- package/src/common/api-factory/validator/__tests__/validate/symbol.test.ts +23 -0
- package/src/common/api-factory/validator/__tests__/validate/tuple.test.ts +86 -0
- package/src/common/api-factory/validator/__tests__/validate/type-asserts.test.ts +13 -0
- package/src/common/api-factory/validator/__tests__/validate/utils.test.ts +44 -0
- package/src/common/api-factory/validator/index.ts +107 -0
- package/src/common/api-factory/validator/validate.ts +641 -0
- package/src/common/can-i-use.ts +19 -0
- package/src/common/context/index.ts +85 -0
- package/src/common/context/types.ts +5 -0
- package/src/common/context/url-parse.ts +63 -0
- package/src/common/http/index.ts +29 -0
- package/src/common/http/uuid.ts +11 -0
- package/src/common/http/xua.ts +79 -0
- package/src/common/report/base-tracker.ts +134 -0
- package/src/common/report/create-trace.ts +17 -0
- package/src/common/report/errors/error-types.ts +206 -0
- package/src/common/report/errors/index.ts +20 -0
- package/src/common/report/errors/report/index.ts +63 -0
- package/src/common/report/errors/report/listeners.ts +80 -0
- package/src/common/report/index.ts +3 -0
- package/src/common/report/task-track/index.ts +102 -0
- package/src/common/report/track.ts +49 -0
- package/src/common/report/types.ts +90 -0
- package/src/h5/ads/ads-action-detection.ts +31 -0
- package/src/h5/ads/anti-cheating.ts +244 -0
- package/src/h5/ads/index.ts +658 -0
- package/src/h5/api/base.ts +9 -0
- package/src/h5/api/get-system-info.ts +59 -0
- package/src/h5/api/index.ts +4 -0
- package/src/h5/api/lifecycle.ts +95 -0
- package/src/h5/api/storage.ts +173 -0
- package/src/h5/api/task.ts +190 -0
- package/src/h5/bootstrap/index.ts +16 -0
- package/src/h5/http/index.ts +189 -0
- package/src/h5/http/utils/__tests__/uuid.test.ts +16 -0
- package/src/h5/http/utils/__tests__/xua.test.ts +27 -0
- package/src/h5/http/utils/index.ts +19 -0
- package/src/h5/http/utils/session.ts +10 -0
- package/src/h5/report/errors/index.ts +40 -0
- package/src/h5/report/event-tracker.ts +40 -0
- package/src/h5/report/index.ts +56 -0
- package/src/h5/report/task-tracker.ts +42 -0
- package/src/index.native.ts +7 -0
- package/src/index.ts +9 -0
- package/src/native/api/ads.ts +52 -0
- package/src/native/api/base.ts +8 -0
- package/src/native/api/get-system-info.ts +44 -0
- package/src/native/api/index.ts +8 -0
- package/src/native/api/keyboard.ts +75 -0
- package/src/native/api/lifecycle.ts +76 -0
- package/src/native/api/login.ts +73 -0
- package/src/native/api/request.ts +154 -0
- package/src/native/api/storage.ts +287 -0
- package/src/native/api/task.ts +227 -0
- package/src/native/bootstrap/bridge.ts +59 -0
- package/src/native/bootstrap/index.ts +59 -0
- package/src/native/js-bridge/const.ts +11 -0
- package/src/native/js-bridge/index.ts +2 -0
- package/src/native/js-bridge/invoke.ts +210 -0
- package/src/native/js-bridge/js-bridge.ts +23 -0
- package/src/native/js-bridge/report.ts +311 -0
- package/src/native/js-bridge/subscribe.ts +50 -0
- package/src/native/js-bridge/types.ts +26 -0
- package/src/native/js-bridge/utils.ts +116 -0
- package/src/native/js-core/index.ts +4 -0
- package/src/native/js-core/jolibox-js-core.ts +188 -0
- package/src/native/js-core/message-port.ts +52 -0
- package/src/native/js-core/utils.ts +9 -0
- package/src/native/network/create-fetch.ts +237 -0
- package/src/native/network/index.ts +15 -0
- package/src/native/network/report.ts +58 -0
- package/src/native/network/types.ts +77 -0
- package/src/native/network/utils.ts +90 -0
- package/src/native/report/errors/index.ts +27 -0
- package/src/native/report/index.ts +51 -0
- package/src/native/report/task-tracker.ts +72 -0
- package/src/native/types/global.d.ts +26 -0
- package/src/native/types/native-method-map.d.ts +282 -0
- package/src/native/types/native-method.d.ts +30 -0
- package/src/utils/index.ts +0 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { mergeArray, mergeWith } from '@jolibox/common';
|
|
2
|
+
import { DeviceInfo, HostInfo, HostUserInfo, SdkInfo } from './types';
|
|
3
|
+
import { Env } from '@jolibox/types';
|
|
4
|
+
import { parseUrlQuery } from './url-parse';
|
|
5
|
+
import { getAppVersion, getDeviceId } from '../http/xua';
|
|
6
|
+
|
|
7
|
+
declare const globalThis: {
|
|
8
|
+
joliboxJSCore?: {
|
|
9
|
+
env: () => Env | undefined;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const defaultEnv: Env = {
|
|
14
|
+
deviceInfo: {
|
|
15
|
+
brand: 'UnknownBrand',
|
|
16
|
+
model: 'UnknownModel',
|
|
17
|
+
did: getDeviceId(),
|
|
18
|
+
pixelRatio: window.devicePixelRatio || 1,
|
|
19
|
+
platform: 'h5',
|
|
20
|
+
system: 'UnknownSystemVersion',
|
|
21
|
+
lang: 'zh'
|
|
22
|
+
},
|
|
23
|
+
sdkInfo: {
|
|
24
|
+
nativeSDKVersion: '',
|
|
25
|
+
jssdkVersion: getAppVersion()
|
|
26
|
+
},
|
|
27
|
+
schema: '',
|
|
28
|
+
platform: 'h5'
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const nativeEnv = globalThis.joliboxJSCore?.env;
|
|
32
|
+
|
|
33
|
+
const env = Object.assign({}, nativeEnv?.() ?? defaultEnv);
|
|
34
|
+
|
|
35
|
+
const wrapContext = () => {
|
|
36
|
+
const { payloadJson, headerJson } = parseUrlQuery(env.schema);
|
|
37
|
+
const defaultSessionId = `${env.deviceInfo.did}-${new Date().getTime()}`;
|
|
38
|
+
const urlParams = new URLSearchParams(env.schema.length ? env.schema : window.location.search);
|
|
39
|
+
const defaultGameID = urlParams.get('appId') ?? urlParams.get('gameId') ?? '';
|
|
40
|
+
const sessionId = payloadJson.sessionId ?? urlParams.get('sessionId') ?? defaultSessionId;
|
|
41
|
+
const testAdsMode = !!(payloadJson.testAdsMode ?? urlParams.get('testAdsMode') === 'true');
|
|
42
|
+
const joliboxEnv = payloadJson.joliboxEnv ?? urlParams.get('joliboxEnv') ?? 'production';
|
|
43
|
+
const testMode = joliboxEnv === 'staging';
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
get testMode(): boolean {
|
|
47
|
+
return testMode; // TODO: true test mode
|
|
48
|
+
},
|
|
49
|
+
get testAdsMode(): boolean {
|
|
50
|
+
return testAdsMode;
|
|
51
|
+
},
|
|
52
|
+
get joliboxEnv() {
|
|
53
|
+
return joliboxEnv;
|
|
54
|
+
},
|
|
55
|
+
get mpId(): string {
|
|
56
|
+
return defaultGameID ?? payloadJson['id'];
|
|
57
|
+
},
|
|
58
|
+
get mpVersion(): string {
|
|
59
|
+
return headerJson.ver ?? getAppVersion();
|
|
60
|
+
},
|
|
61
|
+
get platform(): Env['platform'] {
|
|
62
|
+
return env.platform;
|
|
63
|
+
},
|
|
64
|
+
get deviceInfo(): DeviceInfo {
|
|
65
|
+
return env.deviceInfo;
|
|
66
|
+
},
|
|
67
|
+
get sdkInfo(): SdkInfo {
|
|
68
|
+
return env.sdkInfo;
|
|
69
|
+
},
|
|
70
|
+
get hostInfo(): HostInfo {
|
|
71
|
+
return env.hostInfo;
|
|
72
|
+
},
|
|
73
|
+
get hostUserInfo(): HostUserInfo {
|
|
74
|
+
return env.hostUserInfo;
|
|
75
|
+
},
|
|
76
|
+
get sessionId(): string {
|
|
77
|
+
return env.clientSessionId ?? sessionId ?? defaultSessionId;
|
|
78
|
+
},
|
|
79
|
+
onEnvConfigChanged: (newConfig: Partial<Env>) => {
|
|
80
|
+
mergeWith(env, newConfig, mergeArray);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export const context = wrapContext();
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { InternalSchemaParseError } from '@jolibox/common';
|
|
2
|
+
import { reportError } from '../report/errors/report';
|
|
3
|
+
|
|
4
|
+
interface HeaderJson {
|
|
5
|
+
ver?: string;
|
|
6
|
+
channel?: string;
|
|
7
|
+
subChannel?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface PayloadJson {
|
|
11
|
+
id?: string;
|
|
12
|
+
testAdsMode?: boolean;
|
|
13
|
+
joliboxEnv?: 'staging' | 'production';
|
|
14
|
+
sessionId?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface Signature {
|
|
18
|
+
headerSig?: string;
|
|
19
|
+
payloadSig?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface QueryParams {
|
|
23
|
+
headerJson: HeaderJson;
|
|
24
|
+
payloadJson: PayloadJson;
|
|
25
|
+
signature: Signature;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const base64UrlDecode = <T>(input: string): T => {
|
|
29
|
+
const base64 = input.replace(/-/g, '+').replace(/_/g, '/');
|
|
30
|
+
const padding = base64.length % 4 === 0 ? '' : '='.repeat(4 - (base64.length % 4));
|
|
31
|
+
const jsonStr = atob(base64 + padding);
|
|
32
|
+
try {
|
|
33
|
+
return JSON.parse(jsonStr) as T;
|
|
34
|
+
} catch (e) {
|
|
35
|
+
return {} as T;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const parseUrlQuery = (url: string): QueryParams => {
|
|
40
|
+
try {
|
|
41
|
+
const urlObj = new URL(url);
|
|
42
|
+
const params = urlObj.searchParams;
|
|
43
|
+
|
|
44
|
+
const joli_source = params.get('joliSource')?.split('.');
|
|
45
|
+
if (joli_source?.length) {
|
|
46
|
+
const [headerJsonStr, payloadJsonStr, signatureJsonStr] = joli_source;
|
|
47
|
+
return {
|
|
48
|
+
headerJson: base64UrlDecode<HeaderJson>(headerJsonStr),
|
|
49
|
+
payloadJson: base64UrlDecode<PayloadJson>(payloadJsonStr),
|
|
50
|
+
signature: base64UrlDecode<Signature>(signatureJsonStr)
|
|
51
|
+
};
|
|
52
|
+
} else {
|
|
53
|
+
throw `joli_source is missing`;
|
|
54
|
+
}
|
|
55
|
+
} catch (e) {
|
|
56
|
+
reportError(new InternalSchemaParseError(`${url} not a valid schema: ${e}`));
|
|
57
|
+
return {
|
|
58
|
+
headerJson: {},
|
|
59
|
+
payloadJson: {},
|
|
60
|
+
signature: {}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface IHttpClient {
|
|
2
|
+
get<T>(
|
|
3
|
+
path: string,
|
|
4
|
+
{
|
|
5
|
+
query,
|
|
6
|
+
headers,
|
|
7
|
+
timeout
|
|
8
|
+
}: {
|
|
9
|
+
query?: Record<string, string>;
|
|
10
|
+
headers?: Record<string, string>;
|
|
11
|
+
timeout?: number;
|
|
12
|
+
}
|
|
13
|
+
): Promise<T>;
|
|
14
|
+
|
|
15
|
+
post<T = any>(
|
|
16
|
+
path: string,
|
|
17
|
+
{
|
|
18
|
+
data,
|
|
19
|
+
query,
|
|
20
|
+
headers,
|
|
21
|
+
timeout
|
|
22
|
+
}: {
|
|
23
|
+
data?: any;
|
|
24
|
+
query?: Record<string, string>;
|
|
25
|
+
headers?: Record<string, string>;
|
|
26
|
+
timeout?: number;
|
|
27
|
+
}
|
|
28
|
+
): Promise<T>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const uuidv4 = () => {
|
|
2
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
3
|
+
const r = (Math.random() * 16) | 0;
|
|
4
|
+
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
5
|
+
return v.toString(16);
|
|
6
|
+
});
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const isValidUUIDV4 = (uuid: string) => {
|
|
10
|
+
return /^[\da-f]{8}-[\da-f]{4}-4[\da-f]{3}-[89ab][\da-f]{3}-[\da-f]{12}$/i.test(uuid);
|
|
11
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { uuidv4 } from './uuid';
|
|
2
|
+
|
|
3
|
+
export const platform = {
|
|
4
|
+
isiOS:
|
|
5
|
+
navigator.userAgent.includes('iPhone') ||
|
|
6
|
+
navigator.userAgent.includes('iPod') ||
|
|
7
|
+
navigator.userAgent.includes('iPad') ||
|
|
8
|
+
navigator.userAgent.includes('iPhone OS'),
|
|
9
|
+
iosVersion: () => {
|
|
10
|
+
const v = navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/) as string[];
|
|
11
|
+
return [parseInt(v[1], 10), parseInt(v[2], 10), parseInt(v[3] || '0', 10)];
|
|
12
|
+
},
|
|
13
|
+
isAndroid: navigator.userAgent.includes('Android'),
|
|
14
|
+
isMac: navigator.userAgent.includes('Mac'),
|
|
15
|
+
isFacebook: navigator.userAgent.includes('FB_IAB'),
|
|
16
|
+
isPC: !navigator.userAgent.includes('iPhone') && !navigator.userAgent.includes('Android')
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const getPlatform = () => {
|
|
20
|
+
if (platform.isiOS) {
|
|
21
|
+
return 'iOS';
|
|
22
|
+
} else if (platform.isAndroid) {
|
|
23
|
+
return 'Android';
|
|
24
|
+
} else if (platform.isMac) {
|
|
25
|
+
return 'Mac';
|
|
26
|
+
} else if (platform.isFacebook) {
|
|
27
|
+
return 'Facebook';
|
|
28
|
+
} else {
|
|
29
|
+
return 'PC';
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const jssdkVersion = '__JOLIBOX_LOCAL_SDK_VERSION__';
|
|
34
|
+
|
|
35
|
+
export const getAppVersion = () => {
|
|
36
|
+
return jssdkVersion;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const DEVICE_ID = 'device_id';
|
|
40
|
+
export const ADVERTISING_ID = 'advertising_id';
|
|
41
|
+
|
|
42
|
+
export const getStorage = (cookieKey: string) => {
|
|
43
|
+
if (!localStorage.getItem(cookieKey)) {
|
|
44
|
+
localStorage.setItem(cookieKey, uuidv4());
|
|
45
|
+
}
|
|
46
|
+
return localStorage.getItem(cookieKey)!;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const getDeviceId = () => {
|
|
50
|
+
return getStorage(DEVICE_ID);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const getAdvertisingId = () => {
|
|
54
|
+
return getStorage(ADVERTISING_ID);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const firstCharUpperCase = (chars: string) => chars.charAt(0).toUpperCase() + chars.slice(1);
|
|
58
|
+
|
|
59
|
+
export const getUtmSource = () => {
|
|
60
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
61
|
+
return firstCharUpperCase(urlParams.get('utm_source') ?? '') || 'JoliboxSDK';
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const xUserAgent = () => {
|
|
65
|
+
const applicationName = 'JoliboxWebSDK';
|
|
66
|
+
const thePlatform = getPlatform();
|
|
67
|
+
const locale = navigator.language;
|
|
68
|
+
const deviceId = getDeviceId();
|
|
69
|
+
const adid = getAdvertisingId();
|
|
70
|
+
const appVersion = getAppVersion();
|
|
71
|
+
// const parserResult = getUAParser();
|
|
72
|
+
// const deviceModel = parserResult.device.model;
|
|
73
|
+
const deviceModel = 'UnknownModel';
|
|
74
|
+
// const systemVersion = parserResult.os.version;
|
|
75
|
+
const systemVersion = 'UnknownSystemVersion';
|
|
76
|
+
return `${applicationName} (${getUtmSource()}${thePlatform}; ${deviceModel}; ${systemVersion}; ${locale}) uuid/${deviceId} adid/${adid} version/${
|
|
77
|
+
appVersion || ''
|
|
78
|
+
}`;
|
|
79
|
+
};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { context } from '@/common/context';
|
|
2
|
+
import { logger } from '@jolibox/common';
|
|
3
|
+
import { IDevice, IPage, IEventPackage, IEvent, EProject } from '@/common/report/types';
|
|
4
|
+
|
|
5
|
+
const keysOfPage: (keyof IPage)[] = ['name', 'params'];
|
|
6
|
+
const keysOfEvent: (keyof IEvent)[] = ['name', 'type', 'location', 'target', 'extra', 'timestamp', 'userId'];
|
|
7
|
+
const keysOfDevice: (keyof IDevice)[] = [
|
|
8
|
+
'platform',
|
|
9
|
+
'os',
|
|
10
|
+
'appVersion',
|
|
11
|
+
'appId',
|
|
12
|
+
'model',
|
|
13
|
+
'brand',
|
|
14
|
+
'uuid',
|
|
15
|
+
'jsSdkVersion',
|
|
16
|
+
'extra'
|
|
17
|
+
];
|
|
18
|
+
function serializeObject<T>(obj: T, order: (keyof T)[]): any[] {
|
|
19
|
+
return order.map((key) => {
|
|
20
|
+
if (key === 'params' && obj[key]) {
|
|
21
|
+
const params = obj[key] as Record<string, any>;
|
|
22
|
+
return Object.keys(params).reduce((acc, k) => {
|
|
23
|
+
acc[k] = String(params[k]);
|
|
24
|
+
return acc;
|
|
25
|
+
}, {} as Record<string, any>);
|
|
26
|
+
}
|
|
27
|
+
return obj[key];
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function serializeEvent(event: IEvent): any[] {
|
|
32
|
+
const location = event.location ? serializeObject(event.location, keysOfPage) : null;
|
|
33
|
+
const target = event.target ? serializeObject(event.target, keysOfPage) : null;
|
|
34
|
+
|
|
35
|
+
// 定义IEvent的序列化顺序
|
|
36
|
+
return serializeObject({ ...event, location, target }, keysOfEvent);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function serializeEventPackage(eventPackage: IEventPackage): any[] {
|
|
40
|
+
// 序列化事件数组
|
|
41
|
+
const events = eventPackage.events.map((event) => serializeEvent(event));
|
|
42
|
+
|
|
43
|
+
// 定义IDevice的序列化顺序
|
|
44
|
+
const device = serializeObject(eventPackage.device, keysOfDevice);
|
|
45
|
+
|
|
46
|
+
return [eventPackage.protocolVersion, events, device, eventPackage.project];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export abstract class EventTracker {
|
|
50
|
+
deviceInfo: IDevice | null = null;
|
|
51
|
+
|
|
52
|
+
abstract doReport(event: unknown[]): void;
|
|
53
|
+
abstract doReport<T extends Record<string, unknown>>(event: unknown[], extra: T): void;
|
|
54
|
+
abstract doReport<T extends Record<string, unknown>>(event: unknown[], extra?: T): void;
|
|
55
|
+
|
|
56
|
+
private pastTrackings: boolean[] = [];
|
|
57
|
+
|
|
58
|
+
private pushPastTracking = (tracking: boolean) => {
|
|
59
|
+
this.pastTrackings.push(tracking);
|
|
60
|
+
if (this.pastTrackings.length > 10) {
|
|
61
|
+
this.pastTrackings.slice(-10);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
public get networkIsOk() {
|
|
66
|
+
// in the past 10 trackings, at least 60% of them are successful
|
|
67
|
+
return (
|
|
68
|
+
this.pastTrackings.length <= 4 ||
|
|
69
|
+
this.pastTrackings.filter(Boolean).length / this.pastTrackings.length >= 0.6
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
getDevice(): IDevice {
|
|
74
|
+
const { nativeSDKVersion, jssdkVersion } = context.sdkInfo;
|
|
75
|
+
return {
|
|
76
|
+
platform: 1000,
|
|
77
|
+
os: context.deviceInfo.platform,
|
|
78
|
+
appVersion: nativeSDKVersion ?? jssdkVersion ?? '1.0.0', // mock
|
|
79
|
+
appId: context.hostInfo?.aid ?? '1',
|
|
80
|
+
model: context.deviceInfo.model ?? 'UnknownModel',
|
|
81
|
+
brand: context.deviceInfo.brand ?? 'UnknownBrand',
|
|
82
|
+
uuid: context.deviceInfo.did,
|
|
83
|
+
jsSdkVersion: jssdkVersion, // mock
|
|
84
|
+
extra: {}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
getLocation(): IPage {
|
|
89
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
90
|
+
const params: Record<string, any> = {};
|
|
91
|
+
urlParams.forEach((value, key) => {
|
|
92
|
+
params[key] = value;
|
|
93
|
+
});
|
|
94
|
+
return {
|
|
95
|
+
name: 'GamePage',
|
|
96
|
+
params
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async trackEvent(event: IEvent, project: EProject, extraInfo?: Record<string, unknown>) {
|
|
101
|
+
const location = event.location ? event.location : await this.getLocation();
|
|
102
|
+
const target = event.target || null;
|
|
103
|
+
const extra = event.extra || null;
|
|
104
|
+
if (!this.deviceInfo) {
|
|
105
|
+
this.deviceInfo = await this.getDevice();
|
|
106
|
+
}
|
|
107
|
+
const device = this.deviceInfo;
|
|
108
|
+
const events: IEvent[] = [
|
|
109
|
+
{
|
|
110
|
+
...event,
|
|
111
|
+
location,
|
|
112
|
+
target,
|
|
113
|
+
extra,
|
|
114
|
+
timestamp: Date.now(),
|
|
115
|
+
userId: null
|
|
116
|
+
}
|
|
117
|
+
];
|
|
118
|
+
const eventPackage: IEventPackage = {
|
|
119
|
+
protocolVersion: '1.0.0',
|
|
120
|
+
events,
|
|
121
|
+
device,
|
|
122
|
+
project
|
|
123
|
+
};
|
|
124
|
+
try {
|
|
125
|
+
extraInfo
|
|
126
|
+
? this.doReport(serializeEventPackage(eventPackage), extraInfo)
|
|
127
|
+
: this.doReport(serializeEventPackage(eventPackage));
|
|
128
|
+
this.pushPastTracking(true);
|
|
129
|
+
} catch (e) {
|
|
130
|
+
this.pushPastTracking(false);
|
|
131
|
+
logger.log('[Jolibox SDK] report API error', e);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createTrack, createTrackPerformance } from './track';
|
|
2
|
+
import { Track, TrackPerformance, ReportHandler, CommonReportConfig } from './types';
|
|
3
|
+
|
|
4
|
+
interface Tracks {
|
|
5
|
+
track: Track;
|
|
6
|
+
trackPerformance: TrackPerformance;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function createTracks(reportHandler: ReportHandler, common: CommonReportConfig): Tracks {
|
|
10
|
+
const track = createTrack(reportHandler, common);
|
|
11
|
+
const trackPerformance = createTrackPerformance(track);
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
track,
|
|
15
|
+
trackPerformance
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
type InternalLifeCycleErrorName = 'INTERNAL_GAME_LAUNCH_ERROR';
|
|
2
|
+
|
|
3
|
+
// API
|
|
4
|
+
type InternalAPIErrorName = 'INTERNAL_API_ERROR';
|
|
5
|
+
|
|
6
|
+
// 前端埋点
|
|
7
|
+
type InternalMetricErrorName = 'INTERNAL_METRIC_REPORT_ERROR';
|
|
8
|
+
|
|
9
|
+
// reporter
|
|
10
|
+
type InternalReporterErrorName = 'INTERNAL_REPORTER_ERROR';
|
|
11
|
+
|
|
12
|
+
// 内部错误
|
|
13
|
+
type InternalUtilErrorName = 'INTERNAL_BUFFER_ERROR' | 'INTERNAL_SCHEMA_PARSE_ERROR';
|
|
14
|
+
|
|
15
|
+
// Native Inject Error
|
|
16
|
+
type InternalInjectErrorName = 'INTERNAL_CONTEXT_ERROR' | 'INTERNAL_JSCORE_ERROR';
|
|
17
|
+
|
|
18
|
+
type InternalBridgeErrorName =
|
|
19
|
+
| 'INTERNAL_INVOKE_NATIVE_ERROR'
|
|
20
|
+
| 'INTERNAL_APPLY_NATIVE_ERROR'
|
|
21
|
+
| 'INTERNAL_INVOKE_METHOD_ERROR';
|
|
22
|
+
|
|
23
|
+
// User
|
|
24
|
+
type UserErrorName =
|
|
25
|
+
| 'USER_VALIDATE_ERROR'
|
|
26
|
+
| 'USER_GLOBAL_ERROR'
|
|
27
|
+
| 'USER_FETCH_ERROR'
|
|
28
|
+
| 'API_ERROR'
|
|
29
|
+
| 'USER_CUSTOM_ERROR';
|
|
30
|
+
|
|
31
|
+
export type ErrorName =
|
|
32
|
+
| InternalLifeCycleErrorName
|
|
33
|
+
| InternalInjectErrorName
|
|
34
|
+
| InternalAPIErrorName
|
|
35
|
+
| InternalBridgeErrorName
|
|
36
|
+
| InternalUtilErrorName
|
|
37
|
+
| InternalReporterErrorName
|
|
38
|
+
| UserErrorName
|
|
39
|
+
| InternalMetricErrorName;
|
|
40
|
+
|
|
41
|
+
export type ErrorKind = 'INTERNAL_ERROR' | 'USER_ERROR' | 'API_ERROR';
|
|
42
|
+
export type ErrorEnv = 'native' | 'h5';
|
|
43
|
+
export type LoadScriptError = BaseError & { code?: number };
|
|
44
|
+
export enum LoadScriptCode {
|
|
45
|
+
DEVELOPER_FILE_NOT_FOUND = 0,
|
|
46
|
+
INTERNAL_IOS_CAN_NOT_FOUND_PKG = 1,
|
|
47
|
+
USER_IOS_LOAD_TIMEOUT = 2,
|
|
48
|
+
INTERNAL_IOS_PKG_LOAD_ERROR = 3,
|
|
49
|
+
INTERNAL_IOS_PKG_PARSE_FAIL = 4,
|
|
50
|
+
USER_IOS_GET_EMPTY_DATA = 5,
|
|
51
|
+
USER_ANDROID_GET_PKG_FAIL = 6,
|
|
52
|
+
DEVELOPER_ANDROID_PACKAGE_FILE_UNEXPECTED_REQUIRE = 7
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export abstract class BaseError extends Error {
|
|
56
|
+
abstract kind: ErrorKind;
|
|
57
|
+
abstract name: ErrorName;
|
|
58
|
+
priority: 'P0' | 'P1';
|
|
59
|
+
env?: ErrorEnv;
|
|
60
|
+
raw?: Error;
|
|
61
|
+
component?: string;
|
|
62
|
+
constructor(error: string | Error) {
|
|
63
|
+
if (typeof error === 'string') {
|
|
64
|
+
super(error);
|
|
65
|
+
this.priority = 'P1';
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
super(error.message);
|
|
69
|
+
this.priority = 'P1';
|
|
70
|
+
this.stack = error.stack;
|
|
71
|
+
this.raw = error;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export abstract class InternalError extends BaseError {
|
|
76
|
+
readonly kind = 'INTERNAL_ERROR';
|
|
77
|
+
}
|
|
78
|
+
export abstract class UserError extends BaseError {
|
|
79
|
+
readonly kind = 'USER_ERROR';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export class UserValidateError extends UserError {
|
|
83
|
+
readonly name = 'USER_VALIDATE_ERROR';
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export class UserGlobalError extends UserError {
|
|
87
|
+
readonly name = 'USER_GLOBAL_ERROR';
|
|
88
|
+
readonly priority = 'P0';
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export class UserCustomError extends UserError {
|
|
92
|
+
readonly name = 'USER_CUSTOM_ERROR';
|
|
93
|
+
errMsg: string;
|
|
94
|
+
extra?: { [key: string]: unknown };
|
|
95
|
+
|
|
96
|
+
constructor(readonly message: string, readonly errNo?: number, extra?: { [key: string]: unknown }) {
|
|
97
|
+
super(message);
|
|
98
|
+
this.errMsg = message;
|
|
99
|
+
|
|
100
|
+
if (extra) {
|
|
101
|
+
this.extra = Object.assign({}, this.extra, extra);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export class UserFetchError extends UserError {
|
|
107
|
+
readonly name = 'USER_FETCH_ERROR';
|
|
108
|
+
errMsg: string;
|
|
109
|
+
extra?: { [key: string]: unknown };
|
|
110
|
+
|
|
111
|
+
constructor(readonly message: string, readonly errNo?: number, extra?: { [key: string]: unknown }) {
|
|
112
|
+
super(message);
|
|
113
|
+
this.errMsg = message;
|
|
114
|
+
|
|
115
|
+
if (extra) {
|
|
116
|
+
this.extra = Object.assign({}, this.extra, extra);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export class InternalSchemaParseError extends InternalError {
|
|
122
|
+
readonly name = 'INTERNAL_SCHEMA_PARSE_ERROR';
|
|
123
|
+
readonly priority = 'P0';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export class InternalInvokeNativeError extends InternalError {
|
|
127
|
+
readonly name = 'INTERNAL_INVOKE_NATIVE_ERROR';
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export class InternalApplyNativeError extends InternalError {
|
|
131
|
+
readonly name = 'INTERNAL_APPLY_NATIVE_ERROR';
|
|
132
|
+
errorType?: string;
|
|
133
|
+
errorCode?: number;
|
|
134
|
+
constructor(message: string, readonly errNo?: number, errorType?: string, errorCode?: number) {
|
|
135
|
+
super(message);
|
|
136
|
+
this.errorType = errorType;
|
|
137
|
+
this.errorCode = errorCode;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export class InternalInvokeMethodError extends InternalError {
|
|
142
|
+
readonly name = 'INTERNAL_INVOKE_METHOD_ERROR';
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export class InternalJSCoreNotFoundError extends InternalError {
|
|
146
|
+
readonly name = 'INTERNAL_JSCORE_ERROR';
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export class InternalBufferError extends InternalError {
|
|
150
|
+
readonly name = 'INTERNAL_BUFFER_ERROR';
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export class InternalContextError extends InternalError {
|
|
154
|
+
readonly name = 'INTERNAL_CONTEXT_ERROR';
|
|
155
|
+
readonly property: string;
|
|
156
|
+
constructor(readonly message: string, property: string) {
|
|
157
|
+
super(message);
|
|
158
|
+
this.property = property;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export class APIError extends BaseError {
|
|
163
|
+
readonly kind = 'API_ERROR';
|
|
164
|
+
readonly name = 'API_ERROR';
|
|
165
|
+
extra?: Record<string, unknown>;
|
|
166
|
+
errorType?: string;
|
|
167
|
+
|
|
168
|
+
constructor(
|
|
169
|
+
readonly message: string,
|
|
170
|
+
readonly code: number,
|
|
171
|
+
errorType?: string,
|
|
172
|
+
stack?: string,
|
|
173
|
+
priority?: 'P0' | 'P1'
|
|
174
|
+
) {
|
|
175
|
+
super(message);
|
|
176
|
+
|
|
177
|
+
if (errorType) {
|
|
178
|
+
this.errorType = errorType;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (stack !== undefined) {
|
|
182
|
+
this.stack = stack;
|
|
183
|
+
}
|
|
184
|
+
if (priority) {
|
|
185
|
+
this.priority = priority;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
toJSON() {
|
|
190
|
+
return {
|
|
191
|
+
message: this.message,
|
|
192
|
+
stack: this.stack,
|
|
193
|
+
name: this.name,
|
|
194
|
+
code: this.code,
|
|
195
|
+
errorType: this.errorType
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export class InternalMetricReportError extends InternalError {
|
|
201
|
+
readonly name = 'INTERNAL_METRIC_REPORT_ERROR';
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export class InternalReporterError extends InternalError {
|
|
205
|
+
readonly name = 'INTERNAL_REPORTER_ERROR';
|
|
206
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import './report';
|
|
2
|
+
import { APIError, UserCustomError } from '@jolibox/common';
|
|
3
|
+
|
|
4
|
+
export function formatErrorCode(method: string, code?: number) {
|
|
5
|
+
return `[${method}]:${code}`;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// 创建APIError异常对象
|
|
9
|
+
export const createAPIError = (
|
|
10
|
+
error: { code: number; msg: string; type?: string },
|
|
11
|
+
params?: { errNo?: number; errMsg?: string }
|
|
12
|
+
) => {
|
|
13
|
+
return new APIError(params?.errMsg ?? error.msg ?? '', error.code, error.type);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const createUserAPIError = (msg: string) => {
|
|
17
|
+
return new UserCustomError(msg);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export { errorReportEmitter, ErrorData } from './report';
|