@equinor/fusion-framework-dev-server 2.0.19 → 2.1.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.
@@ -0,0 +1 @@
1
+ export {};
@@ -63,7 +63,7 @@ export { UserConfig as DevServerOverrides } from 'vite';
63
63
  * };
64
64
  * ```
65
65
  */
66
- export type DevServerOptions<TEnv extends Partial<FusionTemplateEnv> = Partial<FusionTemplateEnv>> = {
66
+ export interface DevServerOptions<TEnv extends Partial<FusionTemplateEnv> = Partial<FusionTemplateEnv>> {
67
67
  /** SPA template settings. When provided, the dev server injects these values into the HTML template at serve time. */
68
68
  spa?: {
69
69
  /** Static environment object or factory function that produces it on each request. */
@@ -91,4 +91,4 @@ export type DevServerOptions<TEnv extends Partial<FusionTemplateEnv> = Partial<F
91
91
  /** Custom logger instance. When omitted a default {@link ConsoleLogger} is created. */
92
92
  logger?: ConsoleLogger;
93
93
  };
94
- };
94
+ }
@@ -1 +1 @@
1
- export declare const version = "2.0.19";
1
+ export declare const version = "2.1.0";
@@ -0,0 +1,79 @@
1
+ # Advanced usage
2
+
3
+ Use these extension points after the default discovery proxy and SPA environment work. Most
4
+ applications do not need custom service processing.
5
+
6
+ > [!IMPORTANT]
7
+ > These are not the primary service-mocking APIs. Define application mocks in
8
+ > `mocks/<service>.mock.ts` with `defineService`; use `processServices` only when a host must
9
+ > transform real discovery independently of mock behavior.
10
+
11
+ ## Transform discovered services
12
+
13
+ Call `processServices(data, args)` first, then transform its result. This preserves standard local
14
+ URI rewriting and proxy route generation.
15
+
16
+ ```typescript
17
+ import { createDevServer, processServices } from '@equinor/fusion-framework-dev-server';
18
+
19
+ const server = await createDevServer({
20
+ api: {
21
+ serviceDiscoveryUrl: 'https://service-discovery.example.com',
22
+ processServices: (data, args) => {
23
+ const processed = processServices(data, args);
24
+ return {
25
+ ...processed,
26
+ data: processed.data.filter((service) => service.key !== 'deprecated-service'),
27
+ };
28
+ },
29
+ },
30
+ });
31
+ ```
32
+
33
+ Throwing from a processor fails the discovery request. Validate upstream assumptions instead of
34
+ silently returning a partial service list.
35
+
36
+ > [!CAUTION]
37
+ > A custom processor replaces the default processing entry point. Call `processServices` first
38
+ > unless you intend to own all URI rewriting and proxy-route generation yourself.
39
+
40
+ ## Add Vite configuration
41
+
42
+ The second argument is merged over generated Vite configuration:
43
+
44
+ ```typescript
45
+ import { createDevServer } from '@equinor/fusion-framework-dev-server';
46
+ import myPlugin from 'my-vite-plugin';
47
+
48
+ const server = await createDevServer(
49
+ { api: { serviceDiscoveryUrl: 'https://service-discovery.example.com' } },
50
+ {
51
+ plugins: [myPlugin()],
52
+ server: { host: '0.0.0.0', port: 3001 },
53
+ },
54
+ );
55
+ ```
56
+
57
+ Prefer first-class `spa`, `api`, and `log` options when they cover the requirement. Use overrides
58
+ for Vite-owned behavior and additional plugins.
59
+
60
+ ## Own the Vite lifecycle
61
+
62
+ Use `createDevServerConfig` when a test harness or larger CLI creates Vite itself:
63
+
64
+ ```typescript
65
+ import { createDevServerConfig } from '@equinor/fusion-framework-dev-server';
66
+ import { createServer } from 'vite';
67
+
68
+ const config = createDevServerConfig({
69
+ api: { serviceDiscoveryUrl: 'https://service-discovery.example.com' },
70
+ });
71
+ const server = await createServer(config);
72
+ await server.listen();
73
+ ```
74
+
75
+ ## Extend `DevServerOptions`
76
+
77
+ Optional tooling can use declaration merging because `DevServerOptions` is an interface. Keep the
78
+ augmentation in the owning plugin and import that plugin's types where extended options are
79
+ authored. The mock-server plugin's `mockServer` section is the reference implementation.
@@ -0,0 +1,117 @@
1
+ # Configure the dev server
2
+
3
+ `DevServerOptions<TEnv>` has three base sections: `spa`, `api`, and `log`. Start with required
4
+ `api.serviceDiscoveryUrl`, then add browser environment and logging when your host needs them.
5
+
6
+ ## Configure the browser environment
7
+
8
+ `spa.templateEnv` can be a static object or a function. The SPA plugin serializes its value into
9
+ the page for browser-side Fusion modules.
10
+
11
+ ```typescript
12
+ const options = {
13
+ spa: {
14
+ templateEnv: {
15
+ portal: { id: 'my-portal' },
16
+ title: 'My application',
17
+ serviceDiscovery: {
18
+ url: 'https://service-discovery.example.com',
19
+ scopes: ['api://example.com/user_impersonation'],
20
+ },
21
+ msal: {
22
+ clientId: 'client-id',
23
+ tenantId: 'tenant-id',
24
+ redirectUri: '/authentication/login-callback',
25
+ requiresAuth: 'true',
26
+ },
27
+ },
28
+ },
29
+ };
30
+ ```
31
+
32
+ Use a factory when values come from a runtime source:
33
+
34
+ ```typescript
35
+ const options = {
36
+ spa: {
37
+ templateEnv: () => ({
38
+ title: 'Local application',
39
+ telemetry: { consoleLevel: 0 },
40
+ }),
41
+ },
42
+ };
43
+ ```
44
+
45
+ Browser telemetry and server logging use different scales. `telemetry.consoleLevel` controls the
46
+ browser console; `log.level` controls terminal output.
47
+
48
+ ## Configure service discovery and proxying
49
+
50
+ `api.serviceDiscoveryUrl` is the upstream endpoint the Node server fetches. The default
51
+ `processServices` rewrites each discovered URI to the local origin and creates a proxy route.
52
+
53
+ > [!WARNING]
54
+ > `spa.templateEnv.serviceDiscovery.url` configures the browser, while
55
+ > `api.serviceDiscoveryUrl` configures the Node proxy. Setting only one can produce a page that
56
+ > loads successfully but cannot resolve or proxy services.
57
+
58
+ ```typescript
59
+ const options = {
60
+ api: { serviceDiscoveryUrl: 'https://service-discovery.example.com' },
61
+ };
62
+ ```
63
+
64
+ Add `api.routes` for a small server-owned endpoint:
65
+
66
+ ```typescript
67
+ const options = {
68
+ api: {
69
+ serviceDiscoveryUrl: 'https://service-discovery.example.com',
70
+ routes: [
71
+ {
72
+ match: '/health',
73
+ middleware: (_request, response) => {
74
+ response.setHeader('content-type', 'application/json');
75
+ response.end(JSON.stringify({ status: 'ready' }));
76
+ },
77
+ },
78
+ ],
79
+ },
80
+ };
81
+ ```
82
+
83
+ Prefer executable `mocks/<service>.mock.ts` modules from the
84
+ [mock-server guide](mocking.md) for local services. Reserve `api.routes` for server-owned behavior
85
+ that is not a service mock; do not reproduce OpenAPI operations as handwritten dev-server
86
+ middleware.
87
+
88
+ ## Configure terminal logging
89
+
90
+ ```typescript
91
+ const options = {
92
+ api: { serviceDiscoveryUrl: 'https://service-discovery.example.com' },
93
+ log: { level: 4 },
94
+ };
95
+ ```
96
+
97
+ Server levels are `0` None, `1` Error, `2` Warning, `3` Info, and `4` Debug. Info is the default.
98
+ Supply `log.logger` when a host already owns a configured `ConsoleLogger` hierarchy.
99
+
100
+ ## Extend configuration from optional plugins
101
+
102
+ `DevServerOptions` is an interface so optional packages can contribute configuration without the
103
+ base package depending on them. Importing the mock-server plugin types adds `mockServer`:
104
+
105
+ ```typescript
106
+ import type {} from '@equinor/fusion-framework-cli-plugin-mock-server';
107
+ import type { DevServerOptions } from '@equinor/fusion-framework-dev-server';
108
+
109
+ const options: DevServerOptions = {
110
+ api: { serviceDiscoveryUrl: 'https://service-discovery.example.com' },
111
+ mockServer: { path: 'mocks', port: 4010, seed: 42 },
112
+ };
113
+ ```
114
+
115
+ > [!TIP]
116
+ > This empty type import activates TypeScript declaration merging: it adds `mockServer` to
117
+ > `DevServerOptions` for type checking without producing a runtime import.
@@ -0,0 +1,82 @@
1
+ # Getting started
2
+
3
+ Use `@equinor/fusion-framework-dev-server` to create a Fusion-aware Vite server programmatically.
4
+ Application projects that only need to run locally should prefer `ffc app dev`, which builds on
5
+ these lower-level primitives and supplies application conventions.
6
+
7
+ ## Install the package
8
+
9
+ ```sh
10
+ pnpm add -D @equinor/fusion-framework-dev-server vite
11
+ ```
12
+
13
+ The package supports Vite 7 and 8.
14
+
15
+ ## Understand the request flow
16
+
17
+ ```mermaid
18
+ flowchart LR
19
+ Browser[Browser application] -->|reads template environment| SPA[SPA configuration]
20
+ Browser -->|calls local service URI| Proxy[Development server proxy]
21
+ Proxy -->|fetches service list| Discovery[Fusion service discovery]
22
+ Proxy -->|forwards API request| Backend[Backend service]
23
+ ```
24
+
25
+ `spa.templateEnv.serviceDiscovery` tells browser-side Fusion modules where discovery is.
26
+ `api.serviceDiscoveryUrl` tells the Node server where to fetch services before rewriting them
27
+ through local proxy routes. Keeping the roles separate supports custom portals and proxy setups.
28
+
29
+ ## Create the server
30
+
31
+ ```typescript
32
+ import { createDevServer } from '@equinor/fusion-framework-dev-server';
33
+
34
+ const server = await createDevServer({
35
+ spa: {
36
+ templateEnv: {
37
+ portal: { id: 'my-portal' },
38
+ title: 'My application',
39
+ serviceDiscovery: { url: 'https://service-discovery.example.com', scopes: [] },
40
+ msal: {
41
+ clientId: 'client-id',
42
+ tenantId: 'tenant-id',
43
+ redirectUri: '/authentication/login-callback',
44
+ requiresAuth: 'true',
45
+ },
46
+ },
47
+ },
48
+ api: { serviceDiscoveryUrl: 'https://service-discovery.example.com' },
49
+ });
50
+
51
+ await server.listen();
52
+ server.printUrls();
53
+ ```
54
+
55
+ > [!NOTE]
56
+ > `createDevServer` returns a Vite server but does not call `listen()`. Your command chooses when
57
+ > startup happens and how startup failures are handled.
58
+
59
+ ## Generate configuration instead
60
+
61
+ Use `createDevServerConfig` when another tool owns the Vite lifecycle:
62
+
63
+ ```typescript
64
+ import { createDevServerConfig } from '@equinor/fusion-framework-dev-server';
65
+ import { createServer } from 'vite';
66
+
67
+ const config = createDevServerConfig({
68
+ api: { serviceDiscoveryUrl: 'https://service-discovery.example.com' },
69
+ });
70
+
71
+ const server = await createServer(config);
72
+ await server.listen();
73
+ ```
74
+
75
+ The generated configuration includes React Fast Refresh, SPA template injection, service
76
+ discovery proxying, and the default logger.
77
+
78
+ ## Next steps
79
+
80
+ - [Configure the dev server](configuration.md) for environment factories, API routes, and logs.
81
+ - [Develop with mock services](mocking.md) for local or deterministic backends.
82
+ - [Advanced usage](advanced.md) for discovery transforms and Vite plugins.
@@ -0,0 +1,229 @@
1
+ # Develop with mock services
2
+
3
+ Use `@equinor/fusion-framework-cli-plugin-mock-server` when a Fusion application needs a local,
4
+ deterministic, or not-yet-deployed backend. The plugin adds `ffc mock-server`; it does not change
5
+ the base dev-server runtime or start a background process automatically.
6
+
7
+ The recommended application workflow has three parts:
8
+
9
+ 1. Create `mocks/<service>.mock.ts` with `defineService`.
10
+ 2. Run `ffc mock-server` in a foreground terminal.
11
+ 3. Run `ffc app dev` for real discovery plus local overrides, or `ffc app dev --mock` for an
12
+ isolated mock environment.
13
+
14
+ > [!IMPORTANT]
15
+ > Keep service mock behavior in `<service>.mock.ts`, not `dev-server.config.ts`. The executable
16
+ > module is reusable by local development, Playwright, and the programmatic mock server. Reserve
17
+ > `api.routes` and `api.processServices` for advanced server infrastructure and discovery
18
+ > transformations that are not service mocks.
19
+
20
+ ## Migrate existing dev-server configuration
21
+
22
+ Migrate one service at a time. Move behavior owned by a backend service into
23
+ `mocks/<service>.mock.ts`; keep host-level behavior in `dev-server.config.ts`.
24
+
25
+ | Existing configuration | New location | Use when |
26
+ | --- | --- | --- |
27
+ | `api.processServices` adds or redirects one service | `serviceDiscovery` in `<service>.mock.ts` | The change exists only to make that service available locally. |
28
+ | `api.routes` returns a mocked OpenAPI operation | `routes` in `<service>.mock.ts` | The path and method belong to the service's OpenAPI contract. |
29
+ | `api.routes` implements request-aware service behavior | `middleware` in `<service>.mock.ts` | The behavior needs request headers, parameters, or a parsed body. |
30
+ | Schema faker overrides | `components` in `<service>.mock.ts` | Generated OpenAPI responses need deterministic field values. |
31
+ | Filtering or rewriting real discovery for the whole host | Keep `api.processServices` | The transformation is infrastructure behavior rather than a service mock. |
32
+ | Dev-server health checks or other host-owned endpoints | Keep `api.routes` | The route belongs to the local host, not to one backend service. |
33
+
34
+ For example, a legacy configuration might replace the generated proxy route for an existing
35
+ `inventory` service with a local response:
36
+
37
+ ```typescript
38
+ // dev-server.config.ts
39
+ import { defineDevServerConfig, processServices } from '@equinor/fusion-framework-cli/dev-server';
40
+
41
+ export default defineDevServerConfig(() => ({
42
+ api: {
43
+ processServices: (services, args) => {
44
+ const processed = processServices(services, args);
45
+ return {
46
+ ...processed,
47
+ routes: [
48
+ ...processed.routes.filter((route) => route.match !== '/inventory/api*sub'),
49
+ {
50
+ match: '/inventory/api*sub',
51
+ middleware: (_request, response) => {
52
+ response.setHeader('content-type', 'application/json');
53
+ response.end(JSON.stringify([{ id: 'local-item', name: 'Local item' }]));
54
+ },
55
+ },
56
+ ],
57
+ };
58
+ },
59
+ },
60
+ }));
61
+ ```
62
+
63
+ Move that service-owned response into an executable mock module. Paths in `routes` are relative to
64
+ the service and must match an operation in its OpenAPI document:
65
+
66
+ ```typescript
67
+ // mocks/inventory.mock.ts
68
+ import schema from './inventory.openapi.json' with { type: 'json' };
69
+ import { defineService } from '@equinor/fusion-openapi-mock-server/discovery';
70
+
71
+ export default defineService({
72
+ key: 'inventory',
73
+ serviceDiscovery: 'replace',
74
+ schema,
75
+ routes: {
76
+ '/items': {
77
+ get: {
78
+ mock: [{ id: 'local-item', name: 'Local item' }],
79
+ },
80
+ },
81
+ },
82
+ });
83
+ ```
84
+
85
+ `'replace'` is appropriate because the module carries a complete schema and deliberately replaces
86
+ the real discovery entry during normal development or a same-key preset in isolated mode. Use
87
+ `'merge'` only when a selected preset or earlier local mock layer already supplies the service and
88
+ schema; the standalone mock server never inherits schemas from remote discovery. Use `'new'` with
89
+ a `schema` for a pre-production service, or `false` with a `schema` for a direct-only endpoint.
90
+
91
+ Complete the migration:
92
+
93
+ 1. Install `@equinor/fusion-framework-cli-plugin-mock-server` and
94
+ `@equinor/fusion-openapi-mock-server` as development dependencies.
95
+ 2. Start `ffc mock-server` in a foreground terminal.
96
+ 3. Run `ffc app dev` to combine real discovery with local definitions, or use
97
+ `ffc app dev --mock http://localhost:4010` for an isolated environment.
98
+ 4. Verify the migrated service, then remove only its old `api.routes` and `api.processServices`
99
+ branches. Leave unrelated host-level configuration in place.
100
+
101
+ During an incremental migration, migrated and legacy services can coexist. Do not define the same
102
+ service behavior in both places; route precedence can hide which implementation handled a request.
103
+
104
+ ## Install and start the mock server
105
+
106
+ ```sh
107
+ pnpm add -D @equinor/fusion-framework-cli-plugin-mock-server
108
+ ffc mock-server
109
+ ```
110
+
111
+ > [!IMPORTANT]
112
+ > Keep this foreground process running in one terminal and start the application in another. The
113
+ > plugin intentionally does not create an unowned background process.
114
+
115
+ Check that startup completed before connecting the app:
116
+
117
+ ```sh
118
+ curl http://localhost:4010/@fusion-mock/health
119
+ ```
120
+
121
+ > [!TIP]
122
+ > Use the health endpoint as the `url` readiness check in Playwright's `webServer` configuration.
123
+
124
+ ## Define one executable module per service
125
+
126
+ ```text
127
+ mocks/
128
+ inventory.mock.ts
129
+ inventory.openapi.json
130
+ ```
131
+
132
+ ```typescript
133
+ import schema from './inventory.openapi.json' with { type: 'json' };
134
+ import { defineService } from '@equinor/fusion-openapi-mock-server/discovery';
135
+
136
+ export default defineService({
137
+ key: 'inventory',
138
+ serviceDiscovery: 'new',
139
+ schema,
140
+ components: {
141
+ InventoryItem: { name: () => 'Local item' },
142
+ },
143
+ });
144
+ ```
145
+
146
+ The module keeps service ownership, schema, deterministic fields, routes, and middleware in one
147
+ retrieval-friendly place.
148
+
149
+ This example uses `'new'` because `inventory` is not registered yet; startup fails if the key later
150
+ appears in real discovery. Use `'merge'` only when a selected preset or earlier local mock layer
151
+ already provides the service schema and only selected local behavior should change.
152
+
153
+ ## Choose the development mode
154
+
155
+ ### Combine real discovery with selected local services
156
+
157
+ ```sh
158
+ ffc mock-server
159
+ ffc app dev
160
+ ```
161
+
162
+ Normal development fetches real discovery and overlays discovery-visible local definitions by
163
+ service key. Use this when most real backends remain useful.
164
+
165
+ ### Use only predefined and local mocks
166
+
167
+ ```sh
168
+ ffc mock-server
169
+ ffc app dev --mock http://localhost:4010
170
+ ```
171
+
172
+ `--mock` points application discovery at the standalone server. The mock server never fetches real
173
+ service discovery; it resolves only bundled presets and local modules. Use this for isolated
174
+ development, CI, and browser tests.
175
+
176
+ > [!WARNING]
177
+ > `--mock` is intentionally isolated. A service missing from the bundled presets and local modules
178
+ > will not fall back to remote service discovery.
179
+
180
+ A preset is a built-in group of service definitions. The default `fusion` preset supplies common
181
+ services that framework modules resolve during startup. Local modules are layered after presets,
182
+ so app-specific behavior can override the baseline.
183
+
184
+ ## Choose a discovery mode
185
+
186
+ | Mode | Developer scenario |
187
+ | --- | --- |
188
+ | `'merge'` | Override selected behavior of a service supplied by a selected preset or earlier local mock layer while inheriting its schema. Remote discovery alone is not a merge source. |
189
+ | `'new'` | Add a pre-production service expected to enter real discovery before release. Definition resolution fails if the key already exists in discovery or an earlier mock layer. |
190
+ | `'replace'` | Supply a complete local definition and deliberately replace an earlier same-key definition. |
191
+ | `false` | Serve an app-owned endpoint without advertising it through discovery. Configure its `<key>.localhost` mock URL directly in environment-specific app config. |
192
+
193
+ > [!CAUTION]
194
+ > Use `'new'` only as a temporary pre-production contract. Once the real service key appears,
195
+ > definition resolution fails on purpose; register the backend before release and remove or change
196
+ > the local definition.
197
+
198
+ For example, a service with key `my-api` and `serviceDiscovery: false` is still served at
199
+ `http://my-api.localhost:4010`; it is simply absent from `/@fusion-mock/discovery`. This mirrors an
200
+ application-owned API URL that production configuration supplies directly.
201
+
202
+ Register that URL through the app's environment-specific `endpoints` configuration. The
203
+ [HTTP-client guide](../../app/docs/http-clients.md#mock-an-application-config-endpoint-locally)
204
+ contains the complete `app.config.local.ts` recipe and restart caveat.
205
+
206
+ ## Configure shared defaults
207
+
208
+ ```typescript
209
+ import type {} from '@equinor/fusion-framework-cli-plugin-mock-server';
210
+ import { defineDevServerConfig } from '@equinor/fusion-framework-cli';
211
+
212
+ export default defineDevServerConfig(() => ({
213
+ mockServer: {
214
+ path: 'mocks',
215
+ host: 'localhost',
216
+ port: 4010,
217
+ seed: 42,
218
+ },
219
+ }));
220
+ ```
221
+
222
+ Command-line flags override these defaults. `path` is relative to the project root.
223
+
224
+ ## Test in a real browser
225
+
226
+ Use Playwright's `webServer` array to own both foreground processes and stop them after the suite.
227
+ The mock server exposes HTTP endpoints for per-test operation overrides and reset.
228
+
229
+ See the [plugin reference](../../cli-plugins/mock-server/README.md), [OpenAPI mock-server guide](../../utils/openapi-mock-server/docs/getting-started.md), and [Playwright cookbook](../../../cookbooks/app-react-mock-playwright/README.md).
@@ -0,0 +1,68 @@
1
+ # Troubleshooting
2
+
3
+ Start with the visible symptom, then check the responsible layer. Browser environment, server
4
+ discovery, and backend proxying are separate steps.
5
+
6
+ ## The package cannot be resolved
7
+
8
+ ```sh
9
+ pnpm add -D @equinor/fusion-framework-dev-server
10
+ ```
11
+
12
+ Vite must also satisfy the Vite 7 or 8 peer dependency.
13
+
14
+ ## Service discovery fails
15
+
16
+ Check `api.serviceDiscoveryUrl` first. The Node process must reach this URL. Authentication, VPN,
17
+ DNS, and environment availability can differ from browser access.
18
+
19
+ If the browser receives the wrong URL, inspect `spa.templateEnv.serviceDiscovery` instead. It
20
+ controls browser configuration and does not replace the API option.
21
+
22
+ ## A discovered API request fails
23
+
24
+ 1. Confirm the service key exists in discovery.
25
+ 2. Enable server debug logging with `log.level: 4`.
26
+ 3. Inspect the rewritten local service URI returned to the browser.
27
+ 4. Check that the upstream URI is absolute and reachable from Node.
28
+ 5. Review custom `api.processServices` logic and route precedence.
29
+
30
+ ## A mock service is missing
31
+
32
+ The mock server is separate. Confirm `ffc mock-server` is running and
33
+ `/@fusion-mock/health` responds.
34
+
35
+ Confirm the source file matches `mocks/<service>.mock.ts` and default-exports a `defineService(...)`
36
+ result. The service key in that module must match the key requested by the application.
37
+
38
+ Normal `ffc app dev` overlays only discovery-visible definitions. Definitions using
39
+ `serviceDiscovery: false` must be configured directly in app config, for example with a
40
+ `http://<key>.localhost:4010` URL. In `--mock` mode, confirm the application uses the same origin
41
+ and port as the manually started server.
42
+
43
+ If a definition using `serviceDiscovery: 'new'` reports a collision, real discovery or an earlier
44
+ mock layer already owns that key. Do not change it to `'replace'` just to hide the error: remove the
45
+ temporary pre-production mock after registration, or use `'merge'` when the intent is to override
46
+ selected behavior of the existing service.
47
+
48
+ ## Authentication fails
49
+
50
+ Check `clientId`, `tenantId`, and `redirectUri` in `spa.templateEnv.msal`. The redirect URI must
51
+ match the identity provider registration and local URL.
52
+
53
+ ## Turn on diagnostics
54
+
55
+ ```typescript
56
+ const options = {
57
+ api: { serviceDiscoveryUrl: 'https://service-discovery.example.com' },
58
+ log: { level: 4 },
59
+ spa: { templateEnv: { telemetry: { consoleLevel: 0 } } },
60
+ };
61
+ ```
62
+
63
+ The scales differ: `log.level` uses `0` None through `4` Debug, while browser
64
+ `telemetry.consoleLevel` uses `0` Debug through `4` Critical.
65
+
66
+ > [!TIP]
67
+ > Start with `log.level: 4` for discovery and proxy failures. Add browser telemetry only when the
68
+ > failure occurs after the page has loaded.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@equinor/fusion-framework-dev-server",
3
- "version": "2.0.19",
3
+ "version": "2.1.0",
4
4
  "description": "Package for running a development server for fusion-framework",
5
5
  "type": "module",
6
6
  "exports": {
@@ -30,14 +30,14 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@vitejs/plugin-react": "^6.0.1",
33
- "@equinor/fusion-framework-vite-plugin-api-service": "2.0.5",
34
- "@equinor/fusion-framework-vite-plugin-spa": "4.0.17",
35
- "@equinor/fusion-log": "2.0.2"
33
+ "@equinor/fusion-framework-vite-plugin-api-service": "2.0.6",
34
+ "@equinor/fusion-log": "2.0.3",
35
+ "@equinor/fusion-framework-vite-plugin-spa": "4.1.0"
36
36
  },
37
37
  "devDependencies": {
38
38
  "typescript": "^7.0.2",
39
39
  "vite": "^8.0.0",
40
- "vitest": "^4.1.0"
40
+ "vitest": "^4.1.10"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "vite": "^7.0.0 || ^8.0.0"
@@ -0,0 +1,36 @@
1
+ import { IncomingMessage } from 'node:http';
2
+ import { Socket } from 'node:net';
3
+
4
+ import { describe, expect, it } from 'vitest';
5
+
6
+ import { processServices } from './process-services.js';
7
+
8
+ const request = new IncomingMessage(new Socket());
9
+ request.headers.referer = 'http://localhost:3000';
10
+
11
+ describe('processServices', () => {
12
+ it('proxies localhost subdomains through the portable shared-host route', () => {
13
+ const result = processServices(
14
+ [{ key: 'people', name: 'People', uri: 'http://people.localhost:4010' }],
15
+ { route: '/@fusion-api', request },
16
+ );
17
+
18
+ expect(result.routes).toEqual([
19
+ {
20
+ match: '/people/*sub',
21
+ proxy: { target: 'http://localhost:4010' },
22
+ },
23
+ ]);
24
+ });
25
+
26
+ it('preserves normal upstream proxy targets and path rewriting', () => {
27
+ const result = processServices(
28
+ [{ key: 'people', name: 'People', uri: 'https://people.example/api' }],
29
+ { route: '/@fusion-api', request },
30
+ );
31
+ const [route] = result.routes ?? [];
32
+
33
+ expect(route?.proxy?.target).toBe('https://people.example');
34
+ expect(route?.proxy?.rewrite?.('/people/api/persons')).toBe('/api/persons');
35
+ });
36
+ });