@equinor/fusion-framework-module-app 7.4.1 → 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.
Files changed (65) hide show
  1. package/CHANGELOG.md +57 -33
  2. package/README.md +118 -11
  3. package/dist/esm/AppClient.js +16 -3
  4. package/dist/esm/AppClient.js.map +1 -1
  5. package/dist/esm/AppConfig.js +7 -1
  6. package/dist/esm/AppConfig.js.map +1 -1
  7. package/dist/esm/AppConfigurator.js +7 -0
  8. package/dist/esm/AppConfigurator.js.map +1 -1
  9. package/dist/esm/AppModuleProvider.js +80 -17
  10. package/dist/esm/AppModuleProvider.js.map +1 -1
  11. package/dist/esm/app/App.js +17 -1
  12. package/dist/esm/app/App.js.map +1 -1
  13. package/dist/esm/app/actions.js +13 -0
  14. package/dist/esm/app/actions.js.map +1 -1
  15. package/dist/esm/app/create-reducer.js +9 -0
  16. package/dist/esm/app/create-reducer.js.map +1 -1
  17. package/dist/esm/app/create-state.js +11 -0
  18. package/dist/esm/app/create-state.js.map +1 -1
  19. package/dist/esm/app/flows.js +3 -2
  20. package/dist/esm/app/flows.js.map +1 -1
  21. package/dist/esm/app/index.js +7 -0
  22. package/dist/esm/app/index.js.map +1 -1
  23. package/dist/esm/enable-app-module.js +19 -2
  24. package/dist/esm/enable-app-module.js.map +1 -1
  25. package/dist/esm/errors.js.map +1 -1
  26. package/dist/esm/index.js +18 -0
  27. package/dist/esm/index.js.map +1 -1
  28. package/dist/esm/module.js +1 -0
  29. package/dist/esm/module.js.map +1 -1
  30. package/dist/esm/version.js +1 -1
  31. package/dist/tsconfig.tsbuildinfo +1 -1
  32. package/dist/types/AppClient.d.ts +52 -10
  33. package/dist/types/AppConfig.d.ts +8 -0
  34. package/dist/types/AppConfigurator.d.ts +32 -0
  35. package/dist/types/AppModuleProvider.d.ts +80 -17
  36. package/dist/types/app/App.d.ts +28 -3
  37. package/dist/types/app/actions.d.ts +16 -0
  38. package/dist/types/app/create-reducer.d.ts +9 -0
  39. package/dist/types/app/create-state.d.ts +11 -0
  40. package/dist/types/app/events.d.ts +17 -1
  41. package/dist/types/app/index.d.ts +7 -0
  42. package/dist/types/enable-app-module.d.ts +19 -2
  43. package/dist/types/errors.d.ts +8 -0
  44. package/dist/types/index.d.ts +18 -0
  45. package/dist/types/module.d.ts +6 -0
  46. package/dist/types/types.d.ts +92 -3
  47. package/dist/types/version.d.ts +1 -1
  48. package/package.json +10 -10
  49. package/src/AppClient.ts +54 -11
  50. package/src/AppConfig.ts +15 -1
  51. package/src/AppConfigurator.ts +33 -1
  52. package/src/AppModuleProvider.ts +80 -17
  53. package/src/app/App.ts +29 -4
  54. package/src/app/actions.ts +16 -0
  55. package/src/app/create-reducer.ts +9 -0
  56. package/src/app/create-state.ts +11 -0
  57. package/src/app/events.ts +17 -1
  58. package/src/app/flows.ts +6 -2
  59. package/src/app/index.ts +7 -0
  60. package/src/enable-app-module.ts +19 -2
  61. package/src/errors.ts +8 -0
  62. package/src/index.ts +19 -0
  63. package/src/module.ts +6 -0
  64. package/src/types.ts +94 -7
  65. package/src/version.ts +1 -1
