diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9f34f86b13..ea29ced019 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1296,8 +1296,8 @@ importers: specifier: ^0.2.1 version: 0.2.1(next@15.5.19(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) posthog-js: - specifier: ^1.240.6 - version: 1.242.2 + specifier: ^1.395.0 + version: 1.395.0 prettier: specifier: 'catalog:' version: 3.6.2 @@ -1654,10 +1654,6 @@ packages: resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} engines: {node: '>=6.9.0'} - '@babel/code-frame@7.24.2': - resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==} - engines: {node: '>=6.9.0'} - '@babel/code-frame@7.26.2': resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} engines: {node: '>=6.9.0'} @@ -1760,10 +1756,6 @@ packages: resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} engines: {node: '>=6.9.0'} - '@babel/highlight@7.24.5': - resolution: {integrity: sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==} - engines: {node: '>=6.9.0'} - '@babel/parser@7.23.6': resolution: {integrity: sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==} engines: {node: '>=6.0.0'} @@ -5122,6 +5114,12 @@ packages: '@popperjs/core@2.11.8': resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} + '@posthog/core@1.38.0': + resolution: {integrity: sha512-QLrJh0hMVpEJXHNyiJR9YhvIO5tzLDedw4UHdvB+ub4fXHMtHCA8H44qgl11HWR3ajpjxtJ8hs3HyOGVF3Zc1w==} + + '@posthog/types@1.391.1': + resolution: {integrity: sha512-ASwd7Nf4pViqdYRYaNRyPYRVKWa1CcHUAUWR0XeQJLGdNnsWACBwe0sSieb/cHnKsRXjRwO/23KIY83lm/Ccpw==} + '@prisma/instrumentation@5.19.1': resolution: {integrity: sha512-VLnzMQq7CWroL5AeaW0Py2huiNKeoMfCH3SUxstdzPrlWQi6UQ9UrfcbUkNHlVFqOMacqy8X/8YtE0kuKDpD9w==} @@ -9408,10 +9406,6 @@ packages: resolution: {integrity: sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==} engines: {node: '>=10.2.0'} - enhanced-resolve@5.15.0: - resolution: {integrity: sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==} - engines: {node: '>=10.13.0'} - enhanced-resolve@5.18.4: resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==} engines: {node: '>=10.13.0'} @@ -10739,9 +10733,6 @@ packages: is-core-module@2.12.1: resolution: {integrity: sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==} - is-core-module@2.13.1: - resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} - is-core-module@2.16.1: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} @@ -12423,23 +12414,15 @@ packages: resolution: {integrity: sha512-cDWgoah1Gez9rN3H4165peY9qfpEo+SA61oQv65O3cRUE1pOEoJWwddwcqKE8XZYjbblOJlYDlLV4h67HrEVDg==} engines: {node: '>=12'} - posthog-js@1.242.2: - resolution: {integrity: sha512-bj5Bq9Z/TE24k0fbt/VoD13xsqCybuoLp7KkWmfknEiO63+1Ln/PnX/1CjppikE9yM7toQIWY3vY7hT/RTT57Q==} - peerDependencies: - '@rrweb/types': 2.0.0-alpha.17 - rrweb-snapshot: 2.0.0-alpha.17 - peerDependenciesMeta: - '@rrweb/types': - optional: true - rrweb-snapshot: - optional: true + posthog-js@1.395.0: + resolution: {integrity: sha512-5iTb00CGt2eQUUiBQysQiX89RAbCN6wK2sDNzvs9zv0alaY8mJ0ZySrUD3LQ+XyLhgM5pCpacBuUwChqiYDLDw==} posthog-node@4.18.0: resolution: {integrity: sha512-XROs1h+DNatgKh/AlIlCtDxWzwrKdYDb2mOs58n4yN8BkGN9ewqeQwG5ApS4/IzwCb7HPttUkOVulkYatd2PIw==} engines: {node: '>=15.0.0'} - preact@10.26.6: - resolution: {integrity: sha512-5SRRBinwpwkaD+OqlBDeITlRgvd8I8QlxHJw9AxSdMNV6O+LodN9nUyYGpSF7sadHjs6RzeFShMexC6DbtWr9g==} + preact@10.29.3: + resolution: {integrity: sha512-D9NL1GAnJZhc3RndVs4gDdxEeU9TcHgywMrhhOsnpdlvFjdbx0gAsLUnH6JEhlJH5giL7Tx5biWPUSEXE/HPzw==} prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} @@ -12703,6 +12686,9 @@ packages: quansync@0.2.11: resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + query-selector-shadow-dom@1.0.1: + resolution: {integrity: sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==} + querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} @@ -13087,10 +13073,6 @@ packages: engines: {node: '>= 0.4'} hasBin: true - resolve@1.22.2: - resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} - hasBin: true - resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -13680,10 +13662,6 @@ packages: engines: {node: '>=14.0.0'} hasBin: true - tapable@2.2.1: - resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} - engines: {node: '>=6'} - tapable@2.3.0: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} @@ -14383,8 +14361,8 @@ packages: resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==} engines: {node: '>= 14'} - web-vitals@4.2.4: - resolution: {integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==} + web-vitals@5.3.0: + resolution: {integrity: sha512-q6LWsLatGYZp5VGBIOvbTj6JBV2nOmC8KvWztXBmwJcfFAzhwKwbOxhUH306XY3CcaZDUlSmSuNPBsCn0bFu+g==} webcrypto-core@1.7.8: resolution: {integrity: sha512-eBR98r9nQXTqXt/yDRtInszPMjTaSAMJAFDg2AHsgrnczawT1asx9YNBX6k5p+MekbPF4+s/UJJrr88zsTqkSg==} @@ -15252,11 +15230,6 @@ snapshots: '@babel/highlight': 7.23.4 chalk: 2.4.2 - '@babel/code-frame@7.24.2': - dependencies: - '@babel/highlight': 7.24.5 - picocolors: 1.0.0 - '@babel/code-frame@7.26.2': dependencies: '@babel/helper-validator-identifier': 7.28.5 @@ -15376,13 +15349,6 @@ snapshots: chalk: 2.4.2 js-tokens: 4.0.0 - '@babel/highlight@7.24.5': - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - chalk: 2.4.2 - js-tokens: 4.0.0 - picocolors: 1.0.0 - '@babel/parser@7.23.6': dependencies: '@babel/types': 7.23.6 @@ -15430,7 +15396,7 @@ snapshots: '@babel/template@7.24.0': dependencies: - '@babel/code-frame': 7.24.2 + '@babel/code-frame': 7.27.1 '@babel/parser': 7.29.2 '@babel/types': 7.29.0 @@ -19228,6 +19194,12 @@ snapshots: '@popperjs/core@2.11.8': {} + '@posthog/core@1.38.0': + dependencies: + '@posthog/types': 1.391.1 + + '@posthog/types@1.391.1': {} + '@prisma/instrumentation@5.19.1': dependencies: '@opentelemetry/api': 1.9.0 @@ -24098,11 +24070,6 @@ snapshots: - supports-color - utf-8-validate - enhanced-resolve@5.15.0: - dependencies: - graceful-fs: 4.2.11 - tapable: 2.2.1 - enhanced-resolve@5.18.4: dependencies: graceful-fs: 4.2.11 @@ -24452,7 +24419,7 @@ snapshots: eslint: 8.57.1 eslint-import-resolver-node: 0.3.7 eslint-import-resolver-typescript: 3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.27.5(eslint@8.57.1))(eslint@8.57.1) - eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.5.5)(eslint@8.57.1) + eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.27.5(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.7.1(eslint@8.57.1) eslint-plugin-react: 7.33.0(eslint@8.57.1) eslint-plugin-react-hooks: 4.6.0(eslint@8.57.1) @@ -24503,13 +24470,13 @@ snapshots: eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.27.5(eslint@8.57.1))(eslint@8.57.1): dependencies: debug: 4.4.1 - enhanced-resolve: 5.15.0 + enhanced-resolve: 5.18.4 eslint: 8.57.1 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.57.1) - eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.5.5)(eslint@8.57.1) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.27.5(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.27.5(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) get-tsconfig: 4.10.1 globby: 13.2.2 - is-core-module: 2.12.1 + is-core-module: 2.16.1 is-glob: 4.0.3 synckit: 0.8.5 transitivePeerDependencies: @@ -24521,13 +24488,13 @@ snapshots: eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.27.5)(eslint@8.57.1): dependencies: debug: 4.4.1 - enhanced-resolve: 5.15.0 + enhanced-resolve: 5.18.4 eslint: 8.57.1 eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.5.5)(eslint@8.57.1) eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1) get-tsconfig: 4.10.1 globby: 13.2.2 - is-core-module: 2.12.1 + is-core-module: 2.16.1 is-glob: 4.0.3 synckit: 0.8.5 transitivePeerDependencies: @@ -24536,6 +24503,17 @@ snapshots: - eslint-import-resolver-webpack - supports-color + eslint-module-utils@2.8.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.27.5(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): + dependencies: + debug: 4.4.1 + optionalDependencies: + '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.6.2) + eslint: 8.57.1 + eslint-import-resolver-node: 0.3.7 + eslint-import-resolver-typescript: 3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.27.5(eslint@8.57.1))(eslint@8.57.1) + transitivePeerDependencies: + - supports-color + eslint-module-utils@2.8.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.57.1): dependencies: debug: 4.4.1 @@ -24570,7 +24548,7 @@ snapshots: eslint-utils: 2.1.0 regexpp: 3.2.0 - eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.5.5)(eslint@8.57.1): + eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.27.5(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): dependencies: array-includes: 3.1.6 array.prototype.flat: 1.3.1 @@ -24579,13 +24557,13 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.7 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.57.1) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.27.5(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) has: 1.0.3 - is-core-module: 2.12.1 + is-core-module: 2.16.1 is-glob: 4.0.3 minimatch: 3.1.4 object.values: 1.1.6 - resolve: 1.22.2 + resolve: 1.22.11 semver: 6.3.1 tsconfig-paths: 3.14.2 optionalDependencies: @@ -24606,11 +24584,11 @@ snapshots: eslint-import-resolver-node: 0.3.7 eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.57.1) has: 1.0.3 - is-core-module: 2.12.1 + is-core-module: 2.16.1 is-glob: 4.0.3 minimatch: 3.1.4 object.values: 1.1.6 - resolve: 1.22.2 + resolve: 1.22.11 semver: 6.3.1 tsconfig-paths: 3.14.2 optionalDependencies: @@ -25435,7 +25413,7 @@ snapshots: globby@13.2.2: dependencies: dir-glob: 3.0.1 - fast-glob: 3.3.1 + fast-glob: 3.3.2 ignore: 5.3.1 merge2: 1.4.1 slash: 4.0.0 @@ -25997,10 +25975,6 @@ snapshots: dependencies: has: 1.0.3 - is-core-module@2.13.1: - dependencies: - hasown: 2.0.2 - is-core-module@2.16.1: dependencies: hasown: 2.0.2 @@ -27969,12 +27943,16 @@ snapshots: postgres@3.4.5: {} - posthog-js@1.242.2: + posthog-js@1.395.0: dependencies: + '@posthog/core': 1.38.0 + '@posthog/types': 1.391.1 core-js: 3.41.0 + dompurify: 3.4.11 fflate: 0.4.8 - preact: 10.26.6 - web-vitals: 4.2.4 + preact: 10.29.3 + query-selector-shadow-dom: 1.0.1 + web-vitals: 5.3.0 posthog-node@4.18.0: dependencies: @@ -27983,7 +27961,7 @@ snapshots: - debug - supports-color - preact@10.26.6: {} + preact@10.29.3: {} prelude-ls@1.2.1: {} @@ -28235,6 +28213,8 @@ snapshots: quansync@0.2.11: {} + query-selector-shadow-dom@1.0.1: {} + querystringify@2.2.0: {} queue-microtask@1.2.3: {} @@ -28719,12 +28699,6 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - resolve@1.22.2: - dependencies: - is-core-module: 2.12.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - resolve@1.22.8: dependencies: is-core-module: 2.16.1 @@ -28733,7 +28707,7 @@ snapshots: resolve@2.0.0-next.4: dependencies: - is-core-module: 2.13.1 + is-core-module: 2.16.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 @@ -29470,8 +29444,6 @@ snapshots: transitivePeerDependencies: - ts-node - tapable@2.2.1: {} - tapable@2.3.0: {} tar-stream@1.6.2: @@ -30237,7 +30209,7 @@ snapshots: web-streams-polyfill@4.0.0-beta.3: {} - web-vitals@4.2.4: {} + web-vitals@5.3.0: {} webcrypto-core@1.7.8: dependencies: diff --git a/studio/package.json b/studio/package.json index 9c857e4cb0..4aceb4e363 100644 --- a/studio/package.json +++ b/studio/package.json @@ -97,7 +97,7 @@ "monaco-graphql": "^1.4.0", "next": "15.5.19", "next-themes": "^0.2.1", - "posthog-js": "^1.240.6", + "posthog-js": "^1.395.0", "prettier": "catalog:", "pretty-bytes": "^6.1.1", "prism-react-renderer": "^2.0.6", diff --git a/studio/src/components/app-provider.tsx b/studio/src/components/app-provider.tsx index 8c41e08a20..fa1b9fd937 100644 --- a/studio/src/components/app-provider.tsx +++ b/studio/src/components/app-provider.tsx @@ -9,6 +9,7 @@ import { LoginMethod as ProtoLoginMethod } from '@wundergraph/cosmo-connect/dist import { useRouter } from 'next/router'; import { ReactNode, createContext, useEffect, useState } from 'react'; import { useCookieOrganization } from '@/hooks/use-cookie-organization'; +import { useAnalyticsConsent } from '@/hooks/use-analytics-consent'; import { setUser as setSentryUser } from '@sentry/nextjs'; import { OrganizationRole } from '@/lib/constants'; import { WorkspaceProvider } from '@/components/dashboard/workspace-provider'; @@ -145,6 +146,9 @@ export const AppProvider = ({ children }: { children: ReactNode }) => { const [queryResetCounter, setQueryResetCounter] = useState(-1); const queryClient = useQueryClient(); + // identify() skips PostHog while opted out, so re-run it once consent is granted. + const analyticsConsented = useAnalyticsConsent(); + const [user, setUser] = useState(); useEffect(() => { @@ -237,7 +241,7 @@ export const AppProvider = ({ children }: { children: ReactNode }) => { router.replace(params.size !== 0 ? `/${organization.slug}?${params}` : `/${organization.slug}`); } } - }, [router, data, isFetching, error, cookieOrgSlug, isNewUser]); + }, [router, data, isFetching, error, cookieOrgSlug, isNewUser, analyticsConsented]); useEffect(() => { if (!verifiedOrganizationSlug) { diff --git a/studio/src/hooks/use-analytics-consent.ts b/studio/src/hooks/use-analytics-consent.ts new file mode 100644 index 0000000000..1470d40d24 --- /dev/null +++ b/studio/src/hooks/use-analytics-consent.ts @@ -0,0 +1,47 @@ +import { useEffect, useState } from 'react'; + +interface OsanoConsent { + ANALYTICS?: string; + MARKETING?: string; +} + +declare global { + interface Window { + Osano?: { + cm?: { + getConsent?: () => OsanoConsent; + addEventListener: (event: string, callback: (consent?: OsanoConsent) => void) => void; + }; + }; + } +} + +// Accepting analytics or marketing is the gate for PostHog/Reo tracking. +export function hasAnalyticsConsent(consent: OsanoConsent | undefined): boolean { + return consent?.ANALYTICS === 'ACCEPT' || consent?.MARKETING === 'ACCEPT'; +} + +// Reactive Osano analytics-consent state, so consumers can re-run effects when +// the user accepts/rejects (Osano is only present in production). +export function useAnalyticsConsent(): boolean { + const [consented, setConsented] = useState(false); + + useEffect(() => { + const update = (): void => setConsented(hasAnalyticsConsent(window.Osano?.cm?.getConsent?.())); + + const onOsanoReady = (): void => { + update(); + window.Osano?.cm?.addEventListener('osano-cm-consent-changed', update); + }; + + if (window.Osano?.cm) { + onOsanoReady(); + return; + } + + window.addEventListener('osano-cm-initialized', onOsanoReady, { once: true }); + return () => window.removeEventListener('osano-cm-initialized', onOsanoReady); + }, []); + + return consented; +} diff --git a/studio/src/lib/track.ts b/studio/src/lib/track.ts index ae023f4dd8..db9f22cb5c 100644 --- a/studio/src/lib/track.ts +++ b/studio/src/lib/track.ts @@ -10,6 +10,18 @@ declare global { } } +interface TrackingIdentity { + id: string; + email: string; + firstName?: string; + lastName?: string; + fullName?: string; + organizationId: string; + organizationName: string; + organizationSlug: string; + plan?: string; +} + const resetTracking = () => { if (typeof window === 'undefined') { return; @@ -36,17 +48,7 @@ const setupPosthog = ({ organizationName, organizationSlug, plan, -}: { - id: string; - email: string; - firstName?: string; - lastName?: string; - fullName?: string; - organizationId: string; - organizationName: string; - organizationSlug: string; - plan?: string; -}) => { +}: TrackingIdentity) => { // We allow PostHog tracking for any environment, if the key is provided // Identify with PostHog let distinctId = posthog.get_distinct_id(); @@ -85,47 +87,19 @@ const setupPosthog = ({ posthog.reloadFeatureFlags(); }; -const identify = ({ - email, - id, - firstName, - lastName, - fullName, - organizationId, - organizationName, - organizationSlug, - plan, -}: { - id: string; - email: string; - firstName?: string; - lastName?: string; - fullName?: string; - organizationId: string; - organizationName: string; - organizationSlug: string; - plan?: string; -}) => { +const identify = (params: TrackingIdentity) => { if (typeof window === 'undefined') { return; } - if (process.env.NEXT_PUBLIC_POSTHOG_KEY) { - setupPosthog({ - email, - id, - firstName, - lastName, - fullName, - organizationId, - organizationName, - organizationSlug, - plan, - }); + // Only attach identity/PII after the user has opted in. Rejected/default + // opt-out users are tracked anonymously (cookieless), so no PII is sent. + if (process.env.NEXT_PUBLIC_POSTHOG_KEY && posthog.has_opted_in_capturing()) { + setupPosthog(params); } if (process.env.NODE_ENV === 'production') { - setupReo(email); + setupReo(params.email); } }; diff --git a/studio/src/pages/_app.tsx b/studio/src/pages/_app.tsx index fb766da34f..a08232af15 100644 --- a/studio/src/pages/_app.tsx +++ b/studio/src/pages/_app.tsx @@ -21,6 +21,7 @@ import { useEffect } from 'react'; import { Router } from 'next/router'; import posthog from 'posthog-js'; import { PostHogProvider } from 'posthog-js/react'; +import { hasAnalyticsConsent } from '@/hooks/use-analytics-consent'; import { withErrorBoundary } from '@sentry/nextjs'; import { Footer } from '@/components/layout/footer'; import { OnboardingProvider } from '@/components/onboarding/onboarding-provider'; @@ -44,6 +45,9 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) { posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, { api_host: '/ingest', + // Track rejected/default opt-out users anonymously (no cookies); switch to + // full tracking only once the user opts in via Osano consent. + cookieless_mode: 'on_reject', loaded: (ph) => { if (process.env.NODE_ENV === 'development') ph.debug(); }, @@ -58,6 +62,35 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) { }; }, []); + // Drive PostHog opt-in/out from Osano consent. Without consent (reject or no + // prior decision) capturing stays cookieless/anonymous; on accept it switches + // to full cookie-based tracking. + useEffect(() => { + if (!process.env.NEXT_PUBLIC_POSTHOG_KEY) return; + + const applyConsent = () => { + if (hasAnalyticsConsent(window.Osano?.cm?.getConsent?.())) { + posthog.opt_in_capturing(); + posthog.reloadFeatureFlags(); + } else { + posthog.opt_out_capturing(); + } + }; + + const onOsanoReady = () => { + applyConsent(); + window.Osano?.cm?.addEventListener('osano-cm-consent-changed', applyConsent); + }; + + if (window.Osano?.cm) { + onOsanoReady(); + return; + } + + window.addEventListener('osano-cm-initialized', onOsanoReady, { once: true }); + return () => window.removeEventListener('osano-cm-initialized', onOsanoReady); + }, []); + if (pageProps.markdoc) { return (