@equinor/fusion-framework-module-context 9.0.0-next.0 → 9.0.1

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 (43) hide show
  1. package/dist/esm/version.js +1 -1
  2. package/dist/esm/version.js.map +1 -1
  3. package/dist/tsconfig.tsbuildinfo +1 -1
  4. package/dist/types/version.d.ts +1 -1
  5. package/package.json +13 -10
  6. package/CHANGELOG.md +0 -1095
  7. package/docs/data-model.md +0 -134
  8. package/docs/lifecycle.md +0 -163
  9. package/docs/recipes.md +0 -89
  10. package/src/ContextModuleConfig.ts +0 -147
  11. package/src/ContextModuleConfigurator.interface.ts +0 -145
  12. package/src/ContextModuleConfigurator.ts +0 -295
  13. package/src/ContextProvider.ts +0 -1158
  14. package/src/__tests__/ContextModuleConfigurator.test.ts +0 -412
  15. package/src/__tests__/mock/context-mock.test.ts +0 -137
  16. package/src/__tests__/mock/create-context-item-factory.test.ts +0 -60
  17. package/src/__tests__/mock/create-context-items.test.ts +0 -58
  18. package/src/client/ContextClient.ts +0 -149
  19. package/src/errors/FusionContextSearchError.ts +0 -56
  20. package/src/errors/index.ts +0 -1
  21. package/src/index.ts +0 -29
  22. package/src/mock/ContextMockConfigurator.ts +0 -244
  23. package/src/mock/fixtures/create-context-item-factory.ts +0 -62
  24. package/src/mock/fixtures/create-context-items.ts +0 -80
  25. package/src/mock/fixtures/index.ts +0 -28
  26. package/src/mock/fixtures/string-to-seed.ts +0 -18
  27. package/src/mock/index.ts +0 -33
  28. package/src/mock/module.ts +0 -54
  29. package/src/module.ts +0 -178
  30. package/src/selectors/get-context-selector.ts +0 -14
  31. package/src/selectors/index.ts +0 -12
  32. package/src/selectors/query-context-selector.ts +0 -15
  33. package/src/selectors/related-context-selector.ts +0 -15
  34. package/src/types.ts +0 -98
  35. package/src/utils/enable-context.ts +0 -40
  36. package/src/utils/extract-context-id-from-path.ts +0 -39
  37. package/src/utils/index.ts +0 -15
  38. package/src/utils/parse-context-item.ts +0 -39
  39. package/src/utils/resolve-context-from-path.ts +0 -118
  40. package/src/utils/resolve-initial-context.ts +0 -58
  41. package/src/version.ts +0 -2
  42. package/tsconfig.json +0 -33
  43. package/vitest.config.ts +0 -11
