@servicetitan/web-components 30.0.0 → 30.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.
@@ -1,9 +1,9 @@
1
- /**
2
- * Context used to pass data from the host to the MFEs
3
- */
4
-
5
1
  import { createContext, useContext } from 'react';
6
- import { JSON, JSONPrimitive } from '../types';
2
+
3
+ type JSONPrimitive = string | number | boolean | null | undefined;
4
+
5
+ // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
6
+ type JSON = { [key: string]: JSONPrimitive | JSON[] | JSON };
7
7
 
8
8
  // Type complexity below is required to support Interfaces being used
9
9
  export type MFEContextData<T> = {
@@ -16,6 +16,9 @@ export type MFEContextData<T> = {
16
16
  : never;
17
17
  };
18
18
 
19
+ /**
20
+ * Context used to pass data from the host to the MFEs
21
+ */
19
22
  export const MFEDataContext = createContext<JSON>({});
20
23
 
21
24
  export function useMFEDataContext<T extends MFEContextData<T>>() {
package/src/event-bus.ts CHANGED
@@ -1,32 +1,85 @@
1
+ import { symbolToken, SymbolToken } from '@servicetitan/react-ioc';
1
2
  import mitt from 'mitt';
2
3
 
3
- import { symbolToken, SymbolToken } from '@servicetitan/react-ioc';
4
- import { useRef } from 'react';
5
- import { JSON } from './types';
4
+ import { JSON, Serializable } from './types';
5
+
6
+ export const EVENT_BUS_TOKEN = symbolToken<EventBus>('EVENT_BUS_TOKEN');
7
+
8
+ export function typedEventBusToken<EventTypes extends Serializable<EventTypes>>() {
9
+ return symbolToken<EventBus<EventTypes>>('EVENT_BUS_TOKEN');
10
+ }
11
+
12
+ export type EventHandler<EventTypes, Event, T = never> = (
13
+ data: [T] extends [never]
14
+ ? Event extends SymbolToken<infer DataType>
15
+ ? Serializable<DataType>
16
+ : Event extends keyof EventTypes
17
+ ? EventTypes[Event]
18
+ : T
19
+ : Serializable<T>
20
+ ) => void;
6
21
 
7
- export type EventHandler<T = unknown> = (data: T) => void;
8
22
  type JobPayload = JSON | void;
9
23
 
10
- export type JobEventHandler<Result extends JobPayload = void> = (defer: {
11
- resolve(result: Result): void;
12
- reject(reason?: string | Error): void;
13
- }) => void;
14
24
  export type EventType = string | number | symbol;
15
25
  export type SymbolTokenEventType<T, U extends EventType = EventType> =
16
26
  U extends SymbolToken<any> ? SymbolToken<T> : U;
17
27
 
18
- export const EVENT_BUS_TOKEN = symbolToken<EventBus>('EVENT_BUS_TOKEN');
19
- export class EventBus {
28
+ export type JobEventHandler<Event> = (defer: {
29
+ /**
30
+ * Successfully complete a job.
31
+ * @param result The value to return from the successfully completed job.
32
+ */
33
+ resolve(
34
+ ...result: Event extends SymbolToken<infer ResultType>
35
+ ? undefined extends ResultType
36
+ ? [Serializable<ResultType>?]
37
+ : [Serializable<ResultType>]
38
+ : [JobPayload]
39
+ ): void;
40
+ /**
41
+ * Fail a job.
42
+ * @param reason The error to return from the failed job.
43
+ */
44
+ reject(reason?: string | Error): void;
45
+ }) => void;
46
+
47
+ export class EventBus<EventTypes extends Serializable<EventTypes> = never> {
20
48
  job = {
21
- on: <Result extends JobPayload = void>(type: string, handler: JobEventHandler<Result>) => {
22
- this.emitter.on(type, handler);
49
+ /**
50
+ * Register a job event handler. Jobs event handlers return a result or an error.
51
+ * @param event The job event to handle.
52
+ * @param handler The handler to call when the event occurs. This handler is passed a `resolve` callback to return a successful result, and a `reject` callback to return an error.
53
+ */
54
+ on: <Event extends SymbolToken<any> | keyof EventTypes>(
55
+ event: Event,
56
+ handler: JobEventHandler<Event>
57
+ ) => {
58
+ this.emitter.on(event, handler);
23
59
  },
24
- off: <Result extends JobPayload = void>(type: string, handler: JobEventHandler<Result>) => {
25
- this.emitter.off(type, handler);
60
+
61
+ /**
62
+ * Deregister a job event handler.
63
+ * @param event The previously registered event.
64
+ * @param handler The previously registered handler.
65
+ */
66
+ off: <Event extends SymbolToken<any> | keyof EventTypes>(
67
+ event: Event,
68
+ handler: JobEventHandler<Event>
69
+ ) => {
70
+ this.emitter.off(event, handler);
26
71
  },
27
- emit: <Result extends JobPayload = void>(type: string) => {
28
- return new Promise<Result>((resolve, reject) => {
29
- this.emitter.emit(type, {
72
+
73
+ /**
74
+ * Send a job event.
75
+ * @param event The event to send.
76
+ * @returns a Promise that resolves or rejects depending on whether the job completes successfully.
77
+ */
78
+ emit: <Event extends SymbolToken<any> | keyof EventTypes>(event: Event) => {
79
+ return new Promise<
80
+ Event extends SymbolToken<infer ResultType> ? Serializable<ResultType> : JobPayload
81
+ >((resolve, reject) => {
82
+ this.emitter.emit(event, {
30
83
  resolve,
31
84
  reject: (reason?: string | Error) => {
32
85
  if (typeof reason === 'string' || reason instanceof Error) {
@@ -42,25 +95,54 @@ export class EventBus {
42
95
 
43
96
  private emitter = mitt<any>();
44
97
 
45
- on = <T, U extends EventType = EventType>(
46
- type: SymbolTokenEventType<T, U>,
47
- handler: EventHandler<T>
98
+ /**
99
+ * Register an event handler.
100
+ * @param event The event to handle.
101
+ * @param handler The handler to call when the event occurs.
102
+ */
103
+ on = <T extends Serializable<T> = never, Event extends SymbolToken<T> | keyof EventTypes = any>(
104
+ event: SymbolTokenEventType<T, Event>,
105
+ handler: EventHandler<EventTypes, Event, T>
48
106
  ) => {
49
- this.emitter.on(type, handler);
107
+ this.emitter.on(event, handler);
50
108
  };
51
109
 
52
- off = <T, U extends EventType = EventType>(
53
- type: SymbolTokenEventType<T, U>,
54
- handler: EventHandler<T>
110
+ /**
111
+ * Deregister an event handler.
112
+ * @param event The previously registered event.
113
+ * @param handler The previously registered handler.
114
+ */
115
+ off = <
116
+ T extends Serializable<T> = never,
117
+ Event extends SymbolToken<T> | keyof EventTypes = any,
118
+ >(
119
+ event: SymbolTokenEventType<T, Event>,
120
+ handler: EventHandler<EventTypes, Event, T>
55
121
  ) => {
56
- this.emitter.off(type, handler);
122
+ this.emitter.off(event, handler);
57
123
  };
58
124
 
59
- emit = <T, U extends EventType = EventType>(type: SymbolTokenEventType<T, U>, data?: T) => {
60
- this.emitter.emit(type, data);
125
+ /**
126
+ * Send an event.
127
+ * @param event The event to send.
128
+ * @param data The data to pass to the event's handler.
129
+ */
130
+ emit = <T extends Serializable<T>, Event extends SymbolToken<T> | keyof EventTypes = any>(
131
+ event: SymbolTokenEventType<T, Event>,
132
+ ...data: Event extends SymbolToken<any>
133
+ ? undefined extends T
134
+ ? [T?]
135
+ : [T]
136
+ : [EventTypes] extends [never]
137
+ ? [T?]
138
+ : Event extends keyof EventTypes
139
+ ? undefined extends EventTypes[Event]
140
+ ? [EventTypes[Event]?]
141
+ : [EventTypes[Event]] extends [never]
142
+ ? []
143
+ : [EventTypes[Event]]
144
+ : never
145
+ ) => {
146
+ this.emitter.emit(event, data[0]);
61
147
  };
62
148
  }
63
-
64
- export function useEventBus() {
65
- return useRef(new EventBus()).current;
66
- }
package/src/index.ts CHANGED
@@ -5,3 +5,5 @@ export * from './get-value-for-environment';
5
5
  export * from './history-manager';
6
6
  export * from './loader';
7
7
  export * from './register';
8
+
9
+ export type { JSON, JSONPrimitive, Serializable } from './types';
package/src/loader.tsx CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  useEffect,
8
8
  useImperativeHandle,
9
9
  useMemo,
10
+ useRef,
10
11
  } from 'react';
11
12
  import { ErrorBoundary } from '@servicetitan/error-boundary';
12
13
  import { type LDService } from '@servicetitan/launchdarkly-service';
@@ -23,7 +24,7 @@ import {
23
24
  } from './common';
24
25
  import { MFEContextData } from './contexts/mfe-data-context';
25
26
  import { Delayed } from './delayed';
26
- import { EventBus, EVENT_BUS_TOKEN, useEventBus } from './event-bus';
27
+ import { EventBus, EVENT_BUS_TOKEN } from './event-bus';
27
28
  import { EXPOSED_DEPENDENCIES, EXPOSED_INSTANCE_DEPENDENCIES } from './globals';
28
29
  import {
29
30
  BundleInfo,
@@ -260,5 +261,9 @@ function ensureLDService(
260
261
  return exposedInstanceDependencies;
261
262
  }
262
263
 
264
+ function useEventBus() {
265
+ return useRef(new EventBus()).current;
266
+ }
267
+
263
268
  const MINUTE = 1000 * 60;
264
269
  const bundleCache = new TtlCache<BundleInfo>({ ttlMs: 15 * MINUTE });
package/src/types.ts CHANGED
@@ -1,4 +1,13 @@
1
1
  export type JSONPrimitive = string | number | boolean | null | undefined;
2
2
 
3
- // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
4
- export type JSON = { [key: string]: JSONPrimitive | JSON[] | JSON };
3
+ export type JSON = JSONPrimitive | { [key: string | number]: JSON } | JSON[];
4
+
5
+ export type Serializable<T> = {
6
+ [P in keyof T]: T[P] extends JSONPrimitive
7
+ ? T[P]
8
+ : T[P] extends Function | Date | Map<any, any> | Set<any> | symbol
9
+ ? never
10
+ : T[P] extends (infer U)[]
11
+ ? Serializable<U>[]
12
+ : Serializable<T[P]>;
13
+ };