@squide/firefly 16.0.3 → 16.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.
- package/CHANGELOG.md +15 -0
- package/dist/AppRouter.js +1 -1
- package/dist/AppRouter.js.map +1 -1
- package/dist/AppRouterContext.js +2 -2
- package/dist/AppRouterContext.js.map +1 -1
- package/dist/AppRouterReducer.d.ts +3 -1
- package/dist/AppRouterReducer.js +35 -4
- package/dist/AppRouterReducer.js.map +1 -1
- package/dist/AppRouterStore.js +8 -0
- package/dist/AppRouterStore.js.map +1 -1
- package/dist/FireflyRuntime.d.ts +32 -16
- package/dist/FireflyRuntime.js +61 -19
- package/dist/FireflyRuntime.js.map +1 -1
- package/dist/honeycomb/activeSpan.js +2 -2
- package/dist/honeycomb/activeSpan.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/initializeFirefly.d.ts +4 -2
- package/dist/initializeFirefly.js +15 -4
- package/dist/initializeFirefly.js.map +1 -1
- package/dist/useCanUpdateDeferredRegistrations.js +2 -2
- package/dist/useCanUpdateDeferredRegistrations.js.map +1 -1
- package/dist/useDeferredRegistrations.d.ts +1 -1
- package/dist/useDeferredRegistrations.js +6 -5
- package/dist/useDeferredRegistrations.js.map +1 -1
- package/dist/useRegisterDeferredRegistrations.d.ts +1 -2
- package/dist/useRegisterDeferredRegistrations.js +9 -2
- package/dist/useRegisterDeferredRegistrations.js.map +1 -1
- package/dist/useStrictRegistrationMode.js +10 -8
- package/dist/useStrictRegistrationMode.js.map +1 -1
- package/dist/useUpdateDeferredRegistrations.d.ts +1 -2
- package/dist/useUpdateDeferredRegistrations.js +7 -1
- package/dist/useUpdateDeferredRegistrations.js.map +1 -1
- package/package.json +19 -17
- package/src/AppRouter.tsx +1 -1
- package/src/AppRouterContext.ts +1 -1
- package/src/AppRouterReducer.ts +38 -3
- package/src/AppRouterStore.ts +8 -0
- package/src/FireflyRuntime.tsx +85 -30
- package/src/honeycomb/activeSpan.ts +1 -1
- package/src/index.ts +18 -2
- package/src/initializeFirefly.ts +38 -27
- package/src/useCanUpdateDeferredRegistrations.ts +3 -1
- package/src/useDeferredRegistrations.ts +15 -6
- package/src/useRegisterDeferredRegistrations.ts +5 -3
- package/src/useStrictRegistrationMode.ts +11 -11
- package/src/useUpdateDeferredRegistrations.ts +4 -3
package/src/AppRouterContext.ts
CHANGED
package/src/AppRouterReducer.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useEventBus, useLogger, useRuntime } from "@squide/core";
|
|
2
|
+
import type { FeatureFlagSetSnapshotChangedListener } from "@squide/launch-darkly";
|
|
2
3
|
import { useCallback, useEffect, useMemo, useReducer, type Dispatch } from "react";
|
|
3
4
|
import type { FireflyRuntime } from "./FireflyRuntime.tsx";
|
|
4
5
|
import { useAppRouterStore } from "./useAppRouterStore.ts";
|
|
@@ -21,6 +22,7 @@ export interface AppRouterState extends AppRouterWaitState {
|
|
|
21
22
|
isProtectedDataReady: boolean;
|
|
22
23
|
publicDataUpdatedAt?: number;
|
|
23
24
|
protectedDataUpdatedAt?: number;
|
|
25
|
+
featureFlagsUpdatedAt?: number;
|
|
24
26
|
deferredRegistrationsUpdatedAt?: number;
|
|
25
27
|
activeRouteVisibility: ActiveRouteVisiblity;
|
|
26
28
|
isUnauthorized: boolean;
|
|
@@ -34,6 +36,7 @@ export type AppRouterActionType =
|
|
|
34
36
|
| "protected-data-ready"
|
|
35
37
|
| "public-data-updated"
|
|
36
38
|
| "protected-data-updated"
|
|
39
|
+
| "feature-flags-updated"
|
|
37
40
|
| "deferred-registrations-updated"
|
|
38
41
|
| "active-route-is-public"
|
|
39
42
|
| "active-route-is-protected"
|
|
@@ -124,6 +127,14 @@ function reducer(state: AppRouterState, action: AppRouterAction) {
|
|
|
124
127
|
|
|
125
128
|
break;
|
|
126
129
|
}
|
|
130
|
+
case "feature-flags-updated": {
|
|
131
|
+
newState = {
|
|
132
|
+
...newState,
|
|
133
|
+
featureFlagsUpdatedAt: Date.now()
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
127
138
|
case "deferred-registrations-updated": {
|
|
128
139
|
newState = {
|
|
129
140
|
...newState,
|
|
@@ -225,16 +236,39 @@ export function useMswStatusDispatcher(runtime: FireflyRuntime, isMswReadyValue:
|
|
|
225
236
|
useEffect(() => {
|
|
226
237
|
if (runtime.isMswEnabled) {
|
|
227
238
|
if (!isMswReadyValue) {
|
|
228
|
-
runtime.
|
|
239
|
+
runtime.mswState.addMswReadyListener(dispatchMswReady);
|
|
229
240
|
}
|
|
230
241
|
|
|
231
242
|
return () => {
|
|
232
|
-
runtime.
|
|
243
|
+
runtime.mswState.removeMswReadyListener(dispatchMswReady);
|
|
233
244
|
};
|
|
234
245
|
}
|
|
235
246
|
}, [runtime, isMswReadyValue, dispatchMswReady]);
|
|
236
247
|
}
|
|
237
248
|
|
|
249
|
+
export function useFeatureFlagsUpdatedDispatcher(runtime: FireflyRuntime, dispatch: AppRouterDispatch) {
|
|
250
|
+
const logger = useLogger();
|
|
251
|
+
|
|
252
|
+
const dispatchFeatureFlagsUpdated = useCallback((changes => {
|
|
253
|
+
dispatch({ type: "feature-flags-updated" });
|
|
254
|
+
|
|
255
|
+
logger
|
|
256
|
+
.withText("[squide] Feature flags has been updated to:")
|
|
257
|
+
.withObject(changes)
|
|
258
|
+
.debug();
|
|
259
|
+
}) satisfies FeatureFlagSetSnapshotChangedListener, [dispatch, logger]);
|
|
260
|
+
|
|
261
|
+
useEffect(() => {
|
|
262
|
+
if (runtime.isLaunchDarklyEnabled) {
|
|
263
|
+
runtime.featureFlagSetSnapshot.addSnapshotChangedListener(dispatchFeatureFlagsUpdated);
|
|
264
|
+
|
|
265
|
+
return () => {
|
|
266
|
+
runtime.featureFlagSetSnapshot.removeSnapshotChangedListener(dispatchFeatureFlagsUpdated);
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
}, [runtime]);
|
|
270
|
+
}
|
|
271
|
+
|
|
238
272
|
function useBootstrappingCompletedDispatcher(waitState: AppRouterWaitState, state: AppRouterState) {
|
|
239
273
|
const eventBus = useEventBus();
|
|
240
274
|
|
|
@@ -296,7 +330,7 @@ export function useAppRouterReducer(waitForPublicData: boolean, waitForProtected
|
|
|
296
330
|
const isMswEnabled = runtime.isMswEnabled;
|
|
297
331
|
const areModulesInitiallyRegistered = runtime.moduleManager.getAreModulesRegistered();
|
|
298
332
|
const areModulesInitiallyReady = runtime.moduleManager.getAreModulesReady();
|
|
299
|
-
const isMswInitiallyReady = runtime.isMswEnabled ? runtime.
|
|
333
|
+
const isMswInitiallyReady = runtime.isMswEnabled ? runtime.mswState.isReady : false;
|
|
300
334
|
|
|
301
335
|
const waitState = useMemo(() => ({
|
|
302
336
|
waitForMsw: isMswEnabled,
|
|
@@ -366,6 +400,7 @@ export function useAppRouterReducer(waitForPublicData: boolean, waitForProtected
|
|
|
366
400
|
|
|
367
401
|
useModuleRegistrationStatusDispatcher(runtime, areModulesRegisteredValue, areModulesReadyValue, dispatch);
|
|
368
402
|
useMswStatusDispatcher(runtime, isMswReadyValue, dispatch);
|
|
403
|
+
useFeatureFlagsUpdatedDispatcher(runtime, dispatch);
|
|
369
404
|
useBootstrappingCompletedDispatcher(waitState, state);
|
|
370
405
|
|
|
371
406
|
return [state, dispatch];
|
package/src/AppRouterStore.ts
CHANGED
|
@@ -115,6 +115,14 @@ export class AppRouterStore {
|
|
|
115
115
|
|
|
116
116
|
break;
|
|
117
117
|
}
|
|
118
|
+
case "feature-flags-updated": {
|
|
119
|
+
newState = {
|
|
120
|
+
...newState,
|
|
121
|
+
featureFlagsUpdatedAt: Date.now()
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
118
126
|
case "deferred-registrations-updated": {
|
|
119
127
|
newState = {
|
|
120
128
|
...newState,
|
package/src/FireflyRuntime.tsx
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { RegisterRouteOptions, RuntimeMethodOptions, RuntimeOptions } from "@squide/core";
|
|
2
|
-
import { EnvironmentVariableKey, EnvironmentVariables,
|
|
2
|
+
import { EnvironmentVariableKey, EnvironmentVariables, getEnvironmentVariablesPlugin } from "@squide/env-vars";
|
|
3
|
+
import { FeatureFlagKey, FeatureFlags, FeatureFlagSetSnapshot, getLaunchDarklyPlugin, LaunchDarklyPluginName } from "@squide/launch-darkly";
|
|
3
4
|
import { getMswPlugin, MswPluginName, MswState } from "@squide/msw";
|
|
4
5
|
import { type IReactRouterRuntime, ReactRouterRuntime, ReactRouterRuntimeScope, type Route } from "@squide/react-router";
|
|
5
6
|
import type { HoneycombInstrumentationPartialClient } from "@workleap-telemetry/core";
|
|
6
7
|
import type { Logger } from "@workleap/logging";
|
|
8
|
+
import { LDClient } from "launchdarkly-js-client-sdk";
|
|
7
9
|
import type { RequestHandler } from "msw";
|
|
8
10
|
import { type AppRouterStore, createAppRouterStore } from "./AppRouterStore.ts";
|
|
9
11
|
|
|
@@ -14,22 +16,29 @@ export interface FireflyRuntimeOptions<TRuntime extends FireflyRuntime = Firefly
|
|
|
14
16
|
export interface RegisterRequestHandlersOptions extends RuntimeMethodOptions {}
|
|
15
17
|
|
|
16
18
|
export interface IFireflyRuntime extends IReactRouterRuntime {
|
|
17
|
-
|
|
19
|
+
get isMswEnabled(): boolean;
|
|
20
|
+
get mswState(): MswState;
|
|
18
21
|
registerRequestHandlers: (handlers: RequestHandler[]) => void;
|
|
19
22
|
get requestHandlers(): RequestHandler[];
|
|
20
|
-
|
|
21
|
-
registerEnvironmentVariable(key: EnvironmentVariableKey, value: EnvironmentVariableValue): void;
|
|
23
|
+
registerEnvironmentVariable<T extends EnvironmentVariableKey>(key: T, value: EnvironmentVariables[T]): void;
|
|
22
24
|
registerEnvironmentVariables(variables: Partial<EnvironmentVariables>): void;
|
|
23
|
-
getEnvironmentVariable(key:
|
|
24
|
-
|
|
25
|
+
getEnvironmentVariable<T extends EnvironmentVariableKey>(key: T): EnvironmentVariables[T];
|
|
26
|
+
get environmentVariables(): EnvironmentVariables;
|
|
25
27
|
get appRouterStore(): AppRouterStore;
|
|
26
28
|
get honeycombInstrumentationClient(): HoneycombInstrumentationPartialClient | undefined;
|
|
29
|
+
get isLaunchDarklyEnabled(): boolean;
|
|
30
|
+
get launchDarklyClient(): LDClient;
|
|
31
|
+
get featureFlags(): FeatureFlags;
|
|
32
|
+
getFeatureFlag(key: string, defaultValue?: unknown): unknown;
|
|
33
|
+
get featureFlagSetSnapshot(): FeatureFlagSetSnapshot;
|
|
27
34
|
}
|
|
28
35
|
|
|
29
36
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
37
|
export class FireflyRuntime<TRuntime extends FireflyRuntime = any> extends ReactRouterRuntime<TRuntime> implements IFireflyRuntime {
|
|
31
|
-
|
|
32
|
-
|
|
38
|
+
readonly #appRouterStore: AppRouterStore;
|
|
39
|
+
readonly #honeycombInstrumentationClient: HoneycombInstrumentationPartialClient | undefined;
|
|
40
|
+
readonly #isMswEnabled: boolean;
|
|
41
|
+
readonly #isLaunchDarklyEnabled: boolean;
|
|
33
42
|
|
|
34
43
|
constructor(options: FireflyRuntimeOptions = {}) {
|
|
35
44
|
const {
|
|
@@ -38,8 +47,10 @@ export class FireflyRuntime<TRuntime extends FireflyRuntime = any> extends React
|
|
|
38
47
|
|
|
39
48
|
super(options);
|
|
40
49
|
|
|
41
|
-
this
|
|
42
|
-
this
|
|
50
|
+
this.#appRouterStore = createAppRouterStore(this._logger);
|
|
51
|
+
this.#honeycombInstrumentationClient = honeycombInstrumentationClient;
|
|
52
|
+
this.#isMswEnabled = this._plugins.some(x => x.name === MswPluginName);
|
|
53
|
+
this.#isLaunchDarklyEnabled = this._plugins.some(x => x.name === LaunchDarklyPluginName);
|
|
43
54
|
}
|
|
44
55
|
|
|
45
56
|
registerRoute(route: Route, options: RegisterRouteOptions = {}) {
|
|
@@ -50,7 +61,11 @@ export class FireflyRuntime<TRuntime extends FireflyRuntime = any> extends React
|
|
|
50
61
|
super.registerRoute(route, options);
|
|
51
62
|
}
|
|
52
63
|
|
|
53
|
-
|
|
64
|
+
get isMswEnabled() {
|
|
65
|
+
return this.#isMswEnabled;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
get mswState() {
|
|
54
69
|
const plugin = getMswPlugin(this);
|
|
55
70
|
|
|
56
71
|
return plugin.mswState;
|
|
@@ -76,23 +91,19 @@ export class FireflyRuntime<TRuntime extends FireflyRuntime = any> extends React
|
|
|
76
91
|
return plugin.requestHandlers;
|
|
77
92
|
}
|
|
78
93
|
|
|
79
|
-
get isMswEnabled() {
|
|
80
|
-
return this._plugins.some(x => x.name === MswPluginName);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
94
|
getEnvironmentVariable(key: EnvironmentVariableKey) {
|
|
84
95
|
const plugin = getEnvironmentVariablesPlugin(this);
|
|
85
96
|
|
|
86
97
|
return plugin.getVariable(key);
|
|
87
98
|
}
|
|
88
99
|
|
|
89
|
-
|
|
100
|
+
get environmentVariables() {
|
|
90
101
|
const plugin = getEnvironmentVariablesPlugin(this);
|
|
91
102
|
|
|
92
103
|
return plugin.getVariables();
|
|
93
104
|
}
|
|
94
105
|
|
|
95
|
-
registerEnvironmentVariable(key:
|
|
106
|
+
registerEnvironmentVariable<T extends EnvironmentVariableKey>(key: T, value: EnvironmentVariables[T]) {
|
|
96
107
|
const plugin = getEnvironmentVariablesPlugin(this);
|
|
97
108
|
|
|
98
109
|
return plugin.registerVariable(key, value);
|
|
@@ -105,11 +116,31 @@ export class FireflyRuntime<TRuntime extends FireflyRuntime = any> extends React
|
|
|
105
116
|
}
|
|
106
117
|
|
|
107
118
|
get appRouterStore() {
|
|
108
|
-
return this
|
|
119
|
+
return this.#appRouterStore;
|
|
109
120
|
}
|
|
110
121
|
|
|
111
122
|
get honeycombInstrumentationClient() {
|
|
112
|
-
return this
|
|
123
|
+
return this.#honeycombInstrumentationClient;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
get isLaunchDarklyEnabled() {
|
|
127
|
+
return this.#isLaunchDarklyEnabled;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
get launchDarklyClient() {
|
|
131
|
+
return getLaunchDarklyPlugin(this).client;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
get featureFlags() {
|
|
135
|
+
return this.featureFlagSetSnapshot.value;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
getFeatureFlag<T extends FeatureFlagKey>(key: T, defaultValue?: FeatureFlags[T]) {
|
|
139
|
+
return getLaunchDarklyPlugin(this).getFeatureFlag(key, defaultValue);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
get featureFlagSetSnapshot() {
|
|
143
|
+
return getLaunchDarklyPlugin(this).featureFlagSetSnapshot;
|
|
113
144
|
}
|
|
114
145
|
|
|
115
146
|
startScope(logger: Logger): TRuntime {
|
|
@@ -118,8 +149,12 @@ export class FireflyRuntime<TRuntime extends FireflyRuntime = any> extends React
|
|
|
118
149
|
}
|
|
119
150
|
|
|
120
151
|
export class FireflyRuntimeScope<TRuntime extends FireflyRuntime = FireflyRuntime> extends ReactRouterRuntimeScope<TRuntime> implements IFireflyRuntime {
|
|
121
|
-
|
|
122
|
-
return this._runtime.
|
|
152
|
+
get isMswEnabled() {
|
|
153
|
+
return this._runtime.isMswEnabled;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
get mswState() {
|
|
157
|
+
return this._runtime.mswState;
|
|
123
158
|
}
|
|
124
159
|
|
|
125
160
|
registerRequestHandlers(handlers: RequestHandler[], options: RegisterRequestHandlersOptions = {}) {
|
|
@@ -134,19 +169,15 @@ export class FireflyRuntimeScope<TRuntime extends FireflyRuntime = FireflyRuntim
|
|
|
134
169
|
return this._runtime.requestHandlers;
|
|
135
170
|
}
|
|
136
171
|
|
|
137
|
-
get isMswEnabled() {
|
|
138
|
-
return this._runtime.isMswEnabled;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
getEnvironmentVariables() {
|
|
142
|
-
return this._runtime.getEnvironmentVariables();
|
|
143
|
-
}
|
|
144
|
-
|
|
145
172
|
getEnvironmentVariable(key: EnvironmentVariableKey) {
|
|
146
173
|
return this._runtime.getEnvironmentVariable(key);
|
|
147
174
|
}
|
|
148
175
|
|
|
149
|
-
|
|
176
|
+
get environmentVariables() {
|
|
177
|
+
return this._runtime.environmentVariables;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
registerEnvironmentVariable<T extends EnvironmentVariableKey>(key: T, value: EnvironmentVariables[T]) {
|
|
150
181
|
this._runtime.registerEnvironmentVariable(key, value);
|
|
151
182
|
}
|
|
152
183
|
|
|
@@ -161,4 +192,28 @@ export class FireflyRuntimeScope<TRuntime extends FireflyRuntime = FireflyRuntim
|
|
|
161
192
|
get honeycombInstrumentationClient(): HoneycombInstrumentationPartialClient {
|
|
162
193
|
throw new Error("[squide] Cannot retrieve the Honeycomb instrumentation client from a runtime scope instance.");
|
|
163
194
|
}
|
|
195
|
+
|
|
196
|
+
get isLaunchDarklyEnabled() {
|
|
197
|
+
return this._runtime.isLaunchDarklyEnabled;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
get launchDarklyClient() {
|
|
201
|
+
return this._runtime.launchDarklyClient;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
get featureFlags() {
|
|
205
|
+
return this._runtime.featureFlags;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
getFeatureFlag<T extends FeatureFlagKey>(key: T, defaultValue?: FeatureFlags[T]) {
|
|
209
|
+
// The error is because the FeatureFlags interface is empty as it is expected to be augmented by the
|
|
210
|
+
// consumer application.
|
|
211
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
212
|
+
// @ts-ignore
|
|
213
|
+
return this._runtime.getFeatureFlag(key, defaultValue);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
get featureFlagSetSnapshot() {
|
|
217
|
+
return this._runtime.featureFlagSetSnapshot;
|
|
218
|
+
}
|
|
164
219
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Span } from "@opentelemetry/api";
|
|
2
|
-
import { isPlainObject } from "@squide/core";
|
|
2
|
+
import { isPlainObject } from "@squide/core/internal";
|
|
3
3
|
import type { Logger } from "@workleap/logging";
|
|
4
4
|
import { v4 as uuidv4 } from "uuid";
|
|
5
5
|
import { createTraceContextId } from "./createTraceContextId.ts";
|
package/src/index.ts
CHANGED
|
@@ -7,9 +7,25 @@ export {
|
|
|
7
7
|
useEnvironmentVariables,
|
|
8
8
|
type EnvironmentVariableKey,
|
|
9
9
|
type EnvironmentVariables,
|
|
10
|
-
type EnvironmentVariablesPluginOptions
|
|
11
|
-
type EnvironmentVariableValue
|
|
10
|
+
type EnvironmentVariablesPluginOptions
|
|
12
11
|
} from "@squide/env-vars";
|
|
12
|
+
export {
|
|
13
|
+
FeatureFlagSetSnapshot,
|
|
14
|
+
getFeatureFlag,
|
|
15
|
+
getLaunchDarklyPlugin,
|
|
16
|
+
InMemoryLaunchDarklyClient,
|
|
17
|
+
LaunchDarklyClientNotifier,
|
|
18
|
+
LaunchDarklyPlugin,
|
|
19
|
+
LaunchDarklyPluginName,
|
|
20
|
+
useFeatureFlag,
|
|
21
|
+
useFeatureFlags,
|
|
22
|
+
useLaunchDarklyClient,
|
|
23
|
+
type FeatureFlagKey,
|
|
24
|
+
type FeatureFlags,
|
|
25
|
+
type FeatureFlagSetSnapshotChangedListener,
|
|
26
|
+
type InMemoryLaunchDarklyClientOptions,
|
|
27
|
+
type LaunchDarklyClientListener
|
|
28
|
+
} from "@squide/launch-darkly";
|
|
13
29
|
export {
|
|
14
30
|
getMswPlugin,
|
|
15
31
|
MswPlugin,
|
package/src/initializeFirefly.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ModuleDefinition, toLocalModuleDefinitions, type ModuleRegisterFunction, type RegisterModulesOptions } from "@squide/core";
|
|
2
|
+
import { isFunction } from "@squide/core/internal";
|
|
2
3
|
import { EnvironmentVariables, EnvironmentVariablesPlugin } from "@squide/env-vars";
|
|
4
|
+
import { LaunchDarklyPlugin } from "@squide/launch-darkly";
|
|
3
5
|
import { MswPlugin } from "@squide/msw";
|
|
4
6
|
import type { HoneycombInstrumentationPartialClient } from "@workleap-telemetry/core";
|
|
7
|
+
import { LDClient } from "launchdarkly-js-client-sdk";
|
|
5
8
|
import { FireflyRuntime, type FireflyRuntimeOptions } from "./FireflyRuntime.tsx";
|
|
6
9
|
import { initializeHoneycomb } from "./honeycomb/initializeHoneycomb.ts";
|
|
7
10
|
|
|
@@ -12,18 +15,19 @@ export type OnInitializationErrorFunction = (error: unknown) => void;
|
|
|
12
15
|
export type StartMswFunction<TRuntime = FireflyRuntime> = (runtime: TRuntime) => Promise<void>;
|
|
13
16
|
|
|
14
17
|
export interface InitializeFireflyOptions<TRuntime extends FireflyRuntime, TContext = unknown, TData = unknown> extends RegisterModulesOptions<TContext>, FireflyRuntimeOptions {
|
|
15
|
-
localModules?: ModuleRegisterFunction<TRuntime, TContext, TData>[];
|
|
18
|
+
localModules?: (ModuleRegisterFunction<TRuntime, TContext, TData> | undefined)[];
|
|
16
19
|
moduleDefinitions?: ModuleDefinition<TRuntime, TContext, TData>[];
|
|
17
20
|
useMsw?: boolean;
|
|
18
21
|
environmentVariables?: Partial<EnvironmentVariables>;
|
|
19
22
|
honeycombInstrumentationClient?: HoneycombInstrumentationPartialClient;
|
|
23
|
+
launchDarklyClient?: LDClient;
|
|
20
24
|
startMsw?: StartMswFunction<FireflyRuntime>;
|
|
21
25
|
onError?: OnInitializationErrorFunction;
|
|
22
26
|
}
|
|
23
27
|
|
|
24
28
|
export function bootstrap<TRuntime extends FireflyRuntime = FireflyRuntime, TContext = unknown, TData = unknown>(
|
|
25
29
|
runtime: TRuntime,
|
|
26
|
-
modulesDefinitions: ModuleDefinition<TRuntime, TContext, TData>[],
|
|
30
|
+
modulesDefinitions: (ModuleDefinition<TRuntime, TContext, TData> | undefined)[],
|
|
27
31
|
options: Omit<InitializeFireflyOptions<TRuntime, TContext, TData>, "localModules" | "moduleDefinitions"> = {}
|
|
28
32
|
) {
|
|
29
33
|
const {
|
|
@@ -34,33 +38,35 @@ export function bootstrap<TRuntime extends FireflyRuntime = FireflyRuntime, TCon
|
|
|
34
38
|
|
|
35
39
|
runtime.eventBus.dispatch(ApplicationBootstrappingStartedEvent);
|
|
36
40
|
|
|
37
|
-
runtime.moduleManager.registerModules(
|
|
38
|
-
.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
startMsw(runtime)
|
|
45
|
-
.then(() => {
|
|
46
|
-
if (runtime.isMswEnabled) {
|
|
47
|
-
runtime.getMswState().setAsReady();
|
|
48
|
-
}
|
|
49
|
-
})
|
|
50
|
-
.catch((error: unknown) => {
|
|
51
|
-
runtime.logger
|
|
52
|
-
.withText("[squide] An error occured while starting MSW.")
|
|
53
|
-
.withError(error as Error)
|
|
54
|
-
.error();
|
|
55
|
-
});
|
|
41
|
+
runtime.moduleManager.registerModules(
|
|
42
|
+
modulesDefinitions.filter((x): x is ModuleDefinition => Boolean(x)),
|
|
43
|
+
{ context }
|
|
44
|
+
).then(results => {
|
|
45
|
+
if (runtime.isMswEnabled) {
|
|
46
|
+
if (!isFunction(startMsw)) {
|
|
47
|
+
throw new Error("[squide] When MSW is enabled, the \"startMsw\" function must be provided.");
|
|
56
48
|
}
|
|
57
49
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
50
|
+
startMsw(runtime)
|
|
51
|
+
.then(() => {
|
|
52
|
+
if (runtime.isMswEnabled) {
|
|
53
|
+
runtime.mswState.setAsReady();
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
.catch((error: unknown) => {
|
|
57
|
+
runtime.logger
|
|
58
|
+
.withText("[squide] An error occured while starting MSW.")
|
|
59
|
+
.withError(error as Error)
|
|
60
|
+
.error();
|
|
61
61
|
});
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (onError) {
|
|
65
|
+
results.forEach(error => {
|
|
66
|
+
onError(error);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
});
|
|
64
70
|
}
|
|
65
71
|
|
|
66
72
|
let hasExecuted = false;
|
|
@@ -79,6 +85,7 @@ export function initializeFirefly<TContext = unknown, TData = unknown>(options:
|
|
|
79
85
|
plugins = [],
|
|
80
86
|
environmentVariables,
|
|
81
87
|
honeycombInstrumentationClient,
|
|
88
|
+
launchDarklyClient,
|
|
82
89
|
loggers,
|
|
83
90
|
onError
|
|
84
91
|
} = options;
|
|
@@ -93,6 +100,10 @@ export function initializeFirefly<TContext = unknown, TData = unknown>(options:
|
|
|
93
100
|
plugins.push(x => new MswPlugin(x));
|
|
94
101
|
}
|
|
95
102
|
|
|
103
|
+
if (launchDarklyClient) {
|
|
104
|
+
plugins.push(x => new LaunchDarklyPlugin(x, launchDarklyClient));
|
|
105
|
+
}
|
|
106
|
+
|
|
96
107
|
const runtime = new FireflyRuntime({
|
|
97
108
|
mode,
|
|
98
109
|
honeycombInstrumentationClient,
|
|
@@ -5,6 +5,7 @@ export function useCanUpdateDeferredRegistrations() {
|
|
|
5
5
|
areModulesReady,
|
|
6
6
|
publicDataUpdatedAt,
|
|
7
7
|
protectedDataUpdatedAt,
|
|
8
|
+
featureFlagsUpdatedAt,
|
|
8
9
|
deferredRegistrationsUpdatedAt
|
|
9
10
|
} = useAppRouterState();
|
|
10
11
|
|
|
@@ -17,7 +18,8 @@ export function useCanUpdateDeferredRegistrations() {
|
|
|
17
18
|
// If either the public data or the protected data has been updated, update the deferred registrations.
|
|
18
19
|
&& (
|
|
19
20
|
(publicDataUpdatedAt && publicDataUpdatedAt > deferredRegistrationsUpdatedAt) ||
|
|
20
|
-
(protectedDataUpdatedAt && protectedDataUpdatedAt > deferredRegistrationsUpdatedAt)
|
|
21
|
+
(protectedDataUpdatedAt && protectedDataUpdatedAt > deferredRegistrationsUpdatedAt) ||
|
|
22
|
+
(featureFlagsUpdatedAt && featureFlagsUpdatedAt > deferredRegistrationsUpdatedAt)
|
|
21
23
|
)
|
|
22
24
|
);
|
|
23
25
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useRuntime, type ModuleRegistrationError } from "@squide/core";
|
|
2
2
|
import { useEffect } from "react";
|
|
3
|
+
import { FireflyRuntime } from "./FireflyRuntime.tsx";
|
|
3
4
|
import { useCanRegisterDeferredRegistrations } from "./useCanRegisterDeferredRegistrations.ts";
|
|
4
5
|
import { useCanUpdateDeferredRegistrations } from "./useCanUpdateDeferredRegistrations.ts";
|
|
5
6
|
import { useRegisterDeferredRegistrations } from "./useRegisterDeferredRegistrations.ts";
|
|
@@ -11,8 +12,8 @@ export interface UseDeferredRegistrationsOptions {
|
|
|
11
12
|
onError?: DeferredRegistrationsErrorCallback;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
export function useDeferredRegistrations(data
|
|
15
|
-
const runtime = useRuntime();
|
|
15
|
+
export function useDeferredRegistrations(data?: unknown, { onError }: UseDeferredRegistrationsOptions = {}) {
|
|
16
|
+
const runtime = useRuntime() as FireflyRuntime;
|
|
16
17
|
|
|
17
18
|
const canRegisterDeferredRegistrations = useCanRegisterDeferredRegistrations();
|
|
18
19
|
const canUpdateDeferredRegistrations = useCanUpdateDeferredRegistrations();
|
|
@@ -23,7 +24,7 @@ export function useDeferredRegistrations(data: unknown, { onError }: UseDeferred
|
|
|
23
24
|
useEffect(() => {
|
|
24
25
|
if (canRegisterDeferredRegistrations) {
|
|
25
26
|
const register = async () => {
|
|
26
|
-
const errors = await registerDeferredRegistrations(data
|
|
27
|
+
const errors = await registerDeferredRegistrations(data);
|
|
27
28
|
|
|
28
29
|
if (errors.length > 0 && onError) {
|
|
29
30
|
onError(errors);
|
|
@@ -32,12 +33,12 @@ export function useDeferredRegistrations(data: unknown, { onError }: UseDeferred
|
|
|
32
33
|
|
|
33
34
|
register();
|
|
34
35
|
}
|
|
35
|
-
}, [canRegisterDeferredRegistrations, registerDeferredRegistrations, data, onError
|
|
36
|
+
}, [canRegisterDeferredRegistrations, registerDeferredRegistrations, data, onError]);
|
|
36
37
|
|
|
37
38
|
useEffect(() => {
|
|
38
39
|
if (canUpdateDeferredRegistrations) {
|
|
39
40
|
const update = async () => {
|
|
40
|
-
const errors = await updateDeferredRegistrations(data
|
|
41
|
+
const errors = await updateDeferredRegistrations(data);
|
|
41
42
|
|
|
42
43
|
if (errors.length > 0 && onError) {
|
|
43
44
|
onError(errors);
|
|
@@ -46,5 +47,13 @@ export function useDeferredRegistrations(data: unknown, { onError }: UseDeferred
|
|
|
46
47
|
|
|
47
48
|
update();
|
|
48
49
|
}
|
|
49
|
-
}, [
|
|
50
|
+
}, [
|
|
51
|
+
canUpdateDeferredRegistrations,
|
|
52
|
+
updateDeferredRegistrations,
|
|
53
|
+
data,
|
|
54
|
+
onError,
|
|
55
|
+
// Trigger this closure when the feature flags changed. Using the timestamp because the
|
|
56
|
+
// actual feature flags are not forwarded to the deferred registrations.
|
|
57
|
+
runtime.appRouterStore.state.featureFlagsUpdatedAt
|
|
58
|
+
]);
|
|
50
59
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useRuntime } from "@squide/core";
|
|
2
2
|
import { useCallback } from "react";
|
|
3
3
|
|
|
4
4
|
export function useRegisterDeferredRegistrations() {
|
|
5
|
-
|
|
5
|
+
const runtime = useRuntime();
|
|
6
|
+
|
|
7
|
+
return useCallback(<TData = unknown>(data?: TData) => {
|
|
6
8
|
return runtime.moduleManager.registerDeferredRegistrations(data);
|
|
7
|
-
}, []);
|
|
9
|
+
}, [runtime]);
|
|
8
10
|
}
|
|
@@ -1,13 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useEffect, useSyncExternalStore } from "react";
|
|
3
|
-
|
|
4
|
-
function subscribeToModulesReady(runtime: Runtime) {
|
|
5
|
-
return (callback: () => void) => {
|
|
6
|
-
runtime.moduleManager.registerModulesReadyListener(callback);
|
|
7
|
-
|
|
8
|
-
return () => runtime.moduleManager.removeModulesReadyListener(callback);
|
|
9
|
-
};
|
|
10
|
-
}
|
|
1
|
+
import { useRuntime } from "@squide/core";
|
|
2
|
+
import { useCallback, useEffect, useSyncExternalStore } from "react";
|
|
11
3
|
|
|
12
4
|
export interface UseStrictRegistrationModeOptions {
|
|
13
5
|
isEnabled?: boolean;
|
|
@@ -20,8 +12,16 @@ export function useStrictRegistrationMode(options: UseStrictRegistrationModeOpti
|
|
|
20
12
|
|
|
21
13
|
const runtime = useRuntime();
|
|
22
14
|
|
|
15
|
+
const subscribe = useCallback((callback: () => void) => {
|
|
16
|
+
runtime.moduleManager.registerModulesReadyListener(callback);
|
|
17
|
+
|
|
18
|
+
return () => {
|
|
19
|
+
runtime.moduleManager.removeModulesReadyListener(callback);
|
|
20
|
+
};
|
|
21
|
+
}, [runtime]);
|
|
22
|
+
|
|
23
23
|
// This listener is only executed if the modules are ready.
|
|
24
|
-
const areModulesReady = useSyncExternalStore(
|
|
24
|
+
const areModulesReady = useSyncExternalStore(subscribe, () => runtime.moduleManager.getAreModulesReady());
|
|
25
25
|
|
|
26
26
|
useEffect(() => {
|
|
27
27
|
if (areModulesReady && isEnabled) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useRuntime } from "@squide/core";
|
|
2
2
|
import { useCallback } from "react";
|
|
3
3
|
import { useAppRouterDispatcher } from "./AppRouterContext.ts";
|
|
4
4
|
|
|
@@ -6,9 +6,10 @@ export const DeferredRegistrationsUpdateStartedEvent = "squide-deferred-registra
|
|
|
6
6
|
export const DeferredRegistrationsUpdateCompletedEvent = "squide-deferred-registrations-update-completed-started";
|
|
7
7
|
|
|
8
8
|
export function useUpdateDeferredRegistrations() {
|
|
9
|
+
const runtime = useRuntime();
|
|
9
10
|
const dispatch = useAppRouterDispatcher();
|
|
10
11
|
|
|
11
|
-
return useCallback(async <TData = unknown
|
|
12
|
+
return useCallback(async <TData = unknown>(data?: TData) => {
|
|
12
13
|
runtime.eventBus.dispatch(DeferredRegistrationsUpdateStartedEvent);
|
|
13
14
|
|
|
14
15
|
const errors = await runtime.moduleManager.updateDeferredRegistrations(data);
|
|
@@ -18,5 +19,5 @@ export function useUpdateDeferredRegistrations() {
|
|
|
18
19
|
runtime.eventBus.dispatch(DeferredRegistrationsUpdateCompletedEvent);
|
|
19
20
|
|
|
20
21
|
return errors;
|
|
21
|
-
}, [dispatch]);
|
|
22
|
+
}, [runtime, dispatch]);
|
|
22
23
|
}
|