@@ -1,134 +0,0 @@
1
- # Data Model
2
-
3
- What a context item actually looks like, how context *types* relate to each other, and the
4
- shapes used to query and filter them.
5
-
6
- ## `ContextItem`
7
-
8
- A context item is the thing your application or portal is currently scoped to — a project, a
9
- facility, a contract, or any other entity the Fusion context API knows about.
10
-
11
- ```ts
12
- type ContextItem<TValue = Record<string, unknown>> = {
13
- id: string;
14
- type: ContextItemType;
15
- value: TValue;
16
- externalId?: string;
17
- source?: string;
18
- title?: string;
19
- subTitle?: string;
20
- isActive?: boolean;
21
- isDeleted?: boolean;
22
- created?: Date;
23
- updated?: Date;
24
- graphic?: string | { type: 'html' | 'svg'; content: string };
25
- meta?: string | { type: 'html' | 'svg'; content: string };
26
- };
27
- ```
28
-
29
- The fields that matter most day to day:
30
-
31
- - **`id`** — the identifier the context module itself uses everywhere: `setCurrentContextById`,
32
- `extractContextIdFromPath`, cache keys, and equality checks (`connectParentContext` only
33
- reacts when `id` actually changes).
34
- - **`type`** — see [`ContextItemType`](#contextitemtype-and-hierarchies) below; this is what
35
- `contextType` allow-lists and `validateContext` check against.
36
- - **`value`** — the domain payload for this item (e.g. the actual project or facility record).
37
- Type it with the generic parameter, `ContextItem<MyProjectShape>`, when you know the shape.
38
- - **`externalId`** and **`source`** — identifiers from an upstream system, when the context item
39
- was imported or mirrored from somewhere other than the context API itself.
40
- - **`title`** / **`subTitle`** / **`graphic`** / **`meta`** — presentation hints for UI
41
- components (e.g. a context switcher) to render without needing to know the `value` shape.
42
-
43
- > [!NOTE]
44
- > `ContextItem` is currently a hand-written type, not yet backed by a runtime schema — see
45
- > [issue #5122](https://github.com/equinor/fusion-framework/issues/5122). Values coming back
46
- > from a real context API are not validated at the type boundary; a custom `setContextClient`
47
- > is responsible for shaping its own responses correctly.
48
-
49
- ## `ContextItemType` and hierarchies
50
-
51
- ```ts
52
- interface ContextItemType {
53
- id: string;
54
- isChildType?: boolean;
55
- parentTypeIds?: string[];
56
- }
57
- ```
58
-
59
- Every context item carries a `type` that says what *kind* of entity it is — `'ProjectMaster'`,
60
- `'Facility'`, `'Contract'`, and so on. Types can be organized as a shallow hierarchy:
61
- `isChildType: true` plus `parentTypeIds` marks a type as a child of one or more parent types
62
- (e.g. a `'Facility'` that belongs to a `'ProjectMaster'`).
63
-
64
- This hierarchy is informational — nothing in this module walks `parentTypeIds` automatically.
65
- It exists so that:
66
-
67
- - application code can build a "these types are related" UI (e.g. grouping facilities under
68
- their parent project) without a second API call,
69
- - a custom `resolveContext` or `contextParameterFn` can use `parentTypeIds` to broaden a search
70
- or a relation lookup by type family instead of a single exact type ID.
71
-
72
- `setContextType(['ProjectMaster'])` restricts which type **IDs** `validateContext` accepts — it
73
- does not expand automatically to include child or parent types unless you list them explicitly
74
- or write a custom `setValidateContext`.
75
-
76
- > [!NOTE]
77
- > Type ID matching in `validateContext`'s default implementation is case-insensitive, so
78
- > `'projectmaster'` and `'ProjectMaster'` are treated the same.
79
-
80
- ## Querying and relating
81
-
82
- ```ts
83
- type QueryContextParameters = {
84
- search?: string;
85
- filter?: { type?: string[]; externalId?: string };
86
- };
87
-
88
- type RelatedContextParameters = {
89
- item: ContextItem;
90
- filter?: { type?: string[] };
91
- };
92
-
93
- type ContextFilterFn = (items: ContextItem[]) => ContextItem[];
94
- ```
95
-
96
- - **`QueryContextParameters`** is what `queryContext`/`queryContextAsync` sends to the query
97
- client, after `contextParameterFn` has had a chance to transform it — see
98
- [`setContextParameterFn`](../README.md#configuration-reference) and the
99
- [OData recipe](recipes.md#odata-query-parameters) for a non-default mapping.
100
- - **`RelatedContextParameters`** is what `relatedContexts`/`relatedContextsAsync` sends when
101
- looking up items related to a given `item` — this is what the default `resolveContext`
102
- uses internally when validation fails; see [Lifecycle](lifecycle.md#resolving-context).
103
- - **`ContextFilterFn`** (`setContextFilter`) runs *after* a query returns, entirely client-side —
104
- use it to hide items the API returned but that shouldn't be selectable (e.g. `isDeleted`
105
- items), as opposed to `contextParameterFn`, which shapes the request itself.
106
-
107
- ## The context client
108
-
109
- `ContextClient` is the piece that actually holds "the current context" and fetches a single
110
- item by ID. It underlies `currentContext`/`currentContext$` on `ContextProvider` — the provider
111
- does not keep its own separate copy of the state.
112
-
113
- ```ts
114
- type GetContextParameters = { id: string };
115
- ```
116
-
117
- `currentContext$` (and `currentContext`) can be in exactly three states, and the difference
118
- matters for anything that reacts to it:
119
-
120
- | Value | Meaning |
121
- |---|---|
122
- | `undefined` | No context has been resolved yet — the provider hasn't initialized (or finished initial-context resolution). |
123
- | `null` | Context was explicitly cleared, e.g. via `clearCurrentContext()`. |
124
- | a `ContextItem` | A context is actively set. |
125
-
126
- Treat `undefined` and `null` differently in UI code: `undefined` usually means "still loading,
127
- don't show an empty state yet", while `null` means "there really is no context — show the
128
- picker".
129
-
130
- ## Errors
131
-
132
- `ContextClient`/the query clients throw `FusionContextSearchError` for domain-specific search
133
- failures thrown from a custom `setContextClient`'s `query` — see
134
- [Errors](../README.md#errors) in the README for a full example.
package/docs/lifecycle.md DELETED
@@ -1,163 +0,0 @@
1
- # Lifecycle
2
-
3
- How the context module decides whether to accept a new context, how it resolves one
4
- automatically on startup, and how a parent/child pair of instances stay in sync.
5
-
6
- ## Setting context
7
-
8
- `setCurrentContext(item, opt)` is the entry point behind `setCurrentContextById`,
9
- `connectParentContext`, and the initial-context resolver below. It takes two options, both
10
- optional and both defaulting to `true`:
11
-
12
- - **`validate`** — check `item` against `validateContext` before accepting it.
13
- - **`resolve`** — when validation fails, try to resolve a related item instead of throwing.
14
-
15
- ```mermaid
16
- flowchart TD
17
- callSet["setCurrentContext"] --> sameId{"same id as current context?"}
18
- sameId -- "yes, unchanged" --> keepCurrent["keep current context"]
19
- sameId -- "no" --> shouldValidate{"validate requested?"}
20
-
21
- shouldValidate -- "no" --> changeEvent[["onCurrentContextChange"]]
22
- changeEvent -- "canceled" --> throwChange["throw: change rejected"]
23
- changeEvent -- "not canceled" --> applyContext["apply item as current context"]
24
-
25
- shouldValidate -- "yes" --> runValidate["run validateContext"]
26
- runValidate -- "valid" --> changeEvent
27
- runValidate -- "invalid" --> shouldResolve{"resolve requested?"}
28
-
29
- shouldResolve -- "no" --> throwInvalid["throw: item did not validate"]
30
- shouldResolve -- "yes" --> resolveEvent[["onSetContextResolve"]]
31
- resolveEvent -- "canceled" --> throwResolveCanceled["throw: resolution canceled"]
32
- resolveEvent -- "not canceled" --> runResolve["run resolveContext"]
33
-
34
- runResolve -- "failed" --> throwResolveFailed["throw: no related item resolved"]
35
- runResolve -- "resolved" --> resolvedEvent[["onSetContextResolved"]]
36
- resolvedEvent -- "canceled" --> throwResolvedCanceled["throw: resolved item rejected"]
37
- resolvedEvent -- "not canceled" --> callSet
38
- ```
39
-
40
- A few things worth calling out that aren't obvious from the diagram alone:
41
-
42
- - **Setting context is queued, not immediate.** Every call to `setCurrentContext` is pushed
43
- onto an internal queue and processed in order — even if nobody subscribes to the returned
44
- `Observable`. This means two rapid calls (e.g. a user clicking two picker items quickly)
45
- resolve one after another rather than racing.
46
- - **Unsubscribing aborts the queued task.** If the caller unsubscribes from the returned
47
- observable before it completes, that in-flight context change is aborted and removed from the
48
- queue — it will not silently apply later.
49
- - **`onCurrentContextChange` (no "d") fires *before* the context actually changes** and is
50
- cancelable — a listener calling `event.preventDefault()` makes `setCurrentContext` throw
51
- instead of silently no-op-ing.
52
- - **`onCurrentContextChanged` (with "d") fires *after*** a change has been applied, and is
53
- *not* cancelable — it's an announcement, not a gate. This is the event `connectParentContext`
54
- listens for to bubble changes to a parent.
55
-
56
- ## Resolving context
57
-
58
- When validation fails and `opt.resolve` is `true`, the provider looks for a related item of an
59
- accepted type instead of rejecting the item outright:
60
-
61
- ```mermaid
62
- flowchart LR
63
- start["run resolveContext"] --> related["fetch relatedContexts for item"]
64
- related --> filterValid["keep items where validateContext passes"]
65
- filterValid -- "one or more found" --> firstMatch["return the first matching item"]
66
- filterValid -- "none found" --> fail["throw: no related item found"]
67
- ```
68
-
69
- > [!NOTE]
70
- > If no `contextType` allow-list is configured (`setContextType`), every context item
71
- > validates, so resolution never has anything left to correct — see
72
- > [Configuration](../README.md#configuration).
73
-
74
- The default `resolveContext` implementation can be replaced entirely with `setResolveContext`
75
- when the "look at related items of an accepted type" strategy doesn't fit — see the
76
- [Configuration reference](../README.md#configuration-reference) in the README.
77
-
78
- ## Resolving the initial context
79
-
80
- When a context module instance is initialized, it tries — without any application code asking
81
- it to — to figure out what its current context should be, in this order:
82
-
83
- 1. **From the URL.** If this instance (or its parent, when nested) has a `navigation` module,
84
- its current path is run through `extractContextIdFromPath` (a GUID matcher by default). If an
85
- ID is found, that item is fetched via the context client's `get` and used as a candidate.
86
- 2. **From the parent context.** If step 1 doesn't produce anything — no navigation module, no
87
- ID in the path, or no matching item — the instance falls back to its parent context module's
88
- *current* context, if it has one.
89
- 3. Whichever of the two resolves first is set as the current context, with both
90
- `validate: true` and `resolve: true` — so an ID found in the URL still has to pass
91
- `validateContext` (and can fall through to `resolveContext`) before it "sticks".
92
-
93
- ```mermaid
94
- flowchart TD
95
- init["module initializes"] --> tryPath{"path available and id extracted?"}
96
- tryPath -- "yes" --> fetchById["fetch context item by id"]
97
- fetchById -- "found" --> apply["set current context, validate and resolve"]
98
- fetchById -- "not found or errors" --> tryParent
99
- tryPath -- "no" --> tryParent{"parent has a current context?"}
100
- tryParent -- "yes" --> apply
101
- tryParent -- "no" --> none["current context stays unresolved"]
102
- ```
103
-
104
- A portal opened directly at `/apps/my-app/7fd97952-...` resolves its context straight from that
105
- GUID; an app embedded inside a portal with no context in its own URL instead inherits whatever
106
- project the portal already has selected.
107
-
108
- Replace this entire strategy with `setResolveInitialContext` when neither source fits — for
109
- example, an application that always derives its context from a non-GUID slug, or one that must
110
- never auto-adopt a parent's context. Failures here are caught and logged as a warning rather
111
- than thrown, so a broken initial-context lookup doesn't block the rest of module
112
- initialization.
113
-
114
- ## Parent/child propagation
115
-
116
- Every context module instance observes its nearest ancestor's current context and mirrors it
117
- locally, unless a listener opts out. This is what keeps a portal's selected project and an
118
- embedded application's context in sync without either side polling the other — set once in the
119
- portal, and it propagates down; a validated change from the app can bubble back up.
120
-
121
- ```mermaid
122
- flowchart TD
123
- subgraph parent["parent instance, e.g. a portal"]
124
- parentSet["setCurrentContext is called"]
125
- parentObserve["listens for onCurrentContextChanged"] --> sourceCheck{"event source is a different provider?"}
126
- sourceCheck -- "yes" --> parentSet
127
- end
128
- subgraph child["child instance, e.g. an embedded app"]
129
- childSubscribe["subscribes to parent currentContext stream"] --> parentChangedEvent[["onParentContextChanged"]]
130
- parentChangedEvent -- "not canceled" --> childValidate["validate context"]
131
- childValidate -- "fails" --> childResolve["resolve context"]
132
- childValidate -- "passes" --> childChanged[["onCurrentContextChanged"]]
133
- childResolve -- "resolved" --> childChanged
134
- childResolve -- "fails" --> childNone["child keeps no current context"]
135
- end
136
- parentSet -.->|"currentContext stream emits"| childSubscribe
137
- childChanged -- "not stopped" --> parentObserve
138
- ```
139
-
140
- - A listener calls `event.stopPropagation()` on `onCurrentContextChanged` to keep a context
141
- change local, so it never reaches ancestors or siblings.
142
- - A listener calls `event.preventDefault()` on `onParentContextChanged` to reject an incoming
143
- context change from a parent instead of mirroring it.
144
- - A child that fails to validate *and* resolve a parent's context is left with **no current
145
- context** — the parent's context is never force-applied. This is deliberate: an app that only
146
- understands `'Facility'` context shouldn't be silently handed a `'Contract'` it can't use.
147
- - Only the first parent-context emission after connecting can be skipped
148
- (`connectParentContext(provider, { skipFirst: true })`), and even without that option, a
149
- context that already matches the child's current context by `id` is ignored — so a child
150
- reconnecting to a parent it's already in sync with does not re-trigger validation.
151
-
152
- ```ts
153
- // constrain a context change to this instance only, never bubbling to ancestors
154
- modules.event.addEventListener('onCurrentContextChanged', (event) => {
155
- if (event.source === modules.context) {
156
- event.stopPropagation();
157
- }
158
- });
159
- ```
160
-
161
- See [Events](../README.md#events) in the README for the full list of dispatched events and
162
- whether each is cancelable, and [Data model](data-model.md) for what a context item and its
163
- `type` actually look like.
package/docs/recipes.md DELETED
@@ -1,89 +0,0 @@
1
- # Recipes
2
-
3
- Configuration patterns that go beyond the [Configuration reference](../README.md#configuration-reference)
4
- in the README.
5
-
6
- ## OData query parameters
7
-
8
- `setContextParameterFn` maps a search + type into the parameters `setContextClient`'s `query`
9
- receives. The default shape is a plain `{ search, filter: { type } }` object, but a context API
10
- backed by OData can build the filter with [`odata-query`](https://www.npmjs.com/package/odata-query)
11
- instead:
12
-
13
- ```ts
14
- import buildQuery from 'odata-query';
15
-
16
- enableContext(configurator, (builder) => {
17
- builder.setContextParameterFn(({ search, type }) =>
18
- buildQuery({
19
- search,
20
- filter: { type: { in: type } },
21
- }),
22
- );
23
- });
24
- ```
25
-
26
- ## Rewriting a path on context change
27
-
28
- `setContextPathGenerator` builds the URL a navigation module pushes to when the current
29
- context changes. Beyond a simple GUID swap, a path can also carry an application-specific key
30
- derived from the resolved item:
31
-
32
- ```ts
33
- enableContext(configurator, (builder) => {
34
- builder.setContextPathGenerator((item, path) => {
35
- // /app/old-app-key/overview -> /app/new-app-key/overview
36
- return path.replace(/^(\/)?app\/[^/]+(.*)$/, `/app/${item.value.appKey}$2`);
37
- });
38
- });
39
- ```
40
-
41
- Pair this with a matching `setContextPathExtractor` so the same key round-trips back into a
42
- context id on page load — see [setContextPathExtractor](../README.md#configuration-reference)
43
- in the README.
44
-
45
- ## Accepting a family of related context types
46
-
47
- `setContextType` matches exact type IDs, so an allow-list of `['ProjectMaster']` rejects a
48
- `'Facility'` item even if that facility's [`ContextItemType.parentTypeIds`](data-model.md#contextitemtype-and-hierarchies)
49
- includes `'ProjectMaster'`. To accept a type *and* its declared children, widen validation
50
- instead of the allow-list:
51
-
52
- ```ts
53
- enableContext(configurator, (builder) => {
54
- const acceptedTypes = ['ProjectMaster'];
55
-
56
- builder.setContextType(acceptedTypes);
57
- builder.setValidateContext((item) => {
58
- if (acceptedTypes.includes(item.type.id)) return true;
59
- return Boolean(item.type.isChildType && item.type.parentTypeIds?.some((id) => acceptedTypes.includes(id)));
60
- });
61
- });
62
- ```
63
-
64
- This keeps `setContextType` as the source of truth for the query allow-list (so searches still
65
- scope to the right types server-side) while letting validation reason about the type hierarchy.
66
-
67
- ## Skipping the default initial-context lookup
68
-
69
- By default, a newly initialized instance tries to resolve its context from the URL, then from
70
- its parent — see [Resolving the initial context](lifecycle.md#resolving-the-initial-context).
71
- An application that manages its own startup context entirely (e.g. from application state
72
- rather than the URL or a parent) can replace that lookup outright:
73
-
74
- ```ts
75
- import { EMPTY } from 'rxjs';
76
-
77
- enableContext(configurator, (builder) => {
78
- // never auto-resolve an initial context; the application sets one explicitly later
79
- builder.setResolveInitialContext(() => EMPTY);
80
- });
81
- ```
82
-
83
- ## Custom search errors
84
-
85
- `FusionContextSearchError`, thrown from `setContextClient`'s `query`, lets an application
86
- surface a domain-specific search failure instead of a generic error — see the
87
- [app-react-context-custom-error](https://github.com/equinor/fusion-framework/tree/main/cookbooks/app-react-context-custom-error/src/config.ts)
88
- cookbook for a complete example.
89
-
@@ -1,147 +0,0 @@
1
- import type { AnyModuleInstance, ModuleInstance } from '@equinor/fusion-framework-module';
2
- import type { ObservableInput } from 'rxjs';
3
- import type { QueryCtorOptions } from '@equinor/fusion-query';
4
-
5
- import type {
6
- ContextFilterFn,
7
- ContextItem,
8
- QueryContextParameters,
9
- RelatedContextParameters,
10
- } from './types';
11
- import type { GetContextParameters } from './client/ContextClient';
12
- import type { IContextProvider } from './ContextProvider';
13
-
14
- /**
15
- * Resolved configuration for the context module.
16
- *
17
- * Holds query clients, type filters, parent-connection settings, and
18
- * optional callbacks for validation, resolution, and path integration.
19
- * Produced by {@link ContextModuleConfigurator.createConfigAsync} after all
20
- * registered config builders have run.
21
- *
22
- * @see IContextModuleConfigurator — fluent API for populating this config.
23
- * @see ContextProvider — runtime consumer of this config.
24
- */
25
- export interface ContextModuleConfig {
26
- /**
27
- * Query client options used to fetch, search, and resolve related context items.
28
- *
29
- * - `get` — retrieves a single context item by ID.
30
- * - `query` — searches context items by text and optional type filter.
31
- * - `related` — fetches context items related to a given item (used during resolution).
32
- */
33
- client: {
34
- get: QueryCtorOptions<ContextItem, GetContextParameters>;
35
- query: QueryCtorOptions<ContextItem[], QueryContextParameters>;
36
- related?: QueryCtorOptions<ContextItem[], RelatedContextParameters>;
37
- };
38
-
39
- /**
40
- * Allowed context type IDs (e.g. `['ProjectMaster', 'Facility']`).
41
- *
42
- * When set, {@link ContextProvider.validateContext} only accepts items
43
- * whose `type.id` matches one of these values (case-insensitive).
44
- */
45
- contextType?: string[];
46
-
47
- /**
48
- * Optional post-query filter applied to the result set returned by
49
- * {@link ContextProvider.queryContext}.
50
- */
51
- contextFilter?: ContextFilterFn;
52
-
53
- /**
54
- * Whether to connect the context module to a parent context module.
55
- *
56
- * When `true` (the default), the provider subscribes to the parent's
57
- * `currentContext$` and mirrors changes into its own state.
58
- *
59
- * @defaultValue `true`
60
- */
61
- connectParentContext?: boolean;
62
-
63
- /**
64
- * When `true`, skips resolving an initial context from the path or parent
65
- * during module post-initialization.
66
- */
67
- skipInitialContext?: boolean;
68
-
69
- /**
70
- * Extracts a context ID from a URL path segment.
71
- *
72
- * Used during initial context resolution and deep-link support.
73
- * If not provided, the default GUID-based extractor is used.
74
- *
75
- * @param path - The URL path to inspect.
76
- * @returns The extracted context ID, or `undefined` if none is found.
77
- */
78
- extractContextIdFromPath?: (path: string) => string | undefined;
79
-
80
- /**
81
- * Generates a URL path that embeds the given context item's ID.
82
- *
83
- * Used by navigation integrations to update the browser URL when
84
- * the context changes.
85
- *
86
- * @param context - The active context item.
87
- * @param path - The current URL path.
88
- * @returns The updated path, or `undefined` to leave it unchanged.
89
- */
90
- generatePathFromContext?: (context: ContextItem, path: string) => string | undefined;
91
-
92
- /**
93
- * Transforms a user search string and the configured context type into
94
- * the query parameters sent to the context API.
95
- *
96
- * Override this to customise how free-text searches are mapped to the
97
- * backend query contract.
98
- */
99
- contextParameterFn?: (args: {
100
- search: string;
101
- type: ContextModuleConfig['contextType'];
102
- }) => string | QueryContextParameters;
103
-
104
- /**
105
- * Custom context resolution strategy.
106
- *
107
- * Called with `this` bound to the {@link IContextProvider} when a context
108
- * item fails validation and the caller requests resolution.
109
- *
110
- * @param item - The context item to resolve, or `null`.
111
- * @returns An observable emitting the resolved context item.
112
- */
113
- resolveContext?: (
114
- this: IContextProvider,
115
- item: ContextItem | null,
116
- ) => ReturnType<IContextProvider['resolveContext']>;
117
-
118
- /**
119
- * Custom context validation strategy.
120
- *
121
- * Called with `this` bound to the {@link IContextProvider} to decide
122
- * whether a candidate context item is acceptable.
123
- *
124
- * @param item - The context item to validate, or `null`.
125
- * @returns `true` if the item is valid.
126
- */
127
- validateContext?: (
128
- this: IContextProvider,
129
- item: ContextItem | null,
130
- ) => ReturnType<IContextProvider['validateContext']>;
131
-
132
- /**
133
- * Resolves the initial context during module post-initialization.
134
- *
135
- * The default implementation tries to extract a context ID from the
136
- * current navigation path, falling back to the parent provider's context.
137
- *
138
- * @param args - Module reference and instance map.
139
- * @returns An observable input emitting the initial context item, or void.
140
- */
141
- resolveInitialContext?: (args: {
142
- // biome-ignore lint/suspicious/noExplicitAny: `AnyModuleInstance | any` intentionally widens to accept any module instance shape for `ref`
143
- ref?: AnyModuleInstance | any;
144
- modules: ModuleInstance;
145
- // biome-ignore lint/suspicious/noConfusingVoidType: `void` here relies on TypeScript's special-cased "void-returning callback accepts any return value" behavior — `undefined` would break assignability of resolver functions that only conditionally emit a `ContextItem`
146
- }) => ObservableInput<ContextItem | void>;
147
- }
@@ -1,145 +0,0 @@
1
- import type { Modules, ModuleType } from '@equinor/fusion-framework-module';
2
- import type { QueryCtorOptions, QueryFn } from '@equinor/fusion-query';
3
-
4
- import type { ContextModuleConfig } from './ContextModuleConfig';
5
- import type { ContextItem, QueryContextParameters, RelatedContextParameters } from './types';
6
- import type { GetContextParameters } from './client/ContextClient';
7
-
8
- /**
9
- * Callback passed to {@link IContextModuleConfigurator.addConfigBuilder}.
10
- *
11
- * Receives the {@link IContextModuleConfigurator} itself and may use its
12
- * setter methods to populate the context module configuration. The
13
- * callback may be async.
14
- */
15
- export type ContextConfigBuilderCallback = (
16
- builder: IContextModuleConfigurator,
17
- ) => void | Promise<void>;
18
-
19
- /**
20
- * Public configurator contract for the context module.
21
- *
22
- * Consumers call {@link addConfigBuilder} to register one or more
23
- * {@link ContextConfigBuilderCallback} functions that will run during
24
- * module initialization to populate the {@link ContextModuleConfig}, using
25
- * the fluent setter methods declared below.
26
- */
27
- export interface IContextModuleConfigurator {
28
- /**
29
- * Registers a configuration callback that receives this configurator.
30
- *
31
- * Multiple builders can be added; they execute sequentially against the
32
- * same configurator instance, so later calls win when they touch the
33
- * same field.
34
- *
35
- * @param init - Builder callback invoked during module initialization.
36
- */
37
- addConfigBuilder: (init: ContextConfigBuilderCallback) => void;
38
-
39
- /**
40
- * Requires a module instance by its registered key or name.
41
- *
42
- * Only resolvable from within a {@link ContextConfigBuilderCallback} —
43
- * throws if called before module initialization has started.
44
- *
45
- * @param module - The key or name of the module to resolve.
46
- * @returns A promise that resolves to the requested module instance.
47
- */
48
- requireInstance<TKey extends string = Extract<keyof Modules, string>>(
49
- module: TKey,
50
- ): Promise<ModuleType<Modules[TKey]>>;
51
- requireInstance<T>(module: string): Promise<T>;
52
-
53
- /**
54
- * Sets the context type for the current configuration.
55
- *
56
- * @param type - The context type to assign, as defined by `ContextModuleConfig['contextType']`.
57
- */
58
- setContextType(type: ContextModuleConfig['contextType']): void;
59
-
60
- /**
61
- * Sets the context filter function for the configuration.
62
- *
63
- * @param filter - A function that determines whether a context should be included, as defined by `ContextModuleConfig['contextFilter']`.
64
- */
65
- setContextFilter(filter: ContextModuleConfig['contextFilter']): void;
66
-
67
- /**
68
- * Sets the function or configuration used to connect to a parent context.
69
- *
70
- * @param connect - The function or configuration that defines how to connect to the parent context.
71
- */
72
- connectParentContext(connect: ContextModuleConfig['connectParentContext']): void;
73
-
74
- /**
75
- * Sets the function used to provide context parameters for the module configuration.
76
- *
77
- * @param fn - A function conforming to the `contextParameterFn` type defined in `ContextModuleConfig`.
78
- */
79
- setContextParameterFn(fn: ContextModuleConfig['contextParameterFn']): void;
80
-
81
- /**
82
- * Sets the function used to validate the context within the configuration.
83
- *
84
- * @param fn - A function that implements the `validateContext` signature from `ContextModuleConfig`.
85
- */
86
- setValidateContext(fn: ContextModuleConfig['validateContext']): void;
87
-
88
- /**
89
- * Sets the function used to resolve the context for the module configuration.
90
- *
91
- * @param fn - A function that defines how the context should be resolved, conforming to the `resolveContext` type from `ContextModuleConfig`.
92
- */
93
- setResolveContext(fn: ContextModuleConfig['resolveContext']): void;
94
-
95
- /**
96
- * Sets the function responsible for extracting the context ID from a given path.
97
- *
98
- * @param fn - A function that defines how to extract the context ID from a path.
99
- * This function should match the type defined in `ContextModuleConfig['extractContextIdFromPath']`.
100
- */
101
- setContextPathExtractor(fn: ContextModuleConfig['extractContextIdFromPath']): void;
102
-
103
- /**
104
- * Sets the function responsible for generating a path from the context.
105
- *
106
- * @param fn - A function that takes a context and generates a corresponding path.
107
- */
108
- setContextPathGenerator(fn: ContextModuleConfig['generatePathFromContext']): void;
109
-
110
- /**
111
- * Sets the function used to resolve the initial context during module post-initialization.
112
- *
113
- * @param fn - A function that returns an observable input emitting the initial context item.
114
- * The default resolver extracts a context ID from the navigation path, falling
115
- * back to the parent provider's current context.
116
- */
117
- setResolveInitialContext(fn: ContextModuleConfig['resolveInitialContext']): void;
118
-
119
- /**
120
- * Sets the context client configuration for fetching context items.
121
- *
122
- * This method allows you to provide custom query functions or query constructor options
123
- * for retrieving single context items (`get`), querying multiple context items (`query`),
124
- * and optionally fetching related context items (`related`). Each query can be provided
125
- * as either a function or a configuration object. The expiration time for cached results
126
- * can also be specified.
127
- *
128
- * @param client - An object containing the query functions or options for `get`, `query`, and optionally `related` context items.
129
- * @param expire - Optional. The expiration time (in milliseconds) for cached query results. Defaults to 1 minute.
130
- */
131
- setContextClient(
132
- client: {
133
- get:
134
- | QueryFn<ContextItem, GetContextParameters>
135
- | QueryCtorOptions<ContextItem, GetContextParameters>;
136
- query:
137
- | QueryFn<ContextItem[], QueryContextParameters>
138
- | QueryCtorOptions<ContextItem[], QueryContextParameters>;
139
- related?:
140
- | QueryFn<ContextItem[], RelatedContextParameters>
141
- | QueryCtorOptions<ContextItem[], RelatedContextParameters>;
142
- },
143
- expire?: number,
144
- ): void;
145
- }