@equinor/fusion-framework-module-app 7.4.2-next.0 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -6
- package/README.md +118 -11
- package/dist/esm/AppClient.js +16 -3
- package/dist/esm/AppClient.js.map +1 -1
- package/dist/esm/AppConfig.js +7 -1
- package/dist/esm/AppConfig.js.map +1 -1
- package/dist/esm/AppConfigurator.js +7 -0
- package/dist/esm/AppConfigurator.js.map +1 -1
- package/dist/esm/AppModuleProvider.js +80 -17
- package/dist/esm/AppModuleProvider.js.map +1 -1
- package/dist/esm/app/App.js +17 -1
- package/dist/esm/app/App.js.map +1 -1
- package/dist/esm/app/actions.js +13 -0
- package/dist/esm/app/actions.js.map +1 -1
- package/dist/esm/app/create-reducer.js +9 -0
- package/dist/esm/app/create-reducer.js.map +1 -1
- package/dist/esm/app/create-state.js +11 -0
- package/dist/esm/app/create-state.js.map +1 -1
- package/dist/esm/app/flows.js +3 -2
- package/dist/esm/app/flows.js.map +1 -1
- package/dist/esm/app/index.js +7 -0
- package/dist/esm/app/index.js.map +1 -1
- package/dist/esm/enable-app-module.js +19 -2
- package/dist/esm/enable-app-module.js.map +1 -1
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/index.js +18 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/module.js +1 -0
- package/dist/esm/module.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esm/version.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/AppClient.d.ts +52 -10
- package/dist/types/AppConfig.d.ts +8 -0
- package/dist/types/AppConfigurator.d.ts +32 -0
- package/dist/types/AppModuleProvider.d.ts +80 -17
- package/dist/types/app/App.d.ts +28 -3
- package/dist/types/app/actions.d.ts +16 -0
- package/dist/types/app/create-reducer.d.ts +9 -0
- package/dist/types/app/create-state.d.ts +11 -0
- package/dist/types/app/events.d.ts +17 -1
- package/dist/types/app/index.d.ts +7 -0
- package/dist/types/enable-app-module.d.ts +19 -2
- package/dist/types/errors.d.ts +8 -0
- package/dist/types/index.d.ts +18 -0
- package/dist/types/module.d.ts +6 -0
- package/dist/types/types.d.ts +78 -3
- package/dist/types/version.d.ts +1 -1
- package/package.json +10 -10
- package/src/AppClient.ts +54 -11
- package/src/AppConfig.ts +15 -1
- package/src/AppConfigurator.ts +33 -1
- package/src/AppModuleProvider.ts +80 -17
- package/src/app/App.ts +29 -4
- package/src/app/actions.ts +16 -0
- package/src/app/create-reducer.ts +9 -0
- package/src/app/create-state.ts +11 -0
- package/src/app/events.ts +17 -1
- package/src/app/flows.ts +6 -2
- package/src/app/index.ts +7 -0
- package/src/enable-app-module.ts +19 -2
- package/src/errors.ts +8 -0
- package/src/index.ts +19 -0
- package/src/module.ts +6 -0
- package/src/types.ts +78 -5
- package/src/version.ts +1 -1
package/dist/types/types.d.ts
CHANGED
|
@@ -5,9 +5,19 @@ import type { MsalModule } from '@equinor/fusion-framework-module-msal';
|
|
|
5
5
|
import type { ServiceDiscoveryModule } from '@equinor/fusion-framework-module-service-discovery';
|
|
6
6
|
import type { AppConfig } from './AppConfig';
|
|
7
7
|
import type IApp from './app';
|
|
8
|
+
/**
|
|
9
|
+
* Re-export of {@link ConfigEnvironment} from AppConfig.
|
|
10
|
+
*/
|
|
8
11
|
export type ConfigEnvironment = Record<string, unknown>;
|
|
9
12
|
export type { AppConfig } from './AppConfig';
|
|
10
13
|
type Fusion = any;
|
|
14
|
+
/**
|
|
15
|
+
* Environment bindings passed to an application at render time,
|
|
16
|
+
* including its manifest, configuration, base path, and custom props.
|
|
17
|
+
*
|
|
18
|
+
* @template TEnv - Shape of the environment configuration record.
|
|
19
|
+
* @template TProps - Shape of custom properties passed to the app.
|
|
20
|
+
*/
|
|
11
21
|
export type AppEnv<TEnv extends ConfigEnvironment = ConfigEnvironment, TProps = unknown> = {
|
|
12
22
|
basename?: string;
|
|
13
23
|
manifest?: AppManifest;
|
|
@@ -15,19 +25,48 @@ export type AppEnv<TEnv extends ConfigEnvironment = ConfigEnvironment, TProps =
|
|
|
15
25
|
props?: TProps;
|
|
16
26
|
};
|
|
17
27
|
/**
|
|
18
|
-
* Reference to an
|
|
28
|
+
* Reference to an application, used to fetch the app manifest from the app service.
|
|
29
|
+
* The `tag` defaults to `'latest'` when omitted.
|
|
19
30
|
*/
|
|
20
31
|
export type AppReference = {
|
|
21
32
|
appKey: string;
|
|
22
33
|
tag?: string;
|
|
23
34
|
};
|
|
35
|
+
/**
|
|
36
|
+
* Required module dependencies for the app module.
|
|
37
|
+
*
|
|
38
|
+
* The app module depends on HTTP (for API calls), service discovery
|
|
39
|
+
* (for resolving the apps service URL), and events (for lifecycle notifications).
|
|
40
|
+
*/
|
|
24
41
|
export type ModuleDeps = [HttpModule, ServiceDiscoveryModule, EventModule];
|
|
42
|
+
/**
|
|
43
|
+
* Per-user application settings, stored as an arbitrary key-value record.
|
|
44
|
+
* Read via `getAppSettings` and written via `updateAppSettings` on the provider.
|
|
45
|
+
*/
|
|
25
46
|
export interface AppSettings {
|
|
26
47
|
[key: string]: unknown;
|
|
27
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Discriminant union of supported application types.
|
|
51
|
+
*
|
|
52
|
+
* - `'standalone'` – A full standalone application.
|
|
53
|
+
* - `'template'` / `'template-app'` – Template-based apps.
|
|
54
|
+
* - `'landing-page'` – Portal landing pages.
|
|
55
|
+
* - `'report'` / `'launcher'` – Legacy types (will be removed).
|
|
56
|
+
*/
|
|
28
57
|
export type AppType = 'standalone' | 'report' | 'launcher' | 'template' | 'template-app' | 'landing-page';
|
|
58
|
+
/**
|
|
59
|
+
* The currently active application, or `null` when cleared, or `undefined`
|
|
60
|
+
* when no application has been set yet.
|
|
61
|
+
*
|
|
62
|
+
* @template TModules - Additional framework modules the app depends on.
|
|
63
|
+
* @template TEnv - Shape of the environment configuration record.
|
|
64
|
+
*/
|
|
29
65
|
export type CurrentApp<TModules extends Array<AnyModule> = [], TEnv extends ConfigEnvironment = ConfigEnvironment> = IApp<TEnv, TModules> | null | undefined;
|
|
30
66
|
type Nullable<T> = T | null | undefined;
|
|
67
|
+
/**
|
|
68
|
+
* Represents a person associated with an application (admin or owner).
|
|
69
|
+
*/
|
|
31
70
|
type AppPerson = {
|
|
32
71
|
id: string;
|
|
33
72
|
azureUniqueId: string;
|
|
@@ -38,7 +77,9 @@ type AppPerson = {
|
|
|
38
77
|
accountClassification?: Nullable<string>;
|
|
39
78
|
isExpired?: Nullable<boolean>;
|
|
40
79
|
};
|
|
80
|
+
/** An application administrator. */
|
|
41
81
|
export type AppAdmin = AppPerson;
|
|
82
|
+
/** An application owner. */
|
|
42
83
|
export type AppOwner = AppPerson;
|
|
43
84
|
/**
|
|
44
85
|
* Schema entry format for route documentation in app manifests.
|
|
@@ -52,6 +93,10 @@ export type RouteSchemaEntry = [
|
|
|
52
93
|
search?: Record<string, string>;
|
|
53
94
|
}
|
|
54
95
|
];
|
|
96
|
+
/**
|
|
97
|
+
* Build metadata returned by the app service for a specific application version.
|
|
98
|
+
* Contains the script entry point, asset path, tags, and optional CI metadata.
|
|
99
|
+
*/
|
|
55
100
|
export type AppBuildManifest = {
|
|
56
101
|
version: string;
|
|
57
102
|
entryPoint: string;
|
|
@@ -67,6 +112,10 @@ export type AppBuildManifest = {
|
|
|
67
112
|
allowedExtensions?: Nullable<string[]>;
|
|
68
113
|
uploadedBy?: Nullable<AppOwner>;
|
|
69
114
|
};
|
|
115
|
+
/**
|
|
116
|
+
* Full manifest describing a registered Fusion application, including
|
|
117
|
+
* display metadata, category, admins/owners, build info, and optional route schemas.
|
|
118
|
+
*/
|
|
70
119
|
export interface AppManifest {
|
|
71
120
|
/** @deprecated will be removed, use appKey */
|
|
72
121
|
key?: string;
|
|
@@ -99,25 +148,51 @@ export interface AppManifest {
|
|
|
99
148
|
routes?: Nullable<RouteSchemaEntry[]>;
|
|
100
149
|
}
|
|
101
150
|
/**
|
|
102
|
-
*
|
|
103
|
-
*
|
|
151
|
+
* A loaded application bundle containing its manifest, config, and imported script module.
|
|
152
|
+
*
|
|
153
|
+
* @template TEnvironment - Shape of the environment config record.
|
|
154
|
+
* @template TModule - Type of the dynamically imported ES module.
|
|
104
155
|
*/
|
|
105
156
|
export type AppBundle<TEnvironment extends ConfigEnvironment = ConfigEnvironment, TModule = unknown> = {
|
|
106
157
|
manifest: AppManifest;
|
|
107
158
|
config: AppConfig<TEnvironment>;
|
|
108
159
|
module: TModule;
|
|
109
160
|
};
|
|
161
|
+
/**
|
|
162
|
+
* Combined module type merging the app's own modules with base framework modules
|
|
163
|
+
* (Event, HTTP, MSAL).
|
|
164
|
+
*
|
|
165
|
+
* @template TModules - Additional modules contributed by the application.
|
|
166
|
+
*/
|
|
110
167
|
export type AppModules<TModules extends Array<AnyModule> | unknown = unknown> = CombinedModules<TModules, [
|
|
111
168
|
EventModule,
|
|
112
169
|
HttpModule,
|
|
113
170
|
MsalModule
|
|
114
171
|
]>;
|
|
172
|
+
/**
|
|
173
|
+
* Arguments passed to an application's `renderApp` or default export function
|
|
174
|
+
* when mounting the application into a DOM element.
|
|
175
|
+
*
|
|
176
|
+
* @template TFusion - Type of the Fusion framework instance.
|
|
177
|
+
* @template TEnv - Type of the environment bindings.
|
|
178
|
+
*/
|
|
115
179
|
export type ComponentRenderArgs<TFusion extends Fusion = Fusion, TEnv = AppEnv> = {
|
|
116
180
|
fusion: TFusion;
|
|
117
181
|
env: TEnv;
|
|
118
182
|
};
|
|
183
|
+
/**
|
|
184
|
+
* Shape of the ES module exported by an application's script bundle.
|
|
185
|
+
*
|
|
186
|
+
* Must expose either a `default` export or a `renderApp` function (or both)
|
|
187
|
+
* that mounts the application into a host DOM element.
|
|
188
|
+
*/
|
|
119
189
|
export type AppScriptModule = {
|
|
120
190
|
default: (el: HTMLElement, args: ComponentRenderArgs) => VoidFunction;
|
|
121
191
|
renderApp: (el: HTMLElement, args: ComponentRenderArgs) => VoidFunction;
|
|
122
192
|
};
|
|
193
|
+
/**
|
|
194
|
+
* Instantiated module collection for a running application.
|
|
195
|
+
*
|
|
196
|
+
* @template TModules - Additional modules contributed by the application.
|
|
197
|
+
*/
|
|
123
198
|
export type AppModulesInstance<TModules extends Array<AnyModule> | unknown = unknown> = ModulesInstance<AppModules<TModules>>;
|
package/dist/types/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "
|
|
1
|
+
export declare const version = "8.0.0";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@equinor/fusion-framework-module-app",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/esm/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -60,17 +60,17 @@
|
|
|
60
60
|
"immer": "^11.0.0",
|
|
61
61
|
"rxjs": "^7.8.1",
|
|
62
62
|
"uuid": "^13.0.0",
|
|
63
|
-
"zod": "^4.
|
|
64
|
-
"@equinor/fusion-observable": "^
|
|
65
|
-
"@equinor/fusion-query": "^
|
|
63
|
+
"zod": "^4.3.6",
|
|
64
|
+
"@equinor/fusion-observable": "^9.0.0",
|
|
65
|
+
"@equinor/fusion-query": "^7.0.0"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
|
-
"typescript": "^5.
|
|
69
|
-
"@equinor/fusion-framework-module": "^
|
|
70
|
-
"@equinor/fusion-framework-module-
|
|
71
|
-
"@equinor/fusion-framework-module-
|
|
72
|
-
"@equinor/fusion-framework-module-
|
|
73
|
-
"@equinor/fusion-framework-module-
|
|
68
|
+
"typescript": "^5.9.3",
|
|
69
|
+
"@equinor/fusion-framework-module": "^6.0.0",
|
|
70
|
+
"@equinor/fusion-framework-module-http": "^8.0.0",
|
|
71
|
+
"@equinor/fusion-framework-module-event": "^6.0.0",
|
|
72
|
+
"@equinor/fusion-framework-module-service-discovery": "^10.0.0",
|
|
73
|
+
"@equinor/fusion-framework-module-msal": "^8.0.0"
|
|
74
74
|
},
|
|
75
75
|
"scripts": {
|
|
76
76
|
"build": "tsc -b"
|
package/src/AppClient.ts
CHANGED
|
@@ -22,24 +22,48 @@ import type {
|
|
|
22
22
|
import { AppBuildError, AppConfigError, AppManifestError, AppSettingsError } from './errors';
|
|
23
23
|
import { AppConfigSelector } from './AppClient.Selectors';
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Contract for an app service client that fetches application manifests,
|
|
27
|
+
* build metadata, configurations, and per-user settings from the Fusion apps API.
|
|
28
|
+
*
|
|
29
|
+
* All methods return `ObservableInput` so consumers can use either `Observable`
|
|
30
|
+
* or `Promise`-based consumption patterns.
|
|
31
|
+
*/
|
|
25
32
|
export interface IAppClient extends Disposable {
|
|
26
33
|
/**
|
|
27
|
-
*
|
|
34
|
+
* Fetches the manifest for a single application.
|
|
35
|
+
*
|
|
36
|
+
* @param args - Object containing the `appKey` and an optional version `tag`.
|
|
37
|
+
* @returns An observable that emits the resolved {@link AppManifest}.
|
|
38
|
+
* @throws {AppManifestError} When the manifest cannot be loaded (404, 401, 410, or unknown).
|
|
28
39
|
*/
|
|
29
40
|
getAppManifest: (args: { appKey: string; tag?: string }) => ObservableInput<AppManifest>;
|
|
30
41
|
|
|
31
42
|
/**
|
|
32
|
-
*
|
|
43
|
+
* Fetches the build metadata (entry point, version, asset path) for an application.
|
|
44
|
+
*
|
|
45
|
+
* @param args - Object containing the `appKey` and an optional version `tag`.
|
|
46
|
+
* @returns An observable that emits the resolved {@link AppBuildManifest}.
|
|
47
|
+
* @throws {AppBuildError} When the build metadata cannot be loaded.
|
|
33
48
|
*/
|
|
34
49
|
getAppBuild: (args: { appKey: string; tag?: string }) => ObservableInput<AppBuildManifest>;
|
|
35
50
|
|
|
36
51
|
/**
|
|
37
|
-
*
|
|
52
|
+
* Fetches manifests for all registered applications.
|
|
53
|
+
*
|
|
54
|
+
* @param args - Optional filter; set `filterByCurrentUser` to `true` to return
|
|
55
|
+
* only apps the authenticated user has access to.
|
|
56
|
+
* @returns An observable that emits an array of {@link AppManifest} objects.
|
|
38
57
|
*/
|
|
39
58
|
getAppManifests: (args?: { filterByCurrentUser?: boolean }) => ObservableInput<AppManifest[]>;
|
|
40
59
|
|
|
41
60
|
/**
|
|
42
|
-
*
|
|
61
|
+
* Fetches the runtime configuration (environment variables and endpoints) for an application.
|
|
62
|
+
*
|
|
63
|
+
* @template TType - Shape of the `environment` record in the returned config.
|
|
64
|
+
* @param args - Object containing the `appKey` and an optional version `tag`.
|
|
65
|
+
* @returns An observable that emits the resolved {@link AppConfig}.
|
|
66
|
+
* @throws {AppConfigError} When the configuration cannot be loaded.
|
|
43
67
|
*/
|
|
44
68
|
getAppConfig: <TType extends ConfigEnvironment = ConfigEnvironment>(args: {
|
|
45
69
|
appKey: string;
|
|
@@ -47,14 +71,20 @@ export interface IAppClient extends Disposable {
|
|
|
47
71
|
}) => ObservableInput<AppConfig<TType>>;
|
|
48
72
|
|
|
49
73
|
/**
|
|
50
|
-
*
|
|
74
|
+
* Fetches per-user settings for an application.
|
|
75
|
+
*
|
|
76
|
+
* @param args - Object containing the `appKey`.
|
|
77
|
+
* @returns An observable that emits the {@link AppSettings} record.
|
|
78
|
+
* @throws {AppSettingsError} When settings cannot be loaded.
|
|
51
79
|
*/
|
|
52
80
|
getAppSettings: (args: { appKey: string }) => ObservableInput<AppSettings>;
|
|
53
81
|
|
|
54
82
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* @
|
|
83
|
+
* Persists updated per-user settings for an application via PUT.
|
|
84
|
+
*
|
|
85
|
+
* @param args - Object containing the `appKey` and the `settings` payload to save.
|
|
86
|
+
* @returns An observable that emits the persisted {@link AppSettings}.
|
|
87
|
+
* @throws {AppSettingsError} When the update request fails.
|
|
58
88
|
*/
|
|
59
89
|
updateAppSettings: (args: {
|
|
60
90
|
appKey: string;
|
|
@@ -63,7 +93,8 @@ export interface IAppClient extends Disposable {
|
|
|
63
93
|
}
|
|
64
94
|
|
|
65
95
|
/**
|
|
66
|
-
* Transforms
|
|
96
|
+
* Transforms a raw API application response into an {@link AppManifest},
|
|
97
|
+
* adding backwards-compatible `key` and `name` getters.
|
|
67
98
|
*
|
|
68
99
|
* @returns An object conforming to the AppManifest interface.
|
|
69
100
|
*/
|
|
@@ -85,8 +116,20 @@ const ApplicationSchema = ApiApplicationSchema.transform((x): AppManifest => {
|
|
|
85
116
|
});
|
|
86
117
|
|
|
87
118
|
/**
|
|
88
|
-
*
|
|
89
|
-
*
|
|
119
|
+
* Default implementation of {@link IAppClient} that communicates with the
|
|
120
|
+
* Fusion app service API over HTTP.
|
|
121
|
+
*
|
|
122
|
+
* Uses {@link Query} internally for request deduplication and caching
|
|
123
|
+
* (1-minute expiry by default). Responses are validated against Zod schemas
|
|
124
|
+
* ({@link ApiApplicationSchema}, {@link ApiApplicationBuildSchema}) and
|
|
125
|
+
* HTTP errors are mapped to typed error classes.
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```ts
|
|
129
|
+
* const httpClient = await http.createClient('apps');
|
|
130
|
+
* const appClient = new AppClient(httpClient);
|
|
131
|
+
* appClient.getAppManifest({ appKey: 'my-app' }).subscribe(console.log);
|
|
132
|
+
* ```
|
|
90
133
|
*/
|
|
91
134
|
export class AppClient implements IAppClient {
|
|
92
135
|
#manifest: Query<AppManifest, { appKey: string }>;
|
package/src/AppConfig.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Recursively freezes an object and all of its nested properties.
|
|
3
|
+
*
|
|
4
|
+
* @template T - Object type being frozen.
|
|
5
|
+
* @param obj - The object to deep-freeze.
|
|
6
|
+
* @returns The same object, deeply frozen.
|
|
7
|
+
*/
|
|
2
8
|
const deepFreeze = <T extends Record<string, unknown>>(obj: T): T => {
|
|
3
9
|
for (const property of Object.keys(obj)) {
|
|
4
10
|
if (
|
|
@@ -12,8 +18,16 @@ const deepFreeze = <T extends Record<string, unknown>>(obj: T): T => {
|
|
|
12
18
|
return Object.freeze(obj);
|
|
13
19
|
};
|
|
14
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Arbitrary key-value record representing environment-specific variables
|
|
23
|
+
* injected into an application's runtime configuration.
|
|
24
|
+
*/
|
|
15
25
|
export type ConfigEnvironment = Record<string, unknown>;
|
|
16
26
|
|
|
27
|
+
/**
|
|
28
|
+
* A named endpoint from the application configuration, containing a URL
|
|
29
|
+
* and the OAuth scopes required to call it.
|
|
30
|
+
*/
|
|
17
31
|
export type ConfigEndPoint = {
|
|
18
32
|
url: string;
|
|
19
33
|
scopes: string[];
|
package/src/AppConfigurator.ts
CHANGED
|
@@ -10,21 +10,53 @@ import { moduleKey } from './module';
|
|
|
10
10
|
|
|
11
11
|
import AppClient, { type IAppClient } from './AppClient';
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Resolved configuration for the app module.
|
|
15
|
+
*
|
|
16
|
+
* Produced by {@link AppConfigurator} during module initialization and consumed
|
|
17
|
+
* by {@link AppModuleProvider} at runtime.
|
|
18
|
+
*/
|
|
13
19
|
export interface AppModuleConfig {
|
|
20
|
+
/** HTTP client used to communicate with the Fusion app service API. */
|
|
14
21
|
client: IAppClient;
|
|
15
|
-
|
|
22
|
+
/** Base URI for fetching application script bundles (e.g., `'/apps-proxy'`). */
|
|
16
23
|
assetUri?: string;
|
|
17
24
|
}
|
|
18
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Public interface for configuring the app module before initialization.
|
|
28
|
+
*
|
|
29
|
+
* Consumers use this interface (via the callback in {@link enableAppModule}) to
|
|
30
|
+
* override the default HTTP client or asset URI.
|
|
31
|
+
*/
|
|
19
32
|
export interface IAppConfigurator {
|
|
33
|
+
/**
|
|
34
|
+
* Sets the app service client used to fetch manifests, configs, and settings.
|
|
35
|
+
*
|
|
36
|
+
* @param client_or_cb - A promise resolving to an {@link IAppClient}, or a callback
|
|
37
|
+
* that receives module initializer args and returns one.
|
|
38
|
+
*/
|
|
20
39
|
setClient: (
|
|
21
40
|
client_or_cb:
|
|
22
41
|
| Promise<AppModuleConfig['client']>
|
|
23
42
|
| ConfigBuilderCallback<AppModuleConfig['client']>,
|
|
24
43
|
) => void;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Sets the base URI used to proxy-load application script bundles.
|
|
47
|
+
*
|
|
48
|
+
* @param base_or_cb - A static URI string or a callback returning one.
|
|
49
|
+
*/
|
|
25
50
|
setAssetUri: (base_or_cb: string | ConfigBuilderCallback<string>) => void;
|
|
26
51
|
}
|
|
27
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Configuration builder for the app module.
|
|
55
|
+
*
|
|
56
|
+
* Extends {@link BaseConfigBuilder} to assemble an {@link AppModuleConfig} during
|
|
57
|
+
* framework initialization. If no explicit client is set, a default one is created
|
|
58
|
+
* via service discovery. The default `assetUri` is `'/apps-proxy'`.
|
|
59
|
+
*/
|
|
28
60
|
export class AppConfigurator
|
|
29
61
|
extends BaseConfigBuilder<AppModuleConfig>
|
|
30
62
|
implements IAppConfigurator
|
package/src/AppModuleProvider.ts
CHANGED
|
@@ -28,7 +28,27 @@ import type { IAppClient } from './AppClient';
|
|
|
28
28
|
import { SemanticVersion } from '@equinor/fusion-framework-module';
|
|
29
29
|
import { version } from './version';
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Runtime provider for the app module.
|
|
33
|
+
*
|
|
34
|
+
* Exposes methods for fetching application manifests, configurations, and user
|
|
35
|
+
* settings, and for setting or clearing the current active application. When an
|
|
36
|
+
* {@link EventModule} is available, lifecycle events are dispatched as the
|
|
37
|
+
* current app changes.
|
|
38
|
+
*
|
|
39
|
+
* @remarks
|
|
40
|
+
* Only one application can be active (`current`) at a time. Setting a new current
|
|
41
|
+
* app automatically disposes the previous one. Subscribe to {@link current$} for
|
|
42
|
+
* reactive updates.
|
|
43
|
+
*/
|
|
31
44
|
export class AppModuleProvider {
|
|
45
|
+
/**
|
|
46
|
+
* Shallow-compares two app manifests by JSON serialization.
|
|
47
|
+
*
|
|
48
|
+
* @param a - First manifest to compare.
|
|
49
|
+
* @param b - Second manifest to compare.
|
|
50
|
+
* @returns `true` if the serialized manifests are identical.
|
|
51
|
+
*/
|
|
32
52
|
static compareAppManifest<T extends AppManifest>(a?: T, b?: T): boolean {
|
|
33
53
|
return JSON.stringify(a) === JSON.stringify(b);
|
|
34
54
|
}
|
|
@@ -51,16 +71,22 @@ export class AppModuleProvider {
|
|
|
51
71
|
}
|
|
52
72
|
|
|
53
73
|
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* - null
|
|
58
|
-
* -
|
|
74
|
+
* The current active application instance.
|
|
75
|
+
*
|
|
76
|
+
* - `undefined` – no application has been set yet.
|
|
77
|
+
* - `null` – the current application was explicitly cleared.
|
|
78
|
+
* - `App` – an active application instance.
|
|
59
79
|
*/
|
|
60
80
|
get current(): CurrentApp | null | undefined {
|
|
61
81
|
return this.#current$.value;
|
|
62
82
|
}
|
|
63
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Observable that emits when the current application changes.
|
|
86
|
+
*
|
|
87
|
+
* Emits are deduplicated by `appKey`; re-setting the same app does not trigger
|
|
88
|
+
* a new emission.
|
|
89
|
+
*/
|
|
64
90
|
get current$(): Observable<CurrentApp | null> {
|
|
65
91
|
return this.#current$.pipe(
|
|
66
92
|
distinctUntilChanged((prev, next) => {
|
|
@@ -72,6 +98,12 @@ export class AppModuleProvider {
|
|
|
72
98
|
);
|
|
73
99
|
}
|
|
74
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Creates the app module provider.
|
|
103
|
+
*
|
|
104
|
+
* @param args - Object containing the resolved {@link AppModuleConfig} and an
|
|
105
|
+
* optional {@link EventModule} instance for dispatching lifecycle events.
|
|
106
|
+
*/
|
|
75
107
|
constructor(args: { config: AppModuleConfig; event?: ModuleType<EventModule> }) {
|
|
76
108
|
const { event, config } = args;
|
|
77
109
|
|
|
@@ -108,14 +140,23 @@ export class AppModuleProvider {
|
|
|
108
140
|
}
|
|
109
141
|
|
|
110
142
|
/**
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
* @param
|
|
143
|
+
* Fetches the manifest for a single application by key.
|
|
144
|
+
*
|
|
145
|
+
* @param appKey - Unique application identifier.
|
|
146
|
+
* @param tag - Optional version tag (defaults to latest).
|
|
147
|
+
* @returns An observable that emits the resolved {@link AppManifest}.
|
|
114
148
|
*/
|
|
115
149
|
public getAppManifest(appKey: string, tag?: string): Observable<AppManifest> {
|
|
116
150
|
return from(this.#appClient.getAppManifest({ appKey, tag }));
|
|
117
151
|
}
|
|
118
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Fetches manifests for all registered applications.
|
|
155
|
+
*
|
|
156
|
+
* @param filter - Optional filter; set `filterByCurrentUser` to `true` to scope
|
|
157
|
+
* results to apps accessible by the authenticated user.
|
|
158
|
+
* @returns An observable that emits an array of {@link AppManifest} objects.
|
|
159
|
+
*/
|
|
119
160
|
public getAppManifests(filter?: { filterByCurrentUser: boolean }): Observable<AppManifest[]> {
|
|
120
161
|
return from(this.#appClient.getAppManifests(filter));
|
|
121
162
|
}
|
|
@@ -129,8 +170,12 @@ export class AppModuleProvider {
|
|
|
129
170
|
}
|
|
130
171
|
|
|
131
172
|
/**
|
|
132
|
-
*
|
|
133
|
-
*
|
|
173
|
+
* Fetches the runtime configuration for an application.
|
|
174
|
+
*
|
|
175
|
+
* @template TType - Shape of the `environment` record in the returned config.
|
|
176
|
+
* @param appKey - Unique application identifier.
|
|
177
|
+
* @param tag - Optional version tag.
|
|
178
|
+
* @returns An observable that emits the resolved {@link AppConfig}.
|
|
134
179
|
*/
|
|
135
180
|
public getAppConfig<TType extends ConfigEnvironment = ConfigEnvironment>(
|
|
136
181
|
appKey: string,
|
|
@@ -140,25 +185,33 @@ export class AppModuleProvider {
|
|
|
140
185
|
}
|
|
141
186
|
|
|
142
187
|
/**
|
|
143
|
-
*
|
|
144
|
-
*
|
|
188
|
+
* Fetches per-user settings for an application.
|
|
189
|
+
*
|
|
190
|
+
* @param appKey - Unique application identifier.
|
|
191
|
+
* @returns An observable that emits the {@link AppSettings} record.
|
|
145
192
|
*/
|
|
146
193
|
public getAppSettings(appKey: string): Observable<AppSettings> {
|
|
147
194
|
return from(this.#appClient.getAppSettings({ appKey }));
|
|
148
195
|
}
|
|
149
196
|
|
|
150
197
|
/**
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
* @param
|
|
198
|
+
* Persists updated per-user settings for an application.
|
|
199
|
+
*
|
|
200
|
+
* @param appKey - Unique application identifier.
|
|
201
|
+
* @param settings - The settings record to save.
|
|
202
|
+
* @returns An observable that emits the persisted {@link AppSettings}.
|
|
154
203
|
*/
|
|
155
204
|
public updateAppSettings(appKey: string, settings: AppSettings): Observable<AppSettings> {
|
|
156
205
|
return from(this.#appClient.updateAppSettings({ appKey, settings }));
|
|
157
206
|
}
|
|
158
207
|
|
|
159
208
|
/**
|
|
160
|
-
*
|
|
161
|
-
*
|
|
209
|
+
* Sets the current active application.
|
|
210
|
+
*
|
|
211
|
+
* Accepts an app key string, an {@link IApp} instance, or an {@link AppReference}
|
|
212
|
+
* with both `appKey` and `tag`. Setting a new app disposes the previous one.
|
|
213
|
+
*
|
|
214
|
+
* @param appKeyOrApp - Application key, app reference, or an existing `IApp` instance.
|
|
162
215
|
*/
|
|
163
216
|
public setCurrentApp(appKeyOrApp: string | IApp | AppReference): void {
|
|
164
217
|
if (typeof appKeyOrApp === 'string') {
|
|
@@ -179,10 +232,17 @@ export class AppModuleProvider {
|
|
|
179
232
|
this.#current$.next(appKeyOrApp as CurrentApp);
|
|
180
233
|
}
|
|
181
234
|
|
|
235
|
+
/**
|
|
236
|
+
* Clears the current application, disposing its resources and emitting `null`
|
|
237
|
+
* on {@link current$}.
|
|
238
|
+
*/
|
|
182
239
|
public clearCurrentApp(): void {
|
|
183
240
|
this.#current$.next(null);
|
|
184
241
|
}
|
|
185
242
|
|
|
243
|
+
/**
|
|
244
|
+
* Base URI used for proxying application script imports.
|
|
245
|
+
*/
|
|
186
246
|
public get assetUri(): string {
|
|
187
247
|
return this.#appBaseUri;
|
|
188
248
|
}
|
|
@@ -196,6 +256,9 @@ export class AppModuleProvider {
|
|
|
196
256
|
return new App(value, { provider: this, event: this.#event });
|
|
197
257
|
}
|
|
198
258
|
|
|
259
|
+
/**
|
|
260
|
+
* Tears down the provider, unsubscribing from all internal observables.
|
|
261
|
+
*/
|
|
199
262
|
public dispose() {
|
|
200
263
|
this.#subscription.unsubscribe();
|
|
201
264
|
}
|
package/src/app/App.ts
CHANGED
|
@@ -29,15 +29,25 @@ import isEqual from 'fast-deep-equal';
|
|
|
29
29
|
|
|
30
30
|
import './events';
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
/**
|
|
33
|
+
* RxJS operator that filters out `null` and `undefined` emissions.
|
|
34
|
+
*
|
|
35
|
+
* @template T - The non-nullable value type.
|
|
36
|
+
* @returns An operator that only passes through non-nullable values.
|
|
37
|
+
*/
|
|
33
38
|
export function filterEmpty<T>(): OperatorFunction<T | null | undefined, T> {
|
|
34
39
|
return filter((value): value is T => value !== undefined && value !== null);
|
|
35
40
|
}
|
|
36
41
|
|
|
37
42
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
43
|
+
* Public interface for a single loaded Fusion application.
|
|
44
|
+
*
|
|
45
|
+
* Provides reactive observables and imperative methods for accessing the
|
|
46
|
+
* application's manifest, configuration, per-user settings, script module,
|
|
47
|
+
* and initialized module instance.
|
|
48
|
+
*
|
|
49
|
+
* @template TEnv - Shape of the environment configuration record.
|
|
50
|
+
* @template TModules - Additional framework modules the app depends on.
|
|
41
51
|
*/
|
|
42
52
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
43
53
|
export interface IApp<
|
|
@@ -246,14 +256,29 @@ export interface IApp<
|
|
|
246
256
|
getAppModuleAsync(allow_cache?: boolean): Promise<AppScriptModule>;
|
|
247
257
|
}
|
|
248
258
|
|
|
259
|
+
/** Default empty settings object used when no settings have been fetched. */
|
|
249
260
|
const fallbackSettings: AppSettings = {};
|
|
250
261
|
|
|
262
|
+
/**
|
|
263
|
+
* Result emitted by {@link IApp.initialize}, containing the resolved manifest,
|
|
264
|
+
* imported script module, and runtime configuration.
|
|
265
|
+
*/
|
|
251
266
|
export type AppInitializeResult = {
|
|
252
267
|
manifest: AppManifest;
|
|
253
268
|
script: AppScriptModule;
|
|
254
269
|
config: AppConfig;
|
|
255
270
|
};
|
|
256
271
|
|
|
272
|
+
/**
|
|
273
|
+
* Concrete implementation of {@link IApp}.
|
|
274
|
+
*
|
|
275
|
+
* Manages an internal reactive state machine ({@link FlowSubject}) that orchestrates
|
|
276
|
+
* manifest fetching, config loading, settings management, and script import. Dispatches
|
|
277
|
+
* lifecycle events through the {@link EventModule} when available.
|
|
278
|
+
*
|
|
279
|
+
* @template TEnv - Shape of the environment configuration record.
|
|
280
|
+
* @template TModules - Additional framework modules the app depends on.
|
|
281
|
+
*/
|
|
257
282
|
// TODO make streams distinct until changed from state
|
|
258
283
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
259
284
|
export class App<
|
package/src/app/actions.ts
CHANGED
|
@@ -12,6 +12,18 @@ import type {
|
|
|
12
12
|
AppSettings,
|
|
13
13
|
} from '../types';
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Factory function that creates all action creators used by the {@link App}
|
|
17
|
+
* state machine.
|
|
18
|
+
*
|
|
19
|
+
* Actions are grouped by domain:
|
|
20
|
+
* - **Manifest** – `setManifest`, `fetchManifest` (async)
|
|
21
|
+
* - **Config** – `setConfig`, `fetchConfig` (async)
|
|
22
|
+
* - **Settings** – `setSettings`, `fetchSettings` (async), `updateSettings` (async)
|
|
23
|
+
* - **Script module** – `setModule`, `importApp` (async)
|
|
24
|
+
* - **Instance** – `setInstance`
|
|
25
|
+
* - **Lifecycle** – `initialize` (async)
|
|
26
|
+
*/
|
|
15
27
|
const createActions = () => ({
|
|
16
28
|
/** Manifest loading */
|
|
17
29
|
setManifest: createAction('set_manifest', (manifest: AppManifest, update?: boolean) => ({
|
|
@@ -87,10 +99,14 @@ const createActions = () => ({
|
|
|
87
99
|
),
|
|
88
100
|
});
|
|
89
101
|
|
|
102
|
+
/** Singleton action creator map used by the app state machine. */
|
|
90
103
|
export const actions = createActions();
|
|
91
104
|
|
|
105
|
+
/** Record mapping action names to their creator functions. */
|
|
92
106
|
export type ActionBuilder = ReturnType<typeof createActions>;
|
|
93
107
|
|
|
108
|
+
/** Map of action names to their instantiated action shapes. */
|
|
94
109
|
export type ActionMap = ActionInstanceMap<ActionBuilder>;
|
|
95
110
|
|
|
111
|
+
/** Union of all action types dispatched by the app state machine. */
|
|
96
112
|
export type Actions = ActionTypes<typeof actions>;
|
|
@@ -13,6 +13,15 @@ import { type Actions, actions } from './actions';
|
|
|
13
13
|
|
|
14
14
|
import type { AppBundleState, AppBundleStateInitial } from './types';
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Creates the Immer-powered reducer for the {@link App} state machine.
|
|
18
|
+
*
|
|
19
|
+
* Handles synchronous state updates (set manifest, config, settings, module, instance)
|
|
20
|
+
* and tracks in-progress async operations via a `status` set.
|
|
21
|
+
*
|
|
22
|
+
* @param value - Initial state values (appKey, tag, and any pre-loaded data).
|
|
23
|
+
* @returns A reducer function compatible with {@link FlowSubject}.
|
|
24
|
+
*/
|
|
16
25
|
export const createReducer = (value: AppBundleStateInitial) =>
|
|
17
26
|
makeReducer<AppBundleState, Actions>(
|
|
18
27
|
{ ...value, status: new Set() } as AppBundleState,
|