@financial-times/custom-code-component 2.0.3 → 2.0.5

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 CHANGED
@@ -58,4 +58,37 @@ export default (shadowRoot, props, ...children) => {
58
58
  * `data-asset-type="custom-code-component"`
59
59
  * Part of spec.
60
60
  * <any other attributes>
61
- * All remaining attributes get passed as an object named `props` to render().
61
+ * All remaining attributes get passed as an object named `props` to render().
62
+
63
+ ## client-metrics-adaptor
64
+
65
+ This module is an adaptor of the [dotcom-reliability-kit client metrics package](https://github.com/Financial-Times/dotcom-reliability-kit/tree/main/packages/client-metrics-web) to help integrating RUM metrics for the Custom Code Components.
66
+
67
+ ### Requirements
68
+
69
+ To use it, you are required to have pre-installed the client-metrics-web package.
70
+
71
+ ### Options
72
+
73
+ - **enrichEventCb** (optional): function to enrich the event payload before is sent to AWS RUM
74
+ - **shouldIgnoreEventCb** (optional): function that checks if the event should be sent or not to AWS RUM
75
+
76
+ ### Usage:
77
+
78
+ Initialise the ClientMetrics Adaptor in your project to start listening to CCC Events and dispatch automatically AWS RUM events
79
+
80
+
81
+ #### example.jsx
82
+
83
+ ```js
84
+ import { MetricsClient } from '@dotcom-reliability-kit/client-metrics-web';
85
+ import * as ClientMetricsAdaptor from '@financial-times/custom-code-component';
86
+
87
+ const client = new MetricsClient({
88
+ // Options go here
89
+ });
90
+
91
+ ClientMetricsAdaptor.init(client, {
92
+ enrichEventCb: enrichCCCEventWithHomepageContext,
93
+ shouldIgnoreEventCb: shouldIgnoreCCCEvent,
94
+ });
@@ -0,0 +1,107 @@
1
+ declare class CCCEvent extends Event {
2
+ component: ComponentPath;
3
+ source?: string;
4
+ static eventType: string;
5
+ constructor(eventType: string | undefined, detail: {
6
+ component: ComponentPath;
7
+ source?: string;
8
+ }, opts?: EventInit);
9
+ }
10
+
11
+ declare class ComponentPath {
12
+ org: string;
13
+ repo: string;
14
+ name: string;
15
+ versionRange: string;
16
+ constructor(path?: ComponentPathType | string);
17
+ set path(path: ComponentPathType | string);
18
+ get path(): string;
19
+ get isValid(): boolean;
20
+ toString(): string;
21
+ static fromString(p?: string | null, v?: string | null): ComponentPath;
22
+ }
23
+
24
+ declare type ComponentPathType = {
25
+ org: string;
26
+ repo: string;
27
+ name: string;
28
+ versionRange: string;
29
+ };
30
+
31
+ export declare const DEFAULT_VALUE = "uknown";
32
+
33
+ export declare const EVENT_TYPES: Record<string, EventType>;
34
+
35
+ declare type EventType = {
36
+ namespace: string;
37
+ payloadFn: (event: GenericCCCEvent) => Record<string, unknown>;
38
+ };
39
+
40
+ export declare type GenericCCCEvent = CCCEvent | ErrorEvent;
41
+
42
+ export declare function getComponentProps(eventComponentProp: ComponentPathType): {
43
+ name: string;
44
+ org: string;
45
+ repo: string;
46
+ versionRange: string;
47
+ };
48
+
49
+ export declare function getEnrichEventProps(event: GenericCCCEvent): Record<string, unknown>;
50
+
51
+ export declare function getErrorPayload(event: GenericCCCEvent): Record<string, unknown>;
52
+
53
+ export declare function getPendingEventsQueue(): PendingEvent[];
54
+
55
+ export declare function getSuccessPayload(event: GenericCCCEvent): Record<string, unknown>;
56
+
57
+ /**
58
+ * Initialises the Adaptor with the provided configuration and starts listening to CCC events.
59
+ * If there's any pending event, it'll send them to the Metrics server
60
+ * @param _metricsClient MetricClient instance
61
+ * @param _options Options to configure adaptor
62
+ */
63
+ export declare function init(_metricsClient: MetricsClient, _options?: Options): void;
64
+
65
+ export declare const MAX_PENDING_EVENTS = 50;
66
+
67
+ export declare type MetricsClient = {
68
+ recordEvent: (namespace: string, payload?: Record<string, unknown>) => void;
69
+ };
70
+
71
+ export declare function onEventReceived(_event: Event): void;
72
+
73
+ declare type Options = {
74
+ enrichEventCb?: (event: GenericCCCEvent) => Record<string, unknown> | void;
75
+ shouldIgnoreEventCb?: (event: GenericCCCEvent) => boolean;
76
+ };
77
+
78
+ declare type PendingEvent = {
79
+ time: number;
80
+ event: GenericCCCEvent;
81
+ };
82
+
83
+ export declare function processEvent(event: GenericCCCEvent): void;
84
+
85
+ /**
86
+ * Sends all pending events waiting to be processed
87
+ *
88
+ * Notes:
89
+ * 1. All these events will be registered in RUM with the same time
90
+ * (at this moment the MetricsClient API doesn't allow to override it)
91
+ * 2. It's safe to process them in bulk since ClientMetrics will send them in bulk
92
+ * (all in 1 request)
93
+ */
94
+ export declare function sendPendingEvents(): void;
95
+
96
+ /**
97
+ * Start listening to CCC events
98
+ * In case there's no MetricsClient registered, it'll store them until they can be sent
99
+ */
100
+ export declare function startListeners(): void;
101
+
102
+ /**
103
+ * Stop listening CCC events
104
+ */
105
+ export declare function stopListeners(): void;
106
+
107
+ export { }
@@ -0,0 +1,98 @@
1
+ const f = Object.freeze({
2
+ "ccc:ready": {
3
+ namespace: "ccc.success",
4
+ payloadFn: y
5
+ },
6
+ "ccc:error": {
7
+ namespace: "ccc.failure",
8
+ payloadFn: w
9
+ }
10
+ }), i = "uknown", t = [], g = 50;
11
+ let a, n, s = !1;
12
+ function h() {
13
+ s || (window.addEventListener("ccc:error", u), window.addEventListener("ccc:ready", u)), s = !0;
14
+ }
15
+ function b() {
16
+ s && (window.removeEventListener("ccc:error", u), window.removeEventListener("ccc:ready", u)), s = !1, t.length = 0, a = null, n = {};
17
+ }
18
+ function v(e, c) {
19
+ if (!e || typeof e.recordEvent != "function") {
20
+ console.warn("CCC Can't initialise MetricsClientAdaptor");
21
+ return;
22
+ }
23
+ a = e, n = {}, typeof (c == null ? void 0 : c.shouldIgnoreEventCb) == "function" && (n.shouldIgnoreEventCb = c.shouldIgnoreEventCb), typeof (c == null ? void 0 : c.enrichEventCb) == "function" && (n.enrichEventCb = c.enrichEventCb), o(), h();
24
+ }
25
+ function d(e) {
26
+ var c;
27
+ try {
28
+ const r = ((c = n == null ? void 0 : n.enrichEventCb) == null ? void 0 : c.call(n, e)) || {};
29
+ if (typeof r != "object" || Array.isArray(r))
30
+ throw new TypeError("Enrich event callback returned invalid value");
31
+ return r;
32
+ } catch (r) {
33
+ return console.error("CCC RUM event couldn't be enriched", r), {};
34
+ }
35
+ }
36
+ function l(e) {
37
+ return {
38
+ name: (e == null ? void 0 : e.name) || i,
39
+ org: (e == null ? void 0 : e.org) || i,
40
+ repo: (e == null ? void 0 : e.repo) || i,
41
+ versionRange: (e == null ? void 0 : e.versionRange) || i
42
+ };
43
+ }
44
+ function y(e) {
45
+ return {
46
+ ...d(e),
47
+ component: l(e.component)
48
+ };
49
+ }
50
+ function w(e) {
51
+ const c = e.error, r = c == null ? void 0 : c.name;
52
+ return {
53
+ ...d(e),
54
+ component: l(c == null ? void 0 : c.component),
55
+ error: r || i
56
+ };
57
+ }
58
+ function E(e) {
59
+ if (n.shouldIgnoreEventCb && n.shouldIgnoreEventCb(e))
60
+ return;
61
+ if (!a) {
62
+ console.warn("CCC Couldn't process event: ClientMetrics not initialised");
63
+ return;
64
+ }
65
+ const c = f[e.type];
66
+ if (!c) {
67
+ console.warn("CCC event.type not registered");
68
+ return;
69
+ }
70
+ a.recordEvent(c.namespace, c.payloadFn(e));
71
+ }
72
+ function u(e) {
73
+ const c = e;
74
+ a ? E(c) : (t.push({ event: c, time: Date.now() }), t.splice(0, t.length - g));
75
+ }
76
+ function o() {
77
+ t.forEach(({ event: e }) => E(e)), t.length = 0;
78
+ }
79
+ function L() {
80
+ return t;
81
+ }
82
+ export {
83
+ i as DEFAULT_VALUE,
84
+ f as EVENT_TYPES,
85
+ g as MAX_PENDING_EVENTS,
86
+ l as getComponentProps,
87
+ d as getEnrichEventProps,
88
+ w as getErrorPayload,
89
+ L as getPendingEventsQueue,
90
+ y as getSuccessPayload,
91
+ v as init,
92
+ u as onEventReceived,
93
+ E as processEvent,
94
+ o as sendPendingEvents,
95
+ h as startListeners,
96
+ b as stopListeners
97
+ };
98
+ //# sourceMappingURL=client-metrics-adaptor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-metrics-adaptor.js","sources":["../src/client-metrics-adaptor.ts"],"sourcesContent":["// MetricsClient type from https://github.com/Financial-Times/dotcom-reliability-kit/tree/main/packages/client-metrics-web\n// We intentionally copied this type here to avoid having version conflicts between this module and it's client\nimport type { ComponentPathType } from './path'\nimport type { CCCEvent } from './events'\n\nexport type MetricsClient = {\n recordEvent: (namespace: string, payload?: Record<string, unknown>) => void\n};\n\nexport type GenericCCCEvent = CCCEvent | ErrorEvent;\n\ntype Options = {\n enrichEventCb?: (event: GenericCCCEvent) => Record<string, unknown> | void\n shouldIgnoreEventCb?: (event: GenericCCCEvent) => boolean\n};\n\ntype PendingEvent = {\n time: number\n event: GenericCCCEvent\n};\n\ntype EventType = {\n namespace: string\n payloadFn: (event: GenericCCCEvent) => Record<string, unknown>\n};\n\nexport const EVENT_TYPES: Record<string, EventType> = Object.freeze({\n 'ccc:ready': {\n namespace: 'ccc.success',\n payloadFn: getSuccessPayload,\n },\n 'ccc:error': {\n namespace: 'ccc.failure',\n payloadFn: getErrorPayload,\n },\n});\n\nexport const DEFAULT_VALUE = 'uknown';\n\nconst pendingEvents: PendingEvent[] = [];\nexport const MAX_PENDING_EVENTS = 50;\nlet metricsClient: MetricsClient | null;\nlet options: Options;\nlet isRunning = false;\n\n/**\n * Start listening to CCC events\n * In case there's no MetricsClient registered, it'll store them until they can be sent\n */\nexport function startListeners() {\n if (!isRunning) {\n window.addEventListener('ccc:error', onEventReceived);\n window.addEventListener('ccc:ready', onEventReceived);\n }\n isRunning = true;\n}\n\n/**\n * Stop listening CCC events\n */\nexport function stopListeners() {\n if (isRunning) {\n window.removeEventListener('ccc:error', onEventReceived);\n window.removeEventListener('ccc:ready', onEventReceived);\n }\n\n isRunning = false;\n pendingEvents.length = 0;\n metricsClient = null;\n options = {};\n}\n\n/**\n * Initialises the Adaptor with the provided configuration and starts listening to CCC events.\n * If there's any pending event, it'll send them to the Metrics server\n * @param _metricsClient MetricClient instance\n * @param _options Options to configure adaptor\n */\nexport function init(_metricsClient: MetricsClient, _options?: Options) {\n if (!_metricsClient || typeof _metricsClient.recordEvent !== 'function') {\n console.warn(\"CCC Can't initialise MetricsClientAdaptor\");\n return;\n }\n\n metricsClient = _metricsClient;\n\n options = {};\n if (typeof _options?.shouldIgnoreEventCb === 'function') {\n options.shouldIgnoreEventCb = _options.shouldIgnoreEventCb;\n }\n if (typeof _options?.enrichEventCb === 'function') {\n options.enrichEventCb = _options.enrichEventCb;\n }\n\n sendPendingEvents();\n startListeners();\n}\n\nexport function getEnrichEventProps(event: GenericCCCEvent) {\n try {\n const props = options?.enrichEventCb?.(event) || {};\n if (typeof props !== 'object' || Array.isArray(props)) {\n throw new TypeError('Enrich event callback returned invalid value');\n }\n return props;\n } catch (error) {\n console.error(\"CCC RUM event couldn't be enriched\", error);\n return {};\n }\n}\n\nexport function getComponentProps(eventComponentProp: ComponentPathType) {\n return {\n name: eventComponentProp?.name || DEFAULT_VALUE,\n org: eventComponentProp?.org || DEFAULT_VALUE,\n repo: eventComponentProp?.repo || DEFAULT_VALUE,\n versionRange: eventComponentProp?.versionRange || DEFAULT_VALUE,\n };\n}\n\nexport function getSuccessPayload(event: GenericCCCEvent): Record<string, unknown> {\n return {\n ...getEnrichEventProps(event),\n component: getComponentProps((event as CCCEvent).component),\n };\n}\n\nexport function getErrorPayload(event: GenericCCCEvent): Record<string, unknown> {\n const error = (event as ErrorEvent).error;\n const errorName = error?.name;\n\n return {\n ...getEnrichEventProps(event),\n component: getComponentProps(error?.component),\n error: errorName || DEFAULT_VALUE,\n };\n}\n\nexport function processEvent(event: GenericCCCEvent) {\n // Stop processing the event if we should ignore it\n if (options.shouldIgnoreEventCb && options.shouldIgnoreEventCb(event)) {\n return;\n }\n\n if (!metricsClient) {\n console.warn(\"CCC Couldn't process event: ClientMetrics not initialised\");\n return;\n }\n\n const eventType = EVENT_TYPES[event.type];\n if (!eventType) {\n console.warn('CCC event.type not registered');\n return;\n }\n\n metricsClient.recordEvent(eventType.namespace, eventType.payloadFn(event));\n}\n\nexport function onEventReceived(_event: Event) {\n // The Event object dispatched from the CCC has extra custom props\n const event = _event as GenericCCCEvent\n\n if (metricsClient) {\n processEvent(event);\n } else {\n pendingEvents.push({ event: event, time: Date.now() });\n // keep only the last MAX_PENDING_EVENTS events (FIFO)\n pendingEvents.splice(0, pendingEvents.length - MAX_PENDING_EVENTS);\n }\n}\n\n/**\n * Sends all pending events waiting to be processed\n *\n * Notes:\n * 1. All these events will be registered in RUM with the same time\n * (at this moment the MetricsClient API doesn't allow to override it)\n * 2. It's safe to process them in bulk since ClientMetrics will send them in bulk\n * (all in 1 request)\n */\nexport function sendPendingEvents() {\n pendingEvents.forEach(({ event }) => processEvent(event));\n pendingEvents.length = 0;\n}\n\nexport function getPendingEventsQueue() {\n return pendingEvents;\n}\n"],"names":["EVENT_TYPES","getSuccessPayload","getErrorPayload","DEFAULT_VALUE","pendingEvents","MAX_PENDING_EVENTS","metricsClient","options","isRunning","startListeners","onEventReceived","stopListeners","init","_metricsClient","_options","sendPendingEvents","getEnrichEventProps","event","_a","props","error","getComponentProps","eventComponentProp","errorName","processEvent","eventType","_event","getPendingEventsQueue"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@financial-times/custom-code-component",
3
- "version": "2.0.3",
3
+ "version": "2.0.5",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -11,6 +11,10 @@
11
11
  "types": "./dist/custom-element.d.ts",
12
12
  "default": "./dist/custom-element.js"
13
13
  },
14
+ "./client-metrics-adaptor": {
15
+ "types": "./dist/client-metrics-adaptor.d.ts",
16
+ "default": "./dist/client-metrics-adaptor.js"
17
+ },
14
18
  "./custom-code-component.css": "./src/custom-code-component.css"
15
19
  },
16
20
  "scripts": {
@@ -0,0 +1,188 @@
1
+ // MetricsClient type from https://github.com/Financial-Times/dotcom-reliability-kit/tree/main/packages/client-metrics-web
2
+ // We intentionally copied this type here to avoid having version conflicts between this module and it's client
3
+ import type { ComponentPathType } from './path'
4
+ import type { CCCEvent } from './events'
5
+
6
+ export type MetricsClient = {
7
+ recordEvent: (namespace: string, payload?: Record<string, unknown>) => void
8
+ };
9
+
10
+ export type GenericCCCEvent = CCCEvent | ErrorEvent;
11
+
12
+ type Options = {
13
+ enrichEventCb?: (event: GenericCCCEvent) => Record<string, unknown> | void
14
+ shouldIgnoreEventCb?: (event: GenericCCCEvent) => boolean
15
+ };
16
+
17
+ type PendingEvent = {
18
+ time: number
19
+ event: GenericCCCEvent
20
+ };
21
+
22
+ type EventType = {
23
+ namespace: string
24
+ payloadFn: (event: GenericCCCEvent) => Record<string, unknown>
25
+ };
26
+
27
+ export const EVENT_TYPES: Record<string, EventType> = Object.freeze({
28
+ 'ccc:ready': {
29
+ namespace: 'ccc.success',
30
+ payloadFn: getSuccessPayload,
31
+ },
32
+ 'ccc:error': {
33
+ namespace: 'ccc.failure',
34
+ payloadFn: getErrorPayload,
35
+ },
36
+ });
37
+
38
+ export const DEFAULT_VALUE = 'uknown';
39
+
40
+ const pendingEvents: PendingEvent[] = [];
41
+ export const MAX_PENDING_EVENTS = 50;
42
+ let metricsClient: MetricsClient | null;
43
+ let options: Options;
44
+ let isRunning = false;
45
+
46
+ /**
47
+ * Start listening to CCC events
48
+ * In case there's no MetricsClient registered, it'll store them until they can be sent
49
+ */
50
+ export function startListeners() {
51
+ if (!isRunning) {
52
+ window.addEventListener('ccc:error', onEventReceived);
53
+ window.addEventListener('ccc:ready', onEventReceived);
54
+ }
55
+ isRunning = true;
56
+ }
57
+
58
+ /**
59
+ * Stop listening CCC events
60
+ */
61
+ export function stopListeners() {
62
+ if (isRunning) {
63
+ window.removeEventListener('ccc:error', onEventReceived);
64
+ window.removeEventListener('ccc:ready', onEventReceived);
65
+ }
66
+
67
+ isRunning = false;
68
+ pendingEvents.length = 0;
69
+ metricsClient = null;
70
+ options = {};
71
+ }
72
+
73
+ /**
74
+ * Initialises the Adaptor with the provided configuration and starts listening to CCC events.
75
+ * If there's any pending event, it'll send them to the Metrics server
76
+ * @param _metricsClient MetricClient instance
77
+ * @param _options Options to configure adaptor
78
+ */
79
+ export function init(_metricsClient: MetricsClient, _options?: Options) {
80
+ if (!_metricsClient || typeof _metricsClient.recordEvent !== 'function') {
81
+ console.warn("CCC Can't initialise MetricsClientAdaptor");
82
+ return;
83
+ }
84
+
85
+ metricsClient = _metricsClient;
86
+
87
+ options = {};
88
+ if (typeof _options?.shouldIgnoreEventCb === 'function') {
89
+ options.shouldIgnoreEventCb = _options.shouldIgnoreEventCb;
90
+ }
91
+ if (typeof _options?.enrichEventCb === 'function') {
92
+ options.enrichEventCb = _options.enrichEventCb;
93
+ }
94
+
95
+ sendPendingEvents();
96
+ startListeners();
97
+ }
98
+
99
+ export function getEnrichEventProps(event: GenericCCCEvent) {
100
+ try {
101
+ const props = options?.enrichEventCb?.(event) || {};
102
+ if (typeof props !== 'object' || Array.isArray(props)) {
103
+ throw new TypeError('Enrich event callback returned invalid value');
104
+ }
105
+ return props;
106
+ } catch (error) {
107
+ console.error("CCC RUM event couldn't be enriched", error);
108
+ return {};
109
+ }
110
+ }
111
+
112
+ export function getComponentProps(eventComponentProp: ComponentPathType) {
113
+ return {
114
+ name: eventComponentProp?.name || DEFAULT_VALUE,
115
+ org: eventComponentProp?.org || DEFAULT_VALUE,
116
+ repo: eventComponentProp?.repo || DEFAULT_VALUE,
117
+ versionRange: eventComponentProp?.versionRange || DEFAULT_VALUE,
118
+ };
119
+ }
120
+
121
+ export function getSuccessPayload(event: GenericCCCEvent): Record<string, unknown> {
122
+ return {
123
+ ...getEnrichEventProps(event),
124
+ component: getComponentProps((event as CCCEvent).component),
125
+ };
126
+ }
127
+
128
+ export function getErrorPayload(event: GenericCCCEvent): Record<string, unknown> {
129
+ const error = (event as ErrorEvent).error;
130
+ const errorName = error?.name;
131
+
132
+ return {
133
+ ...getEnrichEventProps(event),
134
+ component: getComponentProps(error?.component),
135
+ error: errorName || DEFAULT_VALUE,
136
+ };
137
+ }
138
+
139
+ export function processEvent(event: GenericCCCEvent) {
140
+ // Stop processing the event if we should ignore it
141
+ if (options.shouldIgnoreEventCb && options.shouldIgnoreEventCb(event)) {
142
+ return;
143
+ }
144
+
145
+ if (!metricsClient) {
146
+ console.warn("CCC Couldn't process event: ClientMetrics not initialised");
147
+ return;
148
+ }
149
+
150
+ const eventType = EVENT_TYPES[event.type];
151
+ if (!eventType) {
152
+ console.warn('CCC event.type not registered');
153
+ return;
154
+ }
155
+
156
+ metricsClient.recordEvent(eventType.namespace, eventType.payloadFn(event));
157
+ }
158
+
159
+ export function onEventReceived(_event: Event) {
160
+ // The Event object dispatched from the CCC has extra custom props
161
+ const event = _event as GenericCCCEvent
162
+
163
+ if (metricsClient) {
164
+ processEvent(event);
165
+ } else {
166
+ pendingEvents.push({ event: event, time: Date.now() });
167
+ // keep only the last MAX_PENDING_EVENTS events (FIFO)
168
+ pendingEvents.splice(0, pendingEvents.length - MAX_PENDING_EVENTS);
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Sends all pending events waiting to be processed
174
+ *
175
+ * Notes:
176
+ * 1. All these events will be registered in RUM with the same time
177
+ * (at this moment the MetricsClient API doesn't allow to override it)
178
+ * 2. It's safe to process them in bulk since ClientMetrics will send them in bulk
179
+ * (all in 1 request)
180
+ */
181
+ export function sendPendingEvents() {
182
+ pendingEvents.forEach(({ event }) => processEvent(event));
183
+ pendingEvents.length = 0;
184
+ }
185
+
186
+ export function getPendingEventsQueue() {
187
+ return pendingEvents;
188
+ }