@etsoo/appscript 1.5.97 → 1.5.99
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/README.md +0 -1
- package/__tests__/app/CoreApp.ts +53 -2
- package/__tests__/app/TestApp.ts +16 -4
- package/lib/cjs/api/AuthApi.d.ts +3 -3
- package/lib/cjs/api/AuthApi.js +4 -2
- package/lib/cjs/api/rq/ApiRefreshTokenRQ.d.ts +2 -2
- package/lib/cjs/api/rq/TokenRQ.d.ts +6 -1
- package/lib/cjs/app/CoreApp.d.ts +6 -0
- package/lib/cjs/app/CoreApp.js +16 -11
- package/lib/cjs/app/ExternalSettings.d.ts +26 -4
- package/lib/cjs/app/ExternalSettings.js +44 -28
- package/lib/cjs/app/IApp.d.ts +0 -4
- package/lib/mjs/api/AuthApi.d.ts +3 -3
- package/lib/mjs/api/AuthApi.js +4 -2
- package/lib/mjs/api/rq/ApiRefreshTokenRQ.d.ts +2 -2
- package/lib/mjs/api/rq/TokenRQ.d.ts +6 -1
- package/lib/mjs/app/CoreApp.d.ts +6 -0
- package/lib/mjs/app/CoreApp.js +16 -11
- package/lib/mjs/app/ExternalSettings.d.ts +26 -4
- package/lib/mjs/app/ExternalSettings.js +44 -28
- package/lib/mjs/app/IApp.d.ts +0 -4
- package/package.json +6 -6
- package/src/api/AuthApi.ts +7 -5
- package/src/api/rq/ApiRefreshTokenRQ.ts +2 -2
- package/src/api/rq/TokenRQ.ts +6 -1
- package/src/app/CoreApp.ts +18 -12
- package/src/app/ExternalSettings.ts +74 -32
- package/src/app/IApp.ts +0 -5
package/README.md
CHANGED
package/__tests__/app/CoreApp.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { ApiDataError, ApiMethod } from "@etsoo/restclient";
|
|
2
2
|
import { DataTypes, IActionResult } from "@etsoo/shared";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
EntityStatus,
|
|
5
|
+
ExternalEndpoint,
|
|
6
|
+
ExternalSettings,
|
|
7
|
+
UserRole
|
|
8
|
+
} from "../../src";
|
|
4
9
|
import { TestApp } from "./TestApp";
|
|
5
10
|
|
|
6
11
|
// Arrange
|
|
@@ -16,7 +21,7 @@ const app = new appClass();
|
|
|
16
21
|
|
|
17
22
|
await app.changeCulture(app.settings.cultures[0]);
|
|
18
23
|
|
|
19
|
-
test("Test for domain
|
|
24
|
+
test("Test for domain substitution", () => {
|
|
20
25
|
expect(app.settings.endpoint).toBe("http://localhost:9000/api/");
|
|
21
26
|
|
|
22
27
|
expect(app.settings.endpoints?.core.endpoint).toBe(
|
|
@@ -24,6 +29,52 @@ test("Test for domain replacement", () => {
|
|
|
24
29
|
);
|
|
25
30
|
});
|
|
26
31
|
|
|
32
|
+
test("Test for formatApp", () => {
|
|
33
|
+
expect(
|
|
34
|
+
ExternalSettings.formatApp(
|
|
35
|
+
"admin.app.local",
|
|
36
|
+
"core",
|
|
37
|
+
"https://{hostname}/api/"
|
|
38
|
+
)
|
|
39
|
+
).toBe("https://core.app.local/api/");
|
|
40
|
+
|
|
41
|
+
expect(
|
|
42
|
+
ExternalSettings.formatApp("localhost", "admin", "https://{hostname}/api/")
|
|
43
|
+
).toBe("https://localhost/api/");
|
|
44
|
+
|
|
45
|
+
// Custom sub domain match
|
|
46
|
+
ExternalSettings.subDomainMatch = /app(?=\.)/i;
|
|
47
|
+
|
|
48
|
+
expect(
|
|
49
|
+
ExternalSettings.formatApp(
|
|
50
|
+
"admin.app.local",
|
|
51
|
+
"core",
|
|
52
|
+
"https://{hostname}/api/"
|
|
53
|
+
)
|
|
54
|
+
).toBe("https://admin.core.local/api/");
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("Test for formatHost with endpoints", () => {
|
|
58
|
+
// Reset sub domain match
|
|
59
|
+
ExternalSettings.subDomainMatch = /(?<=\/\/)[0-9a-z]+(?=\.)/i;
|
|
60
|
+
|
|
61
|
+
const endpoints: Record<string, ExternalEndpoint> = {
|
|
62
|
+
core: {
|
|
63
|
+
endpoint: "https://{hostname}/api/",
|
|
64
|
+
webUrl: "https://{hostname}/"
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const result = ExternalSettings.formatHost(endpoints, "admin.app.local");
|
|
69
|
+
|
|
70
|
+
expect(result).toStrictEqual({
|
|
71
|
+
core: {
|
|
72
|
+
endpoint: "https://core.app.local/api/",
|
|
73
|
+
webUrl: "https://core.app.local/"
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
27
78
|
test("Test for properties", () => {
|
|
28
79
|
expect(app.settings.currentRegion.label).toBe("中国大陆");
|
|
29
80
|
});
|
package/__tests__/app/TestApp.ts
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
InitCallResultData,
|
|
17
17
|
IUser
|
|
18
18
|
} from "../../src";
|
|
19
|
-
import { DataTypes, DomUtils,
|
|
19
|
+
import { DataTypes, DomUtils, WindowStorage } from "@etsoo/shared";
|
|
20
20
|
|
|
21
21
|
// Detected country or region
|
|
22
22
|
const { detectedCountry } = DomUtils;
|
|
@@ -72,7 +72,9 @@ export class TestApp extends CoreApp<
|
|
|
72
72
|
*/
|
|
73
73
|
constructor() {
|
|
74
74
|
super(
|
|
75
|
-
|
|
75
|
+
{
|
|
76
|
+
appId: 0,
|
|
77
|
+
|
|
76
78
|
/**
|
|
77
79
|
* Endpoint of the API service
|
|
78
80
|
*/
|
|
@@ -115,8 +117,8 @@ export class TestApp extends CoreApp<
|
|
|
115
117
|
currentCulture: DomUtils.getCulture(
|
|
116
118
|
supportedCultures,
|
|
117
119
|
detectedCulture
|
|
118
|
-
)
|
|
119
|
-
}
|
|
120
|
+
)[0]
|
|
121
|
+
},
|
|
120
122
|
createClient(),
|
|
121
123
|
container,
|
|
122
124
|
new WindowStorage(),
|
|
@@ -124,6 +126,16 @@ export class TestApp extends CoreApp<
|
|
|
124
126
|
);
|
|
125
127
|
}
|
|
126
128
|
|
|
129
|
+
// Example of local format settings
|
|
130
|
+
protected override formatSettings(settings: IAppSettings): IAppSettings {
|
|
131
|
+
const { endpoint, endpoints, ...rest } = settings;
|
|
132
|
+
return {
|
|
133
|
+
...rest,
|
|
134
|
+
endpoint: ExternalSettings.formatHost(endpoint, "localhost"),
|
|
135
|
+
endpoints: ExternalSettings.formatHost(endpoints, "localhost")
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
127
139
|
freshCountdownUI(callback?: () => PromiseLike<unknown>): void {
|
|
128
140
|
throw new Error("Method not implemented.");
|
|
129
141
|
}
|
package/lib/cjs/api/AuthApi.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { BaseApi } from "./BaseApi";
|
|
|
4
4
|
import { ResultPayload } from "./dto/ResultPayload";
|
|
5
5
|
import { DataTypes, IActionResult } from "@etsoo/shared";
|
|
6
6
|
import { RefreshTokenProps, RefreshTokenResult } from "../app/IApp";
|
|
7
|
-
import {
|
|
7
|
+
import { TokenInputRQ } from "./rq/TokenRQ";
|
|
8
8
|
import { ApiRefreshTokenDto } from "./dto/ApiRefreshTokenDto";
|
|
9
9
|
import { GetLogInUrlRQ } from "./rq/GetLogInUrlRQ";
|
|
10
10
|
import { LoginRQ } from "./rq/LoginRQ";
|
|
@@ -27,7 +27,7 @@ export declare class AuthApi extends BaseApi {
|
|
|
27
27
|
* @param payload Payload
|
|
28
28
|
* @returns Result
|
|
29
29
|
*/
|
|
30
|
-
apiRefreshToken(rq:
|
|
30
|
+
apiRefreshToken(rq: TokenInputRQ, payload?: IApiPayload<ApiRefreshTokenDto>): Promise<ApiRefreshTokenDto | undefined>;
|
|
31
31
|
/**
|
|
32
32
|
* Authorization request
|
|
33
33
|
* @param auth Authorization request data
|
|
@@ -56,7 +56,7 @@ export declare class AuthApi extends BaseApi {
|
|
|
56
56
|
* @param payload Payload
|
|
57
57
|
* @returns Result
|
|
58
58
|
*/
|
|
59
|
-
exchangeToken(rq:
|
|
59
|
+
exchangeToken(rq: TokenInputRQ, payload?: IApiPayload<ApiRefreshTokenDto>): Promise<ApiRefreshTokenDto | undefined>;
|
|
60
60
|
/**
|
|
61
61
|
* Get log in url
|
|
62
62
|
* @param rq Request data
|
package/lib/cjs/api/AuthApi.js
CHANGED
|
@@ -14,7 +14,8 @@ class AuthApi extends BaseApi_1.BaseApi {
|
|
|
14
14
|
* @returns Result
|
|
15
15
|
*/
|
|
16
16
|
apiRefreshToken(rq, payload) {
|
|
17
|
-
|
|
17
|
+
const data = { ...rq, timeZone: this.app.getTimeZone() };
|
|
18
|
+
return this.api.put("Auth/ApiRefreshToken", data, payload);
|
|
18
19
|
}
|
|
19
20
|
/**
|
|
20
21
|
* Authorization request
|
|
@@ -63,7 +64,8 @@ class AuthApi extends BaseApi_1.BaseApi {
|
|
|
63
64
|
* @returns Result
|
|
64
65
|
*/
|
|
65
66
|
exchangeToken(rq, payload) {
|
|
66
|
-
|
|
67
|
+
const data = { ...rq, timeZone: this.app.getTimeZone() };
|
|
68
|
+
return this.api.put("Auth/ExchangeToken", data, payload);
|
|
67
69
|
}
|
|
68
70
|
/**
|
|
69
71
|
* Get log in url
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TokenInputRQ } from "./TokenRQ";
|
|
2
2
|
/**
|
|
3
3
|
* API Refresh Token Request data
|
|
4
4
|
*/
|
|
5
|
-
export type ApiRefreshTokenRQ =
|
|
5
|
+
export type ApiRefreshTokenRQ = TokenInputRQ & {
|
|
6
6
|
/**
|
|
7
7
|
* Application ID, 0 for core system
|
|
8
8
|
*/
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Token request data
|
|
3
3
|
*/
|
|
4
|
-
export type
|
|
4
|
+
export type TokenInputRQ = {
|
|
5
5
|
/**
|
|
6
6
|
* Refresh token
|
|
7
7
|
*/
|
|
8
8
|
token: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Token request data
|
|
12
|
+
*/
|
|
13
|
+
export type TokenRQ = TokenInputRQ & {
|
|
9
14
|
/**
|
|
10
15
|
* Time zone
|
|
11
16
|
*/
|
package/lib/cjs/app/CoreApp.d.ts
CHANGED
|
@@ -176,6 +176,12 @@ export declare abstract class CoreApp<U extends IUser, S extends IAppSettings, N
|
|
|
176
176
|
* @param debug Debug mode
|
|
177
177
|
*/
|
|
178
178
|
protected constructor(settings: S, api: IApi | undefined | null, notifier: INotifier<N, C>, storage: IStorage, name: string, debug?: boolean);
|
|
179
|
+
/**
|
|
180
|
+
* Format settings
|
|
181
|
+
* @param settings Original settings
|
|
182
|
+
* @returns Result
|
|
183
|
+
*/
|
|
184
|
+
protected formatSettings(settings: S): S;
|
|
179
185
|
private getDeviceId;
|
|
180
186
|
private resetKeys;
|
|
181
187
|
/**
|
package/lib/cjs/app/CoreApp.js
CHANGED
|
@@ -164,11 +164,10 @@ class CoreApp {
|
|
|
164
164
|
this.passphrase = "";
|
|
165
165
|
this.apis = {};
|
|
166
166
|
this.tasks = [];
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const region = AddressRegion_1.AddressRegion.getById(settings.regions[0]);
|
|
167
|
+
// Format settings
|
|
168
|
+
this.settings = this.formatSettings(settings);
|
|
169
|
+
// Current region
|
|
170
|
+
const region = AddressRegion_1.AddressRegion.getById(this.settings.regions[0]);
|
|
172
171
|
if (region == null) {
|
|
173
172
|
throw new Error("No default region defined");
|
|
174
173
|
}
|
|
@@ -177,7 +176,7 @@ class CoreApp {
|
|
|
177
176
|
const refresh = async (api, rq) => {
|
|
178
177
|
if (this.lastCalled) {
|
|
179
178
|
// Call refreshToken to update access token
|
|
180
|
-
await this.refreshToken({ token: rq.token,
|
|
179
|
+
await this.refreshToken({ token: rq.token, showLoading: false }, (result) => {
|
|
181
180
|
if (result === true)
|
|
182
181
|
return;
|
|
183
182
|
console.log(`CoreApp.${this.name}.RefreshToken`, result);
|
|
@@ -232,6 +231,14 @@ class CoreApp {
|
|
|
232
231
|
this.setup();
|
|
233
232
|
});
|
|
234
233
|
}
|
|
234
|
+
/**
|
|
235
|
+
* Format settings
|
|
236
|
+
* @param settings Original settings
|
|
237
|
+
* @returns Result
|
|
238
|
+
*/
|
|
239
|
+
formatSettings(settings) {
|
|
240
|
+
return settings;
|
|
241
|
+
}
|
|
235
242
|
getDeviceId() {
|
|
236
243
|
return this.deviceId.substring(0, 15);
|
|
237
244
|
}
|
|
@@ -1420,7 +1427,7 @@ class CoreApp {
|
|
|
1420
1427
|
*/
|
|
1421
1428
|
async refreshToken(props, callback) {
|
|
1422
1429
|
// Check props
|
|
1423
|
-
props ?? (props = {
|
|
1430
|
+
props ?? (props = {});
|
|
1424
1431
|
props.token ?? (props.token = this.getCacheToken());
|
|
1425
1432
|
// Call refresh token API
|
|
1426
1433
|
let data = await this.createAuthApi().refreshToken(props);
|
|
@@ -1519,7 +1526,7 @@ class CoreApp {
|
|
|
1519
1526
|
throw new Error("System API is not allowed to exchange token");
|
|
1520
1527
|
}
|
|
1521
1528
|
// Call the API quietly, no loading bar and no error popup
|
|
1522
|
-
const data = await this.createAuthApi().exchangeToken({ token
|
|
1529
|
+
const data = await this.createAuthApi().exchangeToken({ token }, {
|
|
1523
1530
|
showLoading: false,
|
|
1524
1531
|
onError: (error) => {
|
|
1525
1532
|
console.error(`CoreApp.${api.name}.ExchangeToken error`, error);
|
|
@@ -1610,8 +1617,6 @@ class CoreApp {
|
|
|
1610
1617
|
return;
|
|
1611
1618
|
// App id
|
|
1612
1619
|
const appId = this.settings.appId;
|
|
1613
|
-
// Timezone
|
|
1614
|
-
const timeZone = this.getTimeZone();
|
|
1615
1620
|
// APIs
|
|
1616
1621
|
for (const name in this.apis) {
|
|
1617
1622
|
// Get the API
|
|
@@ -1624,7 +1629,7 @@ class CoreApp {
|
|
|
1624
1629
|
// Ready to trigger
|
|
1625
1630
|
if (api[2] === 0) {
|
|
1626
1631
|
// Refresh token
|
|
1627
|
-
api[3](api[0], { appId, token: api[4]
|
|
1632
|
+
api[3](api[0], { appId, token: api[4] }).then((data) => {
|
|
1628
1633
|
if (data == null) {
|
|
1629
1634
|
// Failed, try it again in 2 seconds
|
|
1630
1635
|
api[2] = 2;
|
|
@@ -31,15 +31,37 @@ export interface IExternalSettings extends ExternalEndpoint {
|
|
|
31
31
|
/**
|
|
32
32
|
* Endpoints to other services
|
|
33
33
|
*/
|
|
34
|
-
readonly endpoints?: Record<"core" | "
|
|
34
|
+
readonly endpoints?: Record<"core" | "admin" | "finance" | "crm" | "oa" | "agile" | string, ExternalEndpoint>;
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
37
|
* External settings namespace
|
|
38
38
|
*/
|
|
39
39
|
export declare namespace ExternalSettings {
|
|
40
40
|
/**
|
|
41
|
-
*
|
|
41
|
+
* Sub domain match regular expression
|
|
42
42
|
*/
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
let subDomainMatch: RegExp;
|
|
44
|
+
/**
|
|
45
|
+
* Create settings instance
|
|
46
|
+
* @param settings Settings
|
|
47
|
+
* @returns Result
|
|
48
|
+
*/
|
|
49
|
+
function create<T extends IExternalSettings = IExternalSettings>(settings: unknown): T;
|
|
50
|
+
/**
|
|
51
|
+
* Format the app
|
|
52
|
+
* @param hostname Hostname
|
|
53
|
+
* @param app App key
|
|
54
|
+
* @param endpoint Endpoint
|
|
55
|
+
* @returns Result
|
|
56
|
+
*/
|
|
57
|
+
function formatApp(hostname: string, app: string, endpoint: string): string;
|
|
58
|
+
/**
|
|
59
|
+
* Format the host
|
|
60
|
+
* @param setting Setting
|
|
61
|
+
* @param hostname Hostname
|
|
62
|
+
* @returns Result
|
|
63
|
+
*/
|
|
64
|
+
function formatHost(setting: string, hostname?: string | null): string;
|
|
65
|
+
function formatHost(setting: Record<string, ExternalEndpoint>, hostname?: string | null): Record<string, ExternalEndpoint>;
|
|
66
|
+
function formatHost(setting: undefined, hostname?: string | null): undefined;
|
|
45
67
|
}
|
|
@@ -7,39 +7,55 @@ exports.ExternalSettings = void 0;
|
|
|
7
7
|
var ExternalSettings;
|
|
8
8
|
(function (ExternalSettings) {
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* Sub domain match regular expression
|
|
11
11
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
12
|
+
ExternalSettings.subDomainMatch = /(?<=\/\/)[0-9a-z]+(?=\.)/i;
|
|
13
|
+
/**
|
|
14
|
+
* Create settings instance
|
|
15
|
+
* @param settings Settings
|
|
16
|
+
* @returns Result
|
|
17
|
+
*/
|
|
18
|
+
function create(settings) {
|
|
19
|
+
// Default settings reading from globalThis
|
|
20
|
+
settings ?? (settings = Reflect.get(globalThis, "settings"));
|
|
21
|
+
if (settings != null &&
|
|
22
|
+
typeof settings === "object" &&
|
|
23
|
+
"appId" in settings &&
|
|
24
|
+
"endpoint" in settings) {
|
|
25
|
+
return settings;
|
|
24
26
|
}
|
|
25
|
-
|
|
27
|
+
throw new Error("No external settings found");
|
|
26
28
|
}
|
|
27
29
|
ExternalSettings.create = create;
|
|
28
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Format the app
|
|
32
|
+
* @param hostname Hostname
|
|
33
|
+
* @param app App key
|
|
34
|
+
* @param endpoint Endpoint
|
|
35
|
+
* @returns Result
|
|
36
|
+
*/
|
|
37
|
+
function formatApp(hostname, app, endpoint) {
|
|
38
|
+
return formatHost(endpoint, hostname).replace(ExternalSettings.subDomainMatch, app);
|
|
39
|
+
}
|
|
40
|
+
ExternalSettings.formatApp = formatApp;
|
|
41
|
+
function formatHost(setting, hostname) {
|
|
42
|
+
// No setting
|
|
43
|
+
if (setting == null)
|
|
44
|
+
return undefined;
|
|
29
45
|
// Default hostname
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
46
|
+
hostname ?? (hostname = globalThis.location.hostname);
|
|
47
|
+
if (typeof setting === "string") {
|
|
48
|
+
return setting.replace("{hostname}", hostname);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
return Object.fromEntries(Object.entries(setting).map(([key, value]) => [
|
|
52
|
+
key,
|
|
53
|
+
{
|
|
54
|
+
endpoint: formatApp(hostname, key, value.endpoint),
|
|
55
|
+
webUrl: formatApp(hostname, key, value.webUrl)
|
|
56
|
+
}
|
|
57
|
+
]));
|
|
41
58
|
}
|
|
42
|
-
return settings;
|
|
43
59
|
}
|
|
44
|
-
ExternalSettings.
|
|
60
|
+
ExternalSettings.formatHost = formatHost;
|
|
45
61
|
})(ExternalSettings || (exports.ExternalSettings = ExternalSettings = {}));
|
package/lib/cjs/app/IApp.d.ts
CHANGED
package/lib/mjs/api/AuthApi.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { BaseApi } from "./BaseApi";
|
|
|
4
4
|
import { ResultPayload } from "./dto/ResultPayload";
|
|
5
5
|
import { DataTypes, IActionResult } from "@etsoo/shared";
|
|
6
6
|
import { RefreshTokenProps, RefreshTokenResult } from "../app/IApp";
|
|
7
|
-
import {
|
|
7
|
+
import { TokenInputRQ } from "./rq/TokenRQ";
|
|
8
8
|
import { ApiRefreshTokenDto } from "./dto/ApiRefreshTokenDto";
|
|
9
9
|
import { GetLogInUrlRQ } from "./rq/GetLogInUrlRQ";
|
|
10
10
|
import { LoginRQ } from "./rq/LoginRQ";
|
|
@@ -27,7 +27,7 @@ export declare class AuthApi extends BaseApi {
|
|
|
27
27
|
* @param payload Payload
|
|
28
28
|
* @returns Result
|
|
29
29
|
*/
|
|
30
|
-
apiRefreshToken(rq:
|
|
30
|
+
apiRefreshToken(rq: TokenInputRQ, payload?: IApiPayload<ApiRefreshTokenDto>): Promise<ApiRefreshTokenDto | undefined>;
|
|
31
31
|
/**
|
|
32
32
|
* Authorization request
|
|
33
33
|
* @param auth Authorization request data
|
|
@@ -56,7 +56,7 @@ export declare class AuthApi extends BaseApi {
|
|
|
56
56
|
* @param payload Payload
|
|
57
57
|
* @returns Result
|
|
58
58
|
*/
|
|
59
|
-
exchangeToken(rq:
|
|
59
|
+
exchangeToken(rq: TokenInputRQ, payload?: IApiPayload<ApiRefreshTokenDto>): Promise<ApiRefreshTokenDto | undefined>;
|
|
60
60
|
/**
|
|
61
61
|
* Get log in url
|
|
62
62
|
* @param rq Request data
|
package/lib/mjs/api/AuthApi.js
CHANGED
|
@@ -11,7 +11,8 @@ export class AuthApi extends BaseApi {
|
|
|
11
11
|
* @returns Result
|
|
12
12
|
*/
|
|
13
13
|
apiRefreshToken(rq, payload) {
|
|
14
|
-
|
|
14
|
+
const data = { ...rq, timeZone: this.app.getTimeZone() };
|
|
15
|
+
return this.api.put("Auth/ApiRefreshToken", data, payload);
|
|
15
16
|
}
|
|
16
17
|
/**
|
|
17
18
|
* Authorization request
|
|
@@ -60,7 +61,8 @@ export class AuthApi extends BaseApi {
|
|
|
60
61
|
* @returns Result
|
|
61
62
|
*/
|
|
62
63
|
exchangeToken(rq, payload) {
|
|
63
|
-
|
|
64
|
+
const data = { ...rq, timeZone: this.app.getTimeZone() };
|
|
65
|
+
return this.api.put("Auth/ExchangeToken", data, payload);
|
|
64
66
|
}
|
|
65
67
|
/**
|
|
66
68
|
* Get log in url
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TokenInputRQ } from "./TokenRQ";
|
|
2
2
|
/**
|
|
3
3
|
* API Refresh Token Request data
|
|
4
4
|
*/
|
|
5
|
-
export type ApiRefreshTokenRQ =
|
|
5
|
+
export type ApiRefreshTokenRQ = TokenInputRQ & {
|
|
6
6
|
/**
|
|
7
7
|
* Application ID, 0 for core system
|
|
8
8
|
*/
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Token request data
|
|
3
3
|
*/
|
|
4
|
-
export type
|
|
4
|
+
export type TokenInputRQ = {
|
|
5
5
|
/**
|
|
6
6
|
* Refresh token
|
|
7
7
|
*/
|
|
8
8
|
token: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Token request data
|
|
12
|
+
*/
|
|
13
|
+
export type TokenRQ = TokenInputRQ & {
|
|
9
14
|
/**
|
|
10
15
|
* Time zone
|
|
11
16
|
*/
|
package/lib/mjs/app/CoreApp.d.ts
CHANGED
|
@@ -176,6 +176,12 @@ export declare abstract class CoreApp<U extends IUser, S extends IAppSettings, N
|
|
|
176
176
|
* @param debug Debug mode
|
|
177
177
|
*/
|
|
178
178
|
protected constructor(settings: S, api: IApi | undefined | null, notifier: INotifier<N, C>, storage: IStorage, name: string, debug?: boolean);
|
|
179
|
+
/**
|
|
180
|
+
* Format settings
|
|
181
|
+
* @param settings Original settings
|
|
182
|
+
* @returns Result
|
|
183
|
+
*/
|
|
184
|
+
protected formatSettings(settings: S): S;
|
|
179
185
|
private getDeviceId;
|
|
180
186
|
private resetKeys;
|
|
181
187
|
/**
|
package/lib/mjs/app/CoreApp.js
CHANGED
|
@@ -161,11 +161,10 @@ export class CoreApp {
|
|
|
161
161
|
this.passphrase = "";
|
|
162
162
|
this.apis = {};
|
|
163
163
|
this.tasks = [];
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const region = AddressRegion.getById(settings.regions[0]);
|
|
164
|
+
// Format settings
|
|
165
|
+
this.settings = this.formatSettings(settings);
|
|
166
|
+
// Current region
|
|
167
|
+
const region = AddressRegion.getById(this.settings.regions[0]);
|
|
169
168
|
if (region == null) {
|
|
170
169
|
throw new Error("No default region defined");
|
|
171
170
|
}
|
|
@@ -174,7 +173,7 @@ export class CoreApp {
|
|
|
174
173
|
const refresh = async (api, rq) => {
|
|
175
174
|
if (this.lastCalled) {
|
|
176
175
|
// Call refreshToken to update access token
|
|
177
|
-
await this.refreshToken({ token: rq.token,
|
|
176
|
+
await this.refreshToken({ token: rq.token, showLoading: false }, (result) => {
|
|
178
177
|
if (result === true)
|
|
179
178
|
return;
|
|
180
179
|
console.log(`CoreApp.${this.name}.RefreshToken`, result);
|
|
@@ -229,6 +228,14 @@ export class CoreApp {
|
|
|
229
228
|
this.setup();
|
|
230
229
|
});
|
|
231
230
|
}
|
|
231
|
+
/**
|
|
232
|
+
* Format settings
|
|
233
|
+
* @param settings Original settings
|
|
234
|
+
* @returns Result
|
|
235
|
+
*/
|
|
236
|
+
formatSettings(settings) {
|
|
237
|
+
return settings;
|
|
238
|
+
}
|
|
232
239
|
getDeviceId() {
|
|
233
240
|
return this.deviceId.substring(0, 15);
|
|
234
241
|
}
|
|
@@ -1417,7 +1424,7 @@ export class CoreApp {
|
|
|
1417
1424
|
*/
|
|
1418
1425
|
async refreshToken(props, callback) {
|
|
1419
1426
|
// Check props
|
|
1420
|
-
props ?? (props = {
|
|
1427
|
+
props ?? (props = {});
|
|
1421
1428
|
props.token ?? (props.token = this.getCacheToken());
|
|
1422
1429
|
// Call refresh token API
|
|
1423
1430
|
let data = await this.createAuthApi().refreshToken(props);
|
|
@@ -1516,7 +1523,7 @@ export class CoreApp {
|
|
|
1516
1523
|
throw new Error("System API is not allowed to exchange token");
|
|
1517
1524
|
}
|
|
1518
1525
|
// Call the API quietly, no loading bar and no error popup
|
|
1519
|
-
const data = await this.createAuthApi().exchangeToken({ token
|
|
1526
|
+
const data = await this.createAuthApi().exchangeToken({ token }, {
|
|
1520
1527
|
showLoading: false,
|
|
1521
1528
|
onError: (error) => {
|
|
1522
1529
|
console.error(`CoreApp.${api.name}.ExchangeToken error`, error);
|
|
@@ -1607,8 +1614,6 @@ export class CoreApp {
|
|
|
1607
1614
|
return;
|
|
1608
1615
|
// App id
|
|
1609
1616
|
const appId = this.settings.appId;
|
|
1610
|
-
// Timezone
|
|
1611
|
-
const timeZone = this.getTimeZone();
|
|
1612
1617
|
// APIs
|
|
1613
1618
|
for (const name in this.apis) {
|
|
1614
1619
|
// Get the API
|
|
@@ -1621,7 +1626,7 @@ export class CoreApp {
|
|
|
1621
1626
|
// Ready to trigger
|
|
1622
1627
|
if (api[2] === 0) {
|
|
1623
1628
|
// Refresh token
|
|
1624
|
-
api[3](api[0], { appId, token: api[4]
|
|
1629
|
+
api[3](api[0], { appId, token: api[4] }).then((data) => {
|
|
1625
1630
|
if (data == null) {
|
|
1626
1631
|
// Failed, try it again in 2 seconds
|
|
1627
1632
|
api[2] = 2;
|
|
@@ -31,15 +31,37 @@ export interface IExternalSettings extends ExternalEndpoint {
|
|
|
31
31
|
/**
|
|
32
32
|
* Endpoints to other services
|
|
33
33
|
*/
|
|
34
|
-
readonly endpoints?: Record<"core" | "
|
|
34
|
+
readonly endpoints?: Record<"core" | "admin" | "finance" | "crm" | "oa" | "agile" | string, ExternalEndpoint>;
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
37
|
* External settings namespace
|
|
38
38
|
*/
|
|
39
39
|
export declare namespace ExternalSettings {
|
|
40
40
|
/**
|
|
41
|
-
*
|
|
41
|
+
* Sub domain match regular expression
|
|
42
42
|
*/
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
let subDomainMatch: RegExp;
|
|
44
|
+
/**
|
|
45
|
+
* Create settings instance
|
|
46
|
+
* @param settings Settings
|
|
47
|
+
* @returns Result
|
|
48
|
+
*/
|
|
49
|
+
function create<T extends IExternalSettings = IExternalSettings>(settings: unknown): T;
|
|
50
|
+
/**
|
|
51
|
+
* Format the app
|
|
52
|
+
* @param hostname Hostname
|
|
53
|
+
* @param app App key
|
|
54
|
+
* @param endpoint Endpoint
|
|
55
|
+
* @returns Result
|
|
56
|
+
*/
|
|
57
|
+
function formatApp(hostname: string, app: string, endpoint: string): string;
|
|
58
|
+
/**
|
|
59
|
+
* Format the host
|
|
60
|
+
* @param setting Setting
|
|
61
|
+
* @param hostname Hostname
|
|
62
|
+
* @returns Result
|
|
63
|
+
*/
|
|
64
|
+
function formatHost(setting: string, hostname?: string | null): string;
|
|
65
|
+
function formatHost(setting: Record<string, ExternalEndpoint>, hostname?: string | null): Record<string, ExternalEndpoint>;
|
|
66
|
+
function formatHost(setting: undefined, hostname?: string | null): undefined;
|
|
45
67
|
}
|
|
@@ -4,39 +4,55 @@
|
|
|
4
4
|
export var ExternalSettings;
|
|
5
5
|
(function (ExternalSettings) {
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* Sub domain match regular expression
|
|
8
8
|
*/
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
9
|
+
ExternalSettings.subDomainMatch = /(?<=\/\/)[0-9a-z]+(?=\.)/i;
|
|
10
|
+
/**
|
|
11
|
+
* Create settings instance
|
|
12
|
+
* @param settings Settings
|
|
13
|
+
* @returns Result
|
|
14
|
+
*/
|
|
15
|
+
function create(settings) {
|
|
16
|
+
// Default settings reading from globalThis
|
|
17
|
+
settings ?? (settings = Reflect.get(globalThis, "settings"));
|
|
18
|
+
if (settings != null &&
|
|
19
|
+
typeof settings === "object" &&
|
|
20
|
+
"appId" in settings &&
|
|
21
|
+
"endpoint" in settings) {
|
|
22
|
+
return settings;
|
|
21
23
|
}
|
|
22
|
-
|
|
24
|
+
throw new Error("No external settings found");
|
|
23
25
|
}
|
|
24
26
|
ExternalSettings.create = create;
|
|
25
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Format the app
|
|
29
|
+
* @param hostname Hostname
|
|
30
|
+
* @param app App key
|
|
31
|
+
* @param endpoint Endpoint
|
|
32
|
+
* @returns Result
|
|
33
|
+
*/
|
|
34
|
+
function formatApp(hostname, app, endpoint) {
|
|
35
|
+
return formatHost(endpoint, hostname).replace(ExternalSettings.subDomainMatch, app);
|
|
36
|
+
}
|
|
37
|
+
ExternalSettings.formatApp = formatApp;
|
|
38
|
+
function formatHost(setting, hostname) {
|
|
39
|
+
// No setting
|
|
40
|
+
if (setting == null)
|
|
41
|
+
return undefined;
|
|
26
42
|
// Default hostname
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
hostname ?? (hostname = globalThis.location.hostname);
|
|
44
|
+
if (typeof setting === "string") {
|
|
45
|
+
return setting.replace("{hostname}", hostname);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
return Object.fromEntries(Object.entries(setting).map(([key, value]) => [
|
|
49
|
+
key,
|
|
50
|
+
{
|
|
51
|
+
endpoint: formatApp(hostname, key, value.endpoint),
|
|
52
|
+
webUrl: formatApp(hostname, key, value.webUrl)
|
|
53
|
+
}
|
|
54
|
+
]));
|
|
38
55
|
}
|
|
39
|
-
return settings;
|
|
40
56
|
}
|
|
41
|
-
ExternalSettings.
|
|
57
|
+
ExternalSettings.formatHost = formatHost;
|
|
42
58
|
})(ExternalSettings || (ExternalSettings = {}));
|
package/lib/mjs/app/IApp.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@etsoo/appscript",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.99",
|
|
4
4
|
"description": "Applications shared TypeScript framework",
|
|
5
5
|
"main": "lib/cjs/index.js",
|
|
6
6
|
"module": "lib/mjs/index.js",
|
|
@@ -37,19 +37,19 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@etsoo/notificationbase": "^1.1.58",
|
|
39
39
|
"@etsoo/restclient": "^1.1.23",
|
|
40
|
-
"@etsoo/shared": "^1.2.
|
|
40
|
+
"@etsoo/shared": "^1.2.61",
|
|
41
41
|
"crypto-js": "^4.2.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@babel/cli": "^7.26.4",
|
|
45
|
-
"@babel/core": "^7.26.
|
|
46
|
-
"@babel/plugin-transform-runtime": "^7.
|
|
47
|
-
"@babel/preset-env": "^7.26.
|
|
45
|
+
"@babel/core": "^7.26.8",
|
|
46
|
+
"@babel/plugin-transform-runtime": "^7.26.8",
|
|
47
|
+
"@babel/preset-env": "^7.26.8",
|
|
48
48
|
"@babel/runtime-corejs3": "^7.26.7",
|
|
49
49
|
"@types/crypto-js": "^4.2.2",
|
|
50
50
|
"@vitejs/plugin-react": "^4.3.4",
|
|
51
51
|
"jsdom": "^26.0.0",
|
|
52
52
|
"typescript": "^5.7.3",
|
|
53
|
-
"vitest": "^3.0.
|
|
53
|
+
"vitest": "^3.0.5"
|
|
54
54
|
}
|
|
55
55
|
}
|
package/src/api/AuthApi.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { BaseApi } from "./BaseApi";
|
|
|
4
4
|
import { ResultPayload } from "./dto/ResultPayload";
|
|
5
5
|
import { ActionResult, DataTypes, IActionResult } from "@etsoo/shared";
|
|
6
6
|
import { RefreshTokenProps, RefreshTokenResult } from "../app/IApp";
|
|
7
|
-
import { TokenRQ } from "./rq/TokenRQ";
|
|
7
|
+
import { TokenInputRQ, TokenRQ } from "./rq/TokenRQ";
|
|
8
8
|
import { ApiRefreshTokenDto } from "./dto/ApiRefreshTokenDto";
|
|
9
9
|
import { GetLogInUrlRQ } from "./rq/GetLogInUrlRQ";
|
|
10
10
|
import { LoginRQ } from "./rq/LoginRQ";
|
|
@@ -32,8 +32,9 @@ export class AuthApi extends BaseApi {
|
|
|
32
32
|
* @param payload Payload
|
|
33
33
|
* @returns Result
|
|
34
34
|
*/
|
|
35
|
-
apiRefreshToken(rq:
|
|
36
|
-
|
|
35
|
+
apiRefreshToken(rq: TokenInputRQ, payload?: IApiPayload<ApiRefreshTokenDto>) {
|
|
36
|
+
const data: TokenRQ = { ...rq, timeZone: this.app.getTimeZone() };
|
|
37
|
+
return this.api.put("Auth/ApiRefreshToken", data, payload);
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
/**
|
|
@@ -93,8 +94,9 @@ export class AuthApi extends BaseApi {
|
|
|
93
94
|
* @param payload Payload
|
|
94
95
|
* @returns Result
|
|
95
96
|
*/
|
|
96
|
-
exchangeToken(rq:
|
|
97
|
-
|
|
97
|
+
exchangeToken(rq: TokenInputRQ, payload?: IApiPayload<ApiRefreshTokenDto>) {
|
|
98
|
+
const data: TokenRQ = { ...rq, timeZone: this.app.getTimeZone() };
|
|
99
|
+
return this.api.put("Auth/ExchangeToken", data, payload);
|
|
98
100
|
}
|
|
99
101
|
|
|
100
102
|
/**
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TokenInputRQ } from "./TokenRQ";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* API Refresh Token Request data
|
|
5
5
|
*/
|
|
6
|
-
export type ApiRefreshTokenRQ =
|
|
6
|
+
export type ApiRefreshTokenRQ = TokenInputRQ & {
|
|
7
7
|
/**
|
|
8
8
|
* Application ID, 0 for core system
|
|
9
9
|
*/
|
package/src/api/rq/TokenRQ.ts
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Token request data
|
|
3
3
|
*/
|
|
4
|
-
export type
|
|
4
|
+
export type TokenInputRQ = {
|
|
5
5
|
/**
|
|
6
6
|
* Refresh token
|
|
7
7
|
*/
|
|
8
8
|
token: string;
|
|
9
|
+
};
|
|
9
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Token request data
|
|
13
|
+
*/
|
|
14
|
+
export type TokenRQ = TokenInputRQ & {
|
|
10
15
|
/**
|
|
11
16
|
* Time zone
|
|
12
17
|
*/
|
package/src/app/CoreApp.ts
CHANGED
|
@@ -336,15 +336,15 @@ export abstract class CoreApp<
|
|
|
336
336
|
name: string,
|
|
337
337
|
debug: boolean = false
|
|
338
338
|
) {
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
}
|
|
342
|
-
this.settings = settings;
|
|
339
|
+
// Format settings
|
|
340
|
+
this.settings = this.formatSettings(settings);
|
|
343
341
|
|
|
344
|
-
|
|
342
|
+
// Current region
|
|
343
|
+
const region = AddressRegion.getById(this.settings.regions[0]);
|
|
345
344
|
if (region == null) {
|
|
346
345
|
throw new Error("No default region defined");
|
|
347
346
|
}
|
|
347
|
+
|
|
348
348
|
this.defaultRegion = region;
|
|
349
349
|
|
|
350
350
|
// Current system refresh token
|
|
@@ -352,7 +352,7 @@ export abstract class CoreApp<
|
|
|
352
352
|
if (this.lastCalled) {
|
|
353
353
|
// Call refreshToken to update access token
|
|
354
354
|
await this.refreshToken(
|
|
355
|
-
{ token: rq.token,
|
|
355
|
+
{ token: rq.token, showLoading: false },
|
|
356
356
|
(result) => {
|
|
357
357
|
if (result === true) return;
|
|
358
358
|
console.log(`CoreApp.${this.name}.RefreshToken`, result);
|
|
@@ -433,6 +433,15 @@ export abstract class CoreApp<
|
|
|
433
433
|
);
|
|
434
434
|
}
|
|
435
435
|
|
|
436
|
+
/**
|
|
437
|
+
* Format settings
|
|
438
|
+
* @param settings Original settings
|
|
439
|
+
* @returns Result
|
|
440
|
+
*/
|
|
441
|
+
protected formatSettings(settings: S) {
|
|
442
|
+
return settings;
|
|
443
|
+
}
|
|
444
|
+
|
|
436
445
|
private getDeviceId() {
|
|
437
446
|
return this.deviceId.substring(0, 15);
|
|
438
447
|
}
|
|
@@ -1938,7 +1947,7 @@ export abstract class CoreApp<
|
|
|
1938
1947
|
callback?: (result?: boolean | IActionResult) => boolean | void
|
|
1939
1948
|
) {
|
|
1940
1949
|
// Check props
|
|
1941
|
-
props ??= {
|
|
1950
|
+
props ??= {};
|
|
1942
1951
|
props.token ??= this.getCacheToken();
|
|
1943
1952
|
|
|
1944
1953
|
// Call refresh token API
|
|
@@ -2052,7 +2061,7 @@ export abstract class CoreApp<
|
|
|
2052
2061
|
|
|
2053
2062
|
// Call the API quietly, no loading bar and no error popup
|
|
2054
2063
|
const data = await this.createAuthApi().exchangeToken(
|
|
2055
|
-
{ token
|
|
2064
|
+
{ token },
|
|
2056
2065
|
{
|
|
2057
2066
|
showLoading: false,
|
|
2058
2067
|
onError: (error) => {
|
|
@@ -2165,9 +2174,6 @@ export abstract class CoreApp<
|
|
|
2165
2174
|
// App id
|
|
2166
2175
|
const appId = this.settings.appId;
|
|
2167
2176
|
|
|
2168
|
-
// Timezone
|
|
2169
|
-
const timeZone = this.getTimeZone();
|
|
2170
|
-
|
|
2171
2177
|
// APIs
|
|
2172
2178
|
for (const name in this.apis) {
|
|
2173
2179
|
// Get the API
|
|
@@ -2182,7 +2188,7 @@ export abstract class CoreApp<
|
|
|
2182
2188
|
// Ready to trigger
|
|
2183
2189
|
if (api[2] === 0) {
|
|
2184
2190
|
// Refresh token
|
|
2185
|
-
api[3](api[0], { appId, token: api[4]
|
|
2191
|
+
api[3](api[0], { appId, token: api[4] }).then((data) => {
|
|
2186
2192
|
if (data == null) {
|
|
2187
2193
|
// Failed, try it again in 2 seconds
|
|
2188
2194
|
api[2] = 2;
|
|
@@ -37,7 +37,7 @@ export interface IExternalSettings extends ExternalEndpoint {
|
|
|
37
37
|
* Endpoints to other services
|
|
38
38
|
*/
|
|
39
39
|
readonly endpoints?: Record<
|
|
40
|
-
"core" | "
|
|
40
|
+
"core" | "admin" | "finance" | "crm" | "oa" | "agile" | string,
|
|
41
41
|
ExternalEndpoint
|
|
42
42
|
>;
|
|
43
43
|
}
|
|
@@ -47,42 +47,84 @@ export interface IExternalSettings extends ExternalEndpoint {
|
|
|
47
47
|
*/
|
|
48
48
|
export namespace ExternalSettings {
|
|
49
49
|
/**
|
|
50
|
-
*
|
|
50
|
+
* Sub domain match regular expression
|
|
51
51
|
*/
|
|
52
|
-
export
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
52
|
+
export let subDomainMatch: RegExp = /(?<=\/\/)[0-9a-z]+(?=\.)/i;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Create settings instance
|
|
56
|
+
* @param settings Settings
|
|
57
|
+
* @returns Result
|
|
58
|
+
*/
|
|
59
|
+
export function create<T extends IExternalSettings = IExternalSettings>(
|
|
60
|
+
settings: unknown
|
|
61
|
+
): T {
|
|
62
|
+
// Default settings reading from globalThis
|
|
63
|
+
settings ??= Reflect.get(globalThis, "settings");
|
|
64
|
+
|
|
65
|
+
if (
|
|
66
|
+
settings != null &&
|
|
67
|
+
typeof settings === "object" &&
|
|
68
|
+
"appId" in settings &&
|
|
69
|
+
"endpoint" in settings
|
|
70
|
+
) {
|
|
71
|
+
return settings as T;
|
|
68
72
|
}
|
|
69
|
-
|
|
73
|
+
|
|
74
|
+
throw new Error("No external settings found");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Format the app
|
|
79
|
+
* @param hostname Hostname
|
|
80
|
+
* @param app App key
|
|
81
|
+
* @param endpoint Endpoint
|
|
82
|
+
* @returns Result
|
|
83
|
+
*/
|
|
84
|
+
export function formatApp(hostname: string, app: string, endpoint: string) {
|
|
85
|
+
return formatHost(endpoint, hostname).replace(subDomainMatch, app);
|
|
70
86
|
}
|
|
71
87
|
|
|
72
|
-
|
|
88
|
+
/**
|
|
89
|
+
* Format the host
|
|
90
|
+
* @param setting Setting
|
|
91
|
+
* @param hostname Hostname
|
|
92
|
+
* @returns Result
|
|
93
|
+
*/
|
|
94
|
+
export function formatHost(setting: string, hostname?: string | null): string;
|
|
95
|
+
|
|
96
|
+
export function formatHost(
|
|
97
|
+
setting: Record<string, ExternalEndpoint>,
|
|
98
|
+
hostname?: string | null
|
|
99
|
+
): Record<string, ExternalEndpoint>;
|
|
100
|
+
|
|
101
|
+
export function formatHost(
|
|
102
|
+
setting: undefined,
|
|
103
|
+
hostname?: string | null
|
|
104
|
+
): undefined;
|
|
105
|
+
|
|
106
|
+
export function formatHost(
|
|
107
|
+
setting?: string | Record<string, ExternalEndpoint>,
|
|
108
|
+
hostname?: string | null
|
|
109
|
+
): string | Record<string, ExternalEndpoint> | undefined {
|
|
110
|
+
// No setting
|
|
111
|
+
if (setting == null) return undefined;
|
|
112
|
+
|
|
73
113
|
// Default hostname
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
// replace {hostname}
|
|
77
|
-
for (const key in settings) {
|
|
78
|
-
const value = settings[key];
|
|
79
|
-
if (typeof value === "string") {
|
|
80
|
-
settings[key] = value.replace("{hostname}", hostname);
|
|
81
|
-
} else if (typeof value === "object") {
|
|
82
|
-
format(value, hostname);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
114
|
+
hostname ??= globalThis.location.hostname;
|
|
85
115
|
|
|
86
|
-
|
|
116
|
+
if (typeof setting === "string") {
|
|
117
|
+
return setting.replace("{hostname}", hostname);
|
|
118
|
+
} else {
|
|
119
|
+
return Object.fromEntries(
|
|
120
|
+
Object.entries(setting).map(([key, value]) => [
|
|
121
|
+
key,
|
|
122
|
+
{
|
|
123
|
+
endpoint: formatApp(hostname, key, value.endpoint),
|
|
124
|
+
webUrl: formatApp(hostname, key, value.webUrl)
|
|
125
|
+
}
|
|
126
|
+
])
|
|
127
|
+
);
|
|
128
|
+
}
|
|
87
129
|
}
|
|
88
130
|
}
|