diff --git a/jest.preset.js b/jest.preset.js index 99f4faee6a..f699c021bc 100644 --- a/jest.preset.js +++ b/jest.preset.js @@ -74,7 +74,7 @@ module.exports = { }, setupFilesAfterEnv: ['../../jest/jest.setup-dom.js'], setupFiles: ['core-js', 'jest-date-mock', '../../jest/jest.polyfills.js'], - testEnvironment: 'jest-environment-jsdom', + testEnvironment: '../../jest/jsdom-extended.js', testRunner: 'jest-circus/runner', cacheDirectory: '../../node_modules/.cache/unit-tests', watchPlugins: ['jest-watch-typeahead/filename', 'jest-watch-typeahead/testname'], diff --git a/jest/jest.polyfills.js b/jest/jest.polyfills.js index ad38c41620..da6191c12e 100644 --- a/jest/jest.polyfills.js +++ b/jest/jest.polyfills.js @@ -1,5 +1,3 @@ -/* eslint-disable import/no-extraneous-dependencies */ - require('isomorphic-fetch'); // Mocking Math random @@ -18,7 +16,3 @@ console.warn = jest.fn(); console.error = jest.fn(); // Mock browsers sendBeacon utility navigator.sendBeacon = jest.fn(); - -import { TextEncoder, TextDecoder } from 'util'; - -Object.assign(global, { TextDecoder, TextEncoder }); diff --git a/jest/jsdom-extended.js b/jest/jsdom-extended.js new file mode 100644 index 0000000000..99395d9683 --- /dev/null +++ b/jest/jsdom-extended.js @@ -0,0 +1,26 @@ +import JSDOMEnvironment from 'jest-environment-jsdom'; + +// Adding relevant polyfilled extensions in the JSDOm to have msw v2 working +// More on: https://github.com/mswjs/msw/issues/1916#issuecomment-1919965699 +class JSDOMEnvironmentExtended extends JSDOMEnvironment { + constructor(...args) { + super(...args); + + this.global.ReadableStream = ReadableStream; + this.global.TextDecoder = TextDecoder; + this.global.TextEncoder = TextEncoder; + + this.global.Blob = Blob; + this.global.File = File; + this.global.Headers = Headers; + this.global.FormData = FormData; + this.global.Request = Request; + this.global.Response = Response; + this.global.Request = Request; + this.global.Response = Response; + this.global.fetch = fetch; + this.global.structuredClone = structuredClone; + } +} + +module.exports = JSDOMEnvironmentExtended; diff --git a/package-lock.json b/package-lock.json index a0e370ef8b..82f8e07402 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,7 @@ "axios": "1.6.7", "axios-retry": "3.9.1", "component-each": "0.2.6", - "component-emitter": "1.3.0", + "component-emitter": "2.0.0", "component-querystring": "2.0.1", "component-url": "0.2.1", "crypto-es": "2.1.0", @@ -86,6 +86,7 @@ "@types/jest": "29.5.12", "@types/lodash.clonedeep": "4.5.9", "@types/lodash.isstring": "4.0.9", + "@types/ms": "0.7.34", "@types/node": "20.11.20", "@types/ramda": "0.29.10", "assert": "2.1.0", @@ -93,7 +94,7 @@ "babel-plugin-transform-object-hasown": "1.1.0", "commitizen": "4.3.0", "commitlint": "18.6.1", - "component-type": "1.2.1", + "component-type": "2.0.0", "core-js": "3.36.0", "dotenv": "16.4.5", "each": "2.6.0", @@ -5994,6 +5995,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/ms": { + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==", + "dev": true + }, "node_modules/@types/mute-stream": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/@types/mute-stream/-/mute-stream-0.0.4.tgz", @@ -8578,14 +8585,15 @@ "to-function": "2.0.6" } }, - "node_modules/component-each/node_modules/component-type": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/component-type/-/component-type-1.0.0.tgz", - "integrity": "sha512-qzUg4SGDH6KFYlcklmeZwucbtosh/XGwuIffqXAhC1dZyjO7Xu1UuaxwKRY29EncuBj/DH+h6Zot3AdZS6xdFw==" - }, "node_modules/component-emitter": { - "version": "1.3.0", - "license": "MIT" + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/component-props": { "version": "1.1.1" @@ -8597,15 +8605,15 @@ "trim": "1.0.0" } }, - "node_modules/component-querystring/node_modules/component-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/component-type/-/component-type-1.1.0.tgz", - "integrity": "sha512-rLfU88D3tytip79EqPsLD+ND+Fl8HsIhz5KkOEeNidNVN1GUO9AWEs8+DPLtZR63BecAC883DuF2GZ1DM78BbA==" - }, "node_modules/component-type": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-type/-/component-type-1.2.1.tgz", - "integrity": "sha512-Kgy+2+Uwr75vAi6ChWXgHuLvd+QLD7ssgpaRq2zCvt80ptvAfMc/hijcJxXkBa2wMlEZcJvC2H8Ubo+A9ATHIg==" + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/component-url": { "version": "0.2.1" @@ -23846,13 +23854,14 @@ "assert": "2.1.0", "axios": "1.6.7", "axios-retry": "3.9.1", - "component-type": "1.2.1", + "component-type": "2.0.0", "join-component": "1.1.0", "lodash.clonedeep": "4.5.0", "lodash.isstring": "4.0.1", "ms": "2.1.3" }, "devDependencies": { + "@types/ms": "0.7.34", "@types/node": "20.11.20", "jest-date-mock": "1.0.8", "msw": "2.2.1" @@ -23868,7 +23877,7 @@ "dependencies": { "@lukeed/uuid": "2.0.1", "@segment/localstorage-retry": "1.3.0", - "component-emitter": "1.3.0", + "component-emitter": "2.0.0", "get-value": "3.0.1", "msw": "2.2.1", "ramda": "0.29.1" @@ -23877,7 +23886,6 @@ "@lukeed/uuid": "2.0.1", "@rudderstack/analytics-js-common": "*", "@segment/localstorage-retry": "1.3.0", - "component-emitter": "1.3.0", "get-value": "3.0.1", "ramda": "0.29.1" } diff --git a/package.json b/package.json index c866527dba..747df05d80 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "axios": "1.6.7", "axios-retry": "3.9.1", "component-each": "0.2.6", - "component-emitter": "1.3.0", + "component-emitter": "2.0.0", "component-querystring": "2.0.1", "component-url": "0.2.1", "crypto-es": "2.1.0", @@ -137,6 +137,7 @@ "@types/jest": "29.5.12", "@types/lodash.clonedeep": "4.5.9", "@types/lodash.isstring": "4.0.9", + "@types/ms": "0.7.34", "@types/node": "20.11.20", "@types/ramda": "0.29.10", "assert": "2.1.0", @@ -144,7 +145,7 @@ "babel-plugin-transform-object-hasown": "1.1.0", "commitizen": "4.3.0", "commitlint": "18.6.1", - "component-type": "1.2.1", + "component-type": "2.0.0", "core-js": "3.36.0", "dotenv": "16.4.5", "each": "2.6.0", @@ -206,7 +207,8 @@ }, "overrides": { "debug": "4.3.4", - "ip": "2.0.1" + "ip": "2.0.1", + "component-type": "2.0.0" }, "lint-staged": { "*.{json,js,md,ts}": "prettier --write" diff --git a/packages/analytics-js-common/__fixtures__/msw.handlers.ts b/packages/analytics-js-common/__fixtures__/msw.handlers.ts index 7e0bac58ce..8c03392595 100644 --- a/packages/analytics-js-common/__fixtures__/msw.handlers.ts +++ b/packages/analytics-js-common/__fixtures__/msw.handlers.ts @@ -1,60 +1,81 @@ -import { rest } from 'msw'; +import { http, HttpResponse } from 'msw'; import { dummyDataplaneHost, dummySourceConfigResponse } from './fixtures'; -// TODO: Why on data plane we allow-origin the domain but in sourceConfig is wildcard? const handlers = [ - rest.get(`${dummyDataplaneHost}/rawSample`, (req, res, ctx) => { - return res(ctx.status(200), ctx.text('{"raw": "sample"}')); + http.get(`${dummyDataplaneHost}/rawSample`, () => { + return new HttpResponse('{"raw": "sample"}', { + status: 200, + }); }), - rest.get(`${dummyDataplaneHost}/brokenJsonSample`, (req, res, ctx) => { - return res( - ctx.status(200), - ctx.text('{raw: sample}'), - ctx.set('Content-Type', 'application/json; charset=utf-8'), - ); + http.get(`${dummyDataplaneHost}/brokenJsonSample`, () => { + return new HttpResponse('{raw: sample}', { + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + }); }), - rest.get(`${dummyDataplaneHost}/emptyJsonSample`, (req, res, ctx) => { - return res( - ctx.status(200), - ctx.text(''), - ctx.set('Content-Type', 'application/json; charset=utf-8'), - ); + http.get(`${dummyDataplaneHost}/emptyJsonSample`, () => { + return new HttpResponse('', { + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + }); }), - rest.get(`${dummyDataplaneHost}/jsonSample`, (req, res, ctx) => { - return res(ctx.status(200), ctx.json({ json: 'sample' })); + http.get(`${dummyDataplaneHost}/jsonSample`, () => { + return new HttpResponse(JSON.stringify({ json: 'sample' }), { + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + }); }), - rest.get(`${dummyDataplaneHost}/404ErrorSample`, (req, res, ctx) => { - return res(ctx.status(404)); + http.get(`${dummyDataplaneHost}/404ErrorSample`, () => { + return new HttpResponse(null, { + status: 404, + }); }), - rest.get(`${dummyDataplaneHost}/429ErrorSample`, (req, res, ctx) => { - return res(ctx.status(429)); + http.get(`${dummyDataplaneHost}/429ErrorSample`, () => { + return new HttpResponse(null, { + status: 429, + }); }), - rest.get(`${dummyDataplaneHost}/500ErrorSample`, (req, res, ctx) => { - return res(ctx.status(500)); + http.get(`${dummyDataplaneHost}/500ErrorSample`, () => { + return new HttpResponse(null, { + status: 500, + }); }), - rest.get(`${dummyDataplaneHost}/noConnectionSample`, (req, res, ctx) => { - return res.networkError('Failed to connect'); + http.get(`${dummyDataplaneHost}/noConnectionSample`, () => { + return HttpResponse.error(); }), - rest.get(`${dummyDataplaneHost}/jsFileSample`, (req, res, ctx) => { + http.get(`${dummyDataplaneHost}/jsFileSample.js`, () => { const fileContents = 'console.log("jsFileSample script executed")'; - return res( - ctx.status(200), - ctx.set('Content-Length', fileContents.length.toString()), - ctx.set('Content-Type', 'text/javascript'), - ctx.body(fileContents), - ); - }), - rest.get(`${dummyDataplaneHost}/jsFileEmpty`, (req, res, ctx) => { + return new HttpResponse(fileContents, { + status: 200, + headers: { + 'Content-Type': 'application/javascript', + 'Content-Length': fileContents.length.toString(), + }, + }); + }), + http.get(`${dummyDataplaneHost}/jsFileEmpty.js`, () => { const fileContents = ''; - return res( - ctx.status(200), - ctx.set('Content-Length', fileContents.length.toString()), - ctx.set('Content-Type', 'text/javascript'), - ctx.body(fileContents), - ); - }), - rest.get(`${dummyDataplaneHost}/sourceConfig`, (req, res, ctx) => { - return res(ctx.status(200), ctx.json(dummySourceConfigResponse)); + return new HttpResponse(fileContents, { + status: 200, + headers: { + 'Content-Type': 'application/javascript', + 'Content-Length': fileContents.length.toString(), + }, + }); + }), + http.get(`${dummyDataplaneHost}/sourceConfig`, () => { + return new HttpResponse(JSON.stringify(dummySourceConfigResponse), { + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + }); }), ]; diff --git a/packages/analytics-js-common/__tests__/services/ExternalSrcLoader/ExternalSrcLoader.test.ts b/packages/analytics-js-common/__tests__/services/ExternalSrcLoader/ExternalSrcLoader.test.ts index bc48d63332..0451f6317c 100644 --- a/packages/analytics-js-common/__tests__/services/ExternalSrcLoader/ExternalSrcLoader.test.ts +++ b/packages/analytics-js-common/__tests__/services/ExternalSrcLoader/ExternalSrcLoader.test.ts @@ -39,12 +39,12 @@ describe('External Source Loader', () => { expect(loadedScript).toStrictEqual('dummyScript'); const newScriptElement = document.getElementById('dummyScript') as HTMLScriptElement; expect(newScriptElement).toBeDefined(); - expect(newScriptElement.src).toStrictEqual(`${dummyDataplaneHost}/jsFileSample`); + expect(newScriptElement.src).toStrictEqual(`${dummyDataplaneHost}/jsFileSample.js`); done(); }; externalSrcLoaderInstance.loadJSFile({ - url: `${dummyDataplaneHost}/jsFileSample`, + url: `${dummyDataplaneHost}/jsFileSample.js`, id: 'dummyScript', callback: cb, }); @@ -78,7 +78,7 @@ describe('External Source Loader', () => { expect(loadedScript).toBeUndefined(); const newScriptElement = document.getElementById('dummyScript') as HTMLScriptElement; expect(newScriptElement).toBeDefined(); - expect(newScriptElement.src).toStrictEqual(`${dummyDataplaneHost}/jsFileSample`); + expect(newScriptElement.src).toStrictEqual(`${dummyDataplaneHost}/jsFileSample.js`); expect(defaultErrorHandler.onError).toHaveBeenCalledTimes(1); expect(defaultErrorHandler.onError).toHaveBeenCalledWith( new Error( @@ -90,11 +90,14 @@ describe('External Source Loader', () => { done(); }; - const dummyElement = createScriptElement(`${dummyDataplaneHost}/jsFileSample`, 'dummyScript'); + const dummyElement = createScriptElement( + `${dummyDataplaneHost}/jsFileSample.js`, + 'dummyScript', + ); insertScript(dummyElement); const scriptElement = document.getElementById('dummyScript') as HTMLScriptElement; expect(scriptElement).toBeDefined(); - expect(scriptElement.src).toStrictEqual(`${dummyDataplaneHost}/jsFileSample`); + expect(scriptElement.src).toStrictEqual(`${dummyDataplaneHost}/jsFileSample.js`); externalSrcLoaderInstance.loadJSFile({ url: `${dummyDataplaneHost}/noConnectionSample`, @@ -104,10 +107,13 @@ describe('External Source Loader', () => { }); it(`should append the script in DOM in correct place`, () => { - const dummyElement = createScriptElement(`${dummyDataplaneHost}/jsFileSample`, 'dummyScript'); + const dummyElement = createScriptElement( + `${dummyDataplaneHost}/jsFileSample.js`, + 'dummyScript', + ); // If head exists should be placed as first script - insertScript(createScriptElement(`${dummyDataplaneHost}/jsFileEmpty`, 'dummyScript1')); + insertScript(createScriptElement(`${dummyDataplaneHost}/jsFileEmpty.js`, 'dummyScript1')); insertScript(dummyElement); let scriptElement = document.getElementById('dummyScript') as HTMLScriptElement; expect(scriptElement).toBeDefined(); @@ -120,7 +126,7 @@ describe('External Source Loader', () => { document.getElementsByTagName('head')[0].remove(); const scriptElement1 = document.createElement('script'); scriptElement1.type = 'text/javascript'; - scriptElement1.src = `${dummyDataplaneHost}/jsFileEmpty`; + scriptElement1.src = `${dummyDataplaneHost}/jsFileEmpty.js`; scriptElement1.id = 'dummyScript1'; document.getElementsByTagName('body')[0].append(scriptElement1); insertScript(dummyElement); @@ -145,14 +151,14 @@ describe('External Source Loader', () => { const cb = () => { const newScriptElement = document.getElementById('dummyScript') as HTMLScriptElement; expect(newScriptElement).toBeDefined(); - expect(newScriptElement.src).toStrictEqual(`${dummyDataplaneHost}/jsFileSample`); + expect(newScriptElement.src).toStrictEqual(`${dummyDataplaneHost}/jsFileSample.js`); expect(newScriptElement.crossOrigin).toStrictEqual('anonymous'); expect(newScriptElement.getAttribute('integrity')).toStrictEqual('filehash'); done(); }; externalSrcLoaderInstance.loadJSFile({ - url: `${dummyDataplaneHost}/jsFileSample`, + url: `${dummyDataplaneHost}/jsFileSample.js`, id: 'dummyScript', callback: cb, extraAttributes: { diff --git a/packages/analytics-js-common/tsconfig.spec.json b/packages/analytics-js-common/tsconfig.spec.json index 0cf827b9d4..ea7d3314d7 100644 --- a/packages/analytics-js-common/tsconfig.spec.json +++ b/packages/analytics-js-common/tsconfig.spec.json @@ -9,7 +9,8 @@ "inlineSourceMap": true, "isolatedModules": true, "verbatimModuleSyntax": false, - "types": ["jest", "node"] + "types": ["jest", "node"], + "target": "es6" }, "include": [ "jest.config.mjs", diff --git a/packages/analytics-js-integrations/tsconfig.spec.json b/packages/analytics-js-integrations/tsconfig.spec.json index 458261bdcb..405305a80f 100644 --- a/packages/analytics-js-integrations/tsconfig.spec.json +++ b/packages/analytics-js-integrations/tsconfig.spec.json @@ -8,7 +8,8 @@ "inlineSourceMap": true, "isolatedModules": true, "verbatimModuleSyntax": false, - "types": ["jest", "node"] + "types": ["jest", "node"], + "target": "es6" }, "include": [ "jest.config.mjs", diff --git a/packages/analytics-js-plugins/__fixtures__/msw.handlers.js b/packages/analytics-js-plugins/__fixtures__/msw.handlers.js index 15a5da633d..c03d6af437 100644 --- a/packages/analytics-js-plugins/__fixtures__/msw.handlers.js +++ b/packages/analytics-js-plugins/__fixtures__/msw.handlers.js @@ -1,4 +1,4 @@ -import { rest } from 'msw'; +import { http, HttpResponse } from 'msw'; import { dummyDataplaneHost, dmtSuccessResponse, @@ -7,27 +7,38 @@ import { } from './fixtures'; const handlers = [ - rest.post(`${dummyDataplaneHost}/success/transform`, (req, res, ctx) => { - return res(ctx.status(200), ctx.json(dmtSuccessResponse)); + http.post(`${dummyDataplaneHost}/success/transform`, () => { + return new HttpResponse(JSON.stringify(dmtSuccessResponse), { + status: 200, + }); }), - rest.post(`${dummyDataplaneHost}/partialSuccess/transform`, (req, res, ctx) => { - return res(ctx.status(200), ctx.json(dmtPartialSuccessResponse)); + http.post(`${dummyDataplaneHost}/partialSuccess/transform`, () => { + return new HttpResponse(JSON.stringify(dmtPartialSuccessResponse), { + status: 200, + }); }), - rest.post(`${dummyDataplaneHost}/invalidResponse/transform`, (req, res, ctx) => { - return res( - ctx.status(200), - ctx.text(dmtSuccessResponse), - ctx.set('Content-Type', 'application/json; charset=utf-8'), - ); + http.post(`${dummyDataplaneHost}/invalidResponse/transform`, () => { + return new HttpResponse(dmtSuccessResponse, { + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + }); }), - rest.post(`${dummyDataplaneHost}/badRequest/transform`, (req, res, ctx) => { - return res(ctx.status(400), ctx.text(errorMessage)); + http.post(`${dummyDataplaneHost}/badRequest/transform`, () => { + return new HttpResponse(errorMessage, { + status: 400, + }); }), - rest.post(`${dummyDataplaneHost}/accessDenied/transform`, (req, res, ctx) => { - return res(ctx.status(404)); + http.post(`${dummyDataplaneHost}/accessDenied/transform`, () => { + return new HttpResponse(errorMessage, { + status: 404, + }); }), - rest.post(`${dummyDataplaneHost}/serverDown/transform`, (req, res, ctx) => { - return res(ctx.status(500)); + http.post(`${dummyDataplaneHost}/serverDown/transform`, () => { + return new HttpResponse(errorMessage, { + status: 500, + }); }), ]; diff --git a/packages/analytics-js-plugins/tsconfig.spec.json b/packages/analytics-js-plugins/tsconfig.spec.json index 6b998df229..9cadca43f6 100644 --- a/packages/analytics-js-plugins/tsconfig.spec.json +++ b/packages/analytics-js-plugins/tsconfig.spec.json @@ -8,7 +8,8 @@ "inlineSourceMap": true, "isolatedModules": true, "verbatimModuleSyntax": false, - "types": ["jest", "node"] + "types": ["jest", "node"], + "target": "es6" }, "include": [ "jest.config.mjs", diff --git a/packages/analytics-js-service-worker/__fixtures__/.gitkeep b/packages/analytics-js-service-worker/__fixtures__/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/analytics-js-service-worker/__tests__/__fixtures__/fixtures.ts b/packages/analytics-js-service-worker/__fixtures__/fixtures.ts similarity index 100% rename from packages/analytics-js-service-worker/__tests__/__fixtures__/fixtures.ts rename to packages/analytics-js-service-worker/__fixtures__/fixtures.ts diff --git a/packages/analytics-js-service-worker/__fixtures__/msw.server.ts b/packages/analytics-js-service-worker/__fixtures__/msw.server.ts new file mode 100644 index 0000000000..99aeb5bd29 --- /dev/null +++ b/packages/analytics-js-service-worker/__fixtures__/msw.server.ts @@ -0,0 +1,13 @@ +import { setupServer } from 'msw/node'; +import { http, HttpResponse } from 'msw'; +import { dummyDataplaneHost } from './fixtures'; + +const server = setupServer( + http.post(`${dummyDataplaneHost}/v1/batch`, () => { + return new HttpResponse(null, { + status: 200, + }); + }), +); + +export { server }; diff --git a/packages/analytics-js-service-worker/__tests__/Analytics.test.ts b/packages/analytics-js-service-worker/__tests__/Analytics.test.ts index 9e6f6fd62a..58f8616d26 100644 --- a/packages/analytics-js-service-worker/__tests__/Analytics.test.ts +++ b/packages/analytics-js-service-worker/__tests__/Analytics.test.ts @@ -1,6 +1,6 @@ import { advanceTo } from 'jest-date-mock'; import { Analytics } from '../src/Analytics'; -import { server } from './__fixtures__/msw.server'; +import { server } from '../__fixtures__/msw.server'; import { aliasRequestPayload, dummyDataplaneHost, @@ -11,7 +11,7 @@ import { pageRequestPayload, screenRequestPayload, trackRequestPayload, -} from './__fixtures__/fixtures'; +} from '../__fixtures__/fixtures'; jest.mock('uuid', () => ({ v4: () => '123456789' })); @@ -30,8 +30,11 @@ describe('JS SDK Service Worker', () => { dummyDataplaneHost, dummyInitOptions as any, ); - server.events.on('request:start', req => { - requestBody = req.body; + server.events.on('request:start', async ({ request }) => { + const requestState = Object.getOwnPropertySymbols(request).find( + s => s.description === 'state', + ); + requestBody = JSON.parse(request[requestState]?.body?.source); }); }); diff --git a/packages/analytics-js-service-worker/__tests__/__fixtures__/msw.server.ts b/packages/analytics-js-service-worker/__tests__/__fixtures__/msw.server.ts deleted file mode 100644 index 6565ffe765..0000000000 --- a/packages/analytics-js-service-worker/__tests__/__fixtures__/msw.server.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { setupServer } from 'msw/node'; -import { dummyDataplaneHost } from './fixtures'; -import { rest } from 'msw'; - -const server = setupServer( - rest.post(`${dummyDataplaneHost}/v1/batch`, (req, res, ctx) => { - return res(ctx.status(200)); - }), -); - -// { -// url: `${dummyDataplaneHost}/v1/batch`, -// response: () => null, -// status: 200, -// method: 'post', -// responseHeaders: { Environment: 'local' }, -// } - -export { server }; diff --git a/packages/analytics-js-service-worker/package.json b/packages/analytics-js-service-worker/package.json index d29d106ca9..38f3e78605 100644 --- a/packages/analytics-js-service-worker/package.json +++ b/packages/analytics-js-service-worker/package.json @@ -67,13 +67,14 @@ "assert": "2.1.0", "axios": "1.6.7", "axios-retry": "3.9.1", - "component-type": "1.2.1", + "component-type": "2.0.0", "join-component": "1.1.0", "lodash.clonedeep": "4.5.0", "lodash.isstring": "4.0.1", "ms": "2.1.3" }, "devDependencies": { + "@types/ms": "0.7.34", "@types/node": "20.11.20", "jest-date-mock": "1.0.8", "msw": "2.2.1" diff --git a/packages/analytics-js-service-worker/tsconfig.spec.json b/packages/analytics-js-service-worker/tsconfig.spec.json index 097cad77d5..a691a65119 100644 --- a/packages/analytics-js-service-worker/tsconfig.spec.json +++ b/packages/analytics-js-service-worker/tsconfig.spec.json @@ -8,7 +8,8 @@ "inlineSourceMap": true, "isolatedModules": true, "verbatimModuleSyntax": false, - "types": ["jest", "node"] + "types": ["jest", "node"], + "target": "es6" }, "include": [ "jest.config.mjs", diff --git a/packages/analytics-js/__fixtures__/msw.handlers.ts b/packages/analytics-js/__fixtures__/msw.handlers.ts index 7e0bac58ce..88dce1fba2 100644 --- a/packages/analytics-js/__fixtures__/msw.handlers.ts +++ b/packages/analytics-js/__fixtures__/msw.handlers.ts @@ -1,60 +1,81 @@ -import { rest } from 'msw'; +import { http, HttpResponse } from 'msw'; import { dummyDataplaneHost, dummySourceConfigResponse } from './fixtures'; -// TODO: Why on data plane we allow-origin the domain but in sourceConfig is wildcard? const handlers = [ - rest.get(`${dummyDataplaneHost}/rawSample`, (req, res, ctx) => { - return res(ctx.status(200), ctx.text('{"raw": "sample"}')); + http.get(`${dummyDataplaneHost}/rawSample`, () => { + return new HttpResponse('{"raw": "sample"}', { + status: 200, + }); }), - rest.get(`${dummyDataplaneHost}/brokenJsonSample`, (req, res, ctx) => { - return res( - ctx.status(200), - ctx.text('{raw: sample}'), - ctx.set('Content-Type', 'application/json; charset=utf-8'), - ); + http.get(`${dummyDataplaneHost}/brokenJsonSample`, () => { + return new HttpResponse('{raw: sample}', { + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + }); }), - rest.get(`${dummyDataplaneHost}/emptyJsonSample`, (req, res, ctx) => { - return res( - ctx.status(200), - ctx.text(''), - ctx.set('Content-Type', 'application/json; charset=utf-8'), - ); + http.get(`${dummyDataplaneHost}/emptyJsonSample`, () => { + return new HttpResponse('', { + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + }); }), - rest.get(`${dummyDataplaneHost}/jsonSample`, (req, res, ctx) => { - return res(ctx.status(200), ctx.json({ json: 'sample' })); + http.get(`${dummyDataplaneHost}/jsonSample`, () => { + return new HttpResponse(JSON.stringify({ json: 'sample' }), { + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + }); }), - rest.get(`${dummyDataplaneHost}/404ErrorSample`, (req, res, ctx) => { - return res(ctx.status(404)); + http.get(`${dummyDataplaneHost}/404ErrorSample`, () => { + return new HttpResponse(null, { + status: 404, + }); }), - rest.get(`${dummyDataplaneHost}/429ErrorSample`, (req, res, ctx) => { - return res(ctx.status(429)); + http.get(`${dummyDataplaneHost}/429ErrorSample`, () => { + return new HttpResponse(null, { + status: 429, + }); }), - rest.get(`${dummyDataplaneHost}/500ErrorSample`, (req, res, ctx) => { - return res(ctx.status(500)); + http.get(`${dummyDataplaneHost}/500ErrorSample`, () => { + return new HttpResponse(null, { + status: 500, + }); }), - rest.get(`${dummyDataplaneHost}/noConnectionSample`, (req, res, ctx) => { - return res.networkError('Failed to connect'); + http.get(`${dummyDataplaneHost}/noConnectionSample`, () => { + return HttpResponse.error(); }), - rest.get(`${dummyDataplaneHost}/jsFileSample`, (req, res, ctx) => { + http.get(`${dummyDataplaneHost}/jsFileSample`, () => { const fileContents = 'console.log("jsFileSample script executed")'; - return res( - ctx.status(200), - ctx.set('Content-Length', fileContents.length.toString()), - ctx.set('Content-Type', 'text/javascript'), - ctx.body(fileContents), - ); - }), - rest.get(`${dummyDataplaneHost}/jsFileEmpty`, (req, res, ctx) => { + return new HttpResponse(fileContents, { + status: 200, + headers: { + 'Content-Type': 'text/javascript', + 'Content-Length': fileContents.length.toString(), + }, + }); + }), + http.get(`${dummyDataplaneHost}/jsFileEmpty`, () => { const fileContents = ''; - return res( - ctx.status(200), - ctx.set('Content-Length', fileContents.length.toString()), - ctx.set('Content-Type', 'text/javascript'), - ctx.body(fileContents), - ); - }), - rest.get(`${dummyDataplaneHost}/sourceConfig`, (req, res, ctx) => { - return res(ctx.status(200), ctx.json(dummySourceConfigResponse)); + return new HttpResponse(fileContents, { + status: 200, + headers: { + 'Content-Type': 'text/javascript', + 'Content-Length': fileContents.length.toString(), + }, + }); + }), + http.get(`${dummyDataplaneHost}/sourceConfig`, () => { + return new HttpResponse(JSON.stringify(dummySourceConfigResponse), { + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + }); }), ]; diff --git a/packages/analytics-js/__tests__/components/configManager/ConfigManager.test.ts b/packages/analytics-js/__tests__/components/configManager/ConfigManager.test.ts index 93ea995d71..194c5104ef 100644 --- a/packages/analytics-js/__tests__/components/configManager/ConfigManager.test.ts +++ b/packages/analytics-js/__tests__/components/configManager/ConfigManager.test.ts @@ -1,5 +1,5 @@ import { batch, effect, signal } from '@preact/signals-core'; -import { rest } from 'msw'; +import { http, HttpResponse } from 'msw'; import { defaultHttpClient } from '../../../src/services/HttpClient'; import { defaultErrorHandler } from '../../../src/services/ErrorHandler'; import { defaultLogger } from '../../../src/services/Logger'; @@ -136,9 +136,14 @@ describe('ConfigManager', () => { const counter = signal(0); server.use( - rest.get(`${sampleConfigUrl}/sourceConfigClone`, (req, res, ctx) => { + http.get(`${sampleConfigUrl}/sourceConfigClone`, () => { counter.value = 1; - return res(ctx.status(200), ctx.json(dummySourceConfigResponse)); + return new HttpResponse(JSON.stringify(dummySourceConfigResponse), { + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + }); }), ); diff --git a/packages/analytics-js/package.json b/packages/analytics-js/package.json index 69396f139e..5ba0bf9ab2 100644 --- a/packages/analytics-js/package.json +++ b/packages/analytics-js/package.json @@ -76,6 +76,7 @@ "check:support:modern": "NODE_ENV=modern npx browserslist --mobile-to-desktop", "check:duplicates": "jscpd src", "check:security": "npm audit --recursive --audit-level=high", + "check:pub": "npx publint", "build:modern": "npm run build:browser:modern && npm run build:npm:modern", "package": "npm pack", "release": "npm publish", diff --git a/packages/analytics-js/tsconfig.spec.json b/packages/analytics-js/tsconfig.spec.json index 346350f898..6907e37033 100644 --- a/packages/analytics-js/tsconfig.spec.json +++ b/packages/analytics-js/tsconfig.spec.json @@ -8,7 +8,8 @@ "inlineSourceMap": true, "isolatedModules": true, "verbatimModuleSyntax": false, - "types": ["jest", "node"] + "types": ["jest", "node"], + "target": "es6" }, "include": [ "jest.config.mjs", diff --git a/packages/analytics-v1.1/__fixtures__/msw.handlers.js b/packages/analytics-v1.1/__fixtures__/msw.handlers.js index 3132d332ca..074865a783 100644 --- a/packages/analytics-v1.1/__fixtures__/msw.handlers.js +++ b/packages/analytics-v1.1/__fixtures__/msw.handlers.js @@ -1,4 +1,4 @@ -import { rest } from 'msw'; +import { http, HttpResponse } from 'msw'; import { dummyDataplaneHost, samplePayloadSuccess, @@ -7,27 +7,44 @@ import { } from './fixtures'; const handlers = [ - rest.post(`${dummyDataplaneHost}/success/transform`, (req, res, ctx) => { - return res(ctx.status(200), ctx.json(samplePayloadSuccess)); + http.post(`${dummyDataplaneHost}/success/transform`, () => { + return new HttpResponse(JSON.stringify(samplePayloadSuccess), { + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + }); }), - rest.post(`${dummyDataplaneHost}/partialSuccess/transform`, (req, res, ctx) => { - return res(ctx.status(200), ctx.json(samplePayloadPartialSuccess)); + http.post(`${dummyDataplaneHost}/partialSuccess/transform`, () => { + return new HttpResponse(JSON.stringify(samplePayloadPartialSuccess), { + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + }); }), - rest.post(`${dummyDataplaneHost}/invalidResponse/transform`, (req, res, ctx) => { - return res( - ctx.status(200), - ctx.text(samplePayloadSuccess), - ctx.set('Content-Type', 'application/json; charset=utf-8'), - ); + http.post(`${dummyDataplaneHost}/invalidResponse/transform`, () => { + return new HttpResponse(samplePayloadSuccess, { + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + }); }), - rest.post(`${dummyDataplaneHost}/badRequest/transform`, (req, res, ctx) => { - return res(ctx.status(400), ctx.text(errorMessage)); + http.post(`${dummyDataplaneHost}/badRequest/transform`, () => { + return new HttpResponse(errorMessage, { + status: 400, + }); }), - rest.post(`${dummyDataplaneHost}/accessDenied/transform`, (req, res, ctx) => { - return res(ctx.status(404)); + http.post(`${dummyDataplaneHost}/accessDenied/transform`, () => { + return new HttpResponse(errorMessage, { + status: 404, + }); }), - rest.post(`${dummyDataplaneHost}/serverDown/transform`, (req, res, ctx) => { - return res(ctx.status(500)); + http.post(`${dummyDataplaneHost}/serverDown/transform`, () => { + return new HttpResponse(errorMessage, { + status: 500, + }); }), ]; diff --git a/packages/analytics-v1.1/__tests__/transformationHandler.test.js b/packages/analytics-v1.1/__tests__/transformationHandler.test.js index 3c23c3f709..20a6584247 100644 --- a/packages/analytics-v1.1/__tests__/transformationHandler.test.js +++ b/packages/analytics-v1.1/__tests__/transformationHandler.test.js @@ -1,5 +1,5 @@ /* eslint-disable no-plusplus */ -import { rest } from 'msw'; +import { http, HttpResponse } from 'msw'; import { DeviceModeTransformations } from '../src/features/core/deviceModeTransformation/transformationHandler'; import { createPayload } from '../src/features/core/deviceModeTransformation/util'; import { server } from '../__fixtures__/msw.server'; @@ -18,6 +18,10 @@ describe('Test suite for device mode transformation feature', () => { server.listen(); }); + afterEach(() => { + server.resetHandlers(); + }); + afterAll(() => { server.close(); }); @@ -62,7 +66,7 @@ describe('Test suite for device mode transformation feature', () => { }); }); - it('Validate whether the SDK is sending the orginal event in case server returns 404', async () => { + it('Validate whether the SDK is sending the original event in case server returns 404', async () => { DeviceModeTransformations.init(dummyWriteKey, `${dummyDataplaneHost}/accessDenied`); await DeviceModeTransformations.sendEventForTransformation(payload, retryCount) @@ -78,9 +82,11 @@ describe('Test suite for device mode transformation feature', () => { it('Validate whether the SDK is retrying the request in case failures', async () => { let counter = 0; server.use( - rest.post(`${dummyDataplaneHost}/serverDown/transform`, (req, res, ctx) => { + http.post(`${dummyDataplaneHost}/serverDown/transform`, () => { counter += 1; - return res(ctx.status(500)); + return new HttpResponse(null, { + status: 500, + }); }), ); @@ -138,13 +144,17 @@ describe('Test suite for device mode transformation feature', () => { it('Transformation server returns success after intermediate retry', async () => { let counter = 0; server.use( - rest.post(`${dummyDataplaneHost}/success/transform`, (req, res, ctx) => { + http.post(`${dummyDataplaneHost}/success/transform`, () => { if (counter === 0) { counter += 1; - return res(ctx.status(500)); + return new HttpResponse(null, { + status: 500, + }); } counter += 1; - return res(ctx.status(200), ctx.json(samplePayloadSuccess)); + return new HttpResponse(JSON.stringify(samplePayloadSuccess), { + status: 200, + }); }), ); diff --git a/packages/analytics-v1.1/package.json b/packages/analytics-v1.1/package.json index d7e371f1fd..0383f60ba5 100644 --- a/packages/analytics-v1.1/package.json +++ b/packages/analytics-v1.1/package.json @@ -78,7 +78,7 @@ }, "dependencies": { "msw": "2.2.1", - "component-emitter": "1.3.0", + "component-emitter": "2.0.0", "ramda": "0.29.1", "get-value": "3.0.1", "@segment/localstorage-retry": "1.3.0", @@ -88,7 +88,6 @@ "@lukeed/uuid": "2.0.1", "@rudderstack/analytics-js-common": "*", "@segment/localstorage-retry": "1.3.0", - "component-emitter": "1.3.0", "get-value": "3.0.1", "ramda": "0.29.1" }, diff --git a/packages/analytics-v1.1/tsconfig.spec.json b/packages/analytics-v1.1/tsconfig.spec.json index 458261bdcb..405305a80f 100644 --- a/packages/analytics-v1.1/tsconfig.spec.json +++ b/packages/analytics-v1.1/tsconfig.spec.json @@ -8,7 +8,8 @@ "inlineSourceMap": true, "isolatedModules": true, "verbatimModuleSyntax": false, - "types": ["jest", "node"] + "types": ["jest", "node"], + "target": "es6" }, "include": [ "jest.config.mjs", diff --git a/packages/loading-scripts/tsconfig.spec.json b/packages/loading-scripts/tsconfig.spec.json index 097cad77d5..a691a65119 100644 --- a/packages/loading-scripts/tsconfig.spec.json +++ b/packages/loading-scripts/tsconfig.spec.json @@ -8,7 +8,8 @@ "inlineSourceMap": true, "isolatedModules": true, "verbatimModuleSyntax": false, - "types": ["jest", "node"] + "types": ["jest", "node"], + "target": "es6" }, "include": [ "jest.config.mjs", diff --git a/packages/sanity-suite/__fixtures__/sourceConfig1.json b/packages/sanity-suite/__fixtures__/sourceConfig1.json index f3da52584a..8c169162e0 100644 --- a/packages/sanity-suite/__fixtures__/sourceConfig1.json +++ b/packages/sanity-suite/__fixtures__/sourceConfig1.json @@ -36,17 +36,18 @@ "name": "GTM", "displayName": "Google Tag Manager", "createdAt": "2020-01-30T08:46:11.787Z", - "updatedAt": "2024-01-10T11:15:19.159Z", + "updatedAt": "2024-02-22T03:31:39.813Z", "config": { "destConfig": { - "web": ["useNativeSDK"], + "web": ["useNativeSDK", "consentManagement"], "defaultConfig": [ "containerID", "serverUrl", "blacklistedEvents", "whitelistedEvents", "eventFilteringOption", - "oneTrustCookieCategories" + "oneTrustCookieCategories", + "ketchConsentPurposes" ] }, "secretKeys": [], @@ -57,6 +58,8 @@ "blacklistedEvents", "whitelistedEvents", "oneTrustCookieCategories", + "ketchConsentPurposes", + "consentManagement", "eventFilteringOption" ], "transformAtV1": "processor", @@ -216,10 +219,10 @@ "name": "HOTJAR", "displayName": "Hotjar", "createdAt": "2019-10-31T07:49:37.450Z", - "updatedAt": "2024-01-10T11:15:50.746Z", + "updatedAt": "2024-02-22T03:31:36.973Z", "config": { "destConfig": { - "web": ["useNativeSDK"], + "web": ["useNativeSDK", "connectionMode"], "defaultConfig": [ "siteID", "blacklistedEvents", @@ -1361,149 +1364,163 @@ "connections": [ { "id": "2M2I7zu5UDw16zeFGgjxrkOIPMd", + "createdAt": "2023-02-21T05:58:06.202Z", + "updatedAt": "2023-11-02T10:36:49.239Z", "sourceId": "2L8FlAECp1sEUP7NVilWLTeA2wp", "destinationId": "2M2I7gZ9L474wHE0mzMdIo84gIK", + "workspaceId": "2L8FgwnU8Q4I4nQbdqmin8uP5n8", "enabled": true, "config": null, - "deleted": false, - "createdAt": "2023-02-21T05:58:06.202Z", - "updatedAt": "2023-11-02T10:36:49.239Z" + "deleted": false }, { "id": "2M5amTXpCHhxORC175ZTkzb1JML", + "createdAt": "2023-02-22T10:00:55.733Z", + "updatedAt": "2023-11-02T11:20:30.335Z", "sourceId": "2L8FlAECp1sEUP7NVilWLTeA2wp", "destinationId": "2M5amK3AVQ31yy9uxD8Usk0y34Q", + "workspaceId": "2L8FgwnU8Q4I4nQbdqmin8uP5n8", "enabled": true, "config": null, - "deleted": false, - "createdAt": "2023-02-22T10:00:55.733Z", - "updatedAt": "2023-11-02T11:20:30.335Z" + "deleted": false }, { "id": "2MBKP4UdjetHMRrToJFCmKHpGOg", + "createdAt": "2023-02-24T10:45:07.442Z", + "updatedAt": "2023-11-02T11:39:41.151Z", "sourceId": "2L8FlAECp1sEUP7NVilWLTeA2wp", "destinationId": "2MBKOwDUcq0pKzHDNWL4NZH1nvW", + "workspaceId": "2L8FgwnU8Q4I4nQbdqmin8uP5n8", "enabled": true, "config": null, - "deleted": false, - "createdAt": "2023-02-24T10:45:07.442Z", - "updatedAt": "2023-11-02T11:39:41.151Z" + "deleted": false }, { "id": "2YIcXH98w4tz8aX89rq4fFldl3c", + "createdAt": "2023-11-17T10:22:51.758Z", + "updatedAt": "2023-11-17T10:46:38.826Z", "sourceId": "2L8FlAECp1sEUP7NVilWLTeA2wp", "destinationId": "2PujzZ64sYMuhdBFgO3E4kFtjoK", + "workspaceId": "2L8FgwnU8Q4I4nQbdqmin8uP5n8", "enabled": true, "config": null, - "deleted": true, - "createdAt": "2023-11-17T10:22:51.758Z", - "updatedAt": "2023-11-17T10:46:38.826Z" + "deleted": true }, { "id": "2L8KCfcreKPAOBJzkCBRNvNOqwG", + "createdAt": "2023-02-01T10:25:43.975Z", + "updatedAt": "2023-02-01T10:25:43.975Z", "sourceId": "2L8FlAECp1sEUP7NVilWLTeA2wp", "destinationId": "2L8KCafGlZAVf1LChEGfeyrELbK", + "workspaceId": "2L8FgwnU8Q4I4nQbdqmin8uP5n8", "enabled": true, "config": null, - "deleted": false, - "createdAt": "2023-02-01T10:25:43.975Z", - "updatedAt": "2023-02-01T10:25:43.975Z" + "deleted": false }, { "id": "2L8KyWqouw4ze0f4afsrxlC0sHw", + "createdAt": "2023-02-01T10:32:04.108Z", + "updatedAt": "2023-11-02T06:29:48.482Z", "sourceId": "2L8FlAECp1sEUP7NVilWLTeA2wp", "destinationId": "2L8KyN0Fo6CmtL1jZ7Rccas42ry", + "workspaceId": "2L8FgwnU8Q4I4nQbdqmin8uP5n8", "enabled": true, "config": null, - "deleted": false, - "createdAt": "2023-02-01T10:32:04.108Z", - "updatedAt": "2023-11-02T06:29:48.482Z" + "deleted": false }, { "id": "2LUHxiGlQWQOJP8DiKidSKdyosg", + "createdAt": "2023-02-09T05:03:09.751Z", + "updatedAt": "2023-02-20T11:37:45.939Z", "sourceId": "2L8FlAECp1sEUP7NVilWLTeA2wp", "destinationId": "2LUHxbh8aM2B1ODT2RGBetg6tDW", + "workspaceId": "2L8FgwnU8Q4I4nQbdqmin8uP5n8", "enabled": true, "config": null, - "deleted": true, - "createdAt": "2023-02-09T05:03:09.751Z", - "updatedAt": "2023-02-20T11:37:45.939Z" + "deleted": true }, { "id": "2LoXyxr2J8DgOyLT4bwi1Rtikx1", + "createdAt": "2023-02-16T09:11:06.721Z", + "updatedAt": "2023-11-02T06:56:37.482Z", "sourceId": "2L8FlAECp1sEUP7NVilWLTeA2wp", "destinationId": "2LoXypOO5xdh7R5xJynzIyWeYJf", + "workspaceId": "2L8FgwnU8Q4I4nQbdqmin8uP5n8", "enabled": true, "config": null, - "deleted": false, - "createdAt": "2023-02-16T09:11:06.721Z", - "updatedAt": "2023-11-02T06:56:37.482Z" + "deleted": false }, { "id": "2LoUx4n5pGXTZOLnAugGaX6gmcG", + "createdAt": "2023-02-16T08:46:11.263Z", + "updatedAt": "2023-11-02T06:36:14.245Z", "sourceId": "2L8FlAECp1sEUP7NVilWLTeA2wp", "destinationId": "2LoUwsaZMiRBsdhwc3zXcNk4oOw", + "workspaceId": "2L8FgwnU8Q4I4nQbdqmin8uP5n8", "enabled": true, "config": null, - "deleted": false, - "createdAt": "2023-02-16T08:46:11.263Z", - "updatedAt": "2023-11-02T06:36:14.245Z" + "deleted": false }, { "id": "2LoR1iFP1UnEedz0A4druIjrKdv", + "createdAt": "2023-02-16T08:13:55.534Z", + "updatedAt": "2023-11-02T06:39:33.645Z", "sourceId": "2L8FlAECp1sEUP7NVilWLTeA2wp", "destinationId": "2LoR1TbVG2bcISXvy7DamldfkgO", + "workspaceId": "2L8FgwnU8Q4I4nQbdqmin8uP5n8", "enabled": true, "config": null, - "deleted": false, - "createdAt": "2023-02-16T08:13:55.534Z", - "updatedAt": "2023-11-02T06:39:33.645Z" + "deleted": false }, { "id": "2M5dOoljKQXLKg0z7L1qFpAGAvp", + "createdAt": "2023-02-22T10:22:27.310Z", + "updatedAt": "2023-11-02T09:44:10.245Z", "sourceId": "2L8FlAECp1sEUP7NVilWLTeA2wp", "destinationId": "2M5dOW6kipDywRHHLJy8blGeaIM", + "workspaceId": "2L8FgwnU8Q4I4nQbdqmin8uP5n8", "enabled": true, "config": null, - "deleted": false, - "createdAt": "2023-02-22T10:22:27.310Z", - "updatedAt": "2023-11-02T09:44:10.245Z" + "deleted": false }, { "id": "2M5beUNhGIEQrnTyRBqYcTG53Vd", + "createdAt": "2023-02-22T10:08:05.044Z", + "updatedAt": "2023-11-02T11:30:43.933Z", "sourceId": "2L8FlAECp1sEUP7NVilWLTeA2wp", "destinationId": "2M5beBXLTjTto62OdCBwFNejrkY", + "workspaceId": "2L8FgwnU8Q4I4nQbdqmin8uP5n8", "enabled": true, "config": null, - "deleted": false, - "createdAt": "2023-02-22T10:08:05.044Z", - "updatedAt": "2023-11-02T11:30:43.933Z" + "deleted": false }, { "id": "2MB1bO3hTkzCoEdc7NVEC1rhGGd", + "createdAt": "2023-02-24T08:10:31.541Z", + "updatedAt": "2023-11-02T06:57:01.248Z", "sourceId": "2L8FlAECp1sEUP7NVilWLTeA2wp", "destinationId": "2MB1bEpAABLRC9oI5G3IXrrBTos", + "workspaceId": "2L8FgwnU8Q4I4nQbdqmin8uP5n8", "enabled": true, "config": null, - "deleted": false, - "createdAt": "2023-02-24T08:10:31.541Z", - "updatedAt": "2023-11-02T06:57:01.248Z" + "deleted": false }, { "id": "2R9DmCRrtLFY88YGXdhz2wr5GPf", + "createdAt": "2023-06-13T10:52:39.735Z", + "updatedAt": "2023-06-13T10:52:55.872Z", "sourceId": "2L8FlAECp1sEUP7NVilWLTeA2wp", "destinationId": "2R9Dm3WHB6dkXuRnA0j3Amjo5Xw", + "workspaceId": "2L8FgwnU8Q4I4nQbdqmin8uP5n8", "enabled": true, "config": null, - "deleted": true, - "createdAt": "2023-06-13T10:52:39.735Z", - "updatedAt": "2023-06-13T10:52:55.872Z" + "deleted": true } ], "deleted": false, "transient": false }, - "updatedAt": "2024-02-19T10:26:47.526Z", + "updatedAt": "2024-02-26T21:10:27.357Z", "consentManagementMetadata": { "providers": [ {