@equinor/fusion-framework-app 13.0.3-next.0 → 13.0.3

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 (47) hide show
  1. package/CHANGELOG.md +3 -5
  2. package/README.md +65 -35
  3. package/dist/esm/configure-modules.js +42 -2
  4. package/dist/esm/configure-modules.js.map +1 -1
  5. package/dist/esm/version.js +1 -1
  6. package/dist/esm/version.js.map +1 -1
  7. package/dist/tsconfig.tsbuildinfo +1 -1
  8. package/dist/types/version.d.ts +1 -1
  9. package/package.json +13 -22
  10. package/src/configure-modules.ts +52 -2
  11. package/src/version.ts +1 -1
  12. package/vitest.config.ts +1 -1
  13. package/dist/esm/__tests__/mock/AppMockConfigurator.test.js +0 -70
  14. package/dist/esm/__tests__/mock/AppMockConfigurator.test.js.map +0 -1
  15. package/dist/esm/__tests__/mock/mock-app.test.js +0 -86
  16. package/dist/esm/__tests__/mock/mock-app.test.js.map +0 -1
  17. package/dist/esm/__tests__/mock/msal-hoisting.test.js +0 -36
  18. package/dist/esm/__tests__/mock/msal-hoisting.test.js.map +0 -1
  19. package/dist/esm/initialize-app-modules.js +0 -65
  20. package/dist/esm/initialize-app-modules.js.map +0 -1
  21. package/dist/esm/mock/AppMockConfigurator.js +0 -183
  22. package/dist/esm/mock/AppMockConfigurator.js.map +0 -1
  23. package/dist/esm/mock/enable-app-manifest-mock.js +0 -49
  24. package/dist/esm/mock/enable-app-manifest-mock.js.map +0 -1
  25. package/dist/esm/mock/index.js +0 -21
  26. package/dist/esm/mock/index.js.map +0 -1
  27. package/dist/esm/mock/mock-app-modules.js +0 -82
  28. package/dist/esm/mock/mock-app-modules.js.map +0 -1
  29. package/dist/types/__tests__/mock/AppMockConfigurator.test.d.ts +0 -1
  30. package/dist/types/__tests__/mock/mock-app.test.d.ts +0 -1
  31. package/dist/types/__tests__/mock/msal-hoisting.test.d.ts +0 -1
  32. package/dist/types/initialize-app-modules.d.ts +0 -31
  33. package/dist/types/mock/AppMockConfigurator.d.ts +0 -142
  34. package/dist/types/mock/enable-app-manifest-mock.d.ts +0 -33
  35. package/dist/types/mock/index.d.ts +0 -20
  36. package/dist/types/mock/mock-app-modules.d.ts +0 -72
  37. package/docs/bookmarks.md +0 -18
  38. package/docs/http-clients.md +0 -71
  39. package/docs/testing.md +0 -105
  40. package/src/__tests__/mock/AppMockConfigurator.test.ts +0 -96
  41. package/src/__tests__/mock/mock-app.test.ts +0 -112
  42. package/src/__tests__/mock/msal-hoisting.test.ts +0 -54
  43. package/src/initialize-app-modules.ts +0 -98
  44. package/src/mock/AppMockConfigurator.ts +0 -218
  45. package/src/mock/enable-app-manifest-mock.ts +0 -62
  46. package/src/mock/index.ts +0 -21
  47. package/src/mock/mock-app-modules.ts +0 -109
@@ -1 +1 @@
1
- export declare const version = "13.0.3-next.0";
1
+ export declare const version = "13.0.3";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@equinor/fusion-framework-app",
3
- "version": "13.0.3-next.0",
3
+ "version": "13.0.3",
4
4
  "description": "",
5
5
  "main": "dist/esm/index.js",
6
6
  "types": "./dist/types/index.d.ts",
@@ -16,10 +16,6 @@
16
16
  "./enable-bookmark": {
17
17
  "types": "./dist/types/enable-bookmark.d.ts",
18
18
  "import": "./dist/esm/enable-bookmark.js"
19
- },
20
- "./mock": {
21
- "types": "./dist/types/mock/index.d.ts",
22
- "import": "./dist/esm/mock/index.js"
23
19
  }
24
20
  },
25
21
  "typesVersions": {
@@ -32,9 +28,6 @@
32
28
  ],
33
29
  "enable-bookmark": [
34
30
  "dist/types/enable-bookmark.d.ts"
35
- ],
36
- "mock": [
37
- "dist/types/mock/index.d.ts"
38
31
  ]
39
32
  }
40
33
  },
