@equinor/fusion-framework-module-widget 16.0.2 → 16.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +51 -0
- package/dist/esm/Widget.js +13 -2
- package/dist/esm/Widget.js.map +1 -1
- package/dist/esm/WidgetManifestLoadError.js +42 -0
- package/dist/esm/WidgetManifestLoadError.js.map +1 -0
- package/dist/esm/WidgetModuleConfigurator.js +2 -0
- package/dist/esm/WidgetModuleConfigurator.js.map +1 -1
- package/dist/esm/WidgetModuleProvider.js +12 -3
- package/dist/esm/WidgetModuleProvider.js.map +1 -1
- package/dist/esm/enable-widget-module.js +1 -1
- package/dist/esm/enable-widget-module.js.map +1 -1
- package/dist/esm/errors/WidgetConfigLoadError.js +40 -0
- package/dist/esm/errors/WidgetConfigLoadError.js.map +1 -0
- package/dist/esm/errors/WidgetScriptModuleError.js +17 -0
- package/dist/esm/errors/WidgetScriptModuleError.js.map +1 -0
- package/dist/esm/module.js +2 -0
- package/dist/esm/module.js.map +1 -1
- package/dist/esm/state/actions.js +1 -1
- package/dist/esm/state/actions.js.map +1 -1
- package/dist/esm/state/create-reducer.js +5 -1
- package/dist/esm/state/create-reducer.js.map +1 -1
- package/dist/esm/state/flows.js +32 -7
- package/dist/esm/state/flows.js.map +1 -1
- package/dist/esm/utils.js +6 -1
- package/dist/esm/utils.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/Widget.d.ts +5 -1
- package/dist/types/WidgetManifestLoadError.d.ts +36 -0
- package/dist/types/WidgetModuleProvider.d.ts +2 -0
- package/dist/types/errors/WidgetConfigLoadError.d.ts +27 -0
- package/dist/types/errors/WidgetScriptModuleError.d.ts +13 -0
- package/dist/types/state/actions.d.ts +8 -8
- package/dist/types/state/create-reducer.d.ts +36 -36
- package/dist/types/version.d.ts +1 -1
- package/package.json +13 -13
- package/src/Widget.ts +13 -2
- package/src/WidgetManifestLoadError.ts +61 -0
- package/src/WidgetModuleConfigurator.ts +2 -0
- package/src/WidgetModuleProvider.ts +8 -1
- package/src/enable-widget-module.ts +1 -1
- package/src/errors/WidgetConfigLoadError.ts +51 -0
- package/src/errors/WidgetScriptModuleError.ts +20 -0
- package/src/module.ts +2 -0
- package/src/state/actions.ts +1 -1
- package/src/state/create-reducer.ts +3 -0
- package/src/state/flows.ts +47 -21
- package/src/types.ts +2 -2
- package/src/utils.ts +6 -1
- package/src/version.ts +1 -1
- package/dist/esm/errors.js +0 -93
- package/dist/esm/errors.js.map +0 -1
- package/dist/types/errors.d.ts +0 -73
- package/src/errors.ts +0 -125
package/dist/types/Widget.d.ts
CHANGED
|
@@ -32,7 +32,11 @@ export declare class Widget {
|
|
|
32
32
|
config?: WidgetModuleConfig;
|
|
33
33
|
/** Optional version or tag parameters forwarded to manifest/config endpoints. */
|
|
34
34
|
widgetPrams?: GetWidgetParameters['args'];
|
|
35
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* Current snapshot of the widget's internal state (manifest, config, modules, status).
|
|
37
|
+
*
|
|
38
|
+
* @returns The current {@link WidgetState}.
|
|
39
|
+
*/
|
|
36
40
|
get state(): WidgetState;
|
|
37
41
|
/**
|
|
38
42
|
* Constructs a new `Widget` instance.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discriminator for categorizing widget HTTP errors.
|
|
3
|
+
*
|
|
4
|
+
* - `'not_found'` — HTTP 404
|
|
5
|
+
* - `'unauthorized'` — HTTP 401
|
|
6
|
+
* - `'unknown'` — any other error
|
|
7
|
+
*/
|
|
8
|
+
export type WidgetErrorType = 'not_found' | 'unauthorized' | 'unknown';
|
|
9
|
+
/**
|
|
10
|
+
* Error thrown when a widget manifest cannot be loaded from the backend API.
|
|
11
|
+
*
|
|
12
|
+
* Use the static {@link fromHttpResponse} factory to create instances from
|
|
13
|
+
* HTTP responses with appropriate type mapping.
|
|
14
|
+
*/
|
|
15
|
+
export declare class WidgetManifestLoadError extends Error {
|
|
16
|
+
readonly type: WidgetErrorType;
|
|
17
|
+
/**
|
|
18
|
+
* Creates a `WidgetManifestLoadError` from an HTTP `Response`.
|
|
19
|
+
*
|
|
20
|
+
* Maps HTTP 401 to `'unauthorized'`, 404 to `'not_found'`, and all other
|
|
21
|
+
* status codes to `'unknown'`.
|
|
22
|
+
*
|
|
23
|
+
* @param response - The failing HTTP response.
|
|
24
|
+
* @param options - Standard `ErrorOptions` (e.g., `cause`).
|
|
25
|
+
* @returns A typed `WidgetManifestLoadError`.
|
|
26
|
+
*/
|
|
27
|
+
static fromHttpResponse(response: Response, options?: ErrorOptions): WidgetManifestLoadError;
|
|
28
|
+
/**
|
|
29
|
+
* @param type - Error category discriminator.
|
|
30
|
+
* @param message - Human-readable error description.
|
|
31
|
+
* @param options - Standard `ErrorOptions` (e.g., `cause`).
|
|
32
|
+
*/
|
|
33
|
+
constructor(type: WidgetErrorType, message?: string, options?: ErrorOptions);
|
|
34
|
+
}
|
|
35
|
+
export { WidgetConfigLoadError } from './errors/WidgetConfigLoadError.js';
|
|
36
|
+
export { WidgetScriptModuleError } from './errors/WidgetScriptModuleError.js';
|
|
@@ -99,6 +99,7 @@ export declare class WidgetModuleProvider implements IWidgetModuleProvider {
|
|
|
99
99
|
* @param widgetKey - Widget identifier.
|
|
100
100
|
* @param args - Optional version or tag selector.
|
|
101
101
|
* @returns Observable emitting the {@link WidgetConfig}.
|
|
102
|
+
* @throws {WidgetManifestLoadError} When the underlying query fails.
|
|
102
103
|
*/
|
|
103
104
|
protected _getWidgetConfig(widgetKey: GetWidgetParameters['widgetKey'], args?: GetWidgetParameters['args']): Observable<WidgetConfig>;
|
|
104
105
|
/**
|
|
@@ -108,6 +109,7 @@ export declare class WidgetModuleProvider implements IWidgetModuleProvider {
|
|
|
108
109
|
* @param widgetKey - Widget identifier.
|
|
109
110
|
* @param args - Optional version or tag selector.
|
|
110
111
|
* @returns Observable emitting the {@link WidgetManifest}.
|
|
112
|
+
* @throws {WidgetConfigLoadError} When the underlying query fails.
|
|
111
113
|
*/
|
|
112
114
|
protected _getWidget(widgetKey: GetWidgetParameters['widgetKey'], args?: GetWidgetParameters['args']): Observable<WidgetManifest>;
|
|
113
115
|
/**
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { WidgetErrorType } from '../WidgetManifestLoadError.js';
|
|
2
|
+
/**
|
|
3
|
+
* Error thrown when a widget configuration cannot be loaded from the backend API.
|
|
4
|
+
*
|
|
5
|
+
* Use the static {@link fromHttpResponse} factory to create instances from
|
|
6
|
+
* HTTP responses with appropriate type mapping.
|
|
7
|
+
*/
|
|
8
|
+
export declare class WidgetConfigLoadError extends Error {
|
|
9
|
+
readonly type: WidgetErrorType;
|
|
10
|
+
/**
|
|
11
|
+
* Creates a `WidgetConfigLoadError` from an HTTP `Response`.
|
|
12
|
+
*
|
|
13
|
+
* Maps HTTP 401 to `'unauthorized'`, 404 to `'not_found'`, and all other
|
|
14
|
+
* status codes to `'unknown'`.
|
|
15
|
+
*
|
|
16
|
+
* @param response - The failing HTTP response.
|
|
17
|
+
* @param options - Standard `ErrorOptions` (e.g., `cause`).
|
|
18
|
+
* @returns A typed `WidgetConfigLoadError`.
|
|
19
|
+
*/
|
|
20
|
+
static fromHttpResponse(response: Response, options?: ErrorOptions): WidgetConfigLoadError;
|
|
21
|
+
/**
|
|
22
|
+
* @param type - Error category discriminator.
|
|
23
|
+
* @param message - Human-readable error description.
|
|
24
|
+
* @param options - Standard `ErrorOptions` (e.g., `cause`).
|
|
25
|
+
*/
|
|
26
|
+
constructor(type: WidgetErrorType, message?: string, options?: ErrorOptions);
|
|
27
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { WidgetErrorType } from '../WidgetManifestLoadError.js';
|
|
2
|
+
/**
|
|
3
|
+
* Error thrown when a widget script module cannot be dynamically imported.
|
|
4
|
+
*/
|
|
5
|
+
export declare class WidgetScriptModuleError extends Error {
|
|
6
|
+
readonly type: WidgetErrorType;
|
|
7
|
+
/**
|
|
8
|
+
* @param type - Error category discriminator.
|
|
9
|
+
* @param message - Human-readable error description.
|
|
10
|
+
* @param options - Standard `ErrorOptions` (e.g., `cause`).
|
|
11
|
+
*/
|
|
12
|
+
constructor(type: WidgetErrorType, message?: string, options?: ErrorOptions);
|
|
13
|
+
}
|
|
@@ -18,10 +18,10 @@ declare const createActions: () => {
|
|
|
18
18
|
/** Async action triplet for fetching the widget manifest from the API. */
|
|
19
19
|
fetchManifest: import("@equinor/fusion-observable").ActionCreatorWithPreparedPayload<[payload: {
|
|
20
20
|
key: string;
|
|
21
|
-
args?: GetWidgetParameters[
|
|
21
|
+
args?: GetWidgetParameters['args'];
|
|
22
22
|
}, update?: boolean | undefined], {
|
|
23
23
|
key: string;
|
|
24
|
-
args?: GetWidgetParameters[
|
|
24
|
+
args?: GetWidgetParameters['args'];
|
|
25
25
|
}, "fetch_manifest::request", never, {
|
|
26
26
|
update: boolean | undefined;
|
|
27
27
|
}> & {
|
|
@@ -33,10 +33,10 @@ declare const createActions: () => {
|
|
|
33
33
|
/** Async action triplet for fetching the widget config from the API. */
|
|
34
34
|
fetchConfig: import("@equinor/fusion-observable").ActionCreatorWithPreparedPayload<[payload: {
|
|
35
35
|
key: string;
|
|
36
|
-
args?: GetWidgetParameters[
|
|
36
|
+
args?: GetWidgetParameters['args'];
|
|
37
37
|
}, update?: boolean | undefined], {
|
|
38
38
|
key: string;
|
|
39
|
-
args?: GetWidgetParameters[
|
|
39
|
+
args?: GetWidgetParameters['args'];
|
|
40
40
|
}, "fetch_config::request", never, {
|
|
41
41
|
update: boolean | undefined;
|
|
42
42
|
}> & {
|
|
@@ -68,10 +68,10 @@ export declare const actions: {
|
|
|
68
68
|
/** Async action triplet for fetching the widget manifest from the API. */
|
|
69
69
|
fetchManifest: import("@equinor/fusion-observable").ActionCreatorWithPreparedPayload<[payload: {
|
|
70
70
|
key: string;
|
|
71
|
-
args?: GetWidgetParameters[
|
|
71
|
+
args?: GetWidgetParameters['args'];
|
|
72
72
|
}, update?: boolean | undefined], {
|
|
73
73
|
key: string;
|
|
74
|
-
args?: GetWidgetParameters[
|
|
74
|
+
args?: GetWidgetParameters['args'];
|
|
75
75
|
}, "fetch_manifest::request", never, {
|
|
76
76
|
update: boolean | undefined;
|
|
77
77
|
}> & {
|
|
@@ -83,10 +83,10 @@ export declare const actions: {
|
|
|
83
83
|
/** Async action triplet for fetching the widget config from the API. */
|
|
84
84
|
fetchConfig: import("@equinor/fusion-observable").ActionCreatorWithPreparedPayload<[payload: {
|
|
85
85
|
key: string;
|
|
86
|
-
args?: GetWidgetParameters[
|
|
86
|
+
args?: GetWidgetParameters['args'];
|
|
87
87
|
}, update?: boolean | undefined], {
|
|
88
88
|
key: string;
|
|
89
|
-
args?: GetWidgetParameters[
|
|
89
|
+
args?: GetWidgetParameters['args'];
|
|
90
90
|
}, "fetch_config::request", never, {
|
|
91
91
|
update: boolean | undefined;
|
|
92
92
|
}> & {
|
|
@@ -9,57 +9,57 @@ import type { WidgetStateInitial, WidgetState } from '../types';
|
|
|
9
9
|
* automatically as an empty `Set`).
|
|
10
10
|
* @returns A reducer function compatible with `FlowSubject`.
|
|
11
11
|
*/
|
|
12
|
-
export declare const createReducer: (value: WidgetStateInitial) => import("@equinor/fusion-observable").ReducerWithInitialState<WidgetState,
|
|
13
|
-
created: number;
|
|
14
|
-
update: boolean | undefined;
|
|
15
|
-
}, never> | import("@equinor/fusion-observable").PayloadAction<{
|
|
16
|
-
key: string;
|
|
17
|
-
args?: import("..").GetWidgetParameters["args"];
|
|
18
|
-
}, "fetch_manifest::request", {
|
|
19
|
-
update: boolean | undefined;
|
|
20
|
-
}, never> | {
|
|
21
|
-
payload: import("..").WidgetConfig;
|
|
22
|
-
type: "set_config";
|
|
23
|
-
} | import("@equinor/fusion-observable").PayloadAction<{
|
|
24
|
-
key: string;
|
|
25
|
-
args?: import("..").GetWidgetParameters["args"];
|
|
26
|
-
}, "fetch_config::request", {
|
|
27
|
-
update: boolean | undefined;
|
|
28
|
-
}, never> | {
|
|
12
|
+
export declare const createReducer: (value: WidgetStateInitial) => import("@equinor/fusion-observable").ReducerWithInitialState<WidgetState, {
|
|
29
13
|
payload: any;
|
|
30
14
|
type: "set_module";
|
|
31
15
|
} | {
|
|
32
|
-
payload:
|
|
33
|
-
type: "
|
|
16
|
+
payload: unknown;
|
|
17
|
+
type: "fetch_config::failure";
|
|
34
18
|
} | {
|
|
35
|
-
payload:
|
|
36
|
-
type: "
|
|
19
|
+
payload: unknown;
|
|
20
|
+
type: "fetch_manifest::failure";
|
|
21
|
+
} | {
|
|
22
|
+
payload: unknown;
|
|
23
|
+
type: "import_widget::failure";
|
|
24
|
+
} | {
|
|
25
|
+
payload: unknown;
|
|
26
|
+
type: "initialize_widget::failure";
|
|
37
27
|
} | {
|
|
38
28
|
payload: null;
|
|
39
29
|
type: "initialize_widget::request";
|
|
40
30
|
} | {
|
|
41
|
-
payload:
|
|
42
|
-
type: "
|
|
31
|
+
payload: null;
|
|
32
|
+
type: "initialize_widget::success";
|
|
43
33
|
} | {
|
|
44
|
-
payload:
|
|
45
|
-
type: "
|
|
34
|
+
payload: string;
|
|
35
|
+
type: "import_widget::request";
|
|
46
36
|
} | {
|
|
47
37
|
payload: import("..").WidgetConfig;
|
|
48
38
|
type: "fetch_config::success";
|
|
49
39
|
} | {
|
|
50
|
-
payload:
|
|
51
|
-
type: "
|
|
40
|
+
payload: import("..").WidgetConfig;
|
|
41
|
+
type: "set_config";
|
|
42
|
+
} | {
|
|
43
|
+
payload: import("..").WidgetManifest;
|
|
44
|
+
type: "fetch_manifest::success";
|
|
52
45
|
} | {
|
|
53
46
|
payload: import("..").WidgetScriptModule;
|
|
54
47
|
type: "import_widget::success";
|
|
55
48
|
} | {
|
|
56
|
-
payload:
|
|
57
|
-
type: "
|
|
58
|
-
} | {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
} | {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
49
|
+
payload: import("..").WidgetModulesInstance;
|
|
50
|
+
type: "set_instance";
|
|
51
|
+
} | import("@equinor/fusion-observable").PayloadAction<import("..").WidgetManifest, "set_manifest", {
|
|
52
|
+
created: number;
|
|
53
|
+
update: boolean | undefined;
|
|
54
|
+
}, never> | import("@equinor/fusion-observable").PayloadAction<{
|
|
55
|
+
key: string;
|
|
56
|
+
args?: import("..").GetWidgetParameters['args'];
|
|
57
|
+
}, "fetch_manifest::request", {
|
|
58
|
+
update: boolean | undefined;
|
|
59
|
+
}, never> | import("@equinor/fusion-observable").PayloadAction<{
|
|
60
|
+
key: string;
|
|
61
|
+
args?: import("..").GetWidgetParameters['args'];
|
|
62
|
+
}, "fetch_config::request", {
|
|
63
|
+
update: boolean | undefined;
|
|
64
|
+
}, never>>;
|
|
65
65
|
export default createReducer;
|
package/dist/types/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "16.0.
|
|
1
|
+
export declare const version = "16.0.4";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@equinor/fusion-framework-module-widget",
|
|
3
|
-
"version": "16.0.
|
|
3
|
+
"version": "16.0.4",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/esm/index.js",
|
|
6
6
|
"types": "dist/types/index.d.ts",
|
|
@@ -38,22 +38,22 @@
|
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"immer": "^11.0.0",
|
|
40
40
|
"rxjs": "^7.8.1",
|
|
41
|
-
"@equinor/fusion-observable": "9.1.
|
|
42
|
-
"@equinor/fusion-query": "7.0.
|
|
41
|
+
"@equinor/fusion-observable": "9.1.1",
|
|
42
|
+
"@equinor/fusion-query": "7.0.3"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"typescript": "^
|
|
46
|
-
"@equinor/fusion-framework-module": "^
|
|
47
|
-
"@equinor/fusion-framework-module-
|
|
48
|
-
"@equinor/fusion-framework-module
|
|
49
|
-
"@equinor/fusion-framework-module-
|
|
50
|
-
"@equinor/fusion-query": "^7.0.
|
|
45
|
+
"typescript": "^7.0.2",
|
|
46
|
+
"@equinor/fusion-framework-module-http": "^8.0.5",
|
|
47
|
+
"@equinor/fusion-framework-module-event": "^6.0.1",
|
|
48
|
+
"@equinor/fusion-framework-module": "^6.1.1",
|
|
49
|
+
"@equinor/fusion-framework-module-service-discovery": "^10.0.2",
|
|
50
|
+
"@equinor/fusion-query": "^7.0.3"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
|
-
"@equinor/fusion-framework-module": "6.1.
|
|
54
|
-
"@equinor/fusion-framework-module-
|
|
55
|
-
"@equinor/fusion-framework-module-
|
|
56
|
-
"@equinor/fusion-framework-module-service-discovery": "10.0.
|
|
53
|
+
"@equinor/fusion-framework-module": "6.1.1",
|
|
54
|
+
"@equinor/fusion-framework-module-http": "8.0.5",
|
|
55
|
+
"@equinor/fusion-framework-module-event": "6.0.1",
|
|
56
|
+
"@equinor/fusion-framework-module-service-discovery": "10.0.2"
|
|
57
57
|
},
|
|
58
58
|
"peerDependenciesMeta": {
|
|
59
59
|
"@equinor/fusion-framework-module-event": {
|
package/src/Widget.ts
CHANGED
|
@@ -51,7 +51,11 @@ export class Widget {
|
|
|
51
51
|
|
|
52
52
|
#subscription = new Subscription();
|
|
53
53
|
|
|
54
|
-
/**
|
|
54
|
+
/**
|
|
55
|
+
* Current snapshot of the widget's internal state (manifest, config, modules, status).
|
|
56
|
+
*
|
|
57
|
+
* @returns The current {@link WidgetState}.
|
|
58
|
+
*/
|
|
55
59
|
get state(): WidgetState {
|
|
56
60
|
return this.#state.value;
|
|
57
61
|
}
|
|
@@ -165,8 +169,10 @@ export class Widget {
|
|
|
165
169
|
*/
|
|
166
170
|
public getManifest(force_refresh = false): Observable<WidgetManifest> {
|
|
167
171
|
return new Observable((subscriber) => {
|
|
172
|
+
// Emit the cached manifest immediately if one is already available
|
|
168
173
|
if (this.#state.value.manifest) {
|
|
169
174
|
subscriber.next(this.#state.value.manifest);
|
|
175
|
+
// Skip the fetch below unless the caller explicitly asked to refresh
|
|
170
176
|
if (!force_refresh) {
|
|
171
177
|
return subscriber.complete();
|
|
172
178
|
}
|
|
@@ -209,8 +215,10 @@ export class Widget {
|
|
|
209
215
|
public getConfig(force_refresh = false): Observable<WidgetConfig> {
|
|
210
216
|
return new Observable((subscriber) => {
|
|
211
217
|
const currentValue = this.#state.value;
|
|
218
|
+
// Emit the cached config immediately if the manifest and config are already available
|
|
212
219
|
if (currentValue.manifest && currentValue.config) {
|
|
213
220
|
subscriber.next(currentValue.config);
|
|
221
|
+
// Skip the fetch below unless the caller explicitly asked to refresh
|
|
214
222
|
if (!force_refresh) {
|
|
215
223
|
return subscriber.complete();
|
|
216
224
|
}
|
|
@@ -273,8 +281,10 @@ export class Widget {
|
|
|
273
281
|
*/
|
|
274
282
|
public getWidgetModule(force_refresh = false): Observable<WidgetScriptModule> {
|
|
275
283
|
return new Observable((subscriber) => {
|
|
284
|
+
// Emit the cached script module immediately if one is already available
|
|
276
285
|
if (this.#state.value.modules) {
|
|
277
286
|
subscriber.next(this.#state.value.modules);
|
|
287
|
+
// Skip the import below unless the caller explicitly asked to refresh
|
|
278
288
|
if (!force_refresh) {
|
|
279
289
|
return subscriber.complete();
|
|
280
290
|
}
|
|
@@ -345,7 +355,8 @@ export class Widget {
|
|
|
345
355
|
},
|
|
346
356
|
}),
|
|
347
357
|
error: (err) => {
|
|
348
|
-
observer.error(err)
|
|
358
|
+
observer.error(err);
|
|
359
|
+
this.#state.next(actions.initialize.failure(err));
|
|
349
360
|
},
|
|
350
361
|
complete: () => {
|
|
351
362
|
this.#state.next(actions.initialize.success());
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discriminator for categorizing widget HTTP errors.
|
|
3
|
+
*
|
|
4
|
+
* - `'not_found'` — HTTP 404
|
|
5
|
+
* - `'unauthorized'` — HTTP 401
|
|
6
|
+
* - `'unknown'` — any other error
|
|
7
|
+
*/
|
|
8
|
+
export type WidgetErrorType = 'not_found' | 'unauthorized' | 'unknown';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Error thrown when a widget manifest cannot be loaded from the backend API.
|
|
12
|
+
*
|
|
13
|
+
* Use the static {@link fromHttpResponse} factory to create instances from
|
|
14
|
+
* HTTP responses with appropriate type mapping.
|
|
15
|
+
*/
|
|
16
|
+
export class WidgetManifestLoadError extends Error {
|
|
17
|
+
/**
|
|
18
|
+
* Creates a `WidgetManifestLoadError` from an HTTP `Response`.
|
|
19
|
+
*
|
|
20
|
+
* Maps HTTP 401 to `'unauthorized'`, 404 to `'not_found'`, and all other
|
|
21
|
+
* status codes to `'unknown'`.
|
|
22
|
+
*
|
|
23
|
+
* @param response - The failing HTTP response.
|
|
24
|
+
* @param options - Standard `ErrorOptions` (e.g., `cause`).
|
|
25
|
+
* @returns A typed `WidgetManifestLoadError`.
|
|
26
|
+
*/
|
|
27
|
+
static fromHttpResponse(response: Response, options?: ErrorOptions) {
|
|
28
|
+
// Map known status codes to a specific error type, otherwise fall through to 'unknown'
|
|
29
|
+
switch (response.status) {
|
|
30
|
+
case 401:
|
|
31
|
+
return new WidgetManifestLoadError(
|
|
32
|
+
'unauthorized',
|
|
33
|
+
'failed to load widget manifest, request not authorized',
|
|
34
|
+
options,
|
|
35
|
+
);
|
|
36
|
+
case 404:
|
|
37
|
+
return new WidgetManifestLoadError('not_found', 'widget manifest not found', options);
|
|
38
|
+
}
|
|
39
|
+
return new WidgetManifestLoadError(
|
|
40
|
+
'unknown',
|
|
41
|
+
`failed to load widget manifest, status code ${response.status}`,
|
|
42
|
+
options,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* @param type - Error category discriminator.
|
|
47
|
+
* @param message - Human-readable error description.
|
|
48
|
+
* @param options - Standard `ErrorOptions` (e.g., `cause`).
|
|
49
|
+
*/
|
|
50
|
+
constructor(
|
|
51
|
+
public readonly type: WidgetErrorType,
|
|
52
|
+
message?: string,
|
|
53
|
+
options?: ErrorOptions,
|
|
54
|
+
) {
|
|
55
|
+
super(message, options);
|
|
56
|
+
this.name = 'GetWidgetLoadManifestErrors';
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { WidgetConfigLoadError } from './errors/WidgetConfigLoadError.js';
|
|
61
|
+
export { WidgetScriptModuleError } from './errors/WidgetScriptModuleError.js';
|
|
@@ -63,6 +63,7 @@ export class WidgetModuleConfigurator extends BaseConfigBuilder<WidgetModuleConf
|
|
|
63
63
|
private async _createHttpClient(clientId: string, init: ConfigBuilderCallbackArgs) {
|
|
64
64
|
const http = await init.requireInstance('http');
|
|
65
65
|
|
|
66
|
+
// Reuse an already-registered client when one exists for this id
|
|
66
67
|
if (http.hasClient(clientId)) {
|
|
67
68
|
return http.createClient(clientId);
|
|
68
69
|
} else {
|
|
@@ -86,6 +87,7 @@ export class WidgetModuleConfigurator extends BaseConfigBuilder<WidgetModuleConf
|
|
|
86
87
|
) {
|
|
87
88
|
const httpClient = await this._createHttpClient('apps', _init);
|
|
88
89
|
|
|
90
|
+
// Only fall back to the default client when the caller hasn't set one
|
|
89
91
|
if (!config.client) {
|
|
90
92
|
config.client = createDefaultClient(httpClient);
|
|
91
93
|
}
|
|
@@ -9,7 +9,7 @@ import { Query } from '@equinor/fusion-query';
|
|
|
9
9
|
import type { GetWidgetParameters, WidgetConfig, WidgetManifest } from './types';
|
|
10
10
|
|
|
11
11
|
import type { WidgetModuleConfig } from './WidgetModuleConfigurator';
|
|
12
|
-
import { WidgetManifestLoadError, WidgetConfigLoadError } from './
|
|
12
|
+
import { WidgetManifestLoadError, WidgetConfigLoadError } from './WidgetManifestLoadError';
|
|
13
13
|
import { Widget } from './Widget';
|
|
14
14
|
|
|
15
15
|
/**
|
|
@@ -143,6 +143,7 @@ export class WidgetModuleProvider implements IWidgetModuleProvider {
|
|
|
143
143
|
* @param widgetKey - Widget identifier.
|
|
144
144
|
* @param args - Optional version or tag selector.
|
|
145
145
|
* @returns Observable emitting the {@link WidgetConfig}.
|
|
146
|
+
* @throws {WidgetManifestLoadError} When the underlying query fails.
|
|
146
147
|
*/
|
|
147
148
|
protected _getWidgetConfig(
|
|
148
149
|
widgetKey: GetWidgetParameters['widgetKey'],
|
|
@@ -150,7 +151,9 @@ export class WidgetModuleProvider implements IWidgetModuleProvider {
|
|
|
150
151
|
): Observable<WidgetConfig> {
|
|
151
152
|
const client = new Query(this.#config.client.getWidgetConfig);
|
|
152
153
|
this.#subscription.add(() => client.complete());
|
|
154
|
+
// Execute the query and handle errors
|
|
153
155
|
return Query.extractQueryValue(
|
|
156
|
+
// Map any query failure to a typed `WidgetManifestLoadError`
|
|
154
157
|
client.query({ widgetKey, args }).pipe(
|
|
155
158
|
catchError((err) => {
|
|
156
159
|
// Extract the cause since the error will be a `QueryError`
|
|
@@ -160,6 +163,7 @@ export class WidgetModuleProvider implements IWidgetModuleProvider {
|
|
|
160
163
|
if (cause instanceof WidgetManifestLoadError) {
|
|
161
164
|
throw cause;
|
|
162
165
|
}
|
|
166
|
+
// Map HTTP failures to a `WidgetManifestLoadError` carrying the response
|
|
163
167
|
if (cause instanceof HttpResponseError) {
|
|
164
168
|
throw WidgetManifestLoadError.fromHttpResponse(cause.response, {
|
|
165
169
|
cause,
|
|
@@ -181,6 +185,7 @@ export class WidgetModuleProvider implements IWidgetModuleProvider {
|
|
|
181
185
|
* @param widgetKey - Widget identifier.
|
|
182
186
|
* @param args - Optional version or tag selector.
|
|
183
187
|
* @returns Observable emitting the {@link WidgetManifest}.
|
|
188
|
+
* @throws {WidgetConfigLoadError} When the underlying query fails.
|
|
184
189
|
*/
|
|
185
190
|
protected _getWidget(
|
|
186
191
|
widgetKey: GetWidgetParameters['widgetKey'],
|
|
@@ -192,6 +197,7 @@ export class WidgetModuleProvider implements IWidgetModuleProvider {
|
|
|
192
197
|
|
|
193
198
|
// Execute the query and handle errors
|
|
194
199
|
return Query.extractQueryValue(
|
|
200
|
+
// Map any query failure to a typed `WidgetConfigLoadError`
|
|
195
201
|
client.query({ widgetKey, args }).pipe(
|
|
196
202
|
catchError((err) => {
|
|
197
203
|
// Extract the cause since the error will be a `QueryError`
|
|
@@ -201,6 +207,7 @@ export class WidgetModuleProvider implements IWidgetModuleProvider {
|
|
|
201
207
|
if (cause instanceof WidgetConfigLoadError) {
|
|
202
208
|
throw cause;
|
|
203
209
|
}
|
|
210
|
+
// Map HTTP failures to a `WidgetConfigLoadError` carrying the response
|
|
204
211
|
if (cause instanceof HttpResponseError) {
|
|
205
212
|
throw WidgetConfigLoadError.fromHttpResponse(cause.response, { cause });
|
|
206
213
|
}
|
|
@@ -22,7 +22,7 @@ import type { WidgetModuleConfigBuilderCallback } from './WidgetModuleConfigurat
|
|
|
22
22
|
* ```
|
|
23
23
|
*/
|
|
24
24
|
export const enableWidgetModule = (
|
|
25
|
-
//
|
|
25
|
+
// biome-ignore lint/suspicious/noExplicitAny: `IModulesConfigurator<any, any>` widens to accept a configurator for any concrete module set — `unknown` would break assignability of a real configurator instance to this parameter
|
|
26
26
|
configurator: IModulesConfigurator<any, any>,
|
|
27
27
|
builder?: WidgetModuleConfigBuilderCallback,
|
|
28
28
|
): void => {
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { WidgetErrorType } from '../WidgetManifestLoadError.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Error thrown when a widget configuration cannot be loaded from the backend API.
|
|
5
|
+
*
|
|
6
|
+
* Use the static {@link fromHttpResponse} factory to create instances from
|
|
7
|
+
* HTTP responses with appropriate type mapping.
|
|
8
|
+
*/
|
|
9
|
+
export class WidgetConfigLoadError extends Error {
|
|
10
|
+
/**
|
|
11
|
+
* Creates a `WidgetConfigLoadError` from an HTTP `Response`.
|
|
12
|
+
*
|
|
13
|
+
* Maps HTTP 401 to `'unauthorized'`, 404 to `'not_found'`, and all other
|
|
14
|
+
* status codes to `'unknown'`.
|
|
15
|
+
*
|
|
16
|
+
* @param response - The failing HTTP response.
|
|
17
|
+
* @param options - Standard `ErrorOptions` (e.g., `cause`).
|
|
18
|
+
* @returns A typed `WidgetConfigLoadError`.
|
|
19
|
+
*/
|
|
20
|
+
static fromHttpResponse(response: Response, options?: ErrorOptions) {
|
|
21
|
+
// Map known status codes to a specific error type, otherwise fall through to 'unknown'
|
|
22
|
+
switch (response.status) {
|
|
23
|
+
case 401:
|
|
24
|
+
return new WidgetConfigLoadError(
|
|
25
|
+
'unauthorized',
|
|
26
|
+
'failed to load widget config, request not authorized',
|
|
27
|
+
options,
|
|
28
|
+
);
|
|
29
|
+
case 404:
|
|
30
|
+
return new WidgetConfigLoadError('not_found', 'widget config not found', options);
|
|
31
|
+
}
|
|
32
|
+
return new WidgetConfigLoadError(
|
|
33
|
+
'unknown',
|
|
34
|
+
`failed to load widget config, status code ${response.status}`,
|
|
35
|
+
options,
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* @param type - Error category discriminator.
|
|
40
|
+
* @param message - Human-readable error description.
|
|
41
|
+
* @param options - Standard `ErrorOptions` (e.g., `cause`).
|
|
42
|
+
*/
|
|
43
|
+
constructor(
|
|
44
|
+
public readonly type: WidgetErrorType,
|
|
45
|
+
message?: string,
|
|
46
|
+
options?: ErrorOptions,
|
|
47
|
+
) {
|
|
48
|
+
super(message, options);
|
|
49
|
+
this.name = 'GetWidgetLoadConfigError';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { WidgetErrorType } from '../WidgetManifestLoadError.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Error thrown when a widget script module cannot be dynamically imported.
|
|
5
|
+
*/
|
|
6
|
+
export class WidgetScriptModuleError extends Error {
|
|
7
|
+
/**
|
|
8
|
+
* @param type - Error category discriminator.
|
|
9
|
+
* @param message - Human-readable error description.
|
|
10
|
+
* @param options - Standard `ErrorOptions` (e.g., `cause`).
|
|
11
|
+
*/
|
|
12
|
+
constructor(
|
|
13
|
+
public readonly type: WidgetErrorType,
|
|
14
|
+
message?: string,
|
|
15
|
+
options?: ErrorOptions,
|
|
16
|
+
) {
|
|
17
|
+
super(message, options);
|
|
18
|
+
this.name = 'WidgetScriptModuleError';
|
|
19
|
+
}
|
|
20
|
+
}
|
package/src/module.ts
CHANGED
|
@@ -42,6 +42,8 @@ export const module: WidgetModule = {
|
|
|
42
42
|
return new WidgetModuleProvider({ config, event });
|
|
43
43
|
},
|
|
44
44
|
dispose: (args) => {
|
|
45
|
+
// `args.instance` is typed as the generic module instance, but the module descriptor
|
|
46
|
+
// guarantees it was created as a `WidgetModuleProvider` — safe to cast for disposal.
|
|
45
47
|
(args.instance as unknown as WidgetModuleProvider).dispose();
|
|
46
48
|
},
|
|
47
49
|
};
|
package/src/state/actions.ts
CHANGED
|
@@ -53,7 +53,7 @@ const createActions = () => ({
|
|
|
53
53
|
(error: unknown) => ({ payload: error }),
|
|
54
54
|
),
|
|
55
55
|
/** Sets the dynamically imported widget script module in state. */
|
|
56
|
-
//
|
|
56
|
+
// biome-ignore lint/suspicious/noExplicitAny: module payload widens to accept any script module shape when set
|
|
57
57
|
setModule: createAction('set_module', (module: any) => ({ payload: module })),
|
|
58
58
|
/** Async action triplet for dynamically importing the widget script. */
|
|
59
59
|
importWidget: createAsyncAction(
|
|
@@ -23,10 +23,13 @@ import type { WidgetStateInitial, WidgetState } from '../types';
|
|
|
23
23
|
* @returns A reducer function compatible with `FlowSubject`.
|
|
24
24
|
*/
|
|
25
25
|
export const createReducer = (value: WidgetStateInitial) =>
|
|
26
|
+
// Seed the reducer's initial state with an empty in-progress status set.
|
|
26
27
|
makeReducer<WidgetState, Actions>({ ...value, status: new Set() } as WidgetState, (builder) =>
|
|
27
28
|
builder
|
|
28
29
|
.addCase(actions.setManifest, (state, action) => {
|
|
30
|
+
// Merge with existing state when caller requested an update, otherwise replace
|
|
29
31
|
if (action.meta.update) {
|
|
32
|
+
// Shallow-merge the new payload over the existing manifest fields.
|
|
30
33
|
state.manifest = { ...state.manifest, ...action.payload };
|
|
31
34
|
} else {
|
|
32
35
|
state.manifest = action.payload;
|