@etsoo/appscript 1.5.98 → 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 CHANGED
@@ -55,7 +55,6 @@ $ yarn add @etsoo/appscript
55
55
  #### ExternalSettings.ts
56
56
 
57
57
  - IExternalSettings - External settings items
58
- - IExternalSettingsHost - External settings host passed by external script
59
58
 
60
59
  #### UserRole.ts
61
60
 
@@ -1,6 +1,11 @@
1
1
  import { ApiDataError, ApiMethod } from "@etsoo/restclient";
2
2
  import { DataTypes, IActionResult } from "@etsoo/shared";
3
- import { EntityStatus, UserRole } from "../../src";
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 replacement", () => {
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
  });
@@ -16,7 +16,7 @@ import {
16
16
  InitCallResultData,
17
17
  IUser
18
18
  } from "../../src";
19
- import { DataTypes, DomUtils, Utils, WindowStorage } from "@etsoo/shared";
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
- ExternalSettings.format({
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
- )![0]
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
  }
@@ -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
  /**
@@ -164,11 +164,10 @@ class CoreApp {
164
164
  this.passphrase = "";
165
165
  this.apis = {};
166
166
  this.tasks = [];
167
- if (settings?.regions?.length === 0) {
168
- throw new Error("No regions defined");
169
- }
170
- this.settings = settings;
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
  }
@@ -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
  }
@@ -31,15 +31,37 @@ export interface IExternalSettings extends ExternalEndpoint {
31
31
  /**
32
32
  * Endpoints to other services
33
33
  */
34
- readonly endpoints?: Record<"core" | "accounting" | "crm" | "calandar" | "task" | string, ExternalEndpoint>;
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
- * Create instance
41
+ * Sub domain match regular expression
42
42
  */
43
- function create<T extends IExternalSettings = IExternalSettings>(): T | undefined;
44
- function format(settings: any, hostname?: string): any;
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
- * Create instance
10
+ * Sub domain match regular expression
11
11
  */
12
- function create() {
13
- if ("settings" in globalThis) {
14
- const settings = Reflect.get(globalThis, "settings");
15
- if (typeof settings === "object") {
16
- if (typeof window !== "undefined") {
17
- // Host name
18
- const hostname = globalThis.location.hostname;
19
- // replace {hostname}
20
- format(settings, hostname);
21
- }
22
- return settings;
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
- return undefined;
27
+ throw new Error("No external settings found");
26
28
  }
27
29
  ExternalSettings.create = create;
28
- function format(settings, hostname) {
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
- if (!hostname)
31
- hostname = "localhost";
32
- // replace {hostname}
33
- for (const key in settings) {
34
- const value = settings[key];
35
- if (typeof value === "string") {
36
- settings[key] = value.replace("{hostname}", hostname);
37
- }
38
- else if (typeof value === "object") {
39
- format(value, hostname);
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.format = format;
60
+ ExternalSettings.formatHost = formatHost;
45
61
  })(ExternalSettings || (exports.ExternalSettings = ExternalSettings = {}));
@@ -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
  /**
@@ -161,11 +161,10 @@ export class CoreApp {
161
161
  this.passphrase = "";
162
162
  this.apis = {};
163
163
  this.tasks = [];
164
- if (settings?.regions?.length === 0) {
165
- throw new Error("No regions defined");
166
- }
167
- this.settings = settings;
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
  }
@@ -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
  }
@@ -31,15 +31,37 @@ export interface IExternalSettings extends ExternalEndpoint {
31
31
  /**
32
32
  * Endpoints to other services
33
33
  */
34
- readonly endpoints?: Record<"core" | "accounting" | "crm" | "calandar" | "task" | string, ExternalEndpoint>;
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
- * Create instance
41
+ * Sub domain match regular expression
42
42
  */
43
- function create<T extends IExternalSettings = IExternalSettings>(): T | undefined;
44
- function format(settings: any, hostname?: string): any;
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
- * Create instance
7
+ * Sub domain match regular expression
8
8
  */
9
- function create() {
10
- if ("settings" in globalThis) {
11
- const settings = Reflect.get(globalThis, "settings");
12
- if (typeof settings === "object") {
13
- if (typeof window !== "undefined") {
14
- // Host name
15
- const hostname = globalThis.location.hostname;
16
- // replace {hostname}
17
- format(settings, hostname);
18
- }
19
- return settings;
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
- return undefined;
24
+ throw new Error("No external settings found");
23
25
  }
24
26
  ExternalSettings.create = create;
25
- function format(settings, hostname) {
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
- if (!hostname)
28
- hostname = "localhost";
29
- // replace {hostname}
30
- for (const key in settings) {
31
- const value = settings[key];
32
- if (typeof value === "string") {
33
- settings[key] = value.replace("{hostname}", hostname);
34
- }
35
- else if (typeof value === "object") {
36
- format(value, hostname);
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.format = format;
57
+ ExternalSettings.formatHost = formatHost;
42
58
  })(ExternalSettings || (ExternalSettings = {}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/appscript",
3
- "version": "1.5.98",
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,7 +37,7 @@
37
37
  "dependencies": {
38
38
  "@etsoo/notificationbase": "^1.1.58",
39
39
  "@etsoo/restclient": "^1.1.23",
40
- "@etsoo/shared": "^1.2.60",
40
+ "@etsoo/shared": "^1.2.61",
41
41
  "crypto-js": "^4.2.0"
42
42
  },
43
43
  "devDependencies": {
@@ -336,15 +336,15 @@ export abstract class CoreApp<
336
336
  name: string,
337
337
  debug: boolean = false
338
338
  ) {
339
- if (settings?.regions?.length === 0) {
340
- throw new Error("No regions defined");
341
- }
342
- this.settings = settings;
339
+ // Format settings
340
+ this.settings = this.formatSettings(settings);
343
341
 
344
- const region = AddressRegion.getById(settings.regions[0]);
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
@@ -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
  }
@@ -37,7 +37,7 @@ export interface IExternalSettings extends ExternalEndpoint {
37
37
  * Endpoints to other services
38
38
  */
39
39
  readonly endpoints?: Record<
40
- "core" | "accounting" | "crm" | "calandar" | "task" | string,
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
- * Create instance
50
+ * Sub domain match regular expression
51
51
  */
52
- export function create<T extends IExternalSettings = IExternalSettings>():
53
- | T
54
- | undefined {
55
- if ("settings" in globalThis) {
56
- const settings = Reflect.get(globalThis, "settings");
57
- if (typeof settings === "object") {
58
- if (typeof window !== "undefined") {
59
- // Host name
60
- const hostname = globalThis.location.hostname;
61
-
62
- // replace {hostname}
63
- format(settings, hostname);
64
- }
65
-
66
- return settings as T;
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
- return undefined;
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
- export function format(settings: any, hostname?: string) {
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
- if (!hostname) hostname = "localhost";
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
- return settings;
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
  }