@@ -61,24 +54,23 @@
61
54
  "dependencies": {
62
55
  "lodash.clonedeep": "^4.5.0",
63
56
  "rxjs": "^7.8.1",
64
- "@equinor/fusion-framework": "8.1.0-next.1",
65
- "@equinor/fusion-framework-module": "6.1.3-next.0",
66
- "@equinor/fusion-framework-module-app": "8.0.6-next.0",
67
- "@equinor/fusion-framework-module-event": "6.1.0-next.0",
68
- "@equinor/fusion-framework-module-http": "8.1.0-next.0",
69
- "@equinor/fusion-framework-module-msal": "11.0.0-next.0",
70
- "@equinor/fusion-framework-module-telemetry": "8.0.0-next.1"
57
+ "@equinor/fusion-framework": "8.0.16",
58
+ "@equinor/fusion-framework-module": "6.1.2",
59
+ "@equinor/fusion-framework-module-app": "8.0.5",
60
+ "@equinor/fusion-framework-module-event": "6.0.1",
61
+ "@equinor/fusion-framework-module-msal": "10.0.2",
62
+ "@equinor/fusion-framework-module-http": "8.0.5",
63
+ "@equinor/fusion-framework-module-telemetry": "7.0.3"
71
64
  },
72
65
  "devDependencies": {
73
66
  "@types/lodash.clonedeep": "^4.5.9",
74
67
  "typescript": "^7.0.2",
75
- "vitest": "^4.1.10",
76
- "@equinor/fusion-framework-module-bookmark": "^4.1.0-next.0",
77
- "@equinor/fusion-framework-module-state": "^2.0.2-next.0"
68
+ "@equinor/fusion-framework-module-bookmark": "^4.0.4",
69
+ "@equinor/fusion-framework-module-state": "^2.0.1"
78
70
  },
79
71
  "peerDependencies": {
80
- "@equinor/fusion-framework-module-bookmark": "^4.1.0-next.0",
81
- "@equinor/fusion-framework-module-state": "^2.0.2-next.0"
72
+ "@equinor/fusion-framework-module-state": "^2.0.1",
73
+ "@equinor/fusion-framework-module-bookmark": "^4.0.4"
82
74
  },
83
75
  "peerDependenciesMeta": {
84
76
  "@equinor/fusion-framework-module-bookmark": {
@@ -89,7 +81,6 @@
89
81
  }
90
82
  },
91
83
  "scripts": {
92
- "build": "tsc -b",
93
- "test": "vitest"
84
+ "build": "tsc -b"
94
85
  }
95
86
  }
@@ -7,11 +7,14 @@
7
7
 
8
8
  import type { Fusion } from '@equinor/fusion-framework';
9
9
  import type { AnyModule } from '@equinor/fusion-framework-module';
10
+ import {
11
+ enableTelemetry,
12
+ type MetadataExtractor,
13
+ } from '@equinor/fusion-framework-module-telemetry';
10
14
 
11
15
  import { AppConfigurator } from './AppConfigurator';
12
16
 
13
17
  import type { AppModulesInstance, AppModuleInitiator, AppEnv } from './types';
14
- import { initializeAppModules } from './initialize-app-modules';
15
18
 
16
19
  /**
17
20
  * Create an application module initializer for a Fusion application.
@@ -63,9 +66,56 @@ export const configureModules =
63
66
  * @returns The fully initialized application module instance.
64
67
  */