@@ -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 app, used to fetch app manifest from app service
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,8 +77,26 @@ 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;
84
+ /**
85
+ * Schema entry format for route documentation in app manifests.
86
+ * Each entry represents a route with its path, description, and optional parameter/search schemas.
87
+ */
88
+ export type RouteSchemaEntry = [
89
+ path: string,
90
+ description: string,
91
+ options?: {
92
+ params?: Record<string, string>;
93
+ search?: Record<string, string>;
94
+ }
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
+ */
43
100
  export type AppBuildManifest = {
44
101
  version: string;
45
102
  entryPoint: string;
@@ -55,6 +112,10 @@ export type AppBuildManifest = {
55
112
  allowedExtensions?: Nullable<string[]>;
56
113
  uploadedBy?: Nullable<AppOwner>;
57
114
  };
115
+ /**
116
+ * Full manifest describing a registered Fusion application, including
117
+ * display metadata, category, admins/owners, build info, and optional route schemas.
118
+ */
58
119
  export interface AppManifest {
59
120
  /** @deprecated will be removed, use appKey */
60
121
  key?: string;
@@ -83,27 +144,55 @@ export interface AppManifest {
83
144
  admins?: Nullable<AppAdmin[]>;
84
145
  owners?: Nullable<AppOwner[]>;
85
146
  build?: Nullable<AppBuildManifest>;
147
+ /** Route schema entries for documentation and API schema generation */
148
+ routes?: Nullable<RouteSchemaEntry[]>;
86
149
  }
87
150
  /**
88
- * @template TEnvironment - name of hosted environment
89
- * @template TModule - ES module type (import return type)
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.
90
155
  */
91
156
  export type AppBundle<TEnvironment extends ConfigEnvironment = ConfigEnvironment, TModule = unknown> = {
92
157
  manifest: AppManifest;
93
158
  config: AppConfig<TEnvironment>;
94
159
  module: TModule;
95
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
+ */
96
167
  export type AppModules<TModules extends Array<AnyModule> | unknown = unknown> = CombinedModules<TModules, [
97
168
  EventModule,
98
169
  HttpModule,
99
170
  MsalModule
100
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
+ */
101
179
  export type ComponentRenderArgs<TFusion extends Fusion = Fusion, TEnv = AppEnv> = {
102
180
  fusion: TFusion;
103
181
  env: TEnv;
104
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
+ */
105
189
  export type AppScriptModule = {
106
190
  default: (el: HTMLElement, args: ComponentRenderArgs) => VoidFunction;
107
191
  renderApp: (el: HTMLElement, args: ComponentRenderArgs) => VoidFunction;
108
192
  };
193
+ /**
194
+ * Instantiated module collection for a running application.
195
+ *
196
+ * @template TModules - Additional modules contributed by the application.
197
+ */
109
198
  export type AppModulesInstance<TModules extends Array<AnyModule> | unknown = unknown> = ModulesInstance<AppModules<TModules>>;
@@ -1 +1 @@
1
- export declare const version = "7.4.1";
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": "7.4.1",
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.1.8",
64
- "@equinor/fusion-observable": "^8.5.8",
65
- "@equinor/fusion-query": "^6.0.4"
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.8.2",
69
- "@equinor/fusion-framework-module-event": "^5.0.1",
70
- "@equinor/fusion-framework-module-msal": "^7.3.1",
71
- "@equinor/fusion-framework-module": "^5.0.6",
72
- "@equinor/fusion-framework-module-service-discovery": "^9.1.1",
73
- "@equinor/fusion-framework-module-http": "^7.0.8"
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
- * Fetch app manifest by appKey and tag
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
- * Fetch app build manifest by appKey and tag
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
- * Fetch all app manifests
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
- * Fetch app config by appKey and tag
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
- * Fetch app settings by appKey
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
- * Set app settings by appKey
56
- * @param args - Object with appKey and settings
57
- * @returns ObservableInput<AppSettings>
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 an ApiApplicationSchema object into an AppManifest object.
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
- * The `AppClient` class implements the `IAppClient` interface and provides methods to query
89
- * application manifests and configurations from a backend service.
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
- // todo: move to utils
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[];
@@ -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
- // uri which to fetch the assets from aka the bundle of the application
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
@@ -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
- * fetch an application by key
55
- * @param appKey - application key
56
- * @remarks
57
- * - null when current app is cleared
58
- * - undefined if application never set
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
- * fetch an application by key
112
- * @param appKey - application key
113
- * @param tag - application tag (optional)
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
- * fetch configuration for an application
133
- * @param appKey - application key
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
- * fetch user settings for an application
144
- * @param appKey - application key
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
- * Put user settings for an application
152
- * @param appKey - application key
153
- * @param settings - The settings to add save
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
- * set the current application, will internally resolve manifest
161
- * @param appKey - application key
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
- // TODO - move globally
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
- * Represents an application in the framework.
39
- * @template TEnv The type of the environment.
40
- * @template TModules The type of the app modules.
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<
@@ -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>;