@equinor/fusion-framework-module-app 8.0.4 → 8.0.6-next.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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # Change Log
2
2
 
3
+ ## 8.0.6-next.0
4
+
5
+ ### Patch Changes
6
+
7
+ - c8008e3: Internal: rebase `next` onto `main`, syncing in already-published stable releases so they carry a `next` pre-release tag.
8
+
9
+ ## 8.0.5
10
+
11
+ ### Patch Changes
12
+
13
+ - 4a00a7a: Internal: address fusion-lint warnings — mark `FrameworkOptionsSchema` as intentionally co-located per the file's existing convention, and add intent comments to `NavigationProvider`'s path-normalization loops.
14
+
3
15
  ## 8.0.4
4
16
 
5
17
  ### Patch Changes
package/README.md CHANGED
@@ -117,6 +117,36 @@ All API requests map HTTP status codes to typed error classes:
117
117
 
118
118
  Each error includes a `type` property (`'not_found'`, `'unauthorized'`, `'deleted'`, or `'unknown'`) for programmatic handling.
119
119
 
120
+ ## Testing
121
+
122
+ Import from `@equinor/fusion-framework-module-app/mock` to serve one app's manifest
123
+ and config locally instead of contacting the app service. The real `AppClient`
124
+ still backs every other request — other app keys, tagged requests, builds,
125
+ settings — so pointing `setClient` at a different http client or service
126
+ discovery registry keeps working unchanged.
127
+
128
+ ```ts
129
+ import { MockAppClient } from '@equinor/fusion-framework-module-app/mock';
130
+
131
+ enableAppModule(configurator, (builder) => {
132
+ builder.setClient(async ({ requireInstance }) => {
133
+ const http = await requireInstance('http');
134
+ return new MockAppClient(http.createClient('apps'), manifest, config);
135
+ });
136
+ });
137
+ ```
138
+
139
+ `getAppManifest` only resolves locally for `manifest.appKey` with no `tag` at
140
+ all. `getAppConfig` resolves for `manifest.appKey` when `tag` is either absent
141
+ or equal to the manifest's own `build.version` — the same tag `App` requests
142
+ when loading config for the manifest it already resolved. Any other app key,
143
+ tag, or the wrong request falls through to the real client.
144
+
145
+ > [!NOTE]
146
+ > `@equinor/fusion-framework-app/mock`'s `mockAppModules` builds on top of this
147
+ > class and is usually the simpler entry point for testing an application —
148
+ > see its [Testing](../../app/docs/testing.md) guide.
149
+
120
150
  ## Main Exports
121
151
 
122
152
  | Export | Description |