65
68
  async (args: { fusion: TRef; env: TEnv }): Promise<AppModulesInstance<TModules>> => {
69
+ const { fusion } = args;
70
+
66
71
  // Create app configurator
67
72
  const configurator = new AppConfigurator<TModules, TRef['modules'], TEnv>(args.env);
68
- return initializeAppModules(configurator, cb, args);
73
+
74
+ // Extract telemetry metadata from app manifest for tracking and debugging
75
+ const metadataExtractor: MetadataExtractor = () => {
76
+ return {
77
+ fusion: {
78
+ type: 'app-telemetry',
79
+ app: {
80
+ key: args.env.manifest?.appKey || 'unknown-app',
81
+ version: args.env.manifest?.build?.version || 'unknown-version',
82
+ },
83
+ },
84
+ };
85
+ };
86
+
87
+ // Enable telemetry collection for module configuration events
88
+ // attachConfiguratorEvents automatically prefixes events with configurator class name
89
+ enableTelemetry(configurator, {
90
+ attachConfiguratorEvents: true,
91
+ configure: (builder) => {
92
+ builder.setMetadata(metadataExtractor);
93
+ builder.setParent(fusion.modules.telemetry);
94
+ // Scope telemetry to 'app' level for app-specific event filtering
95
+ builder.setDefaultScope(['app']);
96
+ },
97
+ });
98
+
99
+ // Allow user configuration callback to run before module initialization
100
+ if (cb) {
101
+ await Promise.resolve(cb(configurator, args));
102
+ }
103
+ // Type cast is safe because AppConfigurator.initialize() returns the exact module
104
+ // instance that was registered and configured above. The intermediate 'unknown'
105
+ // cast is necessary due to TypeScript's generic inference limitations with the
106
+ // configurator's initialization chain, but the runtime value is guaranteed to match.
107
+ const modules: AppModulesInstance<TModules> = (await configurator.initialize(
108
+ args.fusion.modules,
109
+ )) as unknown as AppModulesInstance<TModules>;
110
+
111
+ // Dispatch app modules loaded event for app lifecycle tracking
112
+ // TODO(#5061): remove check after fusion-cli is updated (app module is not enabled in fusion-cli)
113
+ if (args.env.manifest?.appKey) {
114
+ modules.event.dispatchEvent('onAppModulesLoaded', {
115
+ detail: { appKey: args.env.manifest.appKey, manifest: args.env.manifest, modules },
116
+ });
117
+ }
118
+ return modules;
69
119
  };
70
120
 
71
121
  export default configureModules;
package/src/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by genversion.
2
- export const version = '13.0.3-next.0';
2
+ export const version = '13.0.3';
package/vitest.config.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { defineProject } from 'vitest/config';
2
2
 
3
- import { name, version } from './package.json' with { type: 'json' };
3
+ import { name, version } from './package.json';
4
4
 
