@commercetools-frontend/fullstory 0.0.0-FEC-212-react19-20250122084835

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) commercetools GmbH
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,167 @@
1
+ # @commercetools-frontend/fullstory
2
+
3
+ > This is a package used internally for Merchant Center applications. We do not provide any guarantees or support for the functionality.
4
+
5
+ This package provides an easy to use integration with FullStory. The official documentation of FullStory's SDK can be found [here](https://developer.fullstory.com).
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ $ npm install --save @commercetools-frontend/fullstory
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ### Initialization
16
+
17
+ At first you will need to initialize FullStory and its SDK
18
+
19
+ You need to add this _before_ you render your application's entry point with for instance `ReactDOM.render`:
20
+
21
+ #### Configuration via a Custom Application configuration
22
+
23
+ If you are developing a Custom Application for the Merchant Center we recommend you to add a `FULLSTORY_ORGANIZATION_ID` as a value to the environment.
24
+
25
+ This environment variable should then we exposed via the `additionalEnv` and a `fullstoryOrganizationId` property in your Custom Application's configuration.
26
+
27
+ ```js
28
+ additionalEnv: {
29
+ fullstoryOrganizationId: '${env:FULLSTORY_ORGANIZATION_ID}',
30
+ },
31
+ ```
32
+
33
+ Given that you can just initialize FullStory like this:
34
+
35
+ ```js
36
+ import { initialize as initializeFullStory } from '@commercetools-frontend/fullstory';
37
+
38
+ initializeFullStory();
39
+ ```
40
+
41
+ In order for the SDK to be able to connect with FullStory's APIs you have to extend the `headers.csp` property of your Custom Application config to contain the following properties:
42
+
43
+ ```js
44
+ import { CONTENT_SECURITY_POLICIES as FULLSTORY_CONTENT_SECURITY_POLICIES } from '@commercetools-frontend/fullstory/constants';
45
+
46
+ headers: {
47
+ csp: {
48
+ 'connect-src': [...FULLSTORY_CONTENT_SECURITY_POLICIES.CONNECT_SRC],
49
+ 'script-src': [...FULLSTORY_CONTENT_SECURITY_POLICIES.SCRIPT_SRC],
50
+ },
51
+ },
52
+ ```
53
+
54
+ #### Configuration without Custom Application configuration
55
+
56
+ If you are not building a Custom Application or prefer not to configure FullStory using the Custom Application's configuration you can pass the organization ID of FullStory as an argument like this:
57
+
58
+ ```js
59
+ import { initialize as initializeFullStory } from '@commercetools-frontend/fullstory';
60
+
61
+ initializeFullStory('myFullStoryOrgId');
62
+ ```
63
+
64
+ Please also make sure that the `connect-src` and `script-src` Content Security Policies allow FullStory to connect with their services. If needed you can use the provided constants from `@commercetools-frontend/fullstory/constants` exported as `CONTENT_SECURITY_POLICIES`.
65
+
66
+ #### Setting up the tracking effect
67
+
68
+ As a last step for any case above you have to use the `useTrackingEffect` in the entry point of your application. Make sure that it is rendered below the `ApplicationShell` component as it depends on its React context.
69
+
70
+ ```js
71
+ import { useTrackingEffect as useFullStoryTrackingEffect } from '@commercetools-frontend/fullstory';
72
+
73
+ function EntryPoint() {
74
+ useFullStoryTrackingEffect();
75
+
76
+ return <>
77
+ <Application>
78
+ </>
79
+ }
80
+ ```
81
+
82
+ 1. If you intend to send additional user variables you can pass them using the `additionalUserVars` object
83
+ 2. If you intend to disable FullStory entirely (e.g. based on a feature flag), use the `disable` flag
84
+ - Note that you can only disable until you initialized once.
85
+
86
+ ### Custom events
87
+
88
+ Domain-specific events recorded by FullStory add additional intelligence when you're searching across sessions and creating new user segments. You can define and record these events with FullStory custom events.
89
+
90
+ ```js
91
+ import { sendEvent as sendFullStoryEvent } from '@commercetools-frontend/fullstory';
92
+
93
+ sendFullStoryEvent('eventName', {});
94
+ ```
95
+
96
+ Custom events should be needed only in very rare cases as any user interaction is tracked by default.
97
+
98
+ ### User variables
99
+
100
+ FullStory allows to record custom user data which is an object or dictionary containing simple key/value pairs you'd like to record.
101
+
102
+ ```js
103
+ import { setUserVars as setFullStoryUserVars } from '@commercetools-frontend/fullstory';
104
+
105
+ setFullStoryUserVars({ email: user.email });
106
+ ```
107
+
108
+ It's recommended to be mindful in what you send especially with Personal Identifiable Information.
109
+
110
+ ### Masking
111
+
112
+ FullStory has a built-in way to [mask, unmask or exclude](https://help.fullstory.com/hc/en-us/articles/360020623574-How-do-I-protect-my-users-privacy-in-FullStory-) certain elements on a page. As FullStory should be used with the [Private By Default](https://help.fullstory.com/hc/en-us/articles/360044349073) settings, unmasking may be considered and carefully implemented when needed.
113
+
114
+ If an unmasking request occurs and has been deemed necessary and can not be accomplished via the "app-first" approach within FullStory's settings only then a "code-first" approach should be taken. The "code-first" approach can be implemented using one of three masking components from this package.
115
+
116
+ ```jsx
117
+ import { Masking as FullStoryMasking } from '@commercetools-frontend/fullstory';
118
+
119
+ // Assuming some component three exists you can use one of:
120
+
121
+ <>
122
+ <FullStoryMasking.Unmask>{props.children}</FullStoryMasking.Unmask>
123
+ <FullStoryMasking.Mask>{props.children}</FullStoryMasking.Mask>
124
+ <FullStoryMasking.Exclude>{props.children}</FullStoryMasking.Exclude>
125
+ </>;
126
+ ```
127
+
128
+ Each of the components above accepts an `as` `prop` which can be either `span` or `div` depending on your layout needs.
129
+
130
+ ### Marking
131
+
132
+ FullStory allows definitions of CSS and other Elements that represent key pieces of data you use regularly. When defining these key pieces you will have to write stable CSS selectors to those elements. These selectors should be resilient to changes in the layout of any Merchant Center application.
133
+
134
+ One way to achieve this is to mark elements directly or contextualize them in a `section` element. The `Marking` API of this package helps with this.
135
+
136
+ To wrap an entire section of an application you can use `FullStory.Marking.Section`:
137
+
138
+ ```jsx
139
+ import { Marking as FullStoryMarking } from '@commercetools-frontend/fullstory';
140
+
141
+ <FullStoryMarking.Section name="Discount Rules">
142
+ <PartOfApplication />
143
+ </FullStoryMarking.Section>;
144
+ ```
145
+
146
+ You can also pass additional props to the `FullStoryMarking.Section` component, such as a `className`. These will be forwarded to the underlying `section` HTML element.
147
+
148
+ Please do not wrap individual elements. If you need to mark individual elements such as a unlabelled input you can use `applyMarker`:
149
+
150
+ ```jsx
151
+ import { Marking as FullStoryMarking } from '@commercetools-frontend/fullstory';
152
+
153
+ <input {...FullStoryMarking.applyMarker('Discount Rule')} />;
154
+ ```
155
+
156
+ Both cases will add a `data-tracking="Discount Rule"` to either the `input` or `section` element. You can then use these elements to target the element as in `input[data-tracking="Discount Rule"]` or `section[data-tracking="Discount Rules"] button[label="some label"]`.
157
+
158
+ ## FAQ
159
+
160
+ Question: _I want to disable FullStory on a specific environment_
161
+ Answer: Unset or not set the `FULLSTORY_ORGANIZATION_ID` on that environments dotenv file.
162
+
163
+ Question: _I want to unmask a specific part of the page_
164
+ Answer: Add an `fs-unmask` class name to the outer most element of the area you intend to unmask.
165
+
166
+ Question: _A function of the FullStory SDK is not supported here. How can I use it?_
167
+ Answer: It's recommended to add wrapper to this package and release is to any FullStory SDK usage is encapsulated here.
@@ -0,0 +1,2 @@
1
+ export * from "../../dist/declarations/src/constants.js";
2
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tbWVyY2V0b29scy1mcm9udGVuZC1mdWxsc3RvcnktY29uc3RhbnRzLmNqcy5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vZGlzdC9kZWNsYXJhdGlvbnMvc3JjL2NvbnN0YW50cy5kLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBIn0=
@@ -0,0 +1,10 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ const CONTENT_SECURITY_POLICIES = {
6
+ CONNECT_SRC: ['*.fullstory.com'],
7
+ SCRIPT_SRC: ['*.fullstory.com']
8
+ };
9
+
10
+ exports.CONTENT_SECURITY_POLICIES = CONTENT_SECURITY_POLICIES;
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ if (process.env.NODE_ENV === "production") {
4
+ module.exports = require("./commercetools-frontend-fullstory-constants.cjs.prod.js");
5
+ } else {
6
+ module.exports = require("./commercetools-frontend-fullstory-constants.cjs.dev.js");
7
+ }
@@ -0,0 +1,10 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ const CONTENT_SECURITY_POLICIES = {
6
+ CONNECT_SRC: ['*.fullstory.com'],
7
+ SCRIPT_SRC: ['*.fullstory.com']
8
+ };
9
+
10
+ exports.CONTENT_SECURITY_POLICIES = CONTENT_SECURITY_POLICIES;
@@ -0,0 +1,6 @@
1
+ const CONTENT_SECURITY_POLICIES = {
2
+ CONNECT_SRC: ['*.fullstory.com'],
3
+ SCRIPT_SRC: ['*.fullstory.com']
4
+ };
5
+
6
+ export { CONTENT_SECURITY_POLICIES };
@@ -0,0 +1,4 @@
1
+ {
2
+ "main": "dist/commercetools-frontend-fullstory-constants.cjs.js",
3
+ "module": "dist/commercetools-frontend-fullstory-constants.esm.js"
4
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./declarations/src/index.js";
2
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tbWVyY2V0b29scy1mcm9udGVuZC1mdWxsc3RvcnkuY2pzLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuL2RlY2xhcmF0aW9ucy9zcmMvaW5kZXguZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSJ9
@@ -0,0 +1,190 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var browser = require('@fullstory/browser');
6
+ var _Object$keys = require('@babel/runtime-corejs3/core-js-stable/object/keys');
7
+ var _Object$getOwnPropertySymbols = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols');
8
+ var _filterInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/filter');
9
+ var _Object$getOwnPropertyDescriptor = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor');
10
+ var _forEachInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/for-each');
11
+ var _Object$getOwnPropertyDescriptors = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors');
12
+ var _Object$defineProperties = require('@babel/runtime-corejs3/core-js-stable/object/define-properties');
13
+ var _Object$defineProperty = require('@babel/runtime-corejs3/core-js-stable/object/define-property');
14
+ var _defineProperty = require('@babel/runtime-corejs3/helpers/defineProperty');
15
+ var react = require('react');
16
+ var applicationShellConnectors = require('@commercetools-frontend/application-shell-connectors');
17
+ var jsxRuntime = require('@emotion/react/jsx-runtime');
18
+ var _objectWithoutProperties = require('@babel/runtime-corejs3/helpers/objectWithoutProperties');
19
+
20
+ function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
21
+
22
+ var _Object$keys__default = /*#__PURE__*/_interopDefault(_Object$keys);
23
+ var _Object$getOwnPropertySymbols__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertySymbols);
24
+ var _filterInstanceProperty__default = /*#__PURE__*/_interopDefault(_filterInstanceProperty);
25
+ var _Object$getOwnPropertyDescriptor__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertyDescriptor);
26
+ var _forEachInstanceProperty__default = /*#__PURE__*/_interopDefault(_forEachInstanceProperty);
27
+ var _Object$getOwnPropertyDescriptors__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertyDescriptors);
28
+ var _Object$defineProperties__default = /*#__PURE__*/_interopDefault(_Object$defineProperties);
29
+ var _Object$defineProperty__default = /*#__PURE__*/_interopDefault(_Object$defineProperty);
30
+
31
+ function assertValidFullstoryOrganizationId(fullstoryOrganizationId) {
32
+ if (typeof fullstoryOrganizationId !== 'string') {
33
+ throw new Error('A valid FullStory organization id must be a string.');
34
+ }
35
+ if (fullstoryOrganizationId.length <= 0) {
36
+ throw new Error('A FullStory organization id can not be an empty string.');
37
+ }
38
+ }
39
+ function initialize() {
40
+ let fullstoryOrganizationId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window.app.fullstoryOrganizationId;
41
+ try {
42
+ try {
43
+ assertValidFullstoryOrganizationId(fullstoryOrganizationId);
44
+ } catch (error) {
45
+ console.warn('[@commercetools-frontend/fullstory]: No valid `fullstoryOrganizationId` passed. Not initializing FullStory.');
46
+ return;
47
+ }
48
+ browser.init({
49
+ orgId: fullstoryOrganizationId,
50
+ devMode: process.env.NODE_ENV !== 'production'
51
+ });
52
+ } catch (error) {
53
+ console.warn('[@commercetools-frontend/fullstory]: Failed to initialize FullStory due to an error:', error);
54
+ }
55
+ }
56
+
57
+ function ownKeys$1(e, r) { var t = _Object$keys__default["default"](e); if (_Object$getOwnPropertySymbols__default["default"]) { var o = _Object$getOwnPropertySymbols__default["default"](e); r && (o = _filterInstanceProperty__default["default"](o).call(o, function (r) { return _Object$getOwnPropertyDescriptor__default["default"](e, r).enumerable; })), t.push.apply(t, o); } return t; }
58
+ function _objectSpread$1(e) { for (var r = 1; r < arguments.length; r++) { var _context, _context2; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default["default"](_context = ownKeys$1(Object(t), !0)).call(_context, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](e, _Object$getOwnPropertyDescriptors__default["default"](t)) : _forEachInstanceProperty__default["default"](_context2 = ownKeys$1(Object(t))).call(_context2, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
59
+ const defaultTrackingArgs = {
60
+ disable: false,
61
+ additionalUserVars: undefined
62
+ };
63
+ function useTrackingEffect() {
64
+ let _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultTrackingArgs,
65
+ disable = _ref.disable,
66
+ additionalUserVars = _ref.additionalUserVars;
67
+ const _useApplicationContex = applicationShellConnectors.useApplicationContext(context => ({
68
+ user: context.user,
69
+ project: context.project,
70
+ cloudEnvironment: context.environment.cloudEnvironment,
71
+ organizationId: context.project?.ownerId,
72
+ isProductionProject: context.project?.isProductionProject
73
+ })),
74
+ project = _useApplicationContex.project,
75
+ user = _useApplicationContex.user,
76
+ cloudEnvironment = _useApplicationContex.cloudEnvironment,
77
+ organizationId = _useApplicationContex.organizationId,
78
+ isProductionProject = _useApplicationContex.isProductionProject;
79
+ react.useEffect(() => {
80
+ function getUserRole() {
81
+ switch (project?.isUserAdminOfCurrentProject) {
82
+ case true:
83
+ return 'admin';
84
+ case false:
85
+ return 'regular';
86
+ default:
87
+ return 'unknown';
88
+ }
89
+ }
90
+
91
+ // It's not safe to invoke any FullStory SDK methods.
92
+ if (!browser.isInitialized() || disable) {
93
+ return;
94
+ }
95
+ if (!user?.id) {
96
+ browser.FullStory('setIdentity', {
97
+ anonymous: true
98
+ });
99
+ } else {
100
+ browser.FullStory('setIdentity', {
101
+ uid: user.id,
102
+ properties: _objectSpread$1({
103
+ environment: cloudEnvironment,
104
+ projectKey: project?.key,
105
+ isProductionProject,
106
+ organizationId,
107
+ userBusinessRole: user.businessRole,
108
+ userLocale: user.locale,
109
+ userRole: getUserRole()
110
+ }, additionalUserVars)
111
+ });
112
+ }
113
+ }, [disable, additionalUserVars, cloudEnvironment, project?.key, user?.businessRole, user?.id, user?.locale, isProductionProject, organizationId, project?.isUserAdminOfCurrentProject]);
114
+ return null;
115
+ }
116
+
117
+ // NOTE: This type is not exported from the @fullstory/browser package.
118
+
119
+ function sendEvent(eventName, eventProperties) {
120
+ // Don't send events if FullStory is not initialized.
121
+ if (!browser.isInitialized()) {
122
+ return;
123
+ }
124
+ browser.FullStory('trackEvent', {
125
+ name: eventName,
126
+ properties: eventProperties
127
+ });
128
+ }
129
+
130
+ function setUserVars(userVars) {
131
+ browser.FullStory('setProperties', {
132
+ type: 'user',
133
+ properties: userVars
134
+ });
135
+ }
136
+
137
+ function Exclude(props) {
138
+ const ExcludeElement = props.as || 'div';
139
+ return jsxRuntime.jsx(ExcludeElement, {
140
+ className: "fs-exclude",
141
+ children: props.children
142
+ });
143
+ }
144
+ function Unmask(props) {
145
+ const UnmaskElement = props.as || 'div';
146
+ return jsxRuntime.jsx(UnmaskElement, {
147
+ className: "fs-unmask",
148
+ children: props.children
149
+ });
150
+ }
151
+ function Mask(props) {
152
+ const MaskElement = props.as || 'div';
153
+ return jsxRuntime.jsx(MaskElement, {
154
+ className: "fs-mask",
155
+ children: props.children
156
+ });
157
+ }
158
+ const Masking = {
159
+ Unmask,
160
+ Mask,
161
+ Exclude
162
+ };
163
+
164
+ const _excluded = ["children", "name"];
165
+ function ownKeys(e, r) { var t = _Object$keys__default["default"](e); if (_Object$getOwnPropertySymbols__default["default"]) { var o = _Object$getOwnPropertySymbols__default["default"](e); r && (o = _filterInstanceProperty__default["default"](o).call(o, function (r) { return _Object$getOwnPropertyDescriptor__default["default"](e, r).enumerable; })), t.push.apply(t, o); } return t; }
166
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var _context, _context2; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default["default"](_context = ownKeys(Object(t), !0)).call(_context, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](e, _Object$getOwnPropertyDescriptors__default["default"](t)) : _forEachInstanceProperty__default["default"](_context2 = ownKeys(Object(t))).call(_context2, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
167
+ function applyMarker(name) {
168
+ return {
169
+ 'data-tracking': name
170
+ };
171
+ }
172
+ function Section(_ref) {
173
+ let children = _ref.children,
174
+ name = _ref.name,
175
+ additionalProps = _objectWithoutProperties(_ref, _excluded);
176
+ return jsxRuntime.jsx("section", _objectSpread(_objectSpread(_objectSpread({}, additionalProps), applyMarker(name)), {}, {
177
+ children: children
178
+ }));
179
+ }
180
+ const Marking = {
181
+ Section,
182
+ applyMarker
183
+ };
184
+
185
+ exports.Marking = Marking;
186
+ exports.Masking = Masking;
187
+ exports.initialize = initialize;
188
+ exports.sendEvent = sendEvent;
189
+ exports.setUserVars = setUserVars;
190
+ exports.useTrackingEffect = useTrackingEffect;
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ if (process.env.NODE_ENV === "production") {
4
+ module.exports = require("./commercetools-frontend-fullstory.cjs.prod.js");
5
+ } else {
6
+ module.exports = require("./commercetools-frontend-fullstory.cjs.dev.js");
7
+ }
@@ -0,0 +1,190 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var browser = require('@fullstory/browser');
6
+ var _Object$keys = require('@babel/runtime-corejs3/core-js-stable/object/keys');
7
+ var _Object$getOwnPropertySymbols = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols');
8
+ var _filterInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/filter');
9
+ var _Object$getOwnPropertyDescriptor = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor');
10
+ var _forEachInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/for-each');
11
+ var _Object$getOwnPropertyDescriptors = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors');
12
+ var _Object$defineProperties = require('@babel/runtime-corejs3/core-js-stable/object/define-properties');
13
+ var _Object$defineProperty = require('@babel/runtime-corejs3/core-js-stable/object/define-property');
14
+ var _defineProperty = require('@babel/runtime-corejs3/helpers/defineProperty');
15
+ var react = require('react');
16
+ var applicationShellConnectors = require('@commercetools-frontend/application-shell-connectors');
17
+ var jsxRuntime = require('@emotion/react/jsx-runtime');
18
+ var _objectWithoutProperties = require('@babel/runtime-corejs3/helpers/objectWithoutProperties');
19
+
20
+ function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
21
+
22
+ var _Object$keys__default = /*#__PURE__*/_interopDefault(_Object$keys);
23
+ var _Object$getOwnPropertySymbols__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertySymbols);
24
+ var _filterInstanceProperty__default = /*#__PURE__*/_interopDefault(_filterInstanceProperty);
25
+ var _Object$getOwnPropertyDescriptor__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertyDescriptor);
26
+ var _forEachInstanceProperty__default = /*#__PURE__*/_interopDefault(_forEachInstanceProperty);
27
+ var _Object$getOwnPropertyDescriptors__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertyDescriptors);
28
+ var _Object$defineProperties__default = /*#__PURE__*/_interopDefault(_Object$defineProperties);
29
+ var _Object$defineProperty__default = /*#__PURE__*/_interopDefault(_Object$defineProperty);
30
+
31
+ function assertValidFullstoryOrganizationId(fullstoryOrganizationId) {
32
+ if (typeof fullstoryOrganizationId !== 'string') {
33
+ throw new Error('A valid FullStory organization id must be a string.');
34
+ }
35
+ if (fullstoryOrganizationId.length <= 0) {
36
+ throw new Error('A FullStory organization id can not be an empty string.');
37
+ }
38
+ }
39
+ function initialize() {
40
+ let fullstoryOrganizationId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window.app.fullstoryOrganizationId;
41
+ try {
42
+ try {
43
+ assertValidFullstoryOrganizationId(fullstoryOrganizationId);
44
+ } catch (error) {
45
+ console.warn('[@commercetools-frontend/fullstory]: No valid `fullstoryOrganizationId` passed. Not initializing FullStory.');
46
+ return;
47
+ }
48
+ browser.init({
49
+ orgId: fullstoryOrganizationId,
50
+ devMode: "production" !== 'production'
51
+ });
52
+ } catch (error) {
53
+ console.warn('[@commercetools-frontend/fullstory]: Failed to initialize FullStory due to an error:', error);
54
+ }
55
+ }
56
+
57
+ function ownKeys$1(e, r) { var t = _Object$keys__default["default"](e); if (_Object$getOwnPropertySymbols__default["default"]) { var o = _Object$getOwnPropertySymbols__default["default"](e); r && (o = _filterInstanceProperty__default["default"](o).call(o, function (r) { return _Object$getOwnPropertyDescriptor__default["default"](e, r).enumerable; })), t.push.apply(t, o); } return t; }
58
+ function _objectSpread$1(e) { for (var r = 1; r < arguments.length; r++) { var _context, _context2; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default["default"](_context = ownKeys$1(Object(t), !0)).call(_context, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](e, _Object$getOwnPropertyDescriptors__default["default"](t)) : _forEachInstanceProperty__default["default"](_context2 = ownKeys$1(Object(t))).call(_context2, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
59
+ const defaultTrackingArgs = {
60
+ disable: false,
61
+ additionalUserVars: undefined
62
+ };
63
+ function useTrackingEffect() {
64
+ let _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultTrackingArgs,
65
+ disable = _ref.disable,
66
+ additionalUserVars = _ref.additionalUserVars;
67
+ const _useApplicationContex = applicationShellConnectors.useApplicationContext(context => ({
68
+ user: context.user,
69
+ project: context.project,
70
+ cloudEnvironment: context.environment.cloudEnvironment,
71
+ organizationId: context.project?.ownerId,
72
+ isProductionProject: context.project?.isProductionProject
73
+ })),
74
+ project = _useApplicationContex.project,
75
+ user = _useApplicationContex.user,
76
+ cloudEnvironment = _useApplicationContex.cloudEnvironment,
77
+ organizationId = _useApplicationContex.organizationId,
78
+ isProductionProject = _useApplicationContex.isProductionProject;
79
+ react.useEffect(() => {
80
+ function getUserRole() {
81
+ switch (project?.isUserAdminOfCurrentProject) {
82
+ case true:
83
+ return 'admin';
84
+ case false:
85
+ return 'regular';
86
+ default:
87
+ return 'unknown';
88
+ }
89
+ }
90
+
91
+ // It's not safe to invoke any FullStory SDK methods.
92
+ if (!browser.isInitialized() || disable) {
93
+ return;
94
+ }
95
+ if (!user?.id) {
96
+ browser.FullStory('setIdentity', {
97
+ anonymous: true
98
+ });
99
+ } else {
100
+ browser.FullStory('setIdentity', {
101
+ uid: user.id,
102
+ properties: _objectSpread$1({
103
+ environment: cloudEnvironment,
104
+ projectKey: project?.key,
105
+ isProductionProject,
106
+ organizationId,
107
+ userBusinessRole: user.businessRole,
108
+ userLocale: user.locale,
109
+ userRole: getUserRole()
110
+ }, additionalUserVars)
111
+ });
112
+ }
113
+ }, [disable, additionalUserVars, cloudEnvironment, project?.key, user?.businessRole, user?.id, user?.locale, isProductionProject, organizationId, project?.isUserAdminOfCurrentProject]);
114
+ return null;
115
+ }
116
+
117
+ // NOTE: This type is not exported from the @fullstory/browser package.
118
+
119
+ function sendEvent(eventName, eventProperties) {
120
+ // Don't send events if FullStory is not initialized.
121
+ if (!browser.isInitialized()) {
122
+ return;
123
+ }
124
+ browser.FullStory('trackEvent', {
125
+ name: eventName,
126
+ properties: eventProperties
127
+ });
128
+ }
129
+
130
+ function setUserVars(userVars) {
131
+ browser.FullStory('setProperties', {
132
+ type: 'user',
133
+ properties: userVars
134
+ });
135
+ }
136
+
137
+ function Exclude(props) {
138
+ const ExcludeElement = props.as || 'div';
139
+ return jsxRuntime.jsx(ExcludeElement, {
140
+ className: "fs-exclude",
141
+ children: props.children
142
+ });
143
+ }
144
+ function Unmask(props) {
145
+ const UnmaskElement = props.as || 'div';
146
+ return jsxRuntime.jsx(UnmaskElement, {
147
+ className: "fs-unmask",
148
+ children: props.children
149
+ });
150
+ }
151
+ function Mask(props) {
152
+ const MaskElement = props.as || 'div';
153
+ return jsxRuntime.jsx(MaskElement, {
154
+ className: "fs-mask",
155
+ children: props.children
156
+ });
157
+ }
158
+ const Masking = {
159
+ Unmask,
160
+ Mask,
161
+ Exclude
162
+ };
163
+
164
+ const _excluded = ["children", "name"];
165
+ function ownKeys(e, r) { var t = _Object$keys__default["default"](e); if (_Object$getOwnPropertySymbols__default["default"]) { var o = _Object$getOwnPropertySymbols__default["default"](e); r && (o = _filterInstanceProperty__default["default"](o).call(o, function (r) { return _Object$getOwnPropertyDescriptor__default["default"](e, r).enumerable; })), t.push.apply(t, o); } return t; }
166
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var _context, _context2; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default["default"](_context = ownKeys(Object(t), !0)).call(_context, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](e, _Object$getOwnPropertyDescriptors__default["default"](t)) : _forEachInstanceProperty__default["default"](_context2 = ownKeys(Object(t))).call(_context2, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
167
+ function applyMarker(name) {
168
+ return {
169
+ 'data-tracking': name
170
+ };
171
+ }
172
+ function Section(_ref) {
173
+ let children = _ref.children,
174
+ name = _ref.name,
175
+ additionalProps = _objectWithoutProperties(_ref, _excluded);
176
+ return jsxRuntime.jsx("section", _objectSpread(_objectSpread(_objectSpread({}, additionalProps), applyMarker(name)), {}, {
177
+ children: children
178
+ }));
179
+ }
180
+ const Marking = {
181
+ Section,
182
+ applyMarker
183
+ };
184
+
185
+ exports.Marking = Marking;
186
+ exports.Masking = Masking;
187
+ exports.initialize = initialize;
188
+ exports.sendEvent = sendEvent;
189
+ exports.setUserVars = setUserVars;
190
+ exports.useTrackingEffect = useTrackingEffect;
@@ -0,0 +1,170 @@
1
+ import { init, isInitialized, FullStory } from '@fullstory/browser';
2
+ import _Object$keys from '@babel/runtime-corejs3/core-js-stable/object/keys';
3
+ import _Object$getOwnPropertySymbols from '@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols';
4
+ import _filterInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/filter';
5
+ import _Object$getOwnPropertyDescriptor from '@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor';
6
+ import _forEachInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/for-each';
7
+ import _Object$getOwnPropertyDescriptors from '@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors';
8
+ import _Object$defineProperties from '@babel/runtime-corejs3/core-js-stable/object/define-properties';
9
+ import _Object$defineProperty from '@babel/runtime-corejs3/core-js-stable/object/define-property';
10
+ import _defineProperty from '@babel/runtime-corejs3/helpers/esm/defineProperty';
11
+ import { useEffect } from 'react';
12
+ import { useApplicationContext } from '@commercetools-frontend/application-shell-connectors';
13
+ import { jsx } from '@emotion/react/jsx-runtime';
14
+ import _objectWithoutProperties from '@babel/runtime-corejs3/helpers/esm/objectWithoutProperties';
15
+
16
+ function assertValidFullstoryOrganizationId(fullstoryOrganizationId) {
17
+ if (typeof fullstoryOrganizationId !== 'string') {
18
+ throw new Error('A valid FullStory organization id must be a string.');
19
+ }
20
+ if (fullstoryOrganizationId.length <= 0) {
21
+ throw new Error('A FullStory organization id can not be an empty string.');
22
+ }
23
+ }
24
+ function initialize() {
25
+ let fullstoryOrganizationId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window.app.fullstoryOrganizationId;
26
+ try {
27
+ try {
28
+ assertValidFullstoryOrganizationId(fullstoryOrganizationId);
29
+ } catch (error) {
30
+ console.warn('[@commercetools-frontend/fullstory]: No valid `fullstoryOrganizationId` passed. Not initializing FullStory.');
31
+ return;
32
+ }
33
+ init({
34
+ orgId: fullstoryOrganizationId,
35
+ devMode: process.env.NODE_ENV !== 'production'
36
+ });
37
+ } catch (error) {
38
+ console.warn('[@commercetools-frontend/fullstory]: Failed to initialize FullStory due to an error:', error);
39
+ }
40
+ }
41
+
42
+ function ownKeys$1(e, r) { var t = _Object$keys(e); if (_Object$getOwnPropertySymbols) { var o = _Object$getOwnPropertySymbols(e); r && (o = _filterInstanceProperty(o).call(o, function (r) { return _Object$getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
43
+ function _objectSpread$1(e) { for (var r = 1; r < arguments.length; r++) { var _context, _context2; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty(_context = ownKeys$1(Object(t), !0)).call(_context, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(e, _Object$getOwnPropertyDescriptors(t)) : _forEachInstanceProperty(_context2 = ownKeys$1(Object(t))).call(_context2, function (r) { _Object$defineProperty(e, r, _Object$getOwnPropertyDescriptor(t, r)); }); } return e; }
44
+ const defaultTrackingArgs = {
45
+ disable: false,
46
+ additionalUserVars: undefined
47
+ };
48
+ function useTrackingEffect() {
49
+ let _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultTrackingArgs,
50
+ disable = _ref.disable,
51
+ additionalUserVars = _ref.additionalUserVars;
52
+ const _useApplicationContex = useApplicationContext(context => ({
53
+ user: context.user,
54
+ project: context.project,
55
+ cloudEnvironment: context.environment.cloudEnvironment,
56
+ organizationId: context.project?.ownerId,
57
+ isProductionProject: context.project?.isProductionProject
58
+ })),
59
+ project = _useApplicationContex.project,
60
+ user = _useApplicationContex.user,
61
+ cloudEnvironment = _useApplicationContex.cloudEnvironment,
62
+ organizationId = _useApplicationContex.organizationId,
63
+ isProductionProject = _useApplicationContex.isProductionProject;
64
+ useEffect(() => {
65
+ function getUserRole() {
66
+ switch (project?.isUserAdminOfCurrentProject) {
67
+ case true:
68
+ return 'admin';
69
+ case false:
70
+ return 'regular';
71
+ default:
72
+ return 'unknown';
73
+ }
74
+ }
75
+
76
+ // It's not safe to invoke any FullStory SDK methods.
77
+ if (!isInitialized() || disable) {
78
+ return;
79
+ }
80
+ if (!user?.id) {
81
+ FullStory('setIdentity', {
82
+ anonymous: true
83
+ });
84
+ } else {
85
+ FullStory('setIdentity', {
86
+ uid: user.id,
87
+ properties: _objectSpread$1({
88
+ environment: cloudEnvironment,
89
+ projectKey: project?.key,
90
+ isProductionProject,
91
+ organizationId,
92
+ userBusinessRole: user.businessRole,
93
+ userLocale: user.locale,
94
+ userRole: getUserRole()
95
+ }, additionalUserVars)
96
+ });
97
+ }
98
+ }, [disable, additionalUserVars, cloudEnvironment, project?.key, user?.businessRole, user?.id, user?.locale, isProductionProject, organizationId, project?.isUserAdminOfCurrentProject]);
99
+ return null;
100
+ }
101
+
102
+ // NOTE: This type is not exported from the @fullstory/browser package.
103
+
104
+ function sendEvent(eventName, eventProperties) {
105
+ // Don't send events if FullStory is not initialized.
106
+ if (!isInitialized()) {
107
+ return;
108
+ }
109
+ FullStory('trackEvent', {
110
+ name: eventName,
111
+ properties: eventProperties
112
+ });
113
+ }
114
+
115
+ function setUserVars(userVars) {
116
+ FullStory('setProperties', {
117
+ type: 'user',
118
+ properties: userVars
119
+ });
120
+ }
121
+
122
+ function Exclude(props) {
123
+ const ExcludeElement = props.as || 'div';
124
+ return jsx(ExcludeElement, {
125
+ className: "fs-exclude",
126
+ children: props.children
127
+ });
128
+ }
129
+ function Unmask(props) {
130
+ const UnmaskElement = props.as || 'div';
131
+ return jsx(UnmaskElement, {
132
+ className: "fs-unmask",
133
+ children: props.children
134
+ });
135
+ }
136
+ function Mask(props) {
137
+ const MaskElement = props.as || 'div';
138
+ return jsx(MaskElement, {
139
+ className: "fs-mask",
140
+ children: props.children
141
+ });
142
+ }
143
+ const Masking = {
144
+ Unmask,
145
+ Mask,
146
+ Exclude
147
+ };
148
+
149
+ const _excluded = ["children", "name"];
150
+ function ownKeys(e, r) { var t = _Object$keys(e); if (_Object$getOwnPropertySymbols) { var o = _Object$getOwnPropertySymbols(e); r && (o = _filterInstanceProperty(o).call(o, function (r) { return _Object$getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
151
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var _context, _context2; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty(_context = ownKeys(Object(t), !0)).call(_context, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(e, _Object$getOwnPropertyDescriptors(t)) : _forEachInstanceProperty(_context2 = ownKeys(Object(t))).call(_context2, function (r) { _Object$defineProperty(e, r, _Object$getOwnPropertyDescriptor(t, r)); }); } return e; }
152
+ function applyMarker(name) {
153
+ return {
154
+ 'data-tracking': name
155
+ };
156
+ }
157
+ function Section(_ref) {
158
+ let children = _ref.children,
159
+ name = _ref.name,
160
+ additionalProps = _objectWithoutProperties(_ref, _excluded);
161
+ return jsx("section", _objectSpread(_objectSpread(_objectSpread({}, additionalProps), applyMarker(name)), {}, {
162
+ children: children
163
+ }));
164
+ }
165
+ const Marking = {
166
+ Section,
167
+ applyMarker
168
+ };
169
+
170
+ export { Marking, Masking, initialize, sendEvent, setUserVars, useTrackingEffect };
@@ -0,0 +1,5 @@
1
+ declare const CONTENT_SECURITY_POLICIES: {
2
+ readonly CONNECT_SRC: readonly ["*.fullstory.com"];
3
+ readonly SCRIPT_SRC: readonly ["*.fullstory.com"];
4
+ };
5
+ export { CONTENT_SECURITY_POLICIES };
@@ -0,0 +1,6 @@
1
+ export { initialize } from "./initialize.js";
2
+ export { useTrackingEffect } from "./tracking-effect.js";
3
+ export { sendEvent } from "./send-event.js";
4
+ export { setUserVars } from "./set-user-vars.js";
5
+ export { Masking } from "./masking.js";
6
+ export { Marking } from "./marking.js";
@@ -0,0 +1,7 @@
1
+ declare global {
2
+ interface Window {
3
+ app: Record<string, unknown>;
4
+ }
5
+ }
6
+ declare function initialize(fullstoryOrganizationId?: unknown): void;
7
+ export { initialize };
@@ -0,0 +1,15 @@
1
+ import type { HTMLAttributes, ReactNode } from 'react';
2
+ export type TMarkingProps = HTMLAttributes<HTMLDivElement> & {
3
+ name: string;
4
+ children: ReactNode;
5
+ className?: string;
6
+ };
7
+ declare function applyMarker(name: TMarkingProps['name']): {
8
+ 'data-tracking': string;
9
+ };
10
+ declare function Section({ children, name, ...additionalProps }: TMarkingProps): import("@emotion/react/types/jsx-namespace").EmotionJSX.Element;
11
+ declare const Marking: {
12
+ Section: typeof Section;
13
+ applyMarker: typeof applyMarker;
14
+ };
15
+ export { Marking };
@@ -0,0 +1,14 @@
1
+ import type { ReactNode } from 'react';
2
+ export type TMaskingProps = {
3
+ children: ReactNode;
4
+ as?: 'div' | 'span';
5
+ };
6
+ declare function Exclude(props: TMaskingProps): import("@emotion/react/types/jsx-namespace").EmotionJSX.Element;
7
+ declare function Unmask(props: TMaskingProps): import("@emotion/react/types/jsx-namespace").EmotionJSX.Element;
8
+ declare function Mask(props: TMaskingProps): import("@emotion/react/types/jsx-namespace").EmotionJSX.Element;
9
+ declare const Masking: {
10
+ Unmask: typeof Unmask;
11
+ Mask: typeof Mask;
12
+ Exclude: typeof Exclude;
13
+ };
14
+ export { Masking };
@@ -0,0 +1,3 @@
1
+ type TFullStoryEventProperties = Record<string, unknown>;
2
+ declare function sendEvent(eventName: string, eventProperties: TFullStoryEventProperties): void;
3
+ export { sendEvent };
@@ -0,0 +1,2 @@
1
+ declare function setUserVars(userVars: object): void;
2
+ export { setUserVars };
@@ -0,0 +1,8 @@
1
+ /// <reference types="node" />
2
+ import { KeyObject } from 'crypto';
3
+ type TTrackingArgs = {
4
+ disable?: boolean;
5
+ additionalUserVars?: KeyObject;
6
+ };
7
+ declare function useTrackingEffect({ disable, additionalUserVars, }?: TTrackingArgs): null;
8
+ export { useTrackingEffect };
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@commercetools-frontend/fullstory",
3
+ "version": "0.0.0-FEC-212-react19-20250122084835",
4
+ "description": "A package integrating with the FullStory SDK",
5
+ "license": "MIT",
6
+ "main": "dist/commercetools-frontend-fullstory.cjs.js",
7
+ "module": "dist/commercetools-frontend-fullstory.esm.js",
8
+ "files": [
9
+ "dist",
10
+ "constants",
11
+ "LICENSE",
12
+ "package.json",
13
+ "README.md"
14
+ ],
15
+ "dependencies": {
16
+ "@babel/core": "^7.22.11",
17
+ "@babel/runtime-corejs3": "^7.21.0",
18
+ "@fullstory/browser": "2.0.5"
19
+ },
20
+ "devDependencies": {
21
+ "@apollo/client": "3.12.3",
22
+ "@commercetools-frontend/application-shell": "0.0.0-fec-156-react19-20250117164550",
23
+ "@commercetools-frontend/application-shell-connectors": "0.0.0-fec-156-react19-20250117164550",
24
+ "@commercetools-frontend/constants": "0.0.0-fec-156-react19-20250117164550",
25
+ "@emotion/react": "11.13.3",
26
+ "@testing-library/react": "16.1.0",
27
+ "@types/jest": "^29.5.2",
28
+ "@types/node": "20.17.13",
29
+ "@types/react": "19.0.0",
30
+ "@types/testing-library__jest-dom": "^5.14.6",
31
+ "graphql": "16.9.0",
32
+ "react": "19.0.0",
33
+ "react-dom": "19.0.0",
34
+ "react-intl": "6.6.8",
35
+ "react-redux": "7.2.9",
36
+ "react-router-dom": "5.3.4",
37
+ "redux": "4.2.1",
38
+ "typescript": "5.2.2"
39
+ },
40
+ "peerDependencies": {
41
+ "@commercetools-frontend/application-shell-connectors": "0.0.0-fec-156-react19-20250117164550",
42
+ "@commercetools-frontend/constants": "0.0.0-fec-156-react19-20250117164550",
43
+ "@emotion/react": "11.x",
44
+ "react": "19.x",
45
+ "react-intl": "6.x"
46
+ },
47
+ "publishConfig": {
48
+ "access": "public"
49
+ },
50
+ "preconstruct": {
51
+ "entrypoints": [
52
+ "./index.ts",
53
+ "./constants.ts"
54
+ ]
55
+ },
56
+ "scripts": {
57
+ "typecheck": "tsc --noEmit"
58
+ }
59
+ }