diff --git a/package-lock.json b/package-lock.json
index e20a47365..2cfb15c5e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5957,67 +5957,15 @@
}
},
"@jest/types": {
- "version": "25.1.0",
- "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.1.0.tgz",
- "integrity": "sha512-VpOtt7tCrgvamWZh1reVsGADujKigBUFTi19mlRjqEGsE8qH4r3s+skY33dNdXOwyZIvuftZ5tqdF1IgsMejMA==",
+ "version": "25.5.0",
+ "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.5.0.tgz",
+ "integrity": "sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw==",
"dev": true,
"requires": {
"@types/istanbul-lib-coverage": "^2.0.0",
"@types/istanbul-reports": "^1.1.1",
"@types/yargs": "^15.0.0",
"chalk": "^3.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
- "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
- "dev": true,
- "requires": {
- "@types/color-name": "^1.1.1",
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
- "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "supports-color": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
- "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
}
},
"@loadable/component": {
@@ -6882,6 +6830,29 @@
"integrity": "sha512-INJYZQJP7g+IoDUh/475NlGiTeMfwTXUEr3tmRneckHIxNolGOW9CTq83S8cxq0CgJwwcMzMJFchxvlwe7Rk8Q==",
"dev": true
},
+ "@rudderstack/rudder-sdk-node": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/@rudderstack/rudder-sdk-node/-/rudder-sdk-node-0.0.2.tgz",
+ "integrity": "sha512-KkqQwV8+/YH5AL6vKCuUvUv7o2+c6tYJ6G7b7iJ+bojTL62Hyi1XAe2rCSrKjNgTFSeXkRaHLeCKSGYuJCPy8w==",
+ "requires": {
+ "@segment/loosely-validate-event": "^2.0.0",
+ "auto-changelog": "^1.16.2",
+ "axios": "^0.19.0",
+ "axios-retry": "^3.0.2",
+ "lodash.isstring": "^4.0.1",
+ "md5": "^2.2.1",
+ "ms": "^2.0.0",
+ "remove-trailing-slash": "^0.1.0",
+ "uuid": "^3.2.1"
+ },
+ "dependencies": {
+ "uuid": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
+ }
+ }
+ },
"@samverschueren/stream-to-observable": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz",
@@ -6891,6 +6862,15 @@
"any-observable": "^0.3.0"
}
},
+ "@segment/loosely-validate-event": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@segment/loosely-validate-event/-/loosely-validate-event-2.0.0.tgz",
+ "integrity": "sha512-ZMCSfztDBqwotkl848ODgVcAmN4OItEWDCkshcKz0/W6gGSQayuuCtWV/MlodFivAZD793d6UgANd6wCXUfrIw==",
+ "requires": {
+ "component-type": "^1.2.1",
+ "join-component": "^1.1.0"
+ }
+ },
"@sindresorhus/is": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
@@ -10005,6 +9985,28 @@
"dev": true,
"optional": true
},
+ "auto-changelog": {
+ "version": "1.16.4",
+ "resolved": "https://registry.npmjs.org/auto-changelog/-/auto-changelog-1.16.4.tgz",
+ "integrity": "sha512-h7diyELoq692AA4oqO50ULoYKIomUdzuQ+NW+eFPwIX0xzVbXEu9cIcgzZ3TYNVbpkGtcNKh51aRfAQNef7HVA==",
+ "requires": {
+ "commander": "^5.0.0",
+ "core-js": "^3.6.4",
+ "handlebars": "^4.7.3",
+ "lodash.uniqby": "^4.7.0",
+ "node-fetch": "^2.6.0",
+ "parse-github-url": "^1.0.2",
+ "regenerator-runtime": "^0.13.5",
+ "semver": "^6.3.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+ }
+ }
+ },
"autoprefixer": {
"version": "9.7.5",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.7.5.tgz",
@@ -10168,7 +10170,6 @@
"version": "0.19.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz",
"integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==",
- "dev": true,
"requires": {
"follow-redirects": "1.5.10"
},
@@ -10177,7 +10178,6 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
- "dev": true,
"requires": {
"ms": "2.0.0"
}
@@ -10186,7 +10186,6 @@
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
"integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
- "dev": true,
"requires": {
"debug": "=3.1.0"
}
@@ -10194,11 +10193,18 @@
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
- "dev": true
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
+ "axios-retry": {
+ "version": "3.1.8",
+ "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-3.1.8.tgz",
+ "integrity": "sha512-yPw5Y4Bg6Dgmhm35KaJFtlh23s1TecW0HsUerK4/IS1UKl0gtN2aJqdEKtVomiOS/bDo5w4P3sqgki/M10eF8Q==",
+ "requires": {
+ "is-retry-allowed": "^1.1.0"
+ }
+ },
"axobject-query": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz",
@@ -12805,8 +12811,7 @@
"charenc": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
- "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=",
- "dev": true
+ "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc="
},
"check-types": {
"version": "8.0.3",
@@ -13482,8 +13487,7 @@
"commander": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-5.0.0.tgz",
- "integrity": "sha512-JrDGPAKjMGSP1G0DUoaceEJ3DZgAfr/q6X7FVk4+U5KxUSKviYGM2k6zWkfyyBHy5rAtzgYJFa1ro2O9PtoxwQ==",
- "dev": true
+ "integrity": "sha512-JrDGPAKjMGSP1G0DUoaceEJ3DZgAfr/q6X7FVk4+U5KxUSKviYGM2k6zWkfyyBHy5rAtzgYJFa1ro2O9PtoxwQ=="
},
"comment-json": {
"version": "3.0.2",
@@ -13563,6 +13567,11 @@
"integrity": "sha1-+bffm5kntubZfJvScqqGdnDzSUQ=",
"dev": true
},
+ "component-type": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/component-type/-/component-type-1.2.1.tgz",
+ "integrity": "sha1-ikeQFwAjjk/DIml3EjAibyS0Fak="
+ },
"component-xor": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/component-xor/-/component-xor-0.0.4.tgz",
@@ -13597,9 +13606,9 @@
},
"dependencies": {
"mime-db": {
- "version": "1.43.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz",
- "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==",
+ "version": "1.44.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
+ "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==",
"dev": true
}
}
@@ -14544,8 +14553,7 @@
"crypt": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
- "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=",
- "dev": true
+ "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs="
},
"crypto-browserify": {
"version": "3.12.0",
@@ -21376,28 +21384,28 @@
"dependencies": {
"abbrev": {
"version": "1.1.1",
- "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+ "resolved": false,
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"dev": true,
"optional": true
},
"ansi-regex": {
"version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "resolved": false,
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"dev": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
- "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+ "resolved": false,
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
"dev": true,
"optional": true
},
"are-we-there-yet": {
"version": "1.1.5",
- "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
+ "resolved": false,
"integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
"dev": true,
"optional": true,
@@ -21408,14 +21416,14 @@
},
"balanced-match": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "resolved": false,
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"optional": true,
@@ -21426,42 +21434,42 @@
},
"chownr": {
"version": "1.1.1",
- "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
+ "resolved": false,
"integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==",
"dev": true,
"optional": true
},
"code-point-at": {
"version": "1.1.0",
- "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+ "resolved": false,
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"dev": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "resolved": false,
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
- "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+ "resolved": false,
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
"dev": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "resolved": false,
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"dev": true,
"optional": true
},
"debug": {
"version": "4.1.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "resolved": false,
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"dev": true,
"optional": true,
@@ -21471,28 +21479,28 @@
},
"deep-extend": {
"version": "0.6.0",
- "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+ "resolved": false,
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
"dev": true,
"optional": true
},
"delegates": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
"dev": true,
"optional": true
},
"detect-libc": {
"version": "1.0.3",
- "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+ "resolved": false,
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
"dev": true,
"optional": true
},
"fs-minipass": {
"version": "1.2.5",
- "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz",
+ "resolved": false,
"integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
"dev": true,
"optional": true,
@@ -21502,14 +21510,14 @@
},
"fs.realpath": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true,
"optional": true
},
"gauge": {
"version": "2.7.4",
- "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
+ "resolved": false,
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
"dev": true,
"optional": true,
@@ -21526,7 +21534,7 @@
},
"glob": {
"version": "7.1.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+ "resolved": false,
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
"dev": true,
"optional": true,
@@ -21541,14 +21549,14 @@
},
"has-unicode": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+ "resolved": false,
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
"dev": true,
"optional": true
},
"iconv-lite": {
"version": "0.4.24",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "resolved": false,
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"dev": true,
"optional": true,
@@ -21558,7 +21566,7 @@
},
"ignore-walk": {
"version": "3.0.1",
- "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz",
+ "resolved": false,
"integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
"dev": true,
"optional": true,
@@ -21568,7 +21576,7 @@
},
"inflight": {
"version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "resolved": false,
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"optional": true,
@@ -21579,21 +21587,21 @@
},
"inherits": {
"version": "2.0.3",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "resolved": false,
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
"dev": true,
"optional": true
},
"ini": {
"version": "1.3.5",
- "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+ "resolved": false,
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
"dev": true,
"optional": true
},
"is-fullwidth-code-point": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"dev": true,
"optional": true,
@@ -21603,14 +21611,14 @@
},
"isarray": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"dev": true,
"optional": true
},
"minimatch": {
"version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "resolved": false,
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"optional": true,
@@ -21620,14 +21628,14 @@
},
"minimist": {
"version": "0.0.8",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "resolved": false,
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true,
"optional": true
},
"minipass": {
"version": "2.3.5",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
+ "resolved": false,
"integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
"dev": true,
"optional": true,
@@ -21638,7 +21646,7 @@
},
"minizlib": {
"version": "1.2.1",
- "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz",
+ "resolved": false,
"integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
"dev": true,
"optional": true,
@@ -21648,7 +21656,7 @@
},
"mkdirp": {
"version": "0.5.1",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "resolved": false,
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"optional": true,
@@ -21658,7 +21666,7 @@
},
"ms": {
"version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "resolved": false,
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
"dev": true,
"optional": true
@@ -21672,7 +21680,7 @@
},
"needle": {
"version": "2.3.0",
- "resolved": "https://registry.npmjs.org/needle/-/needle-2.3.0.tgz",
+ "resolved": false,
"integrity": "sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg==",
"dev": true,
"optional": true,
@@ -21684,7 +21692,7 @@
},
"node-pre-gyp": {
"version": "0.12.0",
- "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz",
+ "resolved": false,
"integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==",
"dev": true,
"optional": true,
@@ -21703,7 +21711,7 @@
},
"nopt": {
"version": "4.0.1",
- "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
+ "resolved": false,
"integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
"dev": true,
"optional": true,
@@ -21714,14 +21722,14 @@
},
"npm-bundled": {
"version": "1.0.6",
- "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz",
+ "resolved": false,
"integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==",
"dev": true,
"optional": true
},
"npm-packlist": {
"version": "1.4.1",
- "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.1.tgz",
+ "resolved": false,
"integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==",
"dev": true,
"optional": true,
@@ -21732,7 +21740,7 @@
},
"npmlog": {
"version": "4.1.2",
- "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
+ "resolved": false,
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
"dev": true,
"optional": true,
@@ -21745,21 +21753,21 @@
},
"number-is-nan": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+ "resolved": false,
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
"dev": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "resolved": false,
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
"dev": true,
"optional": true
},
"once": {
"version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "resolved": false,
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"optional": true,
@@ -21769,21 +21777,21 @@
},
"os-homedir": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+ "resolved": false,
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
"dev": true,
"optional": true
},
"os-tmpdir": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+ "resolved": false,
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"dev": true,
"optional": true
},
"osenv": {
"version": "0.1.5",
- "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
+ "resolved": false,
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
"dev": true,
"optional": true,
@@ -21794,21 +21802,21 @@
},
"path-is-absolute": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "resolved": false,
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true,
"optional": true
},
"process-nextick-args": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+ "resolved": false,
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
"dev": true,
"optional": true
},
"rc": {
"version": "1.2.8",
- "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+ "resolved": false,
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
"dev": true,
"optional": true,
@@ -21821,7 +21829,7 @@
"dependencies": {
"minimist": {
"version": "1.2.0",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "resolved": false,
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true,
"optional": true
@@ -21830,7 +21838,7 @@
},
"readable-stream": {
"version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+ "resolved": false,
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"optional": true,
@@ -21846,7 +21854,7 @@
},
"rimraf": {
"version": "2.6.3",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+ "resolved": false,
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
"dev": true,
"optional": true,
@@ -21856,49 +21864,49 @@
},
"safe-buffer": {
"version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "resolved": false,
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
- "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "resolved": false,
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true,
"optional": true
},
"sax": {
"version": "1.2.4",
- "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+ "resolved": false,
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
"dev": true,
"optional": true
},
"semver": {
"version": "5.7.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
+ "resolved": false,
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
"dev": true,
"optional": true
},
"set-blocking": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
"dev": true,
"optional": true
},
"signal-exit": {
"version": "3.0.2",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+ "resolved": false,
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
"dev": true,
"optional": true
},
"string-width": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "resolved": false,
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"dev": true,
"optional": true,
@@ -21910,7 +21918,7 @@
},
"string_decoder": {
"version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "resolved": false,
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"optional": true,
@@ -21920,7 +21928,7 @@
},
"strip-ansi": {
"version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "resolved": false,
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"optional": true,
@@ -21930,14 +21938,14 @@
},
"strip-json-comments": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "resolved": false,
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
"dev": true,
"optional": true
},
"tar": {
"version": "4.4.8",
- "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz",
+ "resolved": false,
"integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==",
"dev": true,
"optional": true,
@@ -21953,14 +21961,14 @@
},
"util-deprecate": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "resolved": false,
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"dev": true,
"optional": true
},
"wide-align": {
"version": "1.1.3",
- "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
+ "resolved": false,
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
"dev": true,
"optional": true,
@@ -21970,14 +21978,14 @@
},
"wrappy": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "resolved": false,
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true,
"optional": true
},
"yallist": {
"version": "3.0.3",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
+ "resolved": false,
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
"dev": true,
"optional": true
@@ -26347,6 +26355,35 @@
"integrity": "sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==",
"dev": true
},
+ "handlebars": {
+ "version": "4.7.6",
+ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz",
+ "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==",
+ "requires": {
+ "minimist": "^1.2.5",
+ "neo-async": "^2.6.0",
+ "source-map": "^0.6.1",
+ "uglify-js": "^3.1.4",
+ "wordwrap": "^1.0.0"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
+ },
+ "neo-async": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz",
+ "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw=="
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ }
+ }
+ },
"har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
@@ -28763,8 +28800,7 @@
"is-retry-allowed": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz",
- "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==",
- "dev": true
+ "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg=="
},
"is-root": {
"version": "2.1.0",
@@ -33044,6 +33080,11 @@
}
}
},
+ "join-component": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/join-component/-/join-component-1.1.0.tgz",
+ "integrity": "sha1-uEF7dQZho5K+4sJTfGiyqdSXfNU="
+ },
"js-base64": {
"version": "2.4.5",
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.5.tgz",
@@ -33969,7 +34010,7 @@
},
"chalk": {
"version": "1.1.3",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"requires": {
@@ -34471,6 +34512,11 @@
"integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=",
"dev": true
},
+ "lodash.uniqby": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz",
+ "integrity": "sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI="
+ },
"log-symbols": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
@@ -34855,7 +34901,6 @@
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz",
"integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=",
- "dev": true,
"requires": {
"charenc": "~0.0.1",
"crypt": "~0.0.1",
@@ -37175,6 +37220,11 @@
"path-root": "^0.1.1"
}
},
+ "parse-github-url": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/parse-github-url/-/parse-github-url-1.0.2.tgz",
+ "integrity": "sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw=="
+ },
"parse-json": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-3.0.0.tgz",
@@ -45662,6 +45712,11 @@
"integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
"dev": true
},
+ "remove-trailing-slash": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/remove-trailing-slash/-/remove-trailing-slash-0.1.0.tgz",
+ "integrity": "sha1-FJjl3wmEwn5Jt26/Boh8otARUNI="
+ },
"renderkid": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.3.tgz",
@@ -49938,7 +49993,6 @@
"version": "3.4.10",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz",
"integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==",
- "dev": true,
"requires": {
"commander": "~2.19.0",
"source-map": "~0.6.1"
@@ -49947,14 +50001,12 @@
"commander": {
"version": "2.19.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz",
- "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==",
- "dev": true
+ "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg=="
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
}
}
},
diff --git a/package.json b/package.json
index 02e0322d2..522af09e1 100644
--- a/package.json
+++ b/package.json
@@ -64,6 +64,7 @@
"@fluent/dom": "^0.6.0",
"@hapi/joi": "^17.1.1",
"@metascraper/helpers": "^5.11.6",
+ "@rudderstack/rudder-sdk-node": "0.0.2",
"abort-controller": "^3.0.0",
"akismet-api": "^5.0.0",
"apollo-server-express": "^2.11.0",
diff --git a/src/core/server/app/index.ts b/src/core/server/app/index.ts
index 14abe9118..f856ca5df 100644
--- a/src/core/server/app/index.ts
+++ b/src/core/server/app/index.ts
@@ -196,6 +196,9 @@ function configureApplicationViews(options: AppOptions) {
// caching.
watch: options.config.get("env") === "development",
noCache: options.config.get("env") === "development",
+ // Trim whitespace in templates.
+ trimBlocks: true,
+ lstripBlocks: true,
});
// assign the nunjucks engine to .njk and .html files.
diff --git a/src/core/server/app/router/client.ts b/src/core/server/app/router/client.ts
index 8fd725758..728a77fb8 100644
--- a/src/core/server/app/router/client.ts
+++ b/src/core/server/app/router/client.ts
@@ -1,5 +1,4 @@
import express, { Router } from "express";
-import { minify } from "html-minifier";
import { Db } from "mongodb";
import path from "path";
@@ -15,6 +14,29 @@ import { RequestHandler } from "coral-server/types/express";
import Entrypoints, { Entrypoint } from "../helpers/entrypoints";
export interface ClientTargetHandlerOptions {
+ /**
+ * analytics contains configuration for frontend analytics from RudderStack.
+ */
+ analytics: {
+ /**
+ * key is the Write Key for the frontend integration.
+ */
+ key: string;
+
+ /**
+ * url is the URL to the data plane for your RudderStack deployment.
+ */
+ url: string;
+
+ /**
+ * sdk is the URL to the JS SDK for the RudderStack deployment.
+ */
+ sdk: string;
+ };
+
+ /**
+ * defaultLocale is the configured fallback locale for this installation.
+ */
defaultLocale: LanguageCode;
/**
@@ -62,6 +84,11 @@ function createClientTargetRouter(options: ClientTargetHandlerOptions) {
}
interface MountClientRouteOptions {
+ analytics: {
+ key: string;
+ url: string;
+ sdk: string;
+ };
defaultLocale: LanguageCode;
tenantCache: TenantCache;
staticURI: string;
@@ -69,6 +96,7 @@ interface MountClientRouteOptions {
}
const clientHandler = ({
+ analytics,
staticURI,
entrypoint,
enableCustomCSS,
@@ -85,28 +113,19 @@ const clientHandler = ({
locale = req.coral.tenant.locale;
}
- res.render(
- "client",
- { staticURI, entrypoint, enableCustomCSS, locale, config },
- (err, html) => {
- if (err) {
- return next(err);
- }
-
- // Send back the HTML minified.
- res.send(
- minify(html, {
- removeComments: true,
- collapseWhitespace: true,
- })
- );
- }
- );
+ res.render("client", {
+ analytics,
+ staticURI,
+ entrypoint,
+ enableCustomCSS,
+ locale,
+ config,
+ });
};
export function mountClientRoutes(
router: Router,
- { staticURI, tenantCache, defaultLocale, mongo }: MountClientRouteOptions
+ { tenantCache, ...options }: MountClientRouteOptions
) {
// TODO: (wyattjoh) figure out a better way of referencing paths.
// Load the entrypoint manifest.
@@ -141,31 +160,25 @@ export function mountClientRoutes(
router.use(
"/embed/stream",
createClientTargetRouter({
- staticURI,
+ ...options,
enableCustomCSS: true,
entrypoint: entrypoints.get("stream"),
- defaultLocale,
- mongo,
})
);
router.use(
"/embed/auth/callback",
createClientTargetRouter({
- staticURI,
+ ...options,
cacheDuration: false,
entrypoint: entrypoints.get("authCallback"),
- defaultLocale,
- mongo,
})
);
router.use(
"/embed/auth",
createClientTargetRouter({
- staticURI,
+ ...options,
cacheDuration: false,
entrypoint: entrypoints.get("auth"),
- defaultLocale,
- mongo,
})
);
@@ -175,11 +188,9 @@ export function mountClientRoutes(
// If we aren't already installed, redirect the user to the install page.
installedMiddleware(),
createClientTargetRouter({
- staticURI,
+ ...options,
cacheDuration: false,
entrypoint: entrypoints.get("account"),
- defaultLocale,
- mongo,
})
);
// Add the standalone targets.
@@ -188,11 +199,9 @@ export function mountClientRoutes(
// If we aren't already installed, redirect the user to the install page.
installedMiddleware(),
createClientTargetRouter({
- staticURI,
+ ...options,
cacheDuration: false,
entrypoint: entrypoints.get("admin"),
- defaultLocale,
- mongo,
})
);
router.use(
@@ -203,11 +212,9 @@ export function mountClientRoutes(
redirectURL: "/admin",
}),
createClientTargetRouter({
- staticURI,
+ ...options,
cacheDuration: false,
entrypoint: entrypoints.get("install"),
- defaultLocale,
- mongo,
})
);
diff --git a/src/core/server/app/router/index.ts b/src/core/server/app/router/index.ts
index 687598bae..0e8ba3aab 100644
--- a/src/core/server/app/router/index.ts
+++ b/src/core/server/app/router/index.ts
@@ -27,6 +27,11 @@ export function createRouter(app: AppOptions, options: RouterOptions) {
if (!options.disableClientRoutes) {
mountClientRoutes(router, {
+ analytics: {
+ key: app.config.get("analytics_frontend_key"),
+ url: app.config.get("analytics_data_plane_url"),
+ sdk: app.config.get("analytics_frontend_sdk_url"),
+ },
defaultLocale: app.config.get("default_locale") as LanguageCode,
// When mounting client routes, we need to provide a staticURI even when
// not provided to the default current domain relative "/".
diff --git a/src/core/server/app/views/client.html b/src/core/server/app/views/client.html
index 0e80660d4..e46ca5f8f 100644
--- a/src/core/server/app/views/client.html
+++ b/src/core/server/app/views/client.html
@@ -13,6 +13,29 @@
{% if enableCustomCSS and tenant and tenant.customCSSURL %}
{{ macros.preload(tenant.customCSSURL, "style") }}
{% endif %}
+ {% if analytics and analytics.key and analytics.url and analytics.sdk %}
+ {# If analytics is enabled and available, configure the rudderstack analytics to load #}
+
+
+ {% endif %}
{% if entrypoint.js %}
{% for asset in entrypoint.js %}
{{ macros.preload(asset.src, "script", prefix = staticURI) }}
diff --git a/src/core/server/config.ts b/src/core/server/config.ts
index b12e77e64..1d9fe2e7c 100644
--- a/src/core/server/config.ts
+++ b/src/core/server/config.ts
@@ -259,6 +259,30 @@ const config = convict({
default: false,
env: "DISABLE_JOB_PROCESSORS",
},
+ analytics_frontend_key: {
+ doc: "Analytics write key from RudderStack for the Javascript client.",
+ format: String,
+ default: "",
+ env: "ANALYTICS_FRONTEND_KEY",
+ },
+ analytics_backend_key: {
+ doc: "Analytics write key from RudderStack for the Node server.",
+ format: String,
+ default: "",
+ env: "ANALYTICS_BACKEND_KEY",
+ },
+ analytics_frontend_sdk_url: {
+ doc: "Analytics URL to the RudderStack Frontend JS SDK. Defaults to the ",
+ format: "url",
+ default: "https://cdn.rudderlabs.com/v1/rudder-analytics.min.js",
+ env: "ANALYTICS_FRONTEND_SDK_URL",
+ },
+ analytics_data_plane_url: {
+ doc: "Analytics URL to the RudderStack data plane instance.",
+ format: "optional-url",
+ default: "",
+ env: "ANALYTICS_DATA_PLANE_URL",
+ },
});
export type Config = typeof config;
diff --git a/src/core/server/events/events.ts b/src/core/server/events/events.ts
index d7dbf7514..dbe49aa33 100644
--- a/src/core/server/events/events.ts
+++ b/src/core/server/events/events.ts
@@ -7,6 +7,7 @@ import {
CommentReplyCreatedInput,
CommentStatusUpdatedInput,
} from "coral-server/graph/resolvers/Subscription";
+import { FLAG_REASON } from "coral-server/models/action/comment";
import { CoralEventPayload, createCoralEvent } from "./event";
import { CoralEventType } from "./types";
@@ -20,6 +21,39 @@ export const CommentEnteredModerationQueueCoralEvent = createCoralEvent<
CommentEnteredModerationQueueCoralEventPayload
>(CoralEventType.COMMENT_ENTERED_MODERATION_QUEUE);
+export type CommentReactionCreatedCoralEventPayload = CoralEventPayload<
+ CoralEventType.COMMENT_REACTION_CREATED,
+ {
+ commentID: string;
+ commentRevisionID: string;
+ commentParentID?: string;
+ actionUserID: string;
+ storyID: string;
+ siteID: string;
+ }
+>;
+
+export const CommentReactionCreatedCoralEvent = createCoralEvent<
+ CommentReactionCreatedCoralEventPayload
+>(CoralEventType.COMMENT_REACTION_CREATED);
+
+export type CommentFlagCreatedCoralEventPayload = CoralEventPayload<
+ CoralEventType.COMMENT_FLAG_CREATED,
+ {
+ commentID: string;
+ commentRevisionID: string;
+ commentParentID?: string;
+ flagReason: FLAG_REASON;
+ actionUserID: string;
+ storyID: string;
+ siteID: string;
+ }
+>;
+
+export const CommentFlagCreatedCoralEvent = createCoralEvent<
+ CommentFlagCreatedCoralEventPayload
+>(CoralEventType.COMMENT_FLAG_CREATED);
+
export type CommentLeftModerationQueueCoralEventPayload = CoralEventPayload<
CoralEventType.COMMENT_LEFT_MODERATION_QUEUE,
CommentLeftModerationQueueInput
diff --git a/src/core/server/events/listeners/analytics.ts b/src/core/server/events/listeners/analytics.ts
new file mode 100644
index 000000000..bbb22e67d
--- /dev/null
+++ b/src/core/server/events/listeners/analytics.ts
@@ -0,0 +1,221 @@
+import Analytics, { Event } from "@rudderstack/rudder-sdk-node";
+
+import { Config } from "coral-server/config";
+import GraphContext from "coral-server/graph/context";
+import { relativeTo } from "coral-server/helpers";
+import logger from "coral-server/logger";
+
+import { GQLCOMMENT_STATUS } from "coral-server/graph/schema/__generated__/types";
+
+import {
+ CommentCreatedCoralEventPayload,
+ CommentFlagCreatedCoralEventPayload,
+ CommentReactionCreatedCoralEventPayload,
+ CommentReplyCreatedCoralEventPayload,
+ CommentStatusUpdatedCoralEventPayload,
+ StoryCreatedCoralEventPayload,
+} from "../events";
+import { CoralEventListener, CoralEventPublisherFactory } from "../publisher";
+import { CoralEventType } from "../types";
+
+type AnalyticsCoralEventListenerPayloads =
+ | CommentStatusUpdatedCoralEventPayload
+ | CommentCreatedCoralEventPayload
+ | CommentReplyCreatedCoralEventPayload
+ | CommentReactionCreatedCoralEventPayload
+ | CommentFlagCreatedCoralEventPayload
+ | StoryCreatedCoralEventPayload;
+
+export class AnalyticsCoralEventListener
+ implements CoralEventListener {
+ public readonly name = "analytics";
+ public readonly events = [
+ CoralEventType.COMMENT_CREATED,
+ CoralEventType.COMMENT_REPLY_CREATED,
+ CoralEventType.COMMENT_STATUS_UPDATED,
+ CoralEventType.COMMENT_REACTION_CREATED,
+ CoralEventType.COMMENT_FLAG_CREATED,
+ CoralEventType.STORY_CREATED,
+ ];
+
+ public readonly disabled: boolean = false;
+ private readonly analytics: Analytics;
+
+ constructor(config: Config) {
+ const key = config.get("analytics_backend_key");
+ const url = config.get("analytics_data_plane_url");
+ if (!key || !url) {
+ this.disabled = true;
+
+ return;
+ }
+
+ this.analytics = new Analytics(key, relativeTo("/v1/batch", url));
+ }
+
+ private filter(event: AnalyticsCoralEventListenerPayloads): boolean {
+ switch (event.type) {
+ case CoralEventType.COMMENT_CREATED:
+ case CoralEventType.COMMENT_REPLY_CREATED:
+ case CoralEventType.COMMENT_REACTION_CREATED:
+ case CoralEventType.COMMENT_FLAG_CREATED:
+ case CoralEventType.STORY_CREATED:
+ return true;
+ case CoralEventType.COMMENT_STATUS_UPDATED:
+ // We only record when a comment has been rejected/approved.
+ if (
+ event.data.newStatus !== GQLCOMMENT_STATUS.APPROVED &&
+ event.data.newStatus !== GQLCOMMENT_STATUS.REJECTED
+ ) {
+ return false;
+ }
+
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private async create(
+ ctx: GraphContext,
+ event: AnalyticsCoralEventListenerPayloads
+ ): Promise | undefined> {
+ switch (event.type) {
+ case CoralEventType.COMMENT_CREATED:
+ case CoralEventType.COMMENT_REPLY_CREATED: {
+ const [comment, story] = await Promise.all([
+ ctx.loaders.Comments.comment.load(event.data.commentID),
+ ctx.loaders.Stories.story.load(event.data.storyID),
+ ]);
+ if (!comment || !story || !comment.authorID) {
+ return;
+ }
+
+ return {
+ event: "Comment Created",
+ properties: {
+ siteID: comment.siteID,
+ storyID: comment.storyID,
+ storyURL: story.url,
+ commentID: comment.id,
+ commentStatus: comment.status,
+ commentIsReply: !!comment.parentID,
+ commentAuthorID: comment.authorID,
+ },
+ };
+ }
+
+ case CoralEventType.STORY_CREATED: {
+ return {
+ event: "Story Created",
+ properties: {
+ siteID: event.data.siteID,
+ storyID: event.data.storyID,
+ storyURL: event.data.storyURL,
+ },
+ };
+ }
+
+ case CoralEventType.COMMENT_REACTION_CREATED: {
+ const story = await ctx.loaders.Stories.story.load(event.data.storyID);
+ if (!story) {
+ return;
+ }
+
+ return {
+ event: "Comment Reaction Created",
+ properties: {
+ siteID: story.siteID,
+ storyID: story.id,
+ storyURL: story.url,
+ commentID: event.data.commentID,
+ commentIsReply: !!event.data.commentParentID,
+ actionUserID: event.data.actionUserID,
+ },
+ };
+ }
+
+ case CoralEventType.COMMENT_FLAG_CREATED: {
+ const story = await ctx.loaders.Stories.story.load(event.data.storyID);
+ if (!story) {
+ return;
+ }
+
+ return {
+ event: "User Flagged Comment",
+ properties: {
+ siteID: story.siteID,
+ storyID: story.id,
+ storyURL: story.url,
+ commentID: event.data.commentID,
+ commentIsReply: !!event.data.commentParentID,
+ actionUserID: event.data.actionUserID,
+ flagReason: event.data.flagReason,
+ },
+ };
+ }
+
+ case CoralEventType.COMMENT_STATUS_UPDATED: {
+ const story = await ctx.loaders.Stories.story.load(event.data.storyID);
+ if (!story) {
+ return;
+ }
+
+ return {
+ event: "Comment Moderated",
+ properties: {
+ siteID: story.siteID,
+ storyID: story.id,
+ storyURL: story.url,
+ commentID: event.data.commentID,
+ commentStatus: event.data.newStatus,
+ commentPreviousStatus: event.data.oldStatus,
+ },
+ };
+ }
+ }
+ }
+
+ public initialize: CoralEventPublisherFactory<
+ AnalyticsCoralEventListenerPayloads
+ > = (ctx) => {
+ return async (event) => {
+ // Check to see if we should process this event.
+ if (!this.filter(event)) {
+ // The event should not be processed.
+ return;
+ }
+
+ // Create the event payload.
+ const details = await this.create(ctx, event);
+ if (!details) {
+ return;
+ }
+
+ // Pull some properties out of the context.
+ const {
+ // Sometimes, the user isn't defined (an anonymous request), so default
+ // so we don't get any spread errors.
+ user: { id: userId } = {},
+ tenant: { id: tenantID, domain: tenantDomain },
+ } = ctx;
+
+ // Assemble the track payload.
+ const payload: Event = {
+ event: details.event,
+ userId,
+ properties: {
+ ...details.properties,
+ tenantID,
+ tenantDomain,
+ },
+ timestamp: event.createdAt,
+ };
+
+ logger.debug({ payload }, "sending analytics event");
+
+ // Send the event payload to analytics.
+ return this.analytics.track(payload);
+ };
+ };
+}
diff --git a/src/core/server/events/listeners/index.ts b/src/core/server/events/listeners/index.ts
index 64d14316b..7c0ca1f14 100644
--- a/src/core/server/events/listeners/index.ts
+++ b/src/core/server/events/listeners/index.ts
@@ -1,3 +1,4 @@
+export * from "./analytics";
export * from "./notifier";
export * from "./perspective";
export * from "./slack";
diff --git a/src/core/server/events/publisher.ts b/src/core/server/events/publisher.ts
index a85b2b735..64ecd630b 100644
--- a/src/core/server/events/publisher.ts
+++ b/src/core/server/events/publisher.ts
@@ -20,6 +20,11 @@ export abstract class CoralEventListener {
*/
public abstract readonly name: string;
+ /**
+ * disabled if true will disable the event listener from handling requests.
+ */
+ public abstract readonly disabled?: boolean;
+
/**
* events is the array of event types that this listener should listen for.
*/
@@ -109,6 +114,11 @@ export default class CoralEventListenerBroker {
return;
}
+ if (listener.disabled) {
+ logger.warn({ listenerName: listener.name }, "listener was disabled");
+ return;
+ }
+
logger.trace(
{ listenerName: listener.name, listenerEvents: listener.events },
"registering listener for events"
diff --git a/src/core/server/events/types.ts b/src/core/server/events/types.ts
index 9737f1298..346945563 100644
--- a/src/core/server/events/types.ts
+++ b/src/core/server/events/types.ts
@@ -7,4 +7,6 @@ export enum CoralEventType {
COMMENT_FEATURED = "COMMENT_FEATURED",
COMMENT_RELEASED = "COMMENT_RELEASED",
STORY_CREATED = "STORY_CREATED",
+ COMMENT_REACTION_CREATED = "COMMENT_REACTION_CREATED",
+ COMMENT_FLAG_CREATED = "COMMENT_FLAG_CREATED",
}
diff --git a/src/core/server/graph/resolvers/Subscription/commentReplyCreated.ts b/src/core/server/graph/resolvers/Subscription/commentReplyCreated.ts
index 12f0f5e3a..a851a4ab4 100644
--- a/src/core/server/graph/resolvers/Subscription/commentReplyCreated.ts
+++ b/src/core/server/graph/resolvers/Subscription/commentReplyCreated.ts
@@ -10,6 +10,7 @@ import {
export interface CommentReplyCreatedInput extends SubscriptionPayload {
ancestorIDs: string[];
commentID: string;
+ storyID: string;
}
export type CommentReplyCreatedSubscription = SubscriptionType<
diff --git a/src/core/server/graph/resolvers/Subscription/commentStatusUpdated.ts b/src/core/server/graph/resolvers/Subscription/commentStatusUpdated.ts
index 562624e29..3a778b43d 100644
--- a/src/core/server/graph/resolvers/Subscription/commentStatusUpdated.ts
+++ b/src/core/server/graph/resolvers/Subscription/commentStatusUpdated.ts
@@ -16,6 +16,7 @@ export interface CommentStatusUpdatedInput extends SubscriptionPayload {
moderatorID: string | null;
commentID: string;
commentRevisionID: string;
+ storyID: string;
}
export type CommentStatusUpdatedSubscription = SubscriptionType<
diff --git a/src/core/server/helpers/index.ts b/src/core/server/helpers/index.ts
index f2469b295..8f34bf25e 100644
--- a/src/core/server/helpers/index.ts
+++ b/src/core/server/helpers/index.ts
@@ -1 +1,2 @@
export { default as createTimer } from "./createTimer";
+export { default as relativeTo } from "./relativeTo";
diff --git a/src/core/server/helpers/relativeTo.spec.ts b/src/core/server/helpers/relativeTo.spec.ts
new file mode 100644
index 000000000..5f6d71773
--- /dev/null
+++ b/src/core/server/helpers/relativeTo.spec.ts
@@ -0,0 +1,7 @@
+import relativeTo from "./relativeTo";
+
+it("strips the leading / from urls", () => {
+ expect(
+ relativeTo("/root/test", "https://coralproject.net/another/path/")
+ ).toEqual("https://coralproject.net/another/path/root/test");
+});
diff --git a/src/core/server/helpers/relativeTo.ts b/src/core/server/helpers/relativeTo.ts
new file mode 100644
index 000000000..df5035e74
--- /dev/null
+++ b/src/core/server/helpers/relativeTo.ts
@@ -0,0 +1,7 @@
+import { URL } from "url";
+
+function relativeTo(input: string, base: string): string {
+ return new URL(input.startsWith("/") ? input.slice(1) : input, base).href;
+}
+
+export default relativeTo;
diff --git a/src/core/server/index.ts b/src/core/server/index.ts
index f677d9c06..a69e4fd3f 100644
--- a/src/core/server/index.ts
+++ b/src/core/server/index.ts
@@ -36,6 +36,7 @@ import {
import { TenantCache } from "coral-server/services/tenant/cache";
import {
+ AnalyticsCoralEventListener,
NotifierCoralEventListener,
PerspectiveCoralEventListener,
SlackCoralEventListener,
@@ -64,10 +65,10 @@ class Server {
private parentApp: Express;
// schema is the GraphQL Schema that relates to the given Tenant.
- private schema: GraphQLSchema;
+ private readonly schema: GraphQLSchema;
// config exposes application specific configuration.
- public config: Config;
+ public readonly config: Config;
// httpServer is the running instance of the HTTP server that will bind to
// the requested port.
@@ -102,10 +103,10 @@ class Server {
private processing = false;
// i18n is the server reference to the i18n framework.
- private i18n: I18n;
+ private readonly i18n: I18n;
// signingConfig is the server reference to the signing configuration.
- private signingConfig: JWTSigningConfig;
+ private readonly signingConfig: JWTSigningConfig;
// persistedQueryCache is the cache of persisted queries used by the GraphQL
// server to handle persisted queries.
@@ -216,6 +217,7 @@ class Server {
// Setup the broker.
this.broker = new CoralEventListenerBroker();
+ this.broker.register(new AnalyticsCoralEventListener(this.config));
this.broker.register(new NotifierCoralEventListener(this.tasks.notifier));
this.broker.register(new SlackCoralEventListener());
this.broker.register(new SubscriptionCoralEventListener());
diff --git a/src/core/server/models/action/comment.spec.ts b/src/core/server/models/action/comment.spec.ts
index 26306666b..5e3fede88 100644
--- a/src/core/server/models/action/comment.spec.ts
+++ b/src/core/server/models/action/comment.spec.ts
@@ -1,4 +1,3 @@
-import { GQLCOMMENT_FLAG_REASON } from "coral-server/graph/schema/__generated__/types";
import {
ACTION_TYPE,
CommentAction,
@@ -9,6 +8,8 @@ import {
validateAction,
} from "coral-server/models/action/comment";
+import { GQLCOMMENT_FLAG_REASON } from "coral-server/graph/schema/__generated__/types";
+
describe("#encodeActionCounts", () => {
it("generates the action counts correctly", () => {
const actions: Array> = [
diff --git a/src/core/server/services/comments/actions.ts b/src/core/server/services/comments/actions.ts
index 0f38fe18a..a939c8c69 100644
--- a/src/core/server/services/comments/actions.ts
+++ b/src/core/server/services/comments/actions.ts
@@ -4,6 +4,7 @@ import { CommentNotFoundError } from "coral-server/errors";
import { CoralEventPublisherBroker } from "coral-server/events/publisher";
import {
ACTION_TYPE,
+ CommentAction,
CreateActionInput,
createActions,
encodeActionCounts,
@@ -28,6 +29,10 @@ import {
} from "coral-server/stacks/helpers";
import { GQLCOMMENT_FLAG_REPORTED_REASON } from "coral-server/graph/schema/__generated__/types";
+import {
+ publishCommentFlagCreated,
+ publishCommentReactionCreated,
+} from "../events";
export type CreateAction = CreateActionInput;
@@ -72,6 +77,11 @@ export async function addCommentActionCounts(
return updatedComment;
}
+interface AddCommentAction {
+ comment: Readonly;
+ action?: CommentAction;
+}
+
async function addCommentAction(
mongo: Db,
redis: AugmentedRedis,
@@ -79,7 +89,7 @@ async function addCommentAction(
tenant: Tenant,
input: Omit,
now = new Date()
-): Promise> {
+): Promise {
const oldComment = await retrieveComment(mongo, tenant.id, input.commentID);
if (!oldComment) {
throw new CommentNotFoundError(input.commentID);
@@ -95,6 +105,9 @@ async function addCommentAction(
// Update the actions for the comment.
const commentActions = await addCommentActions(mongo, tenant, [action], now);
if (commentActions.length > 0) {
+ // Get the comment action.
+ const [commentAction] = commentActions;
+
// Compute the action counts.
const actionCounts = encodeActionCounts(...commentActions);
@@ -122,10 +135,10 @@ async function addCommentAction(
commentRevisionID: input.commentRevisionID,
});
- return updatedComment;
+ return { comment: updatedComment, action: commentAction };
}
- return oldComment;
+ return { comment: oldComment };
}
export async function removeCommentAction(
@@ -218,7 +231,7 @@ export async function createReaction(
input: CreateCommentReaction,
now = new Date()
) {
- return addCommentAction(
+ const { comment, action } = await addCommentAction(
mongo,
redis,
broker,
@@ -231,6 +244,17 @@ export async function createReaction(
},
now
);
+ if (action) {
+ // A comment reaction was created! Publish it.
+ publishCommentReactionCreated(
+ broker,
+ comment,
+ input.commentRevisionID,
+ action
+ );
+ }
+
+ return comment;
}
export type RemoveCommentReaction = Pick;
@@ -264,7 +288,7 @@ export async function createDontAgree(
input: CreateCommentDontAgree,
now = new Date()
) {
- return addCommentAction(
+ const { comment } = await addCommentAction(
mongo,
redis,
broker,
@@ -278,6 +302,8 @@ export async function createDontAgree(
},
now
);
+
+ return comment;
}
export type RemoveCommentDontAgree = Pick;
@@ -313,7 +339,7 @@ export async function createFlag(
input: CreateCommentFlag,
now = new Date()
) {
- return addCommentAction(
+ const { comment, action } = await addCommentAction(
mongo,
redis,
broker,
@@ -328,4 +354,10 @@ export async function createFlag(
},
now
);
+ if (action) {
+ // A action was created! Publish the event.
+ publishCommentFlagCreated(broker, comment, input.commentRevisionID, action);
+ }
+
+ return comment;
}
diff --git a/src/core/server/services/events/comments.ts b/src/core/server/services/events/comments.ts
index 192e9ed7b..0cbcd7476 100644
--- a/src/core/server/services/events/comments.ts
+++ b/src/core/server/services/events/comments.ts
@@ -2,12 +2,15 @@ import {
CommentCreatedCoralEvent,
CommentEnteredModerationQueueCoralEvent,
CommentFeaturedCoralEvent,
+ CommentFlagCreatedCoralEvent,
CommentLeftModerationQueueCoralEvent,
+ CommentReactionCreatedCoralEvent,
CommentReleasedCoralEvent,
CommentReplyCreatedCoralEvent,
CommentStatusUpdatedCoralEvent,
} from "coral-server/events";
import { CoralEventPublisherBroker } from "coral-server/events/publisher";
+import { CommentAction } from "coral-server/models/action/comment";
import {
Comment,
CommentModerationQueueCounts,
@@ -26,6 +29,7 @@ export async function publishCommentStatusChanges(
newStatus: GQLCOMMENT_STATUS,
commentID: string,
commentRevisionID: string,
+ storyID: string,
moderatorID: string | null
) {
if (oldStatus !== newStatus) {
@@ -34,6 +38,7 @@ export async function publishCommentStatusChanges(
oldStatus,
commentID,
commentRevisionID,
+ storyID,
moderatorID,
});
}
@@ -41,12 +46,13 @@ export async function publishCommentStatusChanges(
export async function publishCommentReplyCreated(
broker: CoralEventPublisherBroker,
- comment: Pick
+ comment: Pick
) {
if (getDepth(comment) > 0 && hasPublishedStatus(comment)) {
await CommentReplyCreatedCoralEvent.publish(broker, {
ancestorIDs: comment.ancestorIDs,
commentID: comment.id,
+ storyID: comment.storyID,
});
}
}
@@ -75,6 +81,46 @@ export async function publishCommentReleased(
}
}
+export async function publishCommentReactionCreated(
+ broker: CoralEventPublisherBroker,
+ comment: Pick,
+ commentRevisionID: string,
+ { userID }: Pick
+) {
+ // We only publish reaction created events for reactions created by users.
+ if (userID) {
+ await CommentReactionCreatedCoralEvent.publish(broker, {
+ commentID: comment.id,
+ commentRevisionID,
+ commentParentID: comment.parentID,
+ actionUserID: userID,
+ storyID: comment.storyID,
+ siteID: comment.siteID,
+ });
+ }
+}
+
+export async function publishCommentFlagCreated(
+ broker: CoralEventPublisherBroker,
+ comment: Pick,
+ commentRevisionID: string,
+ { userID, reason }: Pick
+) {
+ // We only publish flag created events for flags created by the system with
+ // a reason.
+ if (userID && reason) {
+ await CommentFlagCreatedCoralEvent.publish(broker, {
+ commentID: comment.id,
+ commentRevisionID,
+ commentParentID: comment.parentID,
+ actionUserID: userID,
+ flagReason: reason,
+ storyID: comment.storyID,
+ siteID: comment.siteID,
+ });
+ }
+}
+
export async function publishCommentFeatured(
broker: CoralEventPublisherBroker,
comment: Pick
diff --git a/src/core/server/stacks/helpers/publishChanges.ts b/src/core/server/stacks/helpers/publishChanges.ts
index f423cbd96..abd3e5bc4 100644
--- a/src/core/server/stacks/helpers/publishChanges.ts
+++ b/src/core/server/stacks/helpers/publishChanges.ts
@@ -37,6 +37,7 @@ export default async function publishChanges(
input.after.status,
input.after.id,
input.commentRevisionID,
+ input.after.storyID,
input.moderatorID || null
);
diff --git a/src/types/@rudderstack/rudder-sdk-node.d.ts b/src/types/@rudderstack/rudder-sdk-node.d.ts
new file mode 100644
index 000000000..c00652843
--- /dev/null
+++ b/src/types/@rudderstack/rudder-sdk-node.d.ts
@@ -0,0 +1,18 @@
+declare module "@rudderstack/rudder-sdk-node" {
+ export interface Event {
+ userId?: string;
+ event: string;
+ properties: Record;
+ timestamp?: Date;
+ }
+
+ type Callback = (err?: Error) => void;
+
+ class Analytics {
+ constructor(writeKey: string, dataPlaneURI: string);
+
+ public track(payload: Event, callback?: Callback): void;
+ }
+
+ export default Analytics;
+}