5
5
  export default defineProject({
6
6
  test: {
@@ -1,70 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { AppConfig } from '@equinor/fusion-framework-module-app';
3
- import { enableTelemetry } from '@equinor/fusion-framework-module-telemetry';
4
- import { AppConfigurator } from '../../AppConfigurator.js';
5
- import { AppMockConfigurator } from '../../mock/AppMockConfigurator.js';
6
- const mockEnv = {
7
- manifest: {
8
- appKey: 'test-app',
9
- displayName: 'Test App',
10
- description: 'A test application',
11
- type: 'standalone',
12
- build: {
13
- version: '1.0.0',
14
- entryPoint: 'index.js',
15
- },
16
- },
17
- };
18
- describe('AppMockConfigurator', () => {
19
- it('is a real AppConfigurator', () => {
20
- const configurator = new AppMockConfigurator(mockEnv);
21
- expect(configurator).toBeInstanceOf(AppMockConfigurator);
22
- expect(configurator).toBeInstanceOf(AppConfigurator);
23
- });
24
- it('constructs without throwing when env.config declares endpoints', async () => {
25
- // the base AppConfigurator constructor auto-registers these via addConfig,
26
- // before this class's own fields (#pinnedModules) are initialized
27
- const env = {
28
- ...mockEnv,
29
- config: new AppConfig({
30
- endpoints: { status: { url: 'https://status.example.com', scopes: [] } },
31
- }),
32
- };
33
- const configurator = new AppMockConfigurator(env);
34
- configurator.http.addMiddleware(async (uri, init, next) => uri === 'https://status.example.com/health' ? Response.json({ ok: true }) : next(uri, init));
35
- enableTelemetry(configurator);
36
- const modules = await configurator.initialize();
37
- await expect(modules.http.createClient('status').json('/health')).resolves.toEqual({
38
- ok: true,
39
- });
40
- });
41
- it('exposes the same http configurator the http module is built from', async () => {
42
- const configurator = new AppMockConfigurator(mockEnv);
43
- configurator.http.configureClient('catalog', { baseUri: 'https://api.example.com' });
44
- configurator.http.addMiddleware(async (uri, init, next) => uri === 'https://api.example.com/items' ? Response.json([{ id: 1 }]) : next(uri, init));
45
- // msal's config schema requires a telemetry module, normally wired by configureModules
46
- enableTelemetry(configurator);
47
- const modules = await configurator.initialize();
48
- await expect(modules.http.createClient('catalog').json('/items')).resolves.toEqual([{ id: 1 }]);
49
- });
50
- it('exposes the same msal configurator the auth module is built from', async () => {
51
- const configurator = new AppMockConfigurator(mockEnv);
52
- configurator.msal.setAccount({ name: 'Ada Lovelace' });
53
- // msal's config schema requires a telemetry module, normally wired by configureModules
54
- enableTelemetry(configurator);
55
- const modules = await configurator.initialize();
56
- expect(modules.auth.account?.name).toBe('Ada Lovelace');
57
- });
58
- it('answers a client registered through configureHttpClient via addMiddleware', async () => {
59
- const configurator = new AppMockConfigurator(mockEnv);
60
- configurator.configureHttpClient('status-api', { baseUri: 'https://status.example.com' });
61
- configurator.http.addMiddleware(async (uri, init, next) => uri === 'https://status.example.com/status' ? Response.json({ ok: true }) : next(uri, init));
62
- // msal's config schema requires a telemetry module, normally wired by configureModules
63
- enableTelemetry(configurator);
64
- const modules = await configurator.initialize();
65
- await expect(modules.http.createClient('status-api').json('/status')).resolves.toEqual({
66
- ok: true,
67
- });
68
- });
69
- });
70
- //# sourceMappingURL=AppMockConfigurator.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AppMockConfigurator.test.js","sourceRoot":"","sources":["../../../../src/__tests__/mock/AppMockConfigurator.test.ts"],"names":[],"mappings":"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"}
@@ -1,86 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { mockFramework } from '@equinor/fusion-framework/mock';
3
- import { AppConfig } from '@equinor/fusion-framework-module-app';
4
- import { AppMockConfigurator } from '../../mock/AppMockConfigurator.js';
5
- import { mockAppModules } from '../../mock/mock-app-modules.js';
6
- const env = {
7
- manifest: {
8
- appKey: 'test-app',
9
- displayName: 'Test App',
10
- description: 'A test application',
11
- type: 'standalone',
12
- build: {
13
- version: '1.0.0',
14
- entryPoint: 'index.js',
15
- },
16
- },
17
- config: new AppConfig({ environment: { foo: 'bar' } }),
18
- };
19
- describe('mockApp', () => {
20
- it('initializes the app module pipeline with no configuration', async () => {
21
- const modules = await mockAppModules(undefined, env);
22
- expect(modules.event).toBeDefined();
23
- expect(modules.auth).toBeDefined();
24
- expect(modules.http).toBeDefined();
25
- });
26
- it('passes a real AppConfigurator to the callback', async () => {
27
- expect.assertions(1);
28
- await mockAppModules((configurator) => {
29
- expect(configurator).toBeInstanceOf(AppMockConfigurator);
30
- }, env);
31
- });
32
- it('answers a service-discovery-resolved client from the app’s own mocked http module', async () => {
33
- const modules = await mockAppModules((configurator) => {
34
- configurator.useFrameworkServiceClient('portal-api');
35
- // matches against the full resolved URL, so the host is part of the match to keep this
36
- // from also answering a different client's request
37
- configurator.http.addMiddleware(async (uri, init, next) => uri === 'https://portal-api.fusion.test/items'
38
- ? Response.json([{ id: 1 }])
39
- : next(uri, init));
40
- }, env);
41
- await expect(modules.http.createClient('portal-api').json('/items')).resolves.toEqual([
42
- { id: 1 },
43
- ]);
44
- });
45
- it('reuses an already-mocked fusion instance instead of creating a new one', async () => {
46
- expect.assertions(1);
47
- const fusion = await mockFramework((configurator) => {
48
- configurator.msal.setAccount({ name: 'Ada Lovelace' });
49
- });
50
- await mockAppModules((_configurator, { fusion: parent }) => {
51
- expect(parent.modules.auth.account?.name).toBe('Ada Lovelace');
52
- }, env, fusion);
53
- });
54
- it('awaits an async configure callback before initialize resolves', async () => {
55
- const modules = await mockAppModules(async (configurator) => {
56
- await Promise.resolve();
57
- configurator.msal.setAccount({ name: 'Ada Lovelace' });
58
- }, env);
59
- expect(modules.auth.account?.name).toBe('Ada Lovelace');
60
- });
61
- it('serves this app’s own manifest and config through the default parent’s app module', async () => {
62
- expect.assertions(2);
63
- await mockAppModules(async (_configurator, { fusion }) => {
64
- // the default parent always has `app` enabled; typed as plain `Fusion` since callers
65
- // may pass in a parent without it, so the module set is narrowed just for this assertion
66
- const { app } = fusion.modules;
67
- app.setCurrentApp(env.manifest.appKey);
68
- await expect(app.current?.getManifestAsync()).resolves.toMatchObject({
69
- appKey: env.manifest.appKey,
70
- displayName: env.manifest.displayName,
71
- });
72
- await expect(app.current?.getConfigAsync()).resolves.toMatchObject({
73
- environment: env.config.environment,
74
- });
75
- }, env);
76
- });
77
- it('falls through to the real client for a manifest not matching this app’s own', async () => {
78
- expect.assertions(1);
79
- await mockAppModules(async (_configurator, { fusion }) => {
80
- const { app } = fusion.modules;
81
- app.setCurrentApp('some-other-app');
82
- await expect(app.current?.getManifestAsync()).rejects.toThrow();
83
- }, env);
84
- });
85
- });
86
- //# sourceMappingURL=mock-app.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mock-app.test.js","sourceRoot":"","sources":["../../../../src/__tests__/mock/mock-app.test.ts"],"names":[],"mappings":"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"}
@@ -1,36 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest';
2
- import { mockFramework } from '@equinor/fusion-framework/mock';
3
- import { mockAppModules } from '../../mock/mock-app-modules.js';
4
- const env = {
5
- manifest: {
6
- appKey: 'test-app',
7
- displayName: 'Test App',
8
- description: 'A test application',
9
- type: 'standalone',
10
- },
11
- };
12
- describe('msal hoisting', () => {
13
- it('delegates acquireToken to the parent’s auth module instead of building its own client', async () => {
14
- const fusion = await mockFramework();
15
- const result = { accessToken: 'parent-issued-token' };
16
- vi.spyOn(fusion.modules.auth, 'acquireToken').mockResolvedValue(result);
17
- const modules = await mockAppModules(undefined, env, fusion);
18
- // the app's own `auth` is a distinct (proxying) object, not the parent's instance itself
19
- expect(modules.auth).not.toBe(fusion.modules.auth);
20
- await expect(modules.auth.acquireToken({ request: { scopes: ['User.Read'] } })).resolves.toMatchObject({ accessToken: 'parent-issued-token' });
21
- });
22
- it('surfaces the parent’s acquisition failures instead of falling back to its own client', async () => {
23
- const fusion = await mockFramework();
24
- vi.spyOn(fusion.modules.auth, 'acquireToken').mockRejectedValue(new Error('acquisition failed'));
25
- const modules = await mockAppModules(undefined, env, fusion);
26
- await expect(modules.auth.acquireToken({ request: { scopes: ['User.Read'] } })).rejects.toThrow('acquisition failed');
27
- });
28
- it('reflects the parent’s signed-in account rather than signing in its own', async () => {
29
- const fusion = await mockFramework((configurator) => {
30
- configurator.msal.setAccount({ name: 'Ada Lovelace' });
31
- });
32
- const modules = await mockAppModules(undefined, env, fusion);
33
- expect(modules.auth.account?.name).toBe('Ada Lovelace');
34
- });
35
- });
36
- //# sourceMappingURL=msal-hoisting.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"msal-hoisting.test.js","sourceRoot":"","sources":["../../../../src/__tests__/mock/msal-hoisting.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAG/D,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAEhE,MAAM,GAAG,GAAG;IACV,QAAQ,EAAE;QACR,MAAM,EAAE,UAAU;QAClB,WAAW,EAAE,UAAU;QACvB,WAAW,EAAE,oBAAoB;QACjC,IAAI,EAAE,YAAqB;KAC5B;CACF,CAAC;AAEF,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,uFAAuF,EAAE,KAAK,IAAI,EAAE;QACrG,MAAM,MAAM,GAAG,MAAM,aAAa,EAAE,CAAC;QACrC,MAAM,MAAM,GAAG,EAAE,WAAW,EAAE,qBAAqB,EAA0B,CAAC;QAC9E,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAExE,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,SAAS,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;QAE7D,yFAAyF;QACzF,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACnD,MAAM,MAAM,CACV,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,CAAC,CAClE,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,WAAW,EAAE,qBAAqB,EAAE,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sFAAsF,EAAE,KAAK,IAAI,EAAE;QACpG,MAAM,MAAM,GAAG,MAAM,aAAa,EAAE,CAAC;QACrC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC,iBAAiB,CAC7D,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAChC,CAAC;QAEF,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,SAAS,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;QAE7D,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAC7F,oBAAoB,CACrB,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wEAAwE,EAAE,KAAK,IAAI,EAAE;QACtF,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,CAAC,YAAY,EAAE,EAAE;YAClD,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC;QACzD,CAAC,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,SAAS,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;QAE7D,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1,65 +0,0 @@
1
- import { enableTelemetry, } from '@equinor/fusion-framework-module-telemetry';
2
- /**
3
- * Runs the telemetry wiring, the caller's configuration callback and module
4
- * initialization against an already constructed configurator.
5
- *
6
- * @remarks
7
- * Extracted so `mockAppModules` (`@equinor/fusion-framework-app/mock`) can drive the
8
- * exact same pipeline against an `AppMockConfigurator` instead of reimplementing
9
- * it — the same way `FrameworkConfigurator` and `FrameworkMockConfigurator`
10
- * share the framework's `init`.
11
- *
12
- * @param configurator - The (real or mock) app configurator to run the pipeline on.
13
- * @param cb - Configuration callback invoked before module initialization, or `undefined` to skip it.
14
- * @param args - Object containing the Fusion instance and the application environment.
15
- * @returns The fully initialized application module instance.
16
- * @template TModules - Application module descriptors beyond the default set.
17
- * @template TRef - The parent Fusion instance type.
18
- * @template TEnv - The application environment descriptor.
19
- * @template TConfigurator - The (real or mock) `AppConfigurator` subclass driving the pipeline.
20
- */
21
- export async function initializeAppModules(configurator, cb, args) {
22
- const { fusion } = args;
23
- // Extract telemetry metadata from app manifest for tracking and debugging
24
- const metadataExtractor = () => {
25
- return {
26
- fusion: {
27
- type: 'app-telemetry',
28
- app: {
29
- key: args.env.manifest?.appKey || 'unknown-app',
30
- version: args.env.manifest?.build?.version || 'unknown-version',
31
- },
32
- },
33
- };
34
- };
35
- // Enable telemetry collection for module configuration events
36
- // attachConfiguratorEvents automatically prefixes events with configurator class name
37
- enableTelemetry(configurator, {
38
- attachConfiguratorEvents: true,
39
- configure: (builder) => {
40
- builder.setMetadata(metadataExtractor);
41
- builder.setParent(fusion.modules.telemetry);
42
- // Scope telemetry to 'app' level for app-specific event filtering
43
- builder.setDefaultScope(['app']);
44
- },
45
- });
46
- // Allow user configuration callback to run before module initialization
47
- if (cb) {
48
- await Promise.resolve(cb(configurator, args));
49
- }
50
- // Type cast is safe because AppConfigurator.initialize() returns the exact module
51
- // instance that was registered and configured above. The intermediate 'unknown'
52
- // cast is necessary due to TypeScript's generic inference limitations with the
53
- // configurator's initialization chain, but the runtime value is guaranteed to match.
54
- const modules = (await configurator.initialize(args.fusion.modules));
55
- // Dispatch app modules loaded event for app lifecycle tracking
56
- // TODO(#5061): remove check after fusion-cli is updated (app module is not enabled in fusion-cli)
57
- if (args.env.manifest?.appKey) {
58
- modules.event.dispatchEvent('onAppModulesLoaded', {
59
- detail: { appKey: args.env.manifest.appKey, manifest: args.env.manifest, modules },
60
- });
61
- }
62
- return modules;
63
- }
64
- export default initializeAppModules;
65
- //# sourceMappingURL=initialize-app-modules.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"initialize-app-modules.js","sourceRoot":"","sources":["../../src/initialize-app-modules.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,eAAe,GAEhB,MAAM,4CAA4C,CAAC;AAKpD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAaxC,YAA2B,EAC3B,EAEa,EACb,IAAiC;IAEjC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAExB,0EAA0E;IAC1E,MAAM,iBAAiB,GAAsB,GAAG,EAAE;QAChD,OAAO;YACL,MAAM,EAAE;gBACN,IAAI,EAAE,eAAe;gBACrB,GAAG,EAAE;oBACH,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,IAAI,aAAa;oBAC/C,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,IAAI,iBAAiB;iBAChE;aACF;SACF,CAAC;IACJ,CAAC,CAAC;IAEF,8DAA8D;IAC9D,sFAAsF;IACtF,eAAe,CAAC,YAAY,EAAE;QAC5B,wBAAwB,EAAE,IAAI;QAC9B,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE;YACrB,OAAO,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC;YACvC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAC5C,kEAAkE;YAClE,OAAO,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QACnC,CAAC;KACF,CAAC,CAAC;IAEH,wEAAwE;IACxE,IAAI,EAAE,EAAE,CAAC;QACP,MAAM,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC,CAAC;IAChD,CAAC;IACD,kFAAkF;IAClF,gFAAgF;IAChF,+EAA+E;IAC/E,qFAAqF;IACrF,MAAM,OAAO,GAAiC,CAAC,MAAM,YAAY,CAAC,UAAU,CAC1E,IAAI,CAAC,MAAM,CAAC,OAAO,CACpB,CAA4C,CAAC;IAE9C,+DAA+D;IAC/D,kGAAkG;IAClG,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;QAC9B,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,oBAAoB,EAAE;YAChD,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE;SACnF,CAAC,CAAC;IACL,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,eAAe,oBAAoB,CAAC"}
@@ -1,183 +0,0 @@
1
- import http from '@equinor/fusion-framework-module-http';
2
- import { msalMockModule, } from '@equinor/fusion-framework-module-msal/mock';
3
- import { AppConfigurator } from '../AppConfigurator.js';
4
- /**
5
- * The real `AppConfigurator`, with the `msal` module it registers backed by
6
- * the same test double `FrameworkMockConfigurator` uses. `http` is the real
7
- * module — fake a response by registering a short-circuiting middleware
8
- * through `.http.addMiddleware(...)` instead of swapping the module out.
9
- *
10
- * @remarks
11
- * Nothing else changes: the same module set (`event`, `http`, `msal`), the same
12
- * configuration pipeline and the same lifecycle are used. `configureHttpClient`,
13
- * `useFrameworkServiceClient` and any callback written for a real
14
- * `AppConfigurator` work against this unchanged.
15
- *
16
- * `http` and `msal` are pinned early — mirroring `FrameworkMockConfigurator`,
17
- * one level down — so `.http` and `.msal` are reachable synchronously, before
18
- * `useFrameworkServiceClient` or a `configureModules` callback ever runs.
19
- * `event` is deliberately not pinned, for the same reason it isn't in
20
- * `FrameworkMockConfigurator`: its `configure` factory reads `ref` to wire
21
- * bubbling to a parent event provider, and pinning would freeze that decision
22
- * before a `ref` could ever be known.
23
- *
24
- * @typeParam TModules - Module descriptors beyond the default set. Supply this
25
- * when a test registers application modules, so they are typed on the result.
26
- * @typeParam TRef - The resolved Fusion modules instance used as a reference during initialization.
27
- * @typeParam TEnv - The application environment descriptor.
28
- *
29
- * @example
30
- * ```typescript
31
- * const manifest = { appKey: 'my-app', displayName: 'My App', description: 'My app', type: 'standalone' } as const;
32
- * const configurator = new AppMockConfigurator({ manifest });
33
- *
34
- * configurator.configureHttpClient('catalog', { baseUri: 'https://api.example.com' });
35
- * configurator.http.addMiddleware(async (uri, init, next) =>
36
- * uri === 'https://api.example.com/items' ? Response.json([{ id: 1 }]) : next(uri, init),
37
- * );
38
- * ```
39
- */
40
- export class AppMockConfigurator extends AppConfigurator {
41
- static className = 'AppMockConfigurator';
42
- // Keyed by module name, so `_getConfig` can look a pinned configurator up
43
- // without needing the module descriptor again.
44
- #configurators = new Map();
45
- // Keyed by module name, so `addConfig` can redirect a registration at the
46
- // pinned descriptor instead of the unpinned one it was given.
47
- #pinnedModules = new Map();
48
- /**
49
- * Creates an app configurator backed by the built-in mock modules.
50
- *
51
- * @param env - The application environment containing manifest, config, and optional basename.
52
- */
53
- constructor(env) {
54
- super(env);
55
- // Pinning up front replaces the modules AppConfigurator's own constructor
56
- // already registered, whether or not a test ever touches the accessor.
57
- this._pin(http);
58
- this._pin(msalMockModule);
59
- // deferred from AppConfigurator's own constructor (see the override below) until
60
- // after pinning, so endpoint-derived clients register against the pinned http module
61
- super._configureHttpClientsFromAppConfig();
62
- }
63
- /**
64
- * No-ops the base constructor's own call to this, since it would otherwise run
65
- * before {@link _pin} has anything to redirect `addConfig` at; this class calls
66
- * {@link AppConfigurator._configureHttpClientsFromAppConfig} itself once pinned.
67
- */
68
- _configureHttpClientsFromAppConfig() { }
69
- /**
70
- * Registers a module configurator, redirecting registrations for a pinned module
71
- * at its pinned descriptor.
72
- *
73
- * @remarks
74
- * `configureHttpClient`, `useFrameworkServiceClient` and similar helpers always
75
- * pass the real, unpinned module descriptor — the base `addConfig` replaces a
76
- * module's descriptor whenever it doesn't recognize the object it's given, even
77
- * under the same name, which would otherwise silently un-pin it.
78
- *
79
- * @param config - The module configurator descriptor to register.
80
- * @template T - The module type being configured.
81
- * @template TConfig - The resolved configuration type for the module.
82
- */
83
- addConfig(config) {
84
- const pinnedModule = this.#pinnedModules.get(config.module.name);
85
- super.addConfig(pinnedModule ? { ...config, module: pinnedModule } : config);
86
- }
87
- /**
88
- * Pins a module to a single configurator instance for the lifetime of this
89
- * configurator, so it can be reached by name through {@link _getConfig}.
90
- *
91
- * @remarks
92
- * The module system otherwise builds a fresh configurator from its own
93
- * `configure` factory during the configure phase — too late for a test to
94
- * reach, and a new instance on every call besides. This replaces that factory
95
- * with one that always returns the same instance, and registers the result
96
- * under the module's own name.
97
- *
98
- * An application module supplied through {@link TModules} uses this the same
99
- * way `.http` and `.msal` do, to expose its own named accessor:
100
- *
101
- * ```typescript
102
- * class MyAppMockConfigurator extends AppMockConfigurator<[WidgetsModule]> {
103
- * constructor(env: AppEnv) {
104
- * super(env);
105
- * this._pin(widgetsMockModule);
106
- * }
107
- *
108
- * public get widgets(): WidgetsMockConfigurator {
109
- * return this._getConfig('widgets');
110
- * }
111
- * }
112
- * ```
113
- *
114
- * @param module - The module descriptor to pin a configurator for.
115
- * @template TModule - The specific module descriptor type being pinned.
116
- * @throws {Error} If the module declares no `configure` factory to pin, or
117
- * the factory returns a promise instead of a configurator — pinning is
118
- * synchronous, so a test can reach the accessor immediately.
119
- */
120
- _pin(module) {
121
- // A module without a configure factory has nothing this method could pin
122
- if (!module.configure) {
123
- throw new Error(`Cannot pin "${module.name}": it declares no configure factory.`);
124
- }
125
- const instance = module.configure();
126
- // Async factories would make the pinned instance unavailable until the module system
127
- // resolves it later, defeating the point of pinning it for immediate synchronous access
128
- if (instance instanceof Promise) {
129
- throw new Error(`Cannot pin "${module.name}": its configure factory returns a promise, so it cannot be resolved synchronously.`);
130
- }
131
- this.#configurators.set(module.name, instance);
132
- const pinnedModule = { ...module, configure: () => instance };
133
- this.#pinnedModules.set(module.name, pinnedModule);
134
- this.addConfig({ module: pinnedModule });
135
- }
136
- /**
137
- * Returns the configurator pinned for a module by name.
138
- *
139
- * @param name - The module's name, as passed to {@link _pin}.
140
- * @template TConfig - The specific configurator type expected for this module.
141
- * @returns The configurator pinned under `name`.
142
- * @throws {Error} If no configurator has been pinned for that name.
143
- */
144
- _getConfig(name) {
145
- const config = this.#configurators.get(name);
146
- // A missing entry means _pin was never called for this module name
147
- if (config === undefined) {
148
- throw new Error(`No configurator is pinned for module "${name}" — call this._pin(module) before this._getConfig("${name}").`);
149
- }
150
- return config;
151
- }
152
- /**
153
- * Configures the app's named HTTP clients.
154
- *
155
- * @remarks
156
- * The same {@link IHttpClientConfigurator} the `http` module is configured
157
- * from — the real one, not a test double. Every client it builds —
158
- * including ones registered through
159
- * {@link AppConfigurator.configureHttpClient} or
160
- * {@link AppConfigurator.useFrameworkServiceClient} — is reachable here to
161
- * register a short-circuiting {@link HttpMiddleware} through
162
- * `addMiddleware`, so it answers from that instead of the network.
163
- *
164
- * @returns The real HTTP configurator.
165
- */
166
- get http() {
167
- return this._getConfig(http.name);
168
- }
169
- /**
170
- * Configures the user the app's `msal` module signs in.
171
- *
172
- * @remarks
173
- * The same {@link MsalMockConfigurator} the `msal` module is configured from,
174
- * so a change made here is what the module sees.
175
- *
176
- * @returns The MSAL mock configurator.
177
- */
178
- get msal() {
179
- return this._getConfig(msalMockModule.name);
180
- }
181
- }
182
- export default AppMockConfigurator;
183
- //# sourceMappingURL=AppMockConfigurator.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AppMockConfigurator.js","sourceRoot":"","sources":["../../../src/mock/AppMockConfigurator.ts"],"names":[],"mappings":"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"}