From 1fc5f2c507e4b11548c6d545596db0737f84c224 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Mon, 16 Dec 2024 15:51:37 +0100 Subject: [PATCH 01/27] chore: prettier is arguing with itself (#1606) --- package.json | 4 +- pnpm-lock.yaml | 44 +++++++++++++------ .../error-conversion.test.ts | 5 ++- .../replay/sessionrecording.test.ts | 6 +-- src/__tests__/heatmaps.test.ts | 2 +- src/entrypoints/dead-clicks-autocapture.ts | 5 ++- .../exception-autocapture/error-conversion.ts | 10 ++--- src/extensions/replay/config.ts | 2 +- src/extensions/replay/external/README.md | 2 +- src/extensions/replay/sessionrecording.ts | 2 +- src/posthog-core.ts | 8 ++-- src/types.ts | 2 +- src/utils/event-utils.ts | 4 +- src/utils/user-agent-utils.ts | 2 +- src/web-experiments-types.ts | 9 ++-- 15 files changed, 65 insertions(+), 42 deletions(-) diff --git a/package.json b/package.json index db3588681..49cb26ee7 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "eslint-plugin-jest": "^28.8.3", "eslint-plugin-no-only-tests": "^3.1.0", "eslint-plugin-posthog-js": "link:eslint-rules", - "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-react": "^7.30.1", "eslint-plugin-react-hooks": "^4.6.0", "expect": "^29.7.0", @@ -102,7 +102,7 @@ "node-fetch": "^2.6.11", "posthog-js": "link:", "preact-render-to-string": "^6.3.1", - "prettier": "^2.7.1", + "prettier": "^3.4.2", "rollup": "^4.24.0", "rollup-plugin-dts": "^6.1.1", "rollup-plugin-visualizer": "^5.12.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c8f1cf03f..656a94c7a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -157,8 +157,8 @@ devDependencies: specifier: link:eslint-rules version: link:eslint-rules eslint-plugin-prettier: - specifier: ^4.2.1 - version: 4.2.1(eslint-config-prettier@8.5.0)(eslint@8.57.0)(prettier@2.7.1) + specifier: ^5.2.1 + version: 5.2.1(@types/eslint@8.44.6)(eslint-config-prettier@8.5.0)(eslint@8.57.0)(prettier@3.4.2) eslint-plugin-react: specifier: ^7.30.1 version: 7.30.1(eslint@8.57.0) @@ -202,8 +202,8 @@ devDependencies: specifier: ^6.3.1 version: 6.3.1(preact@10.19.3) prettier: - specifier: ^2.7.1 - version: 2.7.1 + specifier: ^3.4.2 + version: 3.4.2 rollup: specifier: ^4.24.0 version: 4.24.0 @@ -2624,6 +2624,11 @@ packages: resolution: {integrity: sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==} dev: true + /@pkgr/core@0.1.1: + resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + dev: true + /@rollup/plugin-babel@6.0.4(@babel/core@7.18.9)(rollup@4.24.0): resolution: {integrity: sha512-YF7Y52kFdFT/xVSuVdjkV5ZdX/3YtmX0QulG+x0taQOtJdHYzVU61aSSkAgVJ7NOv6qPkIYiJSgSWWN/DM5sGw==} engines: {node: '>=14.0.0'} @@ -5118,21 +5123,26 @@ packages: engines: {node: '>=5.0.0'} dev: true - /eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.5.0)(eslint@8.57.0)(prettier@2.7.1): - resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==} - engines: {node: '>=12.0.0'} + /eslint-plugin-prettier@5.2.1(@types/eslint@8.44.6)(eslint-config-prettier@8.5.0)(eslint@8.57.0)(prettier@3.4.2): + resolution: {integrity: sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==} + engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: - eslint: '>=7.28.0' + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' eslint-config-prettier: '*' - prettier: '>=2.0.0' + prettier: '>=3.0.0' peerDependenciesMeta: + '@types/eslint': + optional: true eslint-config-prettier: optional: true dependencies: + '@types/eslint': 8.44.6 eslint: 8.57.0 eslint-config-prettier: 8.5.0(eslint@8.57.0) - prettier: 2.7.1 + prettier: 3.4.2 prettier-linter-helpers: 1.0.0 + synckit: 0.9.2 dev: true /eslint-plugin-react-hooks@4.6.0(eslint@8.57.0): @@ -8744,9 +8754,9 @@ packages: fast-diff: 1.2.0 dev: true - /prettier@2.7.1: - resolution: {integrity: sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==} - engines: {node: '>=10.13.0'} + /prettier@3.4.2: + resolution: {integrity: sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==} + engines: {node: '>=14'} hasBin: true dev: true @@ -9816,6 +9826,14 @@ packages: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} dev: true + /synckit@0.9.2: + resolution: {integrity: sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==} + engines: {node: ^14.18.0 || >=16.0.0} + dependencies: + '@pkgr/core': 0.1.1 + tslib: 2.7.0 + dev: true + /temp-fs@0.9.9: resolution: {integrity: sha512-WfecDCR1xC9b0nsrzSaxPf3ZuWeWLUWblW4vlDQAa1biQaKHiImHnJfeQocQe/hXKMcolRzgkcVX/7kK4zoWbw==} engines: {node: '>=0.8.0'} diff --git a/src/__tests__/extensions/exception-autocapture/error-conversion.test.ts b/src/__tests__/extensions/exception-autocapture/error-conversion.test.ts index 16c25c83c..4882df9ec 100644 --- a/src/__tests__/extensions/exception-autocapture/error-conversion.test.ts +++ b/src/__tests__/extensions/exception-autocapture/error-conversion.test.ts @@ -96,7 +96,10 @@ describe('Error conversion', () => { }) class FakeDomError { - constructor(public name: string, public message: string) {} + constructor( + public name: string, + public message: string + ) {} [Symbol.toStringTag] = 'DOMError' } diff --git a/src/__tests__/extensions/replay/sessionrecording.test.ts b/src/__tests__/extensions/replay/sessionrecording.test.ts index 232022864..c866290c1 100644 --- a/src/__tests__/extensions/replay/sessionrecording.test.ts +++ b/src/__tests__/extensions/replay/sessionrecording.test.ts @@ -68,7 +68,7 @@ const createMetaSnapshot = (event = {}): metaEvent => href: 'https://has-to-be-present-or-invalid.com', }, ...event, - } as metaEvent) + }) as metaEvent const createStyleSnapshot = (event = {}): incrementalSnapshotEvent => ({ @@ -77,14 +77,14 @@ const createStyleSnapshot = (event = {}): incrementalSnapshotEvent => source: IncrementalSource.StyleDeclaration, }, ...event, - } as incrementalSnapshotEvent) + }) as incrementalSnapshotEvent const createFullSnapshot = (event = {}): fullSnapshotEvent => ({ type: FULL_SNAPSHOT_EVENT_TYPE, data: {}, ...event, - } as fullSnapshotEvent) + }) as fullSnapshotEvent const createIncrementalSnapshot = (event = {}): incrementalSnapshotEvent => ({ type: INCREMENTAL_SNAPSHOT_EVENT_TYPE, diff --git a/src/__tests__/heatmaps.test.ts b/src/__tests__/heatmaps.test.ts index a346cd476..cb8955261 100644 --- a/src/__tests__/heatmaps.test.ts +++ b/src/__tests__/heatmaps.test.ts @@ -21,7 +21,7 @@ describe('heatmaps', () => { clientX: 10, clientY: 20, ...props, - } as unknown as MouseEvent) + }) as unknown as MouseEvent beforeEach(async () => { beforeSendMock = beforeSendMock.mockClear() diff --git a/src/entrypoints/dead-clicks-autocapture.ts b/src/entrypoints/dead-clicks-autocapture.ts index 496879686..857fc6da3 100644 --- a/src/entrypoints/dead-clicks-autocapture.ts +++ b/src/entrypoints/dead-clicks-autocapture.ts @@ -53,7 +53,10 @@ class LazyLoadedDeadClicksAutocapture implements LazyLoadedDeadClicksAutocapture } } - constructor(readonly instance: PostHog, config?: DeadClicksAutoCaptureConfig) { + constructor( + readonly instance: PostHog, + config?: DeadClicksAutoCaptureConfig + ) { this._config = this.asRequiredConfig(config) this._onCapture = this._config.__onCapture } diff --git a/src/extensions/exception-autocapture/error-conversion.ts b/src/extensions/exception-autocapture/error-conversion.ts index b1c05612d..e6cd8d9f5 100644 --- a/src/extensions/exception-autocapture/error-conversion.ts +++ b/src/extensions/exception-autocapture/error-conversion.ts @@ -143,12 +143,12 @@ function errorPropertiesFromString(candidate: string, metadata?: ErrorMetadata): const exceptionType = metadata?.overrideExceptionType ? metadata.overrideExceptionType - : metadata?.defaultExceptionType ?? 'Error' + : (metadata?.defaultExceptionType ?? 'Error') const exceptionMessage = metadata?.overrideExceptionMessage ? metadata.overrideExceptionMessage : candidate - ? candidate - : metadata?.defaultExceptionMessage + ? candidate + : metadata?.defaultExceptionMessage const exception: Exception = { type: exceptionType, @@ -213,8 +213,8 @@ function errorPropertiesFromObject(candidate: Record, metadata? const exceptionType = metadata?.overrideExceptionType ? metadata.overrideExceptionType : isEvent(candidate) - ? candidate.constructor.name - : 'Error' + ? candidate.constructor.name + : 'Error' const exceptionMessage = metadata?.overrideExceptionMessage ? metadata.overrideExceptionMessage : `Non-Error ${'exception'} captured with keys: ${extractExceptionKeysForMessage(candidate)}` diff --git a/src/extensions/replay/config.ts b/src/extensions/replay/config.ts index 6ed58c1b7..1ec0537c6 100644 --- a/src/extensions/replay/config.ts +++ b/src/extensions/replay/config.ts @@ -247,7 +247,7 @@ export const buildNetworkRequestOptions = ( ? (data) => { const cleanedRequest = enforcedCleaningFn(data) return cleanedRequest - ? instanceConfig.session_recording.maskCapturedNetworkRequestFn?.(cleanedRequest) ?? undefined + ? (instanceConfig.session_recording.maskCapturedNetworkRequestFn?.(cleanedRequest) ?? undefined) : undefined } : (data) => scrubPayloads(enforcedCleaningFn(data)) diff --git a/src/extensions/replay/external/README.md b/src/extensions/replay/external/README.md index d9f2cc70a..d889358f1 100644 --- a/src/extensions/replay/external/README.md +++ b/src/extensions/replay/external/README.md @@ -2,4 +2,4 @@ files in here are intended for the lazy loaded portion of replay you aren't supposed to import them from outside the entrypoint file -they could cause an increase in bundle size \ No newline at end of file +they could cause an increase in bundle size diff --git a/src/extensions/replay/sessionrecording.ts b/src/extensions/replay/sessionrecording.ts index 15d070eb4..8f5d21597 100644 --- a/src/extensions/replay/sessionrecording.ts +++ b/src/extensions/replay/sessionrecording.ts @@ -1081,7 +1081,7 @@ export class SessionRecording { } const eventToSend = - this.instance.config.session_recording.compress_events ?? true ? compressEvent(event) : event + (this.instance.config.session_recording.compress_events ?? true) ? compressEvent(event) : event const size = estimateSize(eventToSend) const properties = { diff --git a/src/posthog-core.ts b/src/posthog-core.ts index 4720cf7ab..725a98daf 100644 --- a/src/posthog-core.ts +++ b/src/posthog-core.ts @@ -575,8 +575,8 @@ export class PostHog { this.compression = includes(config['supportedCompression'], Compression.GZipJS) ? Compression.GZipJS : includes(config['supportedCompression'], Compression.Base64) - ? Compression.Base64 - : undefined + ? Compression.Base64 + : undefined } if (config.analytics?.endpoint) { @@ -587,8 +587,8 @@ export class PostHog { person_profiles: this._initialPersonProfilesConfig ? this._initialPersonProfilesConfig : config['defaultIdentifiedOnly'] - ? 'identified_only' - : 'always', + ? 'identified_only' + : 'always', }) this.siteApps?.onRemoteConfig(config) diff --git a/src/types.ts b/src/types.ts index 36107d358..92dd5c7f7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -758,7 +758,7 @@ export type ErrorEventArgs = [ source?: string | undefined, lineno?: number | undefined, colno?: number | undefined, - error?: Error | undefined + error?: Error | undefined, ] export type ErrorMetadata = { diff --git a/src/utils/event-utils.ts b/src/utils/event-utils.ts index c7d9517ee..c1699630c 100644 --- a/src/utils/event-utils.ts +++ b/src/utils/event-utils.ts @@ -180,8 +180,8 @@ export const Info = { initial_referrer == null ? undefined : initial_referrer == '$direct' - ? '$direct' - : convertToURL(initial_referrer)?.host + ? '$direct' + : convertToURL(initial_referrer)?.host const props: Record = { $initial_referrer: initial_referrer, diff --git a/src/utils/user-agent-utils.ts b/src/utils/user-agent-utils.ts index bd91213fa..7a27b0b90 100644 --- a/src/utils/user-agent-utils.ts +++ b/src/utils/user-agent-utils.ts @@ -183,7 +183,7 @@ export const detectBrowserVersion = function (userAgent: string, vendor: string // the first regex that matches uses its matcher function to return the result const osMatchers: [ RegExp, - [string, string] | ((match: RegExpMatchArray | null, user_agent: string) => [string, string]) + [string, string] | ((match: RegExpMatchArray | null, user_agent: string) => [string, string]), ][] = [ [ new RegExp(XBOX + '; ' + XBOX + ' (.*?)[);]', 'i'), diff --git a/src/web-experiments-types.ts b/src/web-experiments-types.ts index abc27339c..a53bf7085 100644 --- a/src/web-experiments-types.ts +++ b/src/web-experiments-types.ts @@ -1,9 +1,8 @@ export interface WebExperimentTransform { - attributes?: - | { - name: string - value: string - }[] + attributes?: { + name: string + value: string + }[] selector?: string text?: string html?: string From 6f9e089e52a020097bd07918d0013e0ec18d48d4 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Mon, 16 Dec 2024 18:27:15 +0100 Subject: [PATCH 02/27] chore: add websockets example to nextjs playground (#1605) --- playground/nextjs/package.json | 2 + playground/nextjs/pages/_app.tsx | 7 ++ playground/nextjs/pages/api/socket.ts | 39 ++++++ playground/nextjs/pages/chat.tsx | 68 ++++++++++ playground/nextjs/pages/index.tsx | 3 + playground/nextjs/pnpm-lock.yaml | 173 +++++++++++++++++++++++++- 6 files changed, 291 insertions(+), 1 deletion(-) create mode 100644 playground/nextjs/pages/api/socket.ts create mode 100644 playground/nextjs/pages/chat.tsx diff --git a/playground/nextjs/package.json b/playground/nextjs/package.json index 9bb79d1f1..d31f6a4f2 100644 --- a/playground/nextjs/package.json +++ b/playground/nextjs/package.json @@ -24,6 +24,8 @@ "posthog-js": "1.200.1", "react": "18.3.1", "react-dom": "18.3.1", + "socket.io": "^4.8.1", + "socket.io-client": "^4.8.1", "typescript": "4.9.5" }, "devDependencies": { diff --git a/playground/nextjs/pages/_app.tsx b/playground/nextjs/pages/_app.tsx index 0e392ccc2..9988daa3a 100644 --- a/playground/nextjs/pages/_app.tsx +++ b/playground/nextjs/pages/_app.tsx @@ -33,6 +33,13 @@ export default function App({ Component, pageProps }: AppProps) { } }, []) + useEffect(() => { + // make sure we initialize the WebSocket server + // we don't need to support IE11 here + // eslint-disable-next-line compat/compat + fetch('/api/socket') + }, []) + const localhostDomain = process.env.NEXT_PUBLIC_CROSSDOMAIN ? 'https://localhost:8000' : process.env.NEXT_PUBLIC_POSTHOG_HOST diff --git a/playground/nextjs/pages/api/socket.ts b/playground/nextjs/pages/api/socket.ts new file mode 100644 index 000000000..80d40b23a --- /dev/null +++ b/playground/nextjs/pages/api/socket.ts @@ -0,0 +1,39 @@ +import { Server } from 'socket.io' +import type { NextApiRequest, NextApiResponse } from 'next' +import type { Server as HttpServer } from 'http' +import type { Socket as NetSocket } from 'net' + +// Extend the response object to include the custom `io` property +interface CustomServer extends HttpServer { + io?: Server +} + +interface CustomNetSocket extends NetSocket { + server: CustomServer +} + +interface CustomNextApiResponse extends NextApiResponse { + socket: CustomNetSocket +} + +export default function handler(req: NextApiRequest, res: CustomNextApiResponse) { + if (!res.socket.server.io) { + const io = new Server(res.socket.server) + res.socket.server.io = io + + io.on('connection', (socket) => { + // eslint-disable-next-line no-console + console.log('User connected', socket.id) + + socket.on('send chat message', (msg) => { + socket.emit('message', msg) + }) + + socket.on('disconnect', () => { + // eslint-disable-next-line no-console + console.log('User disconnected', socket.id) + }) + }) + } + res.end() +} diff --git a/playground/nextjs/pages/chat.tsx b/playground/nextjs/pages/chat.tsx new file mode 100644 index 000000000..c1d21f205 --- /dev/null +++ b/playground/nextjs/pages/chat.tsx @@ -0,0 +1,68 @@ +import { useState, useEffect } from 'react' +import io, { Socket } from 'socket.io-client' +import { DefaultEventsMap } from 'socket.io' + +const Chat = () => { + // State to store the messages + const [messages, setMessages] = useState([]) + // State to store the current message + const [currentMessage, setCurrentMessage] = useState('') + const [socket, setSocket] = useState | null>(null) + + useEffect(() => { + // Create a socket connection + const createdSocket = io() + + // Listen for incoming messages + createdSocket.on('message', (message) => { + setMessages((prevMessages) => [...prevMessages, message]) + }) + + setSocket(createdSocket) + + // Clean up the socket connection on unmount + return () => { + createdSocket.disconnect() + } + }, []) + + const sendMessage = () => { + if (!socket) { + // eslint-disable-next-line no-console + console.log('socket not running, ruh roh!') + return + } + + socket.emit('send chat message', currentMessage) + setCurrentMessage('') + } + + return ( +
+
+ setCurrentMessage(e.target.value)} + /> + + +
+ +
+ {messages?.length === 0 &&

No messages yet

} + {/* Display the messages */} + {messages + .filter((m) => !!m.trim().length) + .map((message, index) => ( +

+ {message} +

+ ))} +
+
+ ) +} + +export default Chat diff --git a/playground/nextjs/pages/index.tsx b/playground/nextjs/pages/index.tsx index 77f0f3ff0..1ec2b8ce2 100644 --- a/playground/nextjs/pages/index.tsx +++ b/playground/nextjs/pages/index.tsx @@ -43,6 +43,9 @@ export default function Home() { Autocapture a > span + + REAL TIME CHAT OMG +