diff --git a/apps/basic-integration/tanstack-router/tanstack-router-code-based-saas/.env.example b/apps/basic-integration/tanstack-router/tanstack-router-code-based-saas/.env.example new file mode 100644 index 000000000..b2c042ddf --- /dev/null +++ b/apps/basic-integration/tanstack-router/tanstack-router-code-based-saas/.env.example @@ -0,0 +1,2 @@ +VITE_PUBLIC_POSTHOG_PROJECT_TOKEN= +VITE_PUBLIC_POSTHOG_HOST= diff --git a/apps/basic-integration/tanstack-router/tanstack-router-code-based-saas/.gitignore b/apps/basic-integration/tanstack-router/tanstack-router-code-based-saas/.gitignore index d451ff16c..30df6062f 100644 --- a/apps/basic-integration/tanstack-router/tanstack-router-code-based-saas/.gitignore +++ b/apps/basic-integration/tanstack-router/tanstack-router-code-based-saas/.gitignore @@ -3,3 +3,4 @@ node_modules dist dist-ssr *.local +.env diff --git a/apps/basic-integration/tanstack-router/tanstack-router-code-based-saas/package.json b/apps/basic-integration/tanstack-router/tanstack-router-code-based-saas/package.json index 00908a187..d3fcdb6a4 100644 --- a/apps/basic-integration/tanstack-router/tanstack-router-code-based-saas/package.json +++ b/apps/basic-integration/tanstack-router/tanstack-router-code-based-saas/package.json @@ -9,6 +9,7 @@ "start": "vite" }, "dependencies": { + "@posthog/react": "^1.11.3", "@tailwindcss/vite": "^4.1.18", "@tanstack/react-router": "^1.158.1", "@tanstack/react-router-devtools": "^1.158.1", diff --git a/apps/basic-integration/tanstack-router/tanstack-router-code-based-saas/pnpm-lock.yaml b/apps/basic-integration/tanstack-router/tanstack-router-code-based-saas/pnpm-lock.yaml index 74ce37d87..f500e17b3 100644 --- a/apps/basic-integration/tanstack-router/tanstack-router-code-based-saas/pnpm-lock.yaml +++ b/apps/basic-integration/tanstack-router/tanstack-router-code-based-saas/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + '@posthog/react': + specifier: ^1.11.3 + version: 1.11.3(@types/react@19.2.13)(posthog-js@1.441.2(@types/react@19.2.13)(react@19.2.4))(react@19.2.4) '@tailwindcss/vite': specifier: ^4.1.18 version: 4.1.18(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)) @@ -309,6 +312,25 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@posthog/browser-common@0.10.1': + resolution: {integrity: sha512-gKtBGEsjxNExO/19trnkiXTHFX0075vXn69zZ+lPlXy6P/DkED4644WqjDN/GIWr1Y5en2dcVJPOqUmVO+drkg==} + + '@posthog/core@1.61.1': + resolution: {integrity: sha512-qyMTxPfjeJkHIhpcukOgBN3BWXbCyFRPz8/Voy5qZtVh9NZqj3EhC6LLeYZuJhL3WpqhQTgn2FMIwAo/ag6fmw==} + + '@posthog/react@1.11.3': + resolution: {integrity: sha512-YqvZb2y9jh/yW0ojUtAns0l4yHWqpu+5UeIBxZlXpyGuWlh8M4siXRMtqhEh1BKfqp6Sq2usdsQCuoUzx1QFWQ==} + peerDependencies: + '@types/react': '>=16.8.0' + posthog-js: '>=1.257.2' + react: '>=16.8.0' + peerDependenciesMeta: + '@types/react': + optional: true + + '@posthog/types@1.418.0': + resolution: {integrity: sha512-WqDXUWH1R8OilBp2PfDpQIRZSCs3QyOnw7H3YK7lvZLCMIsOqSZAKJrrqYWt4f7FvnVCACRuNGCC0HKh3J/HWw==} + '@rolldown/pluginutils@1.0.0-beta.27': resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} @@ -346,66 +368,79 @@ packages: resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.57.1': resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.57.1': resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.57.1': resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.57.1': resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-loong64-musl@4.57.1': resolution: {integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==} cpu: [loong64] os: [linux] + libc: [musl] '@rollup/rollup-linux-ppc64-gnu@4.57.1': resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-musl@4.57.1': resolution: {integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==} cpu: [ppc64] os: [linux] + libc: [musl] '@rollup/rollup-linux-riscv64-gnu@4.57.1': resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.57.1': resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.57.1': resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.57.1': resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.57.1': resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-openbsd-x64@4.57.1': resolution: {integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==} @@ -475,24 +510,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.1.18': resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-x64-gnu@4.1.18': resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-x64-musl@4.1.18': resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@tailwindcss/oxide-wasm32-wasi@4.1.18': resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} @@ -596,6 +635,9 @@ packages: '@types/react@19.2.13': resolution: {integrity: sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@vitejs/plugin-react@4.7.0': resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} engines: {node: ^14.18.0 || >=16.0.0} @@ -624,6 +666,9 @@ packages: cookie-es@2.0.0: resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==} + core-js@3.51.0: + resolution: {integrity: sha512-7bDKx/5jm5MxzsXxc93g6Z2+4ZsuT/MddrfRmTDJNAkWsYWHU8EVNEsBiIEWnMAMCHMmRfUEjkuo3jeNBOIHRw==} + csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} @@ -640,6 +685,9 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + dompurify@3.4.17: + resolution: {integrity: sha512-B/pSlYVHQ58kqISD/yDjuJ1yfzI34m1gF4lAod2bwSRhiN4K5Cl3H8Af7hqB2PmTL911tdEudnnXn5FnhRoz0w==} + electron-to-chromium@1.5.286: resolution: {integrity: sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==} @@ -665,6 +713,9 @@ packages: picomatch: optional: true + fflate@0.4.9: + resolution: {integrity: sha512-zdxgIEddhfsyCaWpJ2SdXEP8ZMrKJ6+5jl4OupODcywU0IhRk6gdXuVGcPICyfx2H97hVK7xmJtRLPjkxAX8Vw==} + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -741,24 +792,28 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.30.2: resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.30.2: resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.30.2: resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.30.2: resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} @@ -804,6 +859,28 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} + posthog-js@1.441.2: + resolution: {integrity: sha512-PsELSUSVCx80BfbtMtir8fW6scxVj+2CvsG+Vj2j9eTQYQL1AzsaZr73pqJk1XWEcSt+B1hEfirz3iFVQGVQkQ==} + peerDependencies: + '@types/react': '>=16.8.0' + react: '>=16.8.0' + peerDependenciesMeta: + '@types/react': + optional: true + react: + optional: true + + preact@10.29.8: + resolution: {integrity: sha512-ej2aVZ+vZ8WO7tvlQWRM9N63A0KzF9q4mWJfDUHgYaIofWY9hu74QdnQrjoPMmZi2/nZ5gN0bJCQF49xQqx09Q==} + peerDependencies: + preact-render-to-string: '>=5' + peerDependenciesMeta: + preact-render-to-string: + optional: true + + query-selector-shadow-dom@1.0.1: + resolution: {integrity: sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==} + react-dom@19.2.4: resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} peerDependencies: @@ -919,6 +996,12 @@ packages: yaml: optional: true + web-vitals@6.2.1: + resolution: {integrity: sha512-rLcLXA2sx6+9dE88NHFubwTtGxpK4yYBLj6qHPdFoCaLr0cXGb4efOqtKLlm4loGA4OEKHIQKMKzZkKyOh5ctw==} + + web-vitals@6.2.3: + resolution: {integrity: sha512-Dmy+vdO1UPMqXiAtZSNayhl4f794Bxfd94W4HIj2HlYtczEQfEOon969memlcpcHrTuOKLa5baFjX7WbgmOq+A==} + yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} @@ -1136,6 +1219,27 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@posthog/browser-common@0.10.1': + dependencies: + '@posthog/core': 1.61.1 + '@posthog/types': 1.418.0 + preact: 10.29.8 + transitivePeerDependencies: + - preact-render-to-string + + '@posthog/core@1.61.1': + dependencies: + '@posthog/types': 1.418.0 + + '@posthog/react@1.11.3(@types/react@19.2.13)(posthog-js@1.441.2(@types/react@19.2.13)(react@19.2.4))(react@19.2.4)': + dependencies: + posthog-js: 1.441.2(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@posthog/types@1.418.0': {} + '@rolldown/pluginutils@1.0.0-beta.27': {} '@rollup/rollup-android-arm-eabi@4.57.1': @@ -1364,6 +1468,9 @@ snapshots: dependencies: csstype: 3.2.3 + '@types/trusted-types@2.0.7': + optional: true + '@vitejs/plugin-react@4.7.0(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2))': dependencies: '@babel/core': 7.29.0 @@ -1394,6 +1501,8 @@ snapshots: cookie-es@2.0.0: {} + core-js@3.51.0: {} + csstype@3.2.3: {} debug@4.4.3: @@ -1402,6 +1511,10 @@ snapshots: detect-libc@2.1.2: {} + dompurify@3.4.17: + optionalDependencies: + '@types/trusted-types': 2.0.7 + electron-to-chromium@1.5.286: {} enhanced-resolve@5.19.0: @@ -1444,6 +1557,8 @@ snapshots: optionalDependencies: picomatch: 4.0.3 + fflate@0.4.9: {} + fsevents@2.3.3: optional: true @@ -1540,6 +1655,28 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + posthog-js@1.441.2(@types/react@19.2.13)(react@19.2.4): + dependencies: + '@posthog/browser-common': 0.10.1 + '@posthog/core': 1.61.1 + '@posthog/types': 1.418.0 + core-js: 3.51.0 + dompurify: 3.4.17 + fflate: 0.4.9 + preact: 10.29.8 + query-selector-shadow-dom: 1.0.1 + web-vitals: 6.2.3 + web-vitals-soft-navs: web-vitals@6.2.1 + optionalDependencies: + '@types/react': 19.2.13 + react: 19.2.4 + transitivePeerDependencies: + - preact-render-to-string + + preact@10.29.8: {} + + query-selector-shadow-dom@1.0.1: {} + react-dom@19.2.4(react@19.2.4): dependencies: react: 19.2.4 @@ -1632,6 +1769,10 @@ snapshots: jiti: 2.6.1 lightningcss: 1.30.2 + web-vitals@6.2.1: {} + + web-vitals@6.2.3: {} + yallist@3.1.1: {} zod@3.25.76: {} diff --git a/apps/basic-integration/tanstack-router/tanstack-router-code-based-saas/src/main.tsx b/apps/basic-integration/tanstack-router/tanstack-router-code-based-saas/src/main.tsx index 05a68721a..64ae589db 100644 --- a/apps/basic-integration/tanstack-router/tanstack-router-code-based-saas/src/main.tsx +++ b/apps/basic-integration/tanstack-router/tanstack-router-code-based-saas/src/main.tsx @@ -20,6 +20,7 @@ import { useSearch, } from '@tanstack/react-router' import { TanStackRouterDevtools } from '@tanstack/react-router-devtools' +import { PostHogErrorBoundary, PostHogProvider, usePostHog } from '@posthog/react' import { z } from 'zod' import { fetchInvoiceById, @@ -85,6 +86,45 @@ function RouterSpinner() { } function RootComponent() { + const projectToken = import.meta.env.VITE_PUBLIC_POSTHOG_PROJECT_TOKEN + const host = import.meta.env.VITE_PUBLIC_POSTHOG_HOST + + if (!projectToken || !host) { + if (import.meta.env.DEV) { + const missingVariable = projectToken + ? 'VITE_PUBLIC_POSTHOG_HOST' + : 'VITE_PUBLIC_POSTHOG_PROJECT_TOKEN' + + throw new Error( + `${missingVariable} variable required by PostHog is missing or un-configured, this causes events to be silently missed. This error stops appearing once ${missingVariable} is configured`, + ) + } + + return + } + + return ( + + + + + + ) +} + +function RootLayout() { return ( <>
@@ -433,9 +473,17 @@ const invoicesIndexRoute = createRoute({ }) function InvoicesIndexComponent() { + const posthog = usePostHog() const createInvoiceMutation = useMutation({ fn: postInvoice, - onSuccess: () => router.invalidate(), + onSuccess: async () => { + posthog?.capture('invoice_created') + posthog?.logger.info('invoice_created', { + event: 'invoice_created', + operation: 'create', + }) + await router.invalidate() + }, }) return ( @@ -517,9 +565,17 @@ function InvoiceComponent() { const search = invoiceRoute.useSearch() const navigate = useNavigate({ from: invoiceRoute.fullPath }) const invoice = invoiceRoute.useLoaderData() + const posthog = usePostHog() const updateInvoiceMutation = useMutation({ fn: patchInvoice, - onSuccess: () => router.invalidate(), + onSuccess: async () => { + posthog?.capture('invoice_updated') + posthog?.logger.info('invoice_updated', { + event: 'invoice_updated', + operation: 'update', + }) + await router.invalidate() + }, }) const [notes, setNotes] = React.useState(search.notes ?? '') React.useEffect(() => { @@ -1003,6 +1059,7 @@ const profileRoute = createRoute({ function ProfileComponent() { const { username } = profileRoute.useRouteContext() + const posthog = usePostHog() const initials = username?.slice(0, 2).toUpperCase() ?? 'U' @@ -1049,7 +1106,10 @@ function ProfileComponent() {
Free Plan
Basic features included
- @@ -1067,6 +1127,7 @@ function ProfileComponent() {