@dever-labs/ngx-mfe-broker 0.1.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.
package/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# NgxMfeBroker
|
|
2
|
+
|
|
3
|
+
This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 22.0.0.
|
|
4
|
+
|
|
5
|
+
## Code scaffolding
|
|
6
|
+
|
|
7
|
+
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
ng generate component component-name
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
ng generate --help
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Building
|
|
20
|
+
|
|
21
|
+
To build the library, run:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
ng build ngx-mfe-broker
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
This command will compile your project, and the build artifacts will be placed in the `dist/` directory.
|
|
28
|
+
|
|
29
|
+
### Publishing the Library
|
|
30
|
+
|
|
31
|
+
Once the project is built, you can publish your library by following these steps:
|
|
32
|
+
|
|
33
|
+
1. Navigate to the `dist` directory:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
cd dist/ngx-mfe-broker
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
2. Run the `npm publish` command to publish your library to the npm registry:
|
|
40
|
+
```bash
|
|
41
|
+
npm publish
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Running unit tests
|
|
45
|
+
|
|
46
|
+
To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
ng test
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Running end-to-end tests
|
|
53
|
+
|
|
54
|
+
For end-to-end (e2e) testing, run:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
ng e2e
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
|
|
61
|
+
|
|
62
|
+
## Additional Resources
|
|
63
|
+
|
|
64
|
+
For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { InjectionToken, inject, signal, effect, Injectable, makeEnvironmentProviders } from '@angular/core';
|
|
3
|
+
|
|
4
|
+
const CHANNEL_NAME$1 = '@dever-labs/ngx-mfe-broker:state';
|
|
5
|
+
/**
|
|
6
|
+
* Injection token used to supply the initial state shape and default values.
|
|
7
|
+
*
|
|
8
|
+
* Provide this via `provideNgxMfeBroker({ initialState: { ... } })`.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* provideNgxMfeBroker({ initialState: { theme: 'light', token: null } })
|
|
12
|
+
*/
|
|
13
|
+
const NGX_MFE_INITIAL_STATE = new InjectionToken('@dever-labs/ngx-mfe-broker:initial-state', { factory: () => ({}) });
|
|
14
|
+
function serialize(value) {
|
|
15
|
+
return typeof value === 'string' ? value : JSON.stringify(value);
|
|
16
|
+
}
|
|
17
|
+
function deserialize(raw, fallback) {
|
|
18
|
+
if (typeof fallback === 'string')
|
|
19
|
+
return raw;
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(raw);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return fallback;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function stateEqual(a, b) {
|
|
28
|
+
if (a === b)
|
|
29
|
+
return true;
|
|
30
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Generic typed state service for micro-frontends.
|
|
34
|
+
*
|
|
35
|
+
* State is backed by localStorage, reactive via Angular Signals, and
|
|
36
|
+
* synchronised across browser tabs via BroadcastChannel.
|
|
37
|
+
*
|
|
38
|
+
* Consumers define their own state shape by providing `NGX_MFE_INITIAL_STATE`.
|
|
39
|
+
* Use `get<T>(key)` / `set(key, value)` for type-safe access.
|
|
40
|
+
*/
|
|
41
|
+
class MfeStateService {
|
|
42
|
+
signals = new Map();
|
|
43
|
+
defaults = new Map();
|
|
44
|
+
/**
|
|
45
|
+
* Value-based guard: stores the last value received from another tab for
|
|
46
|
+
* each key. The effect checks this map instead of a time-sensitive Set so
|
|
47
|
+
* the check happens at effect execution time — guaranteed after the signal
|
|
48
|
+
* update — rather than racing against queueMicrotask cleanup.
|
|
49
|
+
*/
|
|
50
|
+
inboundValues = new Map();
|
|
51
|
+
storage = typeof localStorage !== 'undefined' ? localStorage : null;
|
|
52
|
+
channel = typeof BroadcastChannel !== 'undefined'
|
|
53
|
+
? new BroadcastChannel(CHANNEL_NAME$1)
|
|
54
|
+
: null;
|
|
55
|
+
constructor() {
|
|
56
|
+
const initialState = inject(NGX_MFE_INITIAL_STATE);
|
|
57
|
+
for (const [key, defaultValue] of Object.entries(initialState)) {
|
|
58
|
+
this.defaults.set(key, defaultValue);
|
|
59
|
+
const raw = this.storage?.getItem(key) ?? null;
|
|
60
|
+
const value = raw !== null ? deserialize(raw, defaultValue) : defaultValue;
|
|
61
|
+
const s = signal(value, /* @ts-ignore */
|
|
62
|
+
...(ngDevMode ? [{ debugName: "s" }] : /* istanbul ignore next */ []));
|
|
63
|
+
this.signals.set(key, s);
|
|
64
|
+
effect(() => {
|
|
65
|
+
const current = s();
|
|
66
|
+
this.storage?.setItem(key, serialize(current));
|
|
67
|
+
// Skip broadcast if this value arrived from another tab to prevent echo loops.
|
|
68
|
+
if (stateEqual(current, this.inboundValues.get(key))) {
|
|
69
|
+
this.inboundValues.delete(key);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
this.channel?.postMessage({ key, value: current });
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
this.channel?.addEventListener('message', ({ data }) => {
|
|
76
|
+
const s = this.signals.get(data.key);
|
|
77
|
+
if (!s)
|
|
78
|
+
return;
|
|
79
|
+
if (stateEqual(s(), data.value))
|
|
80
|
+
return;
|
|
81
|
+
// Record the inbound value before updating the signal. The effect will
|
|
82
|
+
// read inboundValues synchronously during its execution and clear the entry.
|
|
83
|
+
this.inboundValues.set(data.key, data.value);
|
|
84
|
+
s.set(data.value);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
/** Get a typed Signal for the given key. Key must be registered in `NGX_MFE_INITIAL_STATE`. */
|
|
88
|
+
get(key) {
|
|
89
|
+
if (!this.signals.has(key)) {
|
|
90
|
+
throw new Error(`[ngx-mfe-broker] Unknown state key "${key}". ` +
|
|
91
|
+
`Register it in NGX_MFE_INITIAL_STATE via provideNgxMfeBroker({ initialState: { ${key}: <default> } }).`);
|
|
92
|
+
}
|
|
93
|
+
return this.signals.get(key);
|
|
94
|
+
}
|
|
95
|
+
/** Set a value — persists to localStorage and broadcasts cross-tab. */
|
|
96
|
+
set(key, value) {
|
|
97
|
+
this.get(key).set(value);
|
|
98
|
+
}
|
|
99
|
+
ngOnDestroy() {
|
|
100
|
+
this.channel?.close();
|
|
101
|
+
}
|
|
102
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: MfeStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
103
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: MfeStateService, providedIn: 'root' });
|
|
104
|
+
}
|
|
105
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: MfeStateService, decorators: [{
|
|
106
|
+
type: Injectable,
|
|
107
|
+
args: [{ providedIn: 'root' }]
|
|
108
|
+
}], ctorParameters: () => [] });
|
|
109
|
+
|
|
110
|
+
const CHANNEL_NAME = '@dever-labs/ngx-mfe-broker:config';
|
|
111
|
+
/**
|
|
112
|
+
* Generic cross-tab string key-value store backed by localStorage.
|
|
113
|
+
* Changes are broadcast to all other tabs/windows via BroadcastChannel.
|
|
114
|
+
*/
|
|
115
|
+
class ConfigRepositoryService {
|
|
116
|
+
signals = new Map();
|
|
117
|
+
/** Tracks every key ever written so clear() only removes its own keys. */
|
|
118
|
+
ownedKeys = new Set();
|
|
119
|
+
storage = typeof localStorage !== 'undefined' ? localStorage : null;
|
|
120
|
+
channel = typeof BroadcastChannel !== 'undefined'
|
|
121
|
+
? new BroadcastChannel(CHANNEL_NAME)
|
|
122
|
+
: null;
|
|
123
|
+
/**
|
|
124
|
+
* Value-based inbound guard: stores the last value received from another tab.
|
|
125
|
+
* `null` means the last inbound operation was a remove for that key.
|
|
126
|
+
* Checked synchronously in set()/remove() to prevent re-broadcasting received updates.
|
|
127
|
+
*/
|
|
128
|
+
inboundValues = new Map();
|
|
129
|
+
constructor() {
|
|
130
|
+
this.channel?.addEventListener('message', ({ data }) => {
|
|
131
|
+
if (data.type === 'clear') {
|
|
132
|
+
// Iterate only the keys the sender owned — not all signals on this tab.
|
|
133
|
+
data.keys.forEach(k => {
|
|
134
|
+
this.inboundValues.set(k, null);
|
|
135
|
+
this.storage?.removeItem(k);
|
|
136
|
+
this.signals.get(k)?.set(null);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
else if (data.type === 'remove') {
|
|
140
|
+
this.inboundValues.set(data.key, null);
|
|
141
|
+
this.storage?.removeItem(data.key);
|
|
142
|
+
this.signals.get(data.key)?.set(null);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
this.inboundValues.set(data.key, data.value);
|
|
146
|
+
this.storage?.setItem(data.key, data.value);
|
|
147
|
+
this.getWritable(data.key).set(data.value);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
getSignal(key) {
|
|
152
|
+
return this.getWritable(key).asReadonly();
|
|
153
|
+
}
|
|
154
|
+
get(key) {
|
|
155
|
+
return this.getSignal(key)();
|
|
156
|
+
}
|
|
157
|
+
set(key, value) {
|
|
158
|
+
this.ownedKeys.add(key);
|
|
159
|
+
this.storage?.setItem(key, value);
|
|
160
|
+
this.getWritable(key).set(value);
|
|
161
|
+
if (this.inboundValues.get(key) === value) {
|
|
162
|
+
this.inboundValues.delete(key);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
this.channel?.postMessage({ type: 'set', key, value });
|
|
166
|
+
}
|
|
167
|
+
remove(key) {
|
|
168
|
+
this.ownedKeys.delete(key);
|
|
169
|
+
this.storage?.removeItem(key);
|
|
170
|
+
this.signals.get(key)?.set(null);
|
|
171
|
+
if (this.inboundValues.get(key) === null && this.inboundValues.has(key)) {
|
|
172
|
+
this.inboundValues.delete(key);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
this.channel?.postMessage({ type: 'remove', key });
|
|
176
|
+
}
|
|
177
|
+
/** Removes only keys written by this service — does not touch unrelated localStorage entries. */
|
|
178
|
+
clear() {
|
|
179
|
+
const keys = [...this.ownedKeys];
|
|
180
|
+
keys.forEach(k => {
|
|
181
|
+
this.storage?.removeItem(k);
|
|
182
|
+
this.signals.get(k)?.set(null);
|
|
183
|
+
});
|
|
184
|
+
this.ownedKeys.clear();
|
|
185
|
+
this.channel?.postMessage({ type: 'clear', keys });
|
|
186
|
+
}
|
|
187
|
+
ngOnDestroy() {
|
|
188
|
+
this.channel?.close();
|
|
189
|
+
}
|
|
190
|
+
getWritable(key) {
|
|
191
|
+
if (!this.signals.has(key)) {
|
|
192
|
+
this.signals.set(key, signal(this.storage?.getItem(key) ?? null));
|
|
193
|
+
}
|
|
194
|
+
return this.signals.get(key);
|
|
195
|
+
}
|
|
196
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: ConfigRepositoryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
197
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: ConfigRepositoryService, providedIn: 'root' });
|
|
198
|
+
}
|
|
199
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: ConfigRepositoryService, decorators: [{
|
|
200
|
+
type: Injectable,
|
|
201
|
+
args: [{ providedIn: 'root' }]
|
|
202
|
+
}], ctorParameters: () => [] });
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Call in your `app.config.ts` to configure `@dever-labs/ngx-mfe-broker`.
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* export const appConfig: ApplicationConfig = {
|
|
209
|
+
* providers: [
|
|
210
|
+
* provideNgxMfeBroker({ initialState: { theme: 'light', token: null } }),
|
|
211
|
+
* ]
|
|
212
|
+
* };
|
|
213
|
+
*/
|
|
214
|
+
function provideNgxMfeBroker(config) {
|
|
215
|
+
return makeEnvironmentProviders([
|
|
216
|
+
{ provide: NGX_MFE_INITIAL_STATE, useValue: config.initialState },
|
|
217
|
+
]);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/*
|
|
221
|
+
* Public API Surface of @dever-labs/ngx-mfe-broker
|
|
222
|
+
*/
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Generated bundle index. Do not edit.
|
|
226
|
+
*/
|
|
227
|
+
|
|
228
|
+
export { ConfigRepositoryService, MfeStateService, NGX_MFE_INITIAL_STATE, provideNgxMfeBroker };
|
|
229
|
+
//# sourceMappingURL=dever-labs-ngx-mfe-broker.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dever-labs-ngx-mfe-broker.mjs","sources":["../../../projects/ngx-mfe-broker/src/lib/mfe-state.service.ts","../../../projects/ngx-mfe-broker/src/lib/config-repository.service.ts","../../../projects/ngx-mfe-broker/src/lib/provide-ngx-mfe-broker.ts","../../../projects/ngx-mfe-broker/src/public-api.ts","../../../projects/ngx-mfe-broker/src/dever-labs-ngx-mfe-broker.ts"],"sourcesContent":["import { effect, inject, Injectable, InjectionToken, OnDestroy, signal, WritableSignal } from '@angular/core';\n\nconst CHANNEL_NAME = '@dever-labs/ngx-mfe-broker:state';\n\n/**\n * Injection token used to supply the initial state shape and default values.\n *\n * Provide this via `provideNgxMfeBroker({ initialState: { ... } })`.\n *\n * @example\n * provideNgxMfeBroker({ initialState: { theme: 'light', token: null } })\n */\nexport const NGX_MFE_INITIAL_STATE = new InjectionToken<Record<string, unknown>>(\n '@dever-labs/ngx-mfe-broker:initial-state',\n { factory: () => ({}) },\n);\n\nfunction serialize(value: unknown): string {\n return typeof value === 'string' ? value : JSON.stringify(value);\n}\n\nfunction deserialize(raw: string, fallback: unknown): unknown {\n if (typeof fallback === 'string') return raw;\n try { return JSON.parse(raw); } catch { return fallback; }\n}\n\nfunction stateEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n return JSON.stringify(a) === JSON.stringify(b);\n}\n\ntype StateMessage = { key: string; value: unknown };\n\n/**\n * Generic typed state service for micro-frontends.\n *\n * State is backed by localStorage, reactive via Angular Signals, and\n * synchronised across browser tabs via BroadcastChannel.\n *\n * Consumers define their own state shape by providing `NGX_MFE_INITIAL_STATE`.\n * Use `get<T>(key)` / `set(key, value)` for type-safe access.\n */\n@Injectable({ providedIn: 'root' })\nexport class MfeStateService implements OnDestroy {\n private readonly signals = new Map<string, WritableSignal<unknown>>();\n private readonly defaults = new Map<string, unknown>();\n /**\n * Value-based guard: stores the last value received from another tab for\n * each key. The effect checks this map instead of a time-sensitive Set so\n * the check happens at effect execution time — guaranteed after the signal\n * update — rather than racing against queueMicrotask cleanup.\n */\n private readonly inboundValues = new Map<string, unknown>();\n\n private readonly storage: Storage | null = typeof localStorage !== 'undefined' ? localStorage : null;\n\n private readonly channel = typeof BroadcastChannel !== 'undefined'\n ? new BroadcastChannel(CHANNEL_NAME)\n : null;\n\n constructor() {\n const initialState = inject(NGX_MFE_INITIAL_STATE);\n\n for (const [key, defaultValue] of Object.entries(initialState)) {\n this.defaults.set(key, defaultValue);\n const raw = this.storage?.getItem(key) ?? null;\n const value = raw !== null ? deserialize(raw, defaultValue) : defaultValue;\n const s = signal(value);\n this.signals.set(key, s);\n\n effect(() => {\n const current = s();\n this.storage?.setItem(key, serialize(current));\n // Skip broadcast if this value arrived from another tab to prevent echo loops.\n if (stateEqual(current, this.inboundValues.get(key))) {\n this.inboundValues.delete(key);\n return;\n }\n this.channel?.postMessage({ key, value: current } satisfies StateMessage);\n });\n }\n\n this.channel?.addEventListener('message', ({ data }: MessageEvent<StateMessage>) => {\n const s = this.signals.get(data.key);\n if (!s) return;\n if (stateEqual(s(), data.value)) return;\n // Record the inbound value before updating the signal. The effect will\n // read inboundValues synchronously during its execution and clear the entry.\n this.inboundValues.set(data.key, data.value);\n s.set(data.value);\n });\n }\n\n /** Get a typed Signal for the given key. Key must be registered in `NGX_MFE_INITIAL_STATE`. */\n get<T>(key: string): WritableSignal<T> {\n if (!this.signals.has(key)) {\n throw new Error(\n `[ngx-mfe-broker] Unknown state key \"${key}\". ` +\n `Register it in NGX_MFE_INITIAL_STATE via provideNgxMfeBroker({ initialState: { ${key}: <default> } }).`,\n );\n }\n return this.signals.get(key) as WritableSignal<T>;\n }\n\n /** Set a value — persists to localStorage and broadcasts cross-tab. */\n set<T>(key: string, value: T): void {\n this.get<T>(key).set(value);\n }\n\n ngOnDestroy(): void {\n this.channel?.close();\n }\n}\n","import { Injectable, signal, Signal, WritableSignal, OnDestroy } from '@angular/core';\n\nconst CHANNEL_NAME = '@dever-labs/ngx-mfe-broker:config';\n\ntype ConfigMessage =\n | { type: 'set'; key: string; value: string }\n | { type: 'remove'; key: string }\n | { type: 'clear'; keys: string[] };\n\n/**\n * Generic cross-tab string key-value store backed by localStorage.\n * Changes are broadcast to all other tabs/windows via BroadcastChannel.\n */\n@Injectable({ providedIn: 'root' })\nexport class ConfigRepositoryService implements OnDestroy {\n private readonly signals = new Map<string, WritableSignal<string | null>>();\n /** Tracks every key ever written so clear() only removes its own keys. */\n private readonly ownedKeys = new Set<string>();\n\n private readonly storage: Storage | null = typeof localStorage !== 'undefined' ? localStorage : null;\n\n private readonly channel = typeof BroadcastChannel !== 'undefined'\n ? new BroadcastChannel(CHANNEL_NAME)\n : null;\n\n /**\n * Value-based inbound guard: stores the last value received from another tab.\n * `null` means the last inbound operation was a remove for that key.\n * Checked synchronously in set()/remove() to prevent re-broadcasting received updates.\n */\n private readonly inboundValues = new Map<string, string | null>();\n\n constructor() {\n this.channel?.addEventListener('message', ({ data }: MessageEvent<ConfigMessage>) => {\n if (data.type === 'clear') {\n // Iterate only the keys the sender owned — not all signals on this tab.\n data.keys.forEach(k => {\n this.inboundValues.set(k, null);\n this.storage?.removeItem(k);\n this.signals.get(k)?.set(null);\n });\n } else if (data.type === 'remove') {\n this.inboundValues.set(data.key, null);\n this.storage?.removeItem(data.key);\n this.signals.get(data.key)?.set(null);\n } else {\n this.inboundValues.set(data.key, data.value);\n this.storage?.setItem(data.key, data.value);\n this.getWritable(data.key).set(data.value);\n }\n });\n }\n\n getSignal(key: string): Signal<string | null> {\n return this.getWritable(key).asReadonly();\n }\n\n get(key: string): string | null {\n return this.getSignal(key)();\n }\n\n set(key: string, value: string): void {\n this.ownedKeys.add(key);\n this.storage?.setItem(key, value);\n this.getWritable(key).set(value);\n if (this.inboundValues.get(key) === value) {\n this.inboundValues.delete(key);\n return;\n }\n this.channel?.postMessage({ type: 'set', key, value } satisfies ConfigMessage);\n }\n\n remove(key: string): void {\n this.ownedKeys.delete(key);\n this.storage?.removeItem(key);\n this.signals.get(key)?.set(null);\n if (this.inboundValues.get(key) === null && this.inboundValues.has(key)) {\n this.inboundValues.delete(key);\n return;\n }\n this.channel?.postMessage({ type: 'remove', key } satisfies ConfigMessage);\n }\n\n /** Removes only keys written by this service — does not touch unrelated localStorage entries. */\n clear(): void {\n const keys = [...this.ownedKeys];\n keys.forEach(k => {\n this.storage?.removeItem(k);\n this.signals.get(k)?.set(null);\n });\n this.ownedKeys.clear();\n this.channel?.postMessage({ type: 'clear', keys } satisfies ConfigMessage);\n }\n\n ngOnDestroy(): void {\n this.channel?.close();\n }\n\n private getWritable(key: string): WritableSignal<string | null> {\n if (!this.signals.has(key)) {\n this.signals.set(key, signal(this.storage?.getItem(key) ?? null));\n }\n return this.signals.get(key)!;\n }\n}\n","import { EnvironmentProviders, makeEnvironmentProviders } from '@angular/core';\nimport { NGX_MFE_INITIAL_STATE } from './mfe-state.service';\n\nexport interface NgxMfeBrokerConfig {\n /**\n * Initial state values with their default values.\n * Each key becomes a Signal backed by localStorage with cross-tab sync.\n *\n * @example\n * provideNgxMfeBroker({\n * initialState: { theme: 'light', token: null, users: [] }\n * })\n */\n initialState: Record<string, unknown>;\n}\n\n/**\n * Call in your `app.config.ts` to configure `@dever-labs/ngx-mfe-broker`.\n *\n * @example\n * export const appConfig: ApplicationConfig = {\n * providers: [\n * provideNgxMfeBroker({ initialState: { theme: 'light', token: null } }),\n * ]\n * };\n */\nexport function provideNgxMfeBroker(config: NgxMfeBrokerConfig): EnvironmentProviders {\n return makeEnvironmentProviders([\n { provide: NGX_MFE_INITIAL_STATE, useValue: config.initialState },\n ]);\n}\n","/*\n * Public API Surface of @dever-labs/ngx-mfe-broker\n */\n\nexport * from './lib/mfe-state.service';\nexport * from './lib/config-repository.service';\nexport * from './lib/provide-ngx-mfe-broker';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["CHANNEL_NAME"],"mappings":";;;AAEA,MAAMA,cAAY,GAAG,kCAAkC;AAEvD;;;;;;;AAOG;MACU,qBAAqB,GAAG,IAAI,cAAc,CACrD,0CAA0C,EAC1C,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE;AAGzB,SAAS,SAAS,CAAC,KAAc,EAAA;AAC/B,IAAA,OAAO,OAAO,KAAK,KAAK,QAAQ,GAAG,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;AAClE;AAEA,SAAS,WAAW,CAAC,GAAW,EAAE,QAAiB,EAAA;IACjD,IAAI,OAAO,QAAQ,KAAK,QAAQ;AAAE,QAAA,OAAO,GAAG;AAC5C,IAAA,IAAI;AAAE,QAAA,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;IAAE;AAAE,IAAA,MAAM;AAAE,QAAA,OAAO,QAAQ;IAAE;AAC3D;AAEA,SAAS,UAAU,CAAC,CAAU,EAAE,CAAU,EAAA;IACxC,IAAI,CAAC,KAAK,CAAC;AAAE,QAAA,OAAO,IAAI;AACxB,IAAA,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;AAChD;AAIA;;;;;;;;AAQG;MAEU,eAAe,CAAA;AACT,IAAA,OAAO,GAAG,IAAI,GAAG,EAAmC;AACpD,IAAA,QAAQ,GAAG,IAAI,GAAG,EAAmB;AACtD;;;;;AAKG;AACc,IAAA,aAAa,GAAG,IAAI,GAAG,EAAmB;AAE1C,IAAA,OAAO,GAAmB,OAAO,YAAY,KAAK,WAAW,GAAG,YAAY,GAAG,IAAI;AAEnF,IAAA,OAAO,GAAG,OAAO,gBAAgB,KAAK;AACrD,UAAE,IAAI,gBAAgB,CAACA,cAAY;UACjC,IAAI;AAER,IAAA,WAAA,GAAA;AACE,QAAA,MAAM,YAAY,GAAG,MAAM,CAAC,qBAAqB,CAAC;AAElD,QAAA,KAAK,MAAM,CAAC,GAAG,EAAE,YAAY,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE;YAC9D,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC;AACpC,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI;AAC9C,YAAA,MAAM,KAAK,GAAG,GAAG,KAAK,IAAI,GAAG,WAAW,CAAC,GAAG,EAAE,YAAY,CAAC,GAAG,YAAY;AAC1E,YAAA,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK;kFAAC;YACvB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;YAExB,MAAM,CAAC,MAAK;AACV,gBAAA,MAAM,OAAO,GAAG,CAAC,EAAE;AACnB,gBAAA,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;;AAE9C,gBAAA,IAAI,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE;AACpD,oBAAA,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC;oBAC9B;gBACF;AACA,gBAAA,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAyB,CAAC;AAC3E,YAAA,CAAC,CAAC;QACJ;AAEA,QAAA,IAAI,CAAC,OAAO,EAAE,gBAAgB,CAAC,SAAS,EAAE,CAAC,EAAE,IAAI,EAA8B,KAAI;AACjF,YAAA,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;AACpC,YAAA,IAAI,CAAC,CAAC;gBAAE;YACR,IAAI,UAAU,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC;gBAAE;;;AAGjC,YAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC;AAC5C,YAAA,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;AACnB,QAAA,CAAC,CAAC;IACJ;;AAGA,IAAA,GAAG,CAAI,GAAW,EAAA;QAChB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;AAC1B,YAAA,MAAM,IAAI,KAAK,CACb,CAAA,oCAAA,EAAuC,GAAG,CAAA,GAAA,CAAK;gBAC/C,CAAA,+EAAA,EAAkF,GAAG,CAAA,iBAAA,CAAmB,CACzG;QACH;QACA,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAsB;IACnD;;IAGA,GAAG,CAAI,GAAW,EAAE,KAAQ,EAAA;QAC1B,IAAI,CAAC,GAAG,CAAI,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;IAC7B;IAEA,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE;IACvB;uGApEW,eAAe,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAf,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,eAAe,cADF,MAAM,EAAA,CAAA;;2FACnB,eAAe,EAAA,UAAA,EAAA,CAAA;kBAD3B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;ACxClC,MAAM,YAAY,GAAG,mCAAmC;AAOxD;;;AAGG;MAEU,uBAAuB,CAAA;AACjB,IAAA,OAAO,GAAG,IAAI,GAAG,EAAyC;;AAE1D,IAAA,SAAS,GAAG,IAAI,GAAG,EAAU;AAE7B,IAAA,OAAO,GAAmB,OAAO,YAAY,KAAK,WAAW,GAAG,YAAY,GAAG,IAAI;AAEnF,IAAA,OAAO,GAAG,OAAO,gBAAgB,KAAK;AACrD,UAAE,IAAI,gBAAgB,CAAC,YAAY;UACjC,IAAI;AAER;;;;AAIG;AACc,IAAA,aAAa,GAAG,IAAI,GAAG,EAAyB;AAEjE,IAAA,WAAA,GAAA;AACE,QAAA,IAAI,CAAC,OAAO,EAAE,gBAAgB,CAAC,SAAS,EAAE,CAAC,EAAE,IAAI,EAA+B,KAAI;AAClF,YAAA,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE;;AAEzB,gBAAA,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAG;oBACpB,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC;AAC/B,oBAAA,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;AAC3B,oBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC;AAChC,gBAAA,CAAC,CAAC;YACJ;AAAO,iBAAA,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE;gBACjC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC;gBACtC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC;AAClC,gBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC;YACvC;iBAAO;AACL,gBAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC;AAC5C,gBAAA,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC;AAC3C,gBAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;YAC5C;AACF,QAAA,CAAC,CAAC;IACJ;AAEA,IAAA,SAAS,CAAC,GAAW,EAAA;QACnB,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE;IAC3C;AAEA,IAAA,GAAG,CAAC,GAAW,EAAA;AACb,QAAA,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE;IAC9B;IAEA,GAAG,CAAC,GAAW,EAAE,KAAa,EAAA;AAC5B,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;QACvB,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC;QACjC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;QAChC,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,KAAK,EAAE;AACzC,YAAA,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC;YAC9B;QACF;AACA,QAAA,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAA0B,CAAC;IAChF;AAEA,IAAA,MAAM,CAAC,GAAW,EAAA;AAChB,QAAA,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC;AAC1B,QAAA,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,CAAC;AAC7B,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC;QAChC,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;AACvE,YAAA,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC;YAC9B;QACF;AACA,QAAA,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAA0B,CAAC;IAC5E;;IAGA,KAAK,GAAA;QACH,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC;AAChC,QAAA,IAAI,CAAC,OAAO,CAAC,CAAC,IAAG;AACf,YAAA,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;AAC3B,YAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC;AAChC,QAAA,CAAC,CAAC;AACF,QAAA,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE;AACtB,QAAA,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAA0B,CAAC;IAC5E;IAEA,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE;IACvB;AAEQ,IAAA,WAAW,CAAC,GAAW,EAAA;QAC7B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;YAC1B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC;QACnE;QACA,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAE;IAC/B;uGAzFW,uBAAuB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAvB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,uBAAuB,cADV,MAAM,EAAA,CAAA;;2FACnB,uBAAuB,EAAA,UAAA,EAAA,CAAA;kBADnC,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;ACGlC;;;;;;;;;AASG;AACG,SAAU,mBAAmB,CAAC,MAA0B,EAAA;AAC5D,IAAA,OAAO,wBAAwB,CAAC;QAC9B,EAAE,OAAO,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,CAAC,YAAY,EAAE;AAClE,KAAA,CAAC;AACJ;;AC9BA;;AAEG;;ACFH;;AAEG;;;;"}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dever-labs/ngx-mfe-broker",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Angular Signals + BroadcastChannel state broker for micro-frontends. Synchronises state across MFEs and browser tabs via localStorage persistence and BroadcastChannel cross-tab sync.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"angular",
|
|
7
|
+
"micro-frontends",
|
|
8
|
+
"mfe",
|
|
9
|
+
"signals",
|
|
10
|
+
"broadcast-channel",
|
|
11
|
+
"state-management",
|
|
12
|
+
"native-federation",
|
|
13
|
+
"cross-tab",
|
|
14
|
+
"localStorage"
|
|
15
|
+
],
|
|
16
|
+
"author": {
|
|
17
|
+
"name": "Dever Labs",
|
|
18
|
+
"url": "https://github.com/dever-labs"
|
|
19
|
+
},
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/dever-labs/ngx-mfe-broker.git"
|
|
24
|
+
},
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/dever-labs/ngx-mfe-broker/issues"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/dever-labs/ngx-mfe-broker#readme",
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=20.0.0",
|
|
31
|
+
"npm": ">=9.0.0"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@angular/core": ">=22.0.0"
|
|
35
|
+
},
|
|
36
|
+
"peerDependenciesMeta": {
|
|
37
|
+
"@angular/core": {
|
|
38
|
+
"optional": false
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"tslib": "^2.3.0"
|
|
43
|
+
},
|
|
44
|
+
"sideEffects": false,
|
|
45
|
+
"module": "fesm2022/dever-labs-ngx-mfe-broker.mjs",
|
|
46
|
+
"typings": "types/dever-labs-ngx-mfe-broker.d.ts",
|
|
47
|
+
"exports": {
|
|
48
|
+
"./package.json": {
|
|
49
|
+
"default": "./package.json"
|
|
50
|
+
},
|
|
51
|
+
".": {
|
|
52
|
+
"types": "./types/dever-labs-ngx-mfe-broker.d.ts",
|
|
53
|
+
"default": "./fesm2022/dever-labs-ngx-mfe-broker.mjs"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"type": "module"
|
|
57
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { OnDestroy, WritableSignal, InjectionToken, Signal, EnvironmentProviders } from '@angular/core';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Injection token used to supply the initial state shape and default values.
|
|
6
|
+
*
|
|
7
|
+
* Provide this via `provideNgxMfeBroker({ initialState: { ... } })`.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* provideNgxMfeBroker({ initialState: { theme: 'light', token: null } })
|
|
11
|
+
*/
|
|
12
|
+
declare const NGX_MFE_INITIAL_STATE: InjectionToken<Record<string, unknown>>;
|
|
13
|
+
/**
|
|
14
|
+
* Generic typed state service for micro-frontends.
|
|
15
|
+
*
|
|
16
|
+
* State is backed by localStorage, reactive via Angular Signals, and
|
|
17
|
+
* synchronised across browser tabs via BroadcastChannel.
|
|
18
|
+
*
|
|
19
|
+
* Consumers define their own state shape by providing `NGX_MFE_INITIAL_STATE`.
|
|
20
|
+
* Use `get<T>(key)` / `set(key, value)` for type-safe access.
|
|
21
|
+
*/
|
|
22
|
+
declare class MfeStateService implements OnDestroy {
|
|
23
|
+
private readonly signals;
|
|
24
|
+
private readonly defaults;
|
|
25
|
+
/**
|
|
26
|
+
* Value-based guard: stores the last value received from another tab for
|
|
27
|
+
* each key. The effect checks this map instead of a time-sensitive Set so
|
|
28
|
+
* the check happens at effect execution time — guaranteed after the signal
|
|
29
|
+
* update — rather than racing against queueMicrotask cleanup.
|
|
30
|
+
*/
|
|
31
|
+
private readonly inboundValues;
|
|
32
|
+
private readonly storage;
|
|
33
|
+
private readonly channel;
|
|
34
|
+
constructor();
|
|
35
|
+
/** Get a typed Signal for the given key. Key must be registered in `NGX_MFE_INITIAL_STATE`. */
|
|
36
|
+
get<T>(key: string): WritableSignal<T>;
|
|
37
|
+
/** Set a value — persists to localStorage and broadcasts cross-tab. */
|
|
38
|
+
set<T>(key: string, value: T): void;
|
|
39
|
+
ngOnDestroy(): void;
|
|
40
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<MfeStateService, never>;
|
|
41
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<MfeStateService>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Generic cross-tab string key-value store backed by localStorage.
|
|
46
|
+
* Changes are broadcast to all other tabs/windows via BroadcastChannel.
|
|
47
|
+
*/
|
|
48
|
+
declare class ConfigRepositoryService implements OnDestroy {
|
|
49
|
+
private readonly signals;
|
|
50
|
+
/** Tracks every key ever written so clear() only removes its own keys. */
|
|
51
|
+
private readonly ownedKeys;
|
|
52
|
+
private readonly storage;
|
|
53
|
+
private readonly channel;
|
|
54
|
+
/**
|
|
55
|
+
* Value-based inbound guard: stores the last value received from another tab.
|
|
56
|
+
* `null` means the last inbound operation was a remove for that key.
|
|
57
|
+
* Checked synchronously in set()/remove() to prevent re-broadcasting received updates.
|
|
58
|
+
*/
|
|
59
|
+
private readonly inboundValues;
|
|
60
|
+
constructor();
|
|
61
|
+
getSignal(key: string): Signal<string | null>;
|
|
62
|
+
get(key: string): string | null;
|
|
63
|
+
set(key: string, value: string): void;
|
|
64
|
+
remove(key: string): void;
|
|
65
|
+
/** Removes only keys written by this service — does not touch unrelated localStorage entries. */
|
|
66
|
+
clear(): void;
|
|
67
|
+
ngOnDestroy(): void;
|
|
68
|
+
private getWritable;
|
|
69
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ConfigRepositoryService, never>;
|
|
70
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<ConfigRepositoryService>;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
interface NgxMfeBrokerConfig {
|
|
74
|
+
/**
|
|
75
|
+
* Initial state values with their default values.
|
|
76
|
+
* Each key becomes a Signal backed by localStorage with cross-tab sync.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* provideNgxMfeBroker({
|
|
80
|
+
* initialState: { theme: 'light', token: null, users: [] }
|
|
81
|
+
* })
|
|
82
|
+
*/
|
|
83
|
+
initialState: Record<string, unknown>;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Call in your `app.config.ts` to configure `@dever-labs/ngx-mfe-broker`.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* export const appConfig: ApplicationConfig = {
|
|
90
|
+
* providers: [
|
|
91
|
+
* provideNgxMfeBroker({ initialState: { theme: 'light', token: null } }),
|
|
92
|
+
* ]
|
|
93
|
+
* };
|
|
94
|
+
*/
|
|
95
|
+
declare function provideNgxMfeBroker(config: NgxMfeBrokerConfig): EnvironmentProviders;
|
|
96
|
+
|
|
97
|
+
export { ConfigRepositoryService, MfeStateService, NGX_MFE_INITIAL_STATE, provideNgxMfeBroker };
|
|
98
|
+
export type { NgxMfeBrokerConfig };
|