@@ -127,4 +157,5 @@ Each error includes a `type` property (`'not_found'`, `'unauthorized'`, `'delete
127
157
  | `AppConfigurator` | Configuration builder for module setup |
128
158
  | `AppConfig` | Immutable app configuration (env + endpoints) |
129
159
  | `App` / `IApp` | Application instance with reactive state |
130
- | `AppModule` | Module definition for the framework |
160
+ | `AppModule` | Module definition for the framework |
161
+ | `MockAppClient` | Test double serving one app's manifest and config locally (`/mock`) |
@@ -0,0 +1,36 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { mockFramework } from '@equinor/fusion-framework/mock';
3
+ import { createRouterMiddleware } from '@equinor/fusion-framework-module-http/mock';
4
+ import { enableAppModule } from '../enable-app-module';
5
+ /**
6
+ * Boots a full portal-shaped framework instance the same way `packages/dev-portal`'s
7
+ * `configure.ts` does — `enableAppModule` registered directly on the portal's own
8
+ * configurator, alongside its real `http`, `event`, `msal`, etc. — rather than a
9
+ * standalone module graph assembled just for this test. Only the network call
10
+ * itself is faked; the app module creates its client eagerly during its own
11
+ * `requireInstance('http')` in the SAME configure→initialize pipeline, so this also
12
+ * verifies middleware registered before `initialize()` reaches that client.
13
+ */
14
+ const initializePortalWith = () => mockFramework((configurator) => {
15
+ configurator.http.configureClient('apps', { baseUri: 'https://apps.example.com' });
16
+ configurator.http.addMiddleware(createRouterMiddleware('https://apps.example.com', (router) => {
17
+ router.get('/persons/me/apps/:appKey', ({ params }) => Response.json({
18
+ appKey: params.appKey,
19
+ displayName: 'Test App',
20
+ description: 'A test application',
21
+ type: 'standalone',
22
+ }));
23
+ }));
24
+ enableAppModule(configurator);
25
+ });
26
+ describe('AppModuleProvider', () => {
27
+ it("fetches the manifest through the portal's own http client once a current app is set", async () => {
28
+ const fusion = await initializePortalWith();
29
+ fusion.modules.app.setCurrentApp('test-app');
30
+ await expect(fusion.modules.app.current?.getManifestAsync()).resolves.toMatchObject({
31
+ appKey: 'test-app',
32
+ displayName: 'Test App',
33
+ });
34
+ });
35
+ });
36
+ //# sourceMappingURL=AppModuleProvider.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AppModuleProvider.test.js","sourceRoot":"","sources":["../../../src/__tests__/AppModuleProvider.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,4CAA4C,CAAC;AAEpF,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAGvD;;;;;;;;GAQG;AACH,MAAM,oBAAoB,GAAG,GAAG,EAAE,CAChC,aAAa,CAAc,CAAC,YAAY,EAAE,EAAE;IAC1C,YAAY,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,0BAA0B,EAAE,CAAC,CAAC;IACnF,YAAY,CAAC,IAAI,CAAC,aAAa,CAC7B,sBAAsB,CAAC,0BAA0B,EAAE,CAAC,MAAM,EAAE,EAAE;QAC5D,MAAM,CAAC,GAAG,CAAC,0BAA0B,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CACpD,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,WAAW,EAAE,UAAU;YACvB,WAAW,EAAE,oBAAoB;YACjC,IAAI,EAAE,YAAY;SACnB,CAAC,CACH,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;IACF,eAAe,CAAC,YAAY,CAAC,CAAC;AAChC,CAAC,CAAC,CAAC;AAEL,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,qFAAqF,EAAE,KAAK,IAAI,EAAE;QACnG,MAAM,MAAM,GAAG,MAAM,oBAAoB,EAAE,CAAC;QAE5C,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;QAE7C,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,gBAAgB,EAAE,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC;YAClF,MAAM,EAAE,UAAU;YAClB,WAAW,EAAE,UAAU;SACxB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,70 @@
1
+ import { firstValueFrom, of } from 'rxjs';
2
+ import { describe, expect, it, vi } from 'vitest';
3
+ import { AppClient } from '../AppClient.js';
4
+ import { AppConfig } from '../AppConfig.js';
5
+ import { MockAppClient } from '../mock/MockAppClient.js';
6
+ const manifest = {
7
+ appKey: 'my-app',
8
+ displayName: 'My App',
9
+ description: 'My app',
10
+ type: 'standalone',
11
+ build: { version: '1.2.3', entryPoint: 'index.js' },
12
+ };
13
+ const config = new AppConfig({ environment: { key: 'value' } });
14
+ // never invoked directly -- both overrides either answer locally or delegate through
15
+ // the spied `AppClient.prototype` methods below, so the real client is never called
16
+ const client = {};
17
+ describe('MockAppClient', () => {
18
+ describe('getAppManifest', () => {
19
+ it('answers locally for its own app key with no tag', async () => {
20
+ const mockClient = new MockAppClient(client, manifest);
21
+ const result = mockClient.getAppManifest({ appKey: 'my-app' });
22
+ await expect(firstValueFrom(result)).resolves.toBe(manifest);
23
+ });
24
+ it('delegates for its own app key with an explicit empty-string tag', () => {
25
+ const delegate = vi
26
+ .spyOn(AppClient.prototype, 'getAppManifest')
27
+ .mockReturnValue(of(manifest));
28
+ const mockClient = new MockAppClient(client, manifest);
29
+ mockClient.getAppManifest({ appKey: 'my-app', tag: '' });
30
+ expect(delegate).toHaveBeenCalledWith({ appKey: 'my-app', tag: '' });
31
+ delegate.mockRestore();
32
+ });
33
+ it('delegates for a different app key', () => {
34
+ const delegate = vi
35
+ .spyOn(AppClient.prototype, 'getAppManifest')
36
+ .mockReturnValue(of(manifest));
37
+ const mockClient = new MockAppClient(client, manifest);
38
+ mockClient.getAppManifest({ appKey: 'other-app' });
39
+ expect(delegate).toHaveBeenCalledWith({ appKey: 'other-app' });
40
+ delegate.mockRestore();
41
+ });
42
+ });
43
+ describe('getAppConfig', () => {
44
+ it('answers locally for its own app key with no tag', async () => {
45
+ const mockClient = new MockAppClient(client, manifest, config);
46
+ const result = mockClient.getAppConfig({ appKey: 'my-app' });
47
+ await expect(firstValueFrom(result)).resolves.toBe(config);
48
+ });
49
+ it("answers locally for its own app key with a tag matching the manifest's build version", async () => {
50
+ const mockClient = new MockAppClient(client, manifest, config);
51
+ const result = mockClient.getAppConfig({ appKey: 'my-app', tag: '1.2.3' });
52
+ await expect(firstValueFrom(result)).resolves.toBe(config);
53
+ });
54
+ it('delegates for its own app key with an explicit empty-string tag', () => {
55
+ const delegate = vi.spyOn(AppClient.prototype, 'getAppConfig').mockReturnValue(of(config));
56
+ const mockClient = new MockAppClient(client, manifest, config);
57
+ mockClient.getAppConfig({ appKey: 'my-app', tag: '' });
58
+ expect(delegate).toHaveBeenCalledWith({ appKey: 'my-app', tag: '' });
59
+ delegate.mockRestore();
60
+ });
61
+ it('delegates for its own app key with a tag not matching the manifest build version', () => {
62
+ const delegate = vi.spyOn(AppClient.prototype, 'getAppConfig').mockReturnValue(of(config));
63
+ const mockClient = new MockAppClient(client, manifest, config);
64
+ mockClient.getAppConfig({ appKey: 'my-app', tag: '9.9.9' });
65
+ expect(delegate).toHaveBeenCalledWith({ appKey: 'my-app', tag: '9.9.9' });
66
+ delegate.mockRestore();
67
+ });
68
+ });
69
+ });
70
+ //# sourceMappingURL=MockAppClient.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MockAppClient.test.js","sourceRoot":"","sources":["../../../src/__tests__/MockAppClient.test.ts"],"names":[],"mappings":"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"}
package/dist/esm/index.js CHANGED
@@ -18,6 +18,7 @@
18
18
  */
19
19
  export { AppConfigurator, } from './AppConfigurator';
20
20
  export { AppClient } from './AppClient';
21
+ export { AppConfig } from './AppConfig';
21
22
  export { AppModuleProvider } from './AppModuleProvider';
22
23
  export * from './events';
23
24
  export * from './types';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAEL,eAAe,GAGhB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,SAAS,EAAmB,MAAM,aAAa,CAAC;AAEzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAIxD,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AAExB,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,OAAO,EAAa,MAAM,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAEL,eAAe,GAGhB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,SAAS,EAAmB,MAAM,aAAa,CAAC;AAEzD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAIxD,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AAExB,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,OAAO,EAAa,MAAM,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,65 @@
1
+ import { of } from 'rxjs';
2
+ import { AppClient } from '../AppClient.js';
3
+ /**
4
+ * An {@link AppClient} that answers `getAppManifest` and `getAppConfig` for one
5
+ * known app locally, delegating everything else — other app keys, tagged
6
+ * requests, builds, settings — to the real client it wraps.
7
+ *
8
+ * @remarks
9
+ * Whatever `client` was resolved to (a pre-configured http client, or one created
10
+ * through service discovery) still backs every method this class doesn't
11
+ * override, so pointing service discovery at a different registry or a real
12
+ * local mock server keeps working unchanged.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * builder.setClient(async ({ requireInstance }) => {
17
+ * const http = await requireInstance('http');
18
+ * return new MockAppClient(http.createClient('apps'), manifest, config);
19
+ * });
20
+ * ```
21
+ */
22
+ export class MockAppClient extends AppClient {
23
+ #manifest;
24
+ #config;
25
+ /**
26
+ * @param client - The real {@link IHttpClient} to delegate all other requests to.
27
+ * @param manifest - The manifest to return for `getAppManifest({ appKey: manifest.appKey })`.
28
+ * @param config - The config to return for `getAppConfig({ appKey: manifest.appKey })`, if any.
29
+ */
30
+ constructor(client, manifest, config) {
31
+ super(client);
32
+ this.#manifest = manifest;
33
+ this.#config = config;
34
+ }
35
+ /**
36
+ * Answers with the manifest passed to the constructor when `args` matches
37
+ * this client's own app key and no tag; otherwise delegates to the real client.
38
+ *
39
+ * @param args - The app key and optional tag to resolve a manifest for.
40
+ * @returns An observable of the resolved {@link AppManifest}.
41
+ */
42
+ getAppManifest(args) {
43
+ return args.appKey === this.#manifest.appKey && args.tag === undefined
44
+ ? of(this.#manifest)
45
+ : super.getAppManifest(args);
46
+ }
47
+ /**
48
+ * Answers with the config passed to the constructor when `args` matches this
49
+ * client's own app key and tag; otherwise delegates to the real client.
50
+ *
51
+ * @template TType - The shape of the config's `environment` data.
52
+ * @param args - The app key and optional tag to resolve config for.
53
+ * @returns An observable of the resolved {@link AppConfig}.
54
+ */
55
+ getAppConfig(args) {
56
+ // config is fetched against the manifest's own build version, not an explicit override tag,
57
+ // so a matching tag is treated the same as an absent one -- an explicit empty string is not
58
+ const isOwnTag = args.tag === undefined || args.tag === this.#manifest.build?.version;
59
+ return args.appKey === this.#manifest.appKey && isOwnTag && this.#config
60
+ ? of(this.#config)
61
+ : super.getAppConfig(args);
62
+ }
63
+ }
64
+ export default MockAppClient;
65
+ //# sourceMappingURL=MockAppClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MockAppClient.js","sourceRoot":"","sources":["../../../src/mock/MockAppClient.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,MAAM,MAAM,CAAC;AAI1B,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,OAAO,aAAc,SAAQ,SAAS;IAC1C,SAAS,CAAc;IACvB,OAAO,CAAa;IAEpB;;;;OAIG;IACH,YAAY,MAAmB,EAAE,QAAqB,EAAE,MAAkB;QACxE,KAAK,CAAC,MAAM,CAAC,CAAC;QACd,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;QAC1B,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IACxB,CAAC;IAED;;;;;;OAMG;IACM,cAAc,CAAC,IAAsC;QAC5D,OAAO,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS;YACpE,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC;YACpB,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IAED;;;;;;;OAOG;IACM,YAAY,CAAsD,IAG1E;QACC,4FAA4F;QAC5F,4FAA4F;QAC5F,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,KAAK,SAAS,IAAI,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC;QACtF,OAAO,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,QAAQ,IAAI,IAAI,CAAC,OAAO;YACtE,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,OAA2B,CAAC;YACtC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;CACF;AAED,eAAe,aAAa,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Test doubles for the app module.
3
+ *
4
+ * @remarks
5
+ * Imported from `@equinor/fusion-framework-module-app/mock`, so the mock ships
6
+ * and versions with the implementation it stands in for.
7
+ *
8
+ * This entry point has no dependency on any test runner.
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+ export { MockAppClient } from './MockAppClient.js';
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/mock/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
@@ -52,6 +52,27 @@ const ApiApplicationPersonSchema = z.object({
52
52
  })
53
53
  .nullish(),
54
54
  });
55
+ /**
56
+ * Schema for validating the options object on application builds.
57
+ *
58
+ * Known properties:
59
+ * - `contextRouting` (optional): Routing strategy for context — `'path'` or `'query'`.
60
+ *
61
+ * The schema uses `.catchall(z.unknown())` to permit additional properties
62
+ * at runtime without requiring them to be declared here. Add known properties
63
+ * to this schema as they are introduced.
64
+ */
65
+ // Deliberately co-located with ApiApplicationBuildSchema, which depends on it
66
+ // fusion-lint-disable-next-line single-export-per-file
67
+ export const FrameworkOptionsSchema = z
68
+ .object({
69
+ contextRouting: z
70
+ .enum(['path', 'query'], {
71
+ message: "The routing strategy for context, which can be either 'path' or 'query'.",
72
+ })
73
+ .nullish(),
74
+ })
75
+ .catchall(z.unknown());
55
76
  /**
56
77
  * Schema for validating the structure of an API application build.
57
78
  *
@@ -67,6 +88,7 @@ const ApiApplicationPersonSchema = z.object({
67
88
  * - `githubRepo`: An optional GitHub repository associated with the build.
68
89
  * - `projectPage`: An optional project page URL.
69
90
  * - `allowedExtensions`: An optional array of allowed extensions for the build.
91
+ * - `options`: An optional record of additional build options, where the key is a string and the value can be of any type.
70
92
  * - `uploadedBy`: An optional schema for the person who uploaded the build.
71
93
  */
72
94
  // Deliberately co-located with ApiApplicationPersonSchema, which it depends on
@@ -82,6 +104,9 @@ export const ApiApplicationBuildSchema = z.object({
82
104
  commitSha: z.string().nullish(),
83
105
  githubRepo: z.string().nullish(),
84
106
  projectPage: z.string().nullish(),
107
+ options: FrameworkOptionsSchema.nullish().default({
108
+ contextRouting: 'path',
109
+ }),
85
110
  allowedExtensions: z.array(z.string()).nullish(),
86
111
  uploadedBy: ApiApplicationPersonSchema.nullish(),
87
112
  });
@@ -1 +1 @@
1
- {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../src/schemas.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../src/schemas.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,3 @@
1
1
  // Generated by genversion.
2
- export const version = '8.0.4';
2
+ export const version = '8.0.6-next.0';
3
3
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,MAAM,CAAC,MAAM,OAAO,GAAG,cAAc,CAAC"}