From dc7aad1abfbd16808c7eb9f345b4f156e0aed4a3 Mon Sep 17 00:00:00 2001 From: James Salter Date: Tue, 3 Aug 2021 11:55:02 +0100 Subject: [PATCH 1/8] Revert "Revert "Add support for Posthog Analytics under a labs flag"" This reverts commit c5ea2531817e2d254692dd48bc4985184528233d. --- package.json | 1 + src/@types/posthog.d.ts | 748 ++++++++++++++++++ src/Lifecycle.ts | 5 + src/PosthogAnalytics.ts | 355 +++++++++ src/components/structures/MatrixChat.tsx | 6 + .../tabs/user/SecurityUserSettingsTab.js | 2 + src/i18n/strings/en_EN.json | 1 + src/settings/Settings.tsx | 8 + .../PseudonymousAnalyticsController.ts | 26 + test/PosthogAnalytics-test.ts | 232 ++++++ tsconfig.json | 9 +- yarn.lock | 12 + 12 files changed, 1403 insertions(+), 2 deletions(-) create mode 100644 src/@types/posthog.d.ts create mode 100644 src/PosthogAnalytics.ts create mode 100644 src/settings/controllers/PseudonymousAnalyticsController.ts create mode 100644 test/PosthogAnalytics-test.ts diff --git a/package.json b/package.json index 9744aa7685..b7e06fe012 100644 --- a/package.json +++ b/package.json @@ -87,6 +87,7 @@ "pako": "^2.0.3", "parse5": "^6.0.1", "png-chunks-extract": "^1.0.0", + "posthog-js": "1.12.1", "prop-types": "^15.7.2", "qrcode": "^1.4.4", "re-resizable": "^6.9.0", diff --git a/src/@types/posthog.d.ts b/src/@types/posthog.d.ts new file mode 100644 index 0000000000..1ca475cd3b --- /dev/null +++ b/src/@types/posthog.d.ts @@ -0,0 +1,748 @@ +// A clone of the type definitions from posthog-js, stripped of references to transitive +// dependencies which we don't actually use, so that we don't need to install them. +// +// Original file lives in node_modules/posthog/dist/module.d.ts + +/* eslint-disable @typescript-eslint/member-delimiter-style */ +/* eslint-disable @typescript-eslint/naming-convention */ +/* eslint-disable camelcase */ + +// Type definitions for exported methods + +declare class posthog { + /** + * This function initializes a new instance of the PostHog capturing object. + * All new instances are added to the main posthog object as sub properties (such as + * posthog.library_name) and also returned by this function. To define a + * second instance on the page, you would call: + * + * posthog.init('new token', { your: 'config' }, 'library_name'); + * + * and use it like so: + * + * posthog.library_name.capture(...); + * + * @param {String} token Your PostHog API token + * @param {Object} [config] A dictionary of config options to override. See a list of default config options. + * @param {String} [name] The name for the new posthog instance that you want created + */ + static init(token: string, config?: posthog.Config, name?: string): posthog + + /** + * Clears super properties and generates a new random distinct_id for this instance. + * Useful for clearing data when a user logs out. + */ + static reset(reset_device_id?: boolean): void + + /** + * Capture an event. This is the most important and + * frequently used PostHog function. + * + * ### Usage: + * + * // capture an event named 'Registered' + * posthog.capture('Registered', {'Gender': 'Male', 'Age': 21}); + * + * // capture an event using navigator.sendBeacon + * posthog.capture('Left page', {'duration_seconds': 35}, {transport: 'sendBeacon'}); + * + * @param {String} event_name The name of the event. This can be anything the user does - 'Button Click', 'Sign Up', 'Item Purchased', etc. + * @param {Object} [properties] A set of properties to include with the event you're sending. These describe the user who did the event or details about the event itself. + * @param {Object} [options] Optional configuration for this capture request. + * @param {String} [options.transport] Transport method for network request ('XHR' or 'sendBeacon'). + */ + static capture( + event_name: string, + properties?: posthog.Properties, + options?: { transport: 'XHR' | 'sendBeacon' } + ): posthog.CaptureResult + + /** + * Capture a page view event, which is currently ignored by the server. + * This function is called by default on page load unless the + * capture_pageview configuration variable is false. + * + * @param {String} [page] The url of the page to record. If you don't include this, it defaults to the current url. + * @api private + */ + static capture_pageview(page?: string): void + + /** + * Register a set of super properties, which are included with all + * events. This will overwrite previous super property values. + * + * ### Usage: + * + * // register 'Gender' as a super property + * posthog.register({'Gender': 'Female'}); + * + * // register several super properties when a user signs up + * posthog.register({ + * 'Email': 'jdoe@example.com', + * 'Account Type': 'Free' + * }); + * + * @param {Object} properties An associative array of properties to store about the user + * @param {Number} [days] How many days since the user's last visit to store the super properties + */ + static register(properties: posthog.Properties, days?: number): void + + /** + * Register a set of super properties only once. This will not + * overwrite previous super property values, unlike register(). + * + * ### Usage: + * + * // register a super property for the first time only + * posthog.register_once({ + * 'First Login Date': new Date().toISOString() + * }); + * + * ### Notes: + * + * If default_value is specified, current super properties + * with that value will be overwritten. + * + * @param {Object} properties An associative array of properties to store about the user + * @param {*} [default_value] Value to override if already set in super properties (ex: 'False') Default: 'None' + * @param {Number} [days] How many days since the users last visit to store the super properties + */ + static register_once(properties: posthog.Properties, default_value?: posthog.Property, days?: number): void + + /** + * Delete a super property stored with the current user. + * + * @param {String} property The name of the super property to remove + */ + static unregister(property: string): void + + /** + * Identify a user with a unique ID instead of a PostHog + * randomly generated distinct_id. If the method is never called, + * then unique visitors will be identified by a UUID generated + * the first time they visit the site. + * + * If user properties are passed, they are also sent to posthog. + * + * ### Usage: + * + * posthog.identify('[user unique id]') + * posthog.identify('[user unique id]', { email: 'john@example.com' }) + * posthog.identify('[user unique id]', {}, { referral_code: '12345' }) + * + * ### Notes: + * + * You can call this function to overwrite a previously set + * unique ID for the current user. PostHog cannot translate + * between IDs at this time, so when you change a user's ID + * they will appear to be a new user. + * + * When used alone, posthog.identify will change the user's + * distinct_id to the unique ID provided. When used in tandem + * with posthog.alias, it will allow you to identify based on + * unique ID and map that back to the original, anonymous + * distinct_id given to the user upon her first arrival to your + * site (thus connecting anonymous pre-signup activity to + * post-signup activity). Though the two work together, do not + * call identify() at the same time as alias(). Calling the two + * at the same time can cause a race condition, so it is best + * practice to call identify on the original, anonymous ID + * right after you've aliased it. + * + * @param {String} [unique_id] A string that uniquely identifies a user. If not provided, the distinct_id currently in the persistent store (cookie or localStorage) will be used. + * @param {Object} [userProperties] Optional: An associative array of properties to store about the user + * @param {Object} [userPropertiesToSetOnce] Optional: An associative array of properties to store about the user. If property is previously set, this does not override that value. + */ + static identify( + unique_id?: string, + userPropertiesToSet?: posthog.Properties, + userPropertiesToSetOnce?: posthog.Properties + ): void + + /** + * Create an alias, which PostHog will use to link two distinct_ids going forward (not retroactively). + * Multiple aliases can map to the same original ID, but not vice-versa. Aliases can also be chained - the + * following is a valid scenario: + * + * posthog.alias('new_id', 'existing_id'); + * ... + * posthog.alias('newer_id', 'new_id'); + * + * If the original ID is not passed in, we will use the current distinct_id - probably the auto-generated GUID. + * + * ### Notes: + * + * The best practice is to call alias() when a unique ID is first created for a user + * (e.g., when a user first registers for an account and provides an email address). + * alias() should never be called more than once for a given user, except to + * chain a newer ID to a previously new ID, as described above. + * + * @param {String} alias A unique identifier that you want to use for this user in the future. + * @param {String} [original] The current identifier being used for this user. + */ + static alias(alias: string, original?: string): posthog.CaptureResult | number + + /** + * Update the configuration of a posthog library instance. + * + * The default config is: + * + * { + * // HTTP method for capturing requests + * api_method: 'POST' + * + * // transport for sending requests ('XHR' or 'sendBeacon') + * // NB: sendBeacon should only be used for scenarios such as + * // page unload where a "best-effort" attempt to send is + * // acceptable; the sendBeacon API does not support callbacks + * // or any way to know the result of the request. PostHog + * // capturing via sendBeacon will not support any event- + * // batching or retry mechanisms. + * api_transport: 'XHR' + * + * // Automatically capture clicks, form submissions and change events + * autocapture: true + * + * // Capture rage clicks (beta) - useful for session recording + * rageclick: false + * + * // super properties cookie expiration (in days) + * cookie_expiration: 365 + * + * // super properties span subdomains + * cross_subdomain_cookie: true + * + * // debug mode + * debug: false + * + * // if this is true, the posthog cookie or localStorage entry + * // will be deleted, and no user persistence will take place + * disable_persistence: false + * + * // if this is true, PostHog will automatically determine + * // City, Region and Country data using the IP address of + * //the client + * ip: true + * + * // opt users out of capturing by this PostHog instance by default + * opt_out_capturing_by_default: false + * + * // opt users out of browser data storage by this PostHog instance by default + * opt_out_persistence_by_default: false + * + * // persistence mechanism used by opt-in/opt-out methods - cookie + * // or localStorage - falls back to cookie if localStorage is unavailable + * opt_out_capturing_persistence_type: 'localStorage' + * + * // customize the name of cookie/localStorage set by opt-in/opt-out methods + * opt_out_capturing_cookie_prefix: null + * + * // type of persistent store for super properties (cookie/ + * // localStorage) if set to 'localStorage', any existing + * // posthog cookie value with the same persistence_name + * // will be transferred to localStorage and deleted + * persistence: 'cookie' + * + * // name for super properties persistent store + * persistence_name: '' + * + * // names of properties/superproperties which should never + * // be sent with capture() calls + * property_blacklist: [] + * + * // if this is true, posthog cookies will be marked as + * // secure, meaning they will only be transmitted over https + * secure_cookie: false + * + * // should we capture a page view on page load + * capture_pageview: true + * + * // if you set upgrade to be true, the library will check for + * // a cookie from our old js library and import super + * // properties from it, then the old cookie is deleted + * // The upgrade config option only works in the initialization, + * // so make sure you set it when you create the library. + * upgrade: false + * + * // extra HTTP request headers to set for each API request, in + * // the format {'Header-Name': value} + * xhr_headers: {} + * + * // protocol for fetching in-app message resources, e.g. + * // 'https://' or 'http://'; defaults to '//' (which defers to the + * // current page's protocol) + * inapp_protocol: '//' + * + * // whether to open in-app message link in new tab/window + * inapp_link_new_window: false + * + * // a set of rrweb config options that PostHog users can configure + * // see https://github.com/rrweb-io/rrweb/blob/master/guide.md + * session_recording: { + * blockClass: 'ph-no-capture', + * blockSelector: null, + * ignoreClass: 'ph-ignore-input', + * maskAllInputs: false, + * maskInputOptions: {}, + * maskInputFn: null, + * slimDOMOptions: {}, + * collectFonts: false + * } + * + * // prevent autocapture from capturing any attribute names on elements + * mask_all_element_attributes: false + * + * // prevent autocapture from capturing textContent on all elements + * mask_all_text: false + * + * // will disable requests to the /decide endpoint (please review documentation for details) + * // autocapture, feature flags, compression and session recording will be disabled when set to `true` + * advanced_disable_decide: false + * + * } + * + * + * @param {Object} config A dictionary of new configuration values to update + */ + static set_config(config: posthog.Config): void + + /** + * returns the current config object for the library. + */ + static get_config(prop_name: T): posthog.Config[T] + + /** + * Returns the value of the super property named property_name. If no such + * property is set, get_property() will return the undefined value. + * + * ### Notes: + * + * get_property() can only be called after the PostHog library has finished loading. + * init() has a loaded function available to handle this automatically. For example: + * + * // grab value for 'user_id' after the posthog library has loaded + * posthog.init('YOUR PROJECT TOKEN', { + * loaded: function(posthog) { + * user_id = posthog.get_property('user_id'); + * } + * }); + * + * @param {String} property_name The name of the super property you want to retrieve + */ + static get_property(property_name: string): posthog.Property | undefined + + /** + * Returns the current distinct id of the user. This is either the id automatically + * generated by the library or the id that has been passed by a call to identify(). + * + * ### Notes: + * + * get_distinct_id() can only be called after the PostHog library has finished loading. + * init() has a loaded function available to handle this automatically. For example: + * + * // set distinct_id after the posthog library has loaded + * posthog.init('YOUR PROJECT TOKEN', { + * loaded: function(posthog) { + * distinct_id = posthog.get_distinct_id(); + * } + * }); + */ + static get_distinct_id(): string + + /** + * Opt the user out of data capturing and cookies/localstorage for this PostHog instance + * + * ### Usage + * + * // opt user out + * posthog.opt_out_capturing(); + * + * // opt user out with different cookie configuration from PostHog instance + * posthog.opt_out_capturing({ + * cookie_expiration: 30, + * secure_cookie: true + * }); + * + * @param {Object} [options] A dictionary of config options to override + * @param {boolean} [options.clear_persistence=true] If true, will delete all data stored by the sdk in persistence + * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable + * @param {string} [options.cookie_prefix=__ph_opt_in_out] Custom prefix to be used in the cookie/localstorage name + * @param {Number} [options.cookie_expiration] Number of days until the opt-in cookie expires (overrides value specified in this PostHog instance's config) + * @param {boolean} [options.cross_subdomain_cookie] Whether the opt-in cookie is set as cross-subdomain or not (overrides value specified in this PostHog instance's config) + * @param {boolean} [options.secure_cookie] Whether the opt-in cookie is set as secure or not (overrides value specified in this PostHog instance's config) + */ + static opt_out_capturing(options?: posthog.OptInOutCapturingOptions): void + + /** + * Opt the user in to data capturing and cookies/localstorage for this PostHog instance + * + * ### Usage + * + * // opt user in + * posthog.opt_in_capturing(); + * + * // opt user in with specific event name, properties, cookie configuration + * posthog.opt_in_capturing({ + * capture_event_name: 'User opted in', + * capture_event_properties: { + * 'Email': 'jdoe@example.com' + * }, + * cookie_expiration: 30, + * secure_cookie: true + * }); + * + * @param {Object} [options] A dictionary of config options to override + * @param {function} [options.capture] Function used for capturing a PostHog event to record the opt-in action (default is this PostHog instance's capture method) + * @param {string} [options.capture_event_name=$opt_in] Event name to be used for capturing the opt-in action + * @param {Object} [options.capture_properties] Set of properties to be captured along with the opt-in action + * @param {boolean} [options.enable_persistence=true] If true, will re-enable sdk persistence + * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable + * @param {string} [options.cookie_prefix=__ph_opt_in_out] Custom prefix to be used in the cookie/localstorage name + * @param {Number} [options.cookie_expiration] Number of days until the opt-in cookie expires (overrides value specified in this PostHog instance's config) + * @param {boolean} [options.cross_subdomain_cookie] Whether the opt-in cookie is set as cross-subdomain or not (overrides value specified in this PostHog instance's config) + * @param {boolean} [options.secure_cookie] Whether the opt-in cookie is set as secure or not (overrides value specified in this PostHog instance's config) + */ + static opt_in_capturing(options?: posthog.OptInOutCapturingOptions): void + + /** + * Check whether the user has opted out of data capturing and cookies/localstorage for this PostHog instance + * + * ### Usage + * + * const has_opted_out = posthog.has_opted_out_capturing(); + * // use has_opted_out value + * + * @param {Object} [options] A dictionary of config options to override + * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable + * @param {string} [options.cookie_prefix=__ph_opt_in_out] Custom prefix to be used in the cookie/localstorage name + * @returns {boolean} current opt-out status + */ + static has_opted_out_capturing(options?: posthog.HasOptedInOutCapturingOptions): boolean + + /** + * Check whether the user has opted in to data capturing and cookies/localstorage for this PostHog instance + * + * ### Usage + * + * const has_opted_in = posthog.has_opted_in_capturing(); + * // use has_opted_in value + * + * @param {Object} [options] A dictionary of config options to override + * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable + * @param {string} [options.cookie_prefix=__ph_opt_in_out] Custom prefix to be used in the cookie/localstorage name + * @returns {boolean} current opt-in status + */ + static has_opted_in_capturing(options?: posthog.HasOptedInOutCapturingOptions): boolean + + /** + * Clear the user's opt in/out status of data capturing and cookies/localstorage for this PostHog instance + * + * ### Usage + * + * // clear user's opt-in/out status + * posthog.clear_opt_in_out_capturing(); + * + * // clear user's opt-in/out status with specific cookie configuration - should match + * // configuration used when opt_in_capturing/opt_out_capturing methods were called. + * posthog.clear_opt_in_out_capturing({ + * cookie_expiration: 30, + * secure_cookie: true + * }); + * + * @param {Object} [options] A dictionary of config options to override + * @param {boolean} [options.enable_persistence=true] If true, will re-enable sdk persistence + * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable + * @param {string} [options.cookie_prefix=__ph_opt_in_out] Custom prefix to be used in the cookie/localstorage name + * @param {Number} [options.cookie_expiration] Number of days until the opt-in cookie expires (overrides value specified in this PostHog instance's config) + * @param {boolean} [options.cross_subdomain_cookie] Whether the opt-in cookie is set as cross-subdomain or not (overrides value specified in this PostHog instance's config) + * @param {boolean} [options.secure_cookie] Whether the opt-in cookie is set as secure or not (overrides value specified in this PostHog instance's config) + */ + static clear_opt_in_out_capturing(options?: posthog.ClearOptInOutCapturingOptions): void + + /* + * See if feature flag is enabled for user. + * + * ### Usage: + * + * if(posthog.isFeatureEnabled('beta-feature')) { // do something } + * + * @param {Object|String} prop Key of the feature flag. + * @param {Object|String} options (optional) If {send_event: false}, we won't send an $feature_flag_call event to PostHog. + */ + static isFeatureEnabled(key: string, options?: posthog.isFeatureEnabledOptions): boolean + + /* + * See if feature flags are available. + * + * ### Usage: + * + * posthog.onFeatureFlags(function(featureFlags) { // do something }) + * + * @param {Function} [callback] The callback function will be called once the feature flags are ready. It'll return a list of feature flags enabled for the user. + */ + static onFeatureFlags(callback: (flags: string[]) => void): false | undefined + + /* + * Reload all feature flags for the user. + * + * ### Usage: + * + * posthog.reloadFeatureFlags() + */ + static reloadFeatureFlags(): void + + static toString(): string + + /* Will log all capture requests to the Javascript console, including event properties for easy debugging */ + static debug(): void + + /* + * Starts session recording and updates disable_session_recording to false. + * Used for manual session recording management. By default, session recording is enabled and + * starts automatically. + * + * ### Usage: + * + * posthog.startSessionRecording() + */ + static startSessionRecording(): void + + /* + * Stops session recording and updates disable_session_recording to true. + * + * ### Usage: + * + * posthog.stopSessionRecording() + */ + static stopSessionRecording(): void + + /* + * Check if session recording is currently running. + * + * ### Usage: + * + * const isSessionRecordingOn = posthog.sessionRecordingStarted() + */ + static sessionRecordingStarted(): boolean +} + +declare namespace posthog { + /* eslint-disable @typescript-eslint/no-explicit-any */ + type Property = any; + type Properties = Record; + type CaptureResult = { event: string; properties: Properties } | undefined; + type CaptureCallback = (response: any, data: any) => void; + /* eslint-enable @typescript-eslint/no-explicit-any */ + + interface Config { + api_host?: string + api_method?: string + api_transport?: string + autocapture?: boolean + rageclick?: boolean + cdn?: string + cross_subdomain_cookie?: boolean + persistence?: 'localStorage' | 'cookie' | 'memory' + persistence_name?: string + cookie_name?: string + loaded?: (posthog_instance: typeof posthog) => void + store_google?: boolean + save_referrer?: boolean + test?: boolean + verbose?: boolean + img?: boolean + capture_pageview?: boolean + debug?: boolean + cookie_expiration?: number + upgrade?: boolean + disable_session_recording?: boolean + disable_persistence?: boolean + disable_cookie?: boolean + secure_cookie?: boolean + ip?: boolean + opt_out_capturing_by_default?: boolean + opt_out_persistence_by_default?: boolean + opt_out_capturing_persistence_type?: 'localStorage' | 'cookie' + opt_out_capturing_cookie_prefix?: string | null + respect_dnt?: boolean + property_blacklist?: string[] + xhr_headers?: { [header_name: string]: string } + inapp_protocol?: string + inapp_link_new_window?: boolean + request_batching?: boolean + sanitize_properties?: (properties: posthog.Properties, event_name: string) => posthog.Properties + properties_string_max_length?: number + mask_all_element_attributes?: boolean + mask_all_text?: boolean + advanced_disable_decide?: boolean + } + + interface OptInOutCapturingOptions { + clear_persistence: boolean + persistence_type: string + cookie_prefix: string + cookie_expiration: number + cross_subdomain_cookie: boolean + secure_cookie: boolean + } + + interface HasOptedInOutCapturingOptions { + persistence_type: string + cookie_prefix: string + } + + interface ClearOptInOutCapturingOptions { + enable_persistence: boolean + persistence_type: string + cookie_prefix: string + cookie_expiration: number + cross_subdomain_cookie: boolean + secure_cookie: boolean + } + + interface isFeatureEnabledOptions { + send_event: boolean + } + + export class persistence { + static properties(): posthog.Properties + + static load(): void + + static save(): void + + static remove(): void + + static clear(): void + + /** + * @param {Object} props + * @param {*=} default_value + * @param {number=} days + */ + static register_once(props: Properties, default_value?: Property, days?: number): boolean + + /** + * @param {Object} props + * @param {number=} days + */ + static register(props: posthog.Properties, days?: number): boolean + + static unregister(prop: string): void + + static update_campaign_params(): void + + static update_search_keyword(referrer: string): void + + static update_referrer_info(referrer: string): void + + static get_referrer_info(): posthog.Properties + + static safe_merge(props: posthog.Properties): posthog.Properties + + static update_config(config: posthog.Config): void + + static set_disabled(disabled: boolean): void + + static set_cross_subdomain(cross_subdomain: boolean): void + + static get_cross_subdomain(): boolean + + static set_secure(secure: boolean): void + + static set_event_timer(event_name: string, timestamp: Date): void + + static remove_event_timer(event_name: string): Date | undefined + } + + export class people { + /* + * Set properties on a user record. + * + * ### Usage: + * + * posthog.people.set('gender', 'm'); + * + * // or set multiple properties at once + * posthog.people.set({ + * 'Company': 'Acme', + * 'Plan': 'Premium', + * 'Upgrade date': new Date() + * }); + * // properties can be strings, integers, dates, or lists + * + * @param {Object|String} prop If a string, this is the name of the property. If an object, this is an associative array of names and values. + * @param {*} [to] A value to set on the given property name + * @param {Function} [callback] If provided, the callback will be called after capturing the event. + */ + static set( + prop: posthog.Properties | string, + to?: posthog.Property, + callback?: posthog.CaptureCallback + ): posthog.Properties + + /* + * Set properties on a user record, only if they do not yet exist. + * This will not overwrite previous people property values, unlike + * people.set(). + * + * ### Usage: + * + * posthog.people.set_once('First Login Date', new Date()); + * + * // or set multiple properties at once + * posthog.people.set_once({ + * 'First Login Date': new Date(), + * 'Starting Plan': 'Premium' + * }); + * + * // properties can be strings, integers or dates + * + * @param {Object|String} prop If a string, this is the name of the property. If an object, this is an associative array of names and values. + * @param {*} [to] A value to set on the given property name + * @param {Function} [callback] If provided, the callback will be called after capturing the event. + */ + static set_once( + prop: posthog.Properties | string, + to?: posthog.Property, + callback?: posthog.CaptureCallback + ): posthog.Properties + + static toString(): string + } + + export class featureFlags { + static getFlags(): string[] + + static reloadFeatureFlags(): void + + /* + * See if feature flag is enabled for user. + * + * ### Usage: + * + * if(posthog.isFeatureEnabled('beta-feature')) { // do something } + * + * @param {Object|String} prop Key of the feature flag. + * @param {Object|String} options (optional) If {send_event: false}, we won't send an $feature_flag_call event to PostHog. + */ + static isFeatureEnabled(key: string, options?: { send_event?: boolean }): boolean + + /* + * See if feature flags are available. + * + * ### Usage: + * + * posthog.onFeatureFlags(function(featureFlags) { // do something }) + * + * @param {Function} [callback] The callback function will be called once the feature flags are ready. It'll return a list of feature flags enabled for the user. + */ + static onFeatureFlags(callback: (flags: string[]) => void): false | undefined + } + + export class feature_flags extends featureFlags {} +} + +export type PostHog = typeof posthog; + +export default posthog; diff --git a/src/Lifecycle.ts b/src/Lifecycle.ts index 410124a637..e48fd52cb1 100644 --- a/src/Lifecycle.ts +++ b/src/Lifecycle.ts @@ -48,6 +48,7 @@ import { Jitsi } from "./widgets/Jitsi"; import { SSO_HOMESERVER_URL_KEY, SSO_ID_SERVER_URL_KEY, SSO_IDP_ID_KEY } from "./BasePlatform"; import ThreepidInviteStore from "./stores/ThreepidInviteStore"; import CountlyAnalytics from "./CountlyAnalytics"; +import { PosthogAnalytics } from "./PosthogAnalytics"; import CallHandler from './CallHandler'; import LifecycleCustomisations from "./customisations/Lifecycle"; import ErrorDialog from "./components/views/dialogs/ErrorDialog"; @@ -573,6 +574,8 @@ async function doSetLoggedIn( await abortLogin(); } + PosthogAnalytics.instance.updateAnonymityFromSettings(credentials.userId); + Analytics.setLoggedIn(credentials.guest, credentials.homeserverUrl); MatrixClientPeg.replaceUsingCreds(credentials); @@ -700,6 +703,8 @@ export function logout(): void { CountlyAnalytics.instance.enable(/* anonymous = */ true); } + PosthogAnalytics.instance.logout(); + if (MatrixClientPeg.get().isGuest()) { // logout doesn't work for guest sessions // Also we sometimes want to re-log in a guest session if we abort the login. diff --git a/src/PosthogAnalytics.ts b/src/PosthogAnalytics.ts new file mode 100644 index 0000000000..860a155aff --- /dev/null +++ b/src/PosthogAnalytics.ts @@ -0,0 +1,355 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import posthog, { PostHog } from 'posthog-js'; +import PlatformPeg from './PlatformPeg'; +import SdkConfig from './SdkConfig'; +import SettingsStore from './settings/SettingsStore'; + +/* Posthog analytics tracking. + * + * Anonymity behaviour is as follows: + * + * - If Posthog isn't configured in `config.json`, events are not sent. + * - If [Do Not Track](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/doNotTrack) is + * enabled, events are not sent (this detection is built into posthog and turned on via the + * `respect_dnt` flag being passed to `posthog.init`). + * - If the `feature_pseudonymous_analytics_opt_in` labs flag is `true`, track pseudonomously, i.e. + * hash all matrix identifiers in tracking events (user IDs, room IDs etc) using SHA-256. + * - Otherwise, if the existing `analyticsOptIn` flag is `true`, track anonymously, i.e. + * redact all matrix identifiers in tracking events. + * - If both flags are false or not set, events are not sent. + */ + +interface IEvent { + // The event name that will be used by PostHog. Event names should use snake_case. + eventName: string; + + // The properties of the event that will be stored in PostHog. This is just a placeholder, + // extending interfaces must override this with a concrete definition to do type validation. + properties: {}; +} + +export enum Anonymity { + Disabled, + Anonymous, + Pseudonymous +} + +// If an event extends IPseudonymousEvent, the event contains pseudonymous data +// that won't be sent unless the user has explicitly consented to pseudonymous tracking. +// For example, it might contain hashed user IDs or room IDs. +// Such events will be automatically dropped if PosthogAnalytics.anonymity isn't set to Pseudonymous. +export interface IPseudonymousEvent extends IEvent {} + +// If an event extends IAnonymousEvent, the event strictly contains *only* anonymous data; +// i.e. no identifiers that can be associated with the user. +export interface IAnonymousEvent extends IEvent {} + +export interface IRoomEvent extends IPseudonymousEvent { + hashedRoomId: string; +} + +interface IPageView extends IAnonymousEvent { + eventName: "$pageview"; + properties: { + durationMs?: number; + screen?: string; + }; +} + +const hashHex = async (input: string): Promise => { + const buf = new TextEncoder().encode(input); + const digestBuf = await window.crypto.subtle.digest("sha-256", buf); + return [...new Uint8Array(digestBuf)].map((b: number) => b.toString(16).padStart(2, "0")).join(""); +}; + +const whitelistedScreens = new Set([ + "register", "login", "forgot_password", "soft_logout", "new", "settings", "welcome", "home", "start", "directory", + "start_sso", "start_cas", "groups", "complete_security", "post_registration", "room", "user", "group", +]); + +export async function getRedactedCurrentLocation( + origin: string, + hash: string, + pathname: string, + anonymity: Anonymity, +): Promise { + // Redact PII from the current location. + // If anonymous is true, redact entirely, if false, substitute it with a hash. + // For known screens, assumes a URL structure of //might/be/pii + if (origin.startsWith('file://')) { + pathname = "//"; + } + + let hashStr; + if (hash == "") { + hashStr = ""; + } else { + let [beforeFirstSlash, screen, ...parts] = hash.split("/"); + + if (!whitelistedScreens.has(screen)) { + screen = ""; + } + + for (let i = 0; i < parts.length; i++) { + parts[i] = anonymity === Anonymity.Anonymous ? `` : await hashHex(parts[i]); + } + + hashStr = `${beforeFirstSlash}/${screen}/${parts.join("/")}`; + } + return origin + pathname + hashStr; +} + +interface PlatformProperties { + appVersion: string; + appPlatform: string; +} + +export class PosthogAnalytics { + /* Wrapper for Posthog analytics. + * 3 modes of anonymity are supported, governed by this.anonymity + * - Anonymity.Disabled means *no data* is passed to posthog + * - Anonymity.Anonymous means all identifers will be redacted before being passed to posthog + * - Anonymity.Pseudonymous means all identifiers will be hashed via SHA-256 before being passed + * to Posthog + * + * To update anonymity, call updateAnonymityFromSettings() or you can set it directly via setAnonymity(). + * + * To pass an event to Posthog: + * + * 1. Declare a type for the event, extending IAnonymousEvent, IPseudonymousEvent or IRoomEvent. + * 2. Call the appropriate track*() method. Pseudonymous events will be dropped when anonymity is + * Anonymous or Disabled; Anonymous events will be dropped when anonymity is Disabled. + */ + + private anonymity = Anonymity.Disabled; + // set true during the constructor if posthog config is present, otherwise false + private enabled = false; + private static _instance = null; + private platformSuperProperties = {}; + + public static get instance(): PosthogAnalytics { + if (!this._instance) { + this._instance = new PosthogAnalytics(posthog); + } + return this._instance; + } + + constructor(private readonly posthog: PostHog) { + const posthogConfig = SdkConfig.get()["posthog"]; + if (posthogConfig) { + this.posthog.init(posthogConfig.projectApiKey, { + api_host: posthogConfig.apiHost, + autocapture: false, + mask_all_text: true, + mask_all_element_attributes: true, + // This only triggers on page load, which for our SPA isn't particularly useful. + // Plus, the .capture call originating from somewhere in posthog makes it hard + // to redact URLs, which requires async code. + // + // To raise this manually, just call .capture("$pageview") or posthog.capture_pageview. + capture_pageview: false, + sanitize_properties: this.sanitizeProperties, + respect_dnt: true, + }); + this.enabled = true; + } else { + this.enabled = false; + } + } + + private sanitizeProperties = (properties: posthog.Properties): posthog.Properties => { + // Callback from posthog to sanitize properties before sending them to the server. + // + // Here we sanitize posthog's built in properties which leak PII e.g. url reporting. + // See utils.js _.info.properties in posthog-js. + + // Replace the $current_url with a redacted version. + // $redacted_current_url is injected by this class earlier in capture(), as its generation + // is async and can't be done in this non-async callback. + if (!properties['$redacted_current_url']) { + console.log("$redacted_current_url not set in sanitizeProperties, will drop $current_url entirely"); + } + properties['$current_url'] = properties['$redacted_current_url']; + delete properties['$redacted_current_url']; + + if (this.anonymity == Anonymity.Anonymous) { + // drop referrer information for anonymous users + properties['$referrer'] = null; + properties['$referring_domain'] = null; + properties['$initial_referrer'] = null; + properties['$initial_referring_domain'] = null; + + // drop device ID, which is a UUID persisted in local storage + properties['$device_id'] = null; + } + + return properties; + }; + + private static getAnonymityFromSettings(): Anonymity { + // determine the current anonymity level based on current user settings + + // "Send anonymous usage data which helps us improve Element. This will use a cookie." + const analyticsOptIn = SettingsStore.getValue("analyticsOptIn", null, true); + + // (proposed wording) "Send pseudonymous usage data which helps us improve Element. This will use a cookie." + // + // TODO: Currently, this is only a labs flag, for testing purposes. + const pseudonumousOptIn = SettingsStore.getValue("feature_pseudonymous_analytics_opt_in", null, true); + + let anonymity; + if (pseudonumousOptIn) { + anonymity = Anonymity.Pseudonymous; + } else if (analyticsOptIn) { + anonymity = Anonymity.Anonymous; + } else { + anonymity = Anonymity.Disabled; + } + + return anonymity; + } + + private registerSuperProperties(properties: posthog.Properties) { + if (this.enabled) { + this.posthog.register(properties); + } + } + + private static async getPlatformProperties(): Promise { + const platform = PlatformPeg.get(); + let appVersion; + try { + appVersion = await platform.getAppVersion(); + } catch (e) { + // this happens if no version is set i.e. in dev + appVersion = "unknown"; + } + + return { + appVersion, + appPlatform: platform.getHumanReadableName(), + }; + } + + private async capture(eventName: string, properties: posthog.Properties) { + if (!this.enabled) { + return; + } + const { origin, hash, pathname } = window.location; + properties['$redacted_current_url'] = await getRedactedCurrentLocation( + origin, hash, pathname, this.anonymity); + this.posthog.capture(eventName, properties); + } + + public isEnabled(): boolean { + return this.enabled; + } + + public setAnonymity(anonymity: Anonymity): void { + // Update this.anonymity. + // This is public for testing purposes, typically you want to call updateAnonymityFromSettings + // to ensure this value is in step with the user's settings. + if (this.enabled && (anonymity == Anonymity.Disabled || anonymity == Anonymity.Anonymous)) { + // when transitioning to Disabled or Anonymous ensure we clear out any prior state + // set in posthog e.g. distinct ID + this.posthog.reset(); + // Restore any previously set platform super properties + this.registerSuperProperties(this.platformSuperProperties); + } + this.anonymity = anonymity; + } + + public async identifyUser(userId: string): Promise { + if (this.anonymity == Anonymity.Pseudonymous) { + this.posthog.identify(await hashHex(userId)); + } + } + + public getAnonymity(): Anonymity { + return this.anonymity; + } + + public logout(): void { + if (this.enabled) { + this.posthog.reset(); + } + this.setAnonymity(Anonymity.Anonymous); + } + + public async trackPseudonymousEvent( + eventName: E["eventName"], + properties: E["properties"] = {}, + ) { + if (this.anonymity == Anonymity.Anonymous || this.anonymity == Anonymity.Disabled) return; + await this.capture(eventName, properties); + } + + public async trackAnonymousEvent( + eventName: E["eventName"], + properties: E["properties"] = {}, + ): Promise { + if (this.anonymity == Anonymity.Disabled) return; + await this.capture(eventName, properties); + } + + public async trackRoomEvent( + eventName: E["eventName"], + roomId: string, + properties: Omit, + ): Promise { + const updatedProperties = { + ...properties, + hashedRoomId: roomId ? await hashHex(roomId) : null, + }; + await this.trackPseudonymousEvent(eventName, updatedProperties); + } + + public async trackPageView(durationMs: number): Promise { + const hash = window.location.hash; + + let screen = null; + const split = hash.split("/"); + if (split.length >= 2) { + screen = split[1]; + } + + await this.trackAnonymousEvent("$pageview", { + durationMs, + screen, + }); + } + + public async updatePlatformSuperProperties(): Promise { + // Update super properties in posthog with our platform (app version, platform). + // These properties will be subsequently passed in every event. + // + // This only needs to be done once per page lifetime. Note that getPlatformProperties + // is async and can involve a network request if we are running in a browser. + this.platformSuperProperties = await PosthogAnalytics.getPlatformProperties(); + this.registerSuperProperties(this.platformSuperProperties); + } + + public async updateAnonymityFromSettings(userId?: string): Promise { + // Update this.anonymity based on the user's analytics opt-in settings + // Identify the user (via hashed user ID) to posthog if anonymity is pseudonmyous + this.setAnonymity(PosthogAnalytics.getAnonymityFromSettings()); + if (userId && this.getAnonymity() == Anonymity.Pseudonymous) { + await this.identifyUser(userId); + } + } +} diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 8cfe35c4cf..60c78b5f9e 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -107,6 +107,7 @@ import UIStore, { UI_EVENTS } from "../../stores/UIStore"; import SoftLogout from './auth/SoftLogout'; import { makeRoomPermalink } from "../../utils/permalinks/Permalinks"; import { copyPlaintext } from "../../utils/strings"; +import { PosthogAnalytics } from '../../PosthogAnalytics'; /** constants for MatrixChat.state.view */ export enum Views { @@ -387,6 +388,10 @@ export default class MatrixChat extends React.PureComponent { if (SettingsStore.getValue("analyticsOptIn")) { Analytics.enable(); } + + PosthogAnalytics.instance.updateAnonymityFromSettings(); + PosthogAnalytics.instance.updatePlatformSuperProperties(); + CountlyAnalytics.instance.enable(/* anonymous = */ true); } @@ -443,6 +448,7 @@ export default class MatrixChat extends React.PureComponent { const durationMs = this.stopPageChangeTimer(); Analytics.trackPageChange(durationMs); CountlyAnalytics.instance.trackPageChange(durationMs); + PosthogAnalytics.instance.trackPageView(durationMs); } if (this.focusComposer) { dis.fire(Action.FocusSendMessageComposer); diff --git a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js index 79d501e712..25b0b86cb1 100644 --- a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js @@ -36,6 +36,7 @@ import { UIFeature } from "../../../../../settings/UIFeature"; import { isE2eAdvancedPanelPossible } from "../../E2eAdvancedPanel"; import CountlyAnalytics from "../../../../../CountlyAnalytics"; import { replaceableComponent } from "../../../../../utils/replaceableComponent"; +import { PosthogAnalytics } from "../../../../../PosthogAnalytics"; export class IgnoredUser extends React.Component { static propTypes = { @@ -106,6 +107,7 @@ export default class SecurityUserSettingsTab extends React.Component { _updateAnalytics = (checked) => { checked ? Analytics.enable() : Analytics.disable(); CountlyAnalytics.instance.enable(/* anonymous = */ !checked); + PosthogAnalytics.instance.updateAnonymityFromSettings(MatrixClientPeg.get().getUserId()); }; _onExportE2eKeysClicked = () => { diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 3ad8daa85c..87cd9afb5b 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -813,6 +813,7 @@ "Show message previews for reactions in DMs": "Show message previews for reactions in DMs", "Show message previews for reactions in all rooms": "Show message previews for reactions in all rooms", "Offline encrypted messaging using dehydrated devices": "Offline encrypted messaging using dehydrated devices", + "Send pseudonymous analytics data": "Send pseudonymous analytics data", "Enable advanced debugging for the room list": "Enable advanced debugging for the room list", "Show info about bridges in room settings": "Show info about bridges in room settings", "New layout switcher (with message bubbles)": "New layout switcher (with message bubbles)", diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx index c36e2b90bf..cfe2c097fc 100644 --- a/src/settings/Settings.tsx +++ b/src/settings/Settings.tsx @@ -41,6 +41,7 @@ import { Layout } from "./Layout"; import ReducedMotionController from './controllers/ReducedMotionController'; import IncompatibleController from "./controllers/IncompatibleController"; import SdkConfig from "../SdkConfig"; +import PseudonymousAnalyticsController from './controllers/PseudonymousAnalyticsController'; import NewLayoutSwitcherController from './controllers/NewLayoutSwitcherController'; // These are just a bunch of helper arrays to avoid copy/pasting a bunch of times @@ -268,6 +269,13 @@ export const SETTINGS: {[setting: string]: ISetting} = { supportedLevels: LEVELS_FEATURE, default: false, }, + "feature_pseudonymous_analytics_opt_in": { + isFeature: true, + supportedLevels: LEVELS_FEATURE, + displayName: _td('Send pseudonymous analytics data'), + default: false, + controller: new PseudonymousAnalyticsController(), + }, "advancedRoomListLogging": { // TODO: Remove flag before launch: https://github.com/vector-im/element-web/issues/14231 displayName: _td("Enable advanced debugging for the room list"), diff --git a/src/settings/controllers/PseudonymousAnalyticsController.ts b/src/settings/controllers/PseudonymousAnalyticsController.ts new file mode 100644 index 0000000000..a82b9685ef --- /dev/null +++ b/src/settings/controllers/PseudonymousAnalyticsController.ts @@ -0,0 +1,26 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import SettingController from "./SettingController"; +import { SettingLevel } from "../SettingLevel"; +import { PosthogAnalytics } from "../../PosthogAnalytics"; +import { MatrixClientPeg } from "../../MatrixClientPeg"; + +export default class PseudonymousAnalyticsController extends SettingController { + public onChange(level: SettingLevel, roomId: string, newValue: any) { + PosthogAnalytics.instance.updateAnonymityFromSettings(MatrixClientPeg.get().getUserId()); + } +} diff --git a/test/PosthogAnalytics-test.ts b/test/PosthogAnalytics-test.ts new file mode 100644 index 0000000000..6cb1743051 --- /dev/null +++ b/test/PosthogAnalytics-test.ts @@ -0,0 +1,232 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { + Anonymity, + getRedactedCurrentLocation, + IAnonymousEvent, + IPseudonymousEvent, + IRoomEvent, + PosthogAnalytics, +} from '../src/PosthogAnalytics'; + +import SdkConfig from '../src/SdkConfig'; + +class FakePosthog { + public capture; + public init; + public identify; + public reset; + public register; + + constructor() { + this.capture = jest.fn(); + this.init = jest.fn(); + this.identify = jest.fn(); + this.reset = jest.fn(); + this.register = jest.fn(); + } +} + +export interface ITestEvent extends IAnonymousEvent { + key: "jest_test_event"; + properties: { + foo: string; + }; +} + +export interface ITestPseudonymousEvent extends IPseudonymousEvent { + key: "jest_test_pseudo_event"; + properties: { + foo: string; + }; +} + +export interface ITestRoomEvent extends IRoomEvent { + key: "jest_test_room_event"; + properties: { + foo: string; + }; +} + +describe("PosthogAnalytics", () => { + let fakePosthog: FakePosthog; + const shaHashes = { + "42": "73475cb40a568e8da8a045ced110137e159f890ac4da883b6b17dc651b3a8049", + "some": "a6b46dd0d1ae5e86cbc8f37e75ceeb6760230c1ca4ffbcb0c97b96dd7d9c464b", + "pii": "bd75b3e080945674c0351f75e0db33d1e90986fa07b318ea7edf776f5eef38d4", + "foo": "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae", + }; + + beforeEach(() => { + fakePosthog = new FakePosthog(); + + window.crypto = { + subtle: { + digest: async (_, encodedMessage) => { + const message = new TextDecoder().decode(encodedMessage); + const hexHash = shaHashes[message]; + const bytes = []; + for (let c = 0; c < hexHash.length; c += 2) { + bytes.push(parseInt(hexHash.substr(c, 2), 16)); + } + return bytes; + }, + }, + }; + }); + + afterEach(() => { + window.crypto = null; + }); + + describe("Initialisation", () => { + it("Should not be enabled without config being set", () => { + jest.spyOn(SdkConfig, "get").mockReturnValue({}); + const analytics = new PosthogAnalytics(fakePosthog); + expect(analytics.isEnabled()).toBe(false); + }); + + it("Should be enabled if config is set", () => { + jest.spyOn(SdkConfig, "get").mockReturnValue({ + posthog: { + projectApiKey: "foo", + apiHost: "bar", + }, + }); + const analytics = new PosthogAnalytics(fakePosthog); + analytics.setAnonymity(Anonymity.Pseudonymous); + expect(analytics.isEnabled()).toBe(true); + }); + }); + + describe("Tracking", () => { + let analytics: PosthogAnalytics; + + beforeEach(() => { + jest.spyOn(SdkConfig, "get").mockReturnValue({ + posthog: { + projectApiKey: "foo", + apiHost: "bar", + }, + }); + + analytics = new PosthogAnalytics(fakePosthog); + }); + + it("Should pass trackAnonymousEvent() to posthog", async () => { + analytics.setAnonymity(Anonymity.Pseudonymous); + await analytics.trackAnonymousEvent("jest_test_event", { + foo: "bar", + }); + expect(fakePosthog.capture.mock.calls[0][0]).toBe("jest_test_event"); + expect(fakePosthog.capture.mock.calls[0][1]["foo"]).toEqual("bar"); + }); + + it("Should pass trackRoomEvent to posthog", async () => { + analytics.setAnonymity(Anonymity.Pseudonymous); + const roomId = "42"; + await analytics.trackRoomEvent("jest_test_event", roomId, { + foo: "bar", + }); + expect(fakePosthog.capture.mock.calls[0][0]).toBe("jest_test_event"); + expect(fakePosthog.capture.mock.calls[0][1]["foo"]).toEqual("bar"); + expect(fakePosthog.capture.mock.calls[0][1]["hashedRoomId"]) + .toEqual("73475cb40a568e8da8a045ced110137e159f890ac4da883b6b17dc651b3a8049"); + }); + + it("Should pass trackPseudonymousEvent() to posthog", async () => { + analytics.setAnonymity(Anonymity.Pseudonymous); + await analytics.trackPseudonymousEvent("jest_test_pseudo_event", { + foo: "bar", + }); + expect(fakePosthog.capture.mock.calls[0][0]).toBe("jest_test_pseudo_event"); + expect(fakePosthog.capture.mock.calls[0][1]["foo"]).toEqual("bar"); + }); + + it("Should not track pseudonymous messages if anonymous", async () => { + analytics.setAnonymity(Anonymity.Anonymous); + await analytics.trackPseudonymousEvent("jest_test_event", { + foo: "bar", + }); + expect(fakePosthog.capture.mock.calls.length).toBe(0); + }); + + it("Should not track any events if disabled", async () => { + analytics.setAnonymity(Anonymity.Disabled); + await analytics.trackPseudonymousEvent("jest_test_event", { + foo: "bar", + }); + await analytics.trackAnonymousEvent("jest_test_event", { + foo: "bar", + }); + await analytics.trackRoomEvent("room id", "foo", { + foo: "bar", + }); + await analytics.trackPageView(200); + expect(fakePosthog.capture.mock.calls.length).toBe(0); + }); + + it("Should pseudonymise a location of a known screen", async () => { + const location = await getRedactedCurrentLocation( + "https://foo.bar", "#/register/some/pii", "/", Anonymity.Pseudonymous); + expect(location).toBe( + `https://foo.bar/#/register/\ +a6b46dd0d1ae5e86cbc8f37e75ceeb6760230c1ca4ffbcb0c97b96dd7d9c464b/\ +bd75b3e080945674c0351f75e0db33d1e90986fa07b318ea7edf776f5eef38d4`); + }); + + it("Should anonymise a location of a known screen", async () => { + const location = await getRedactedCurrentLocation( + "https://foo.bar", "#/register/some/pii", "/", Anonymity.Anonymous); + expect(location).toBe("https://foo.bar/#/register//"); + }); + + it("Should pseudonymise a location of an unknown screen", async () => { + const location = await getRedactedCurrentLocation( + "https://foo.bar", "#/not_a_screen_name/some/pii", "/", Anonymity.Pseudonymous); + expect(location).toBe( + `https://foo.bar/#//\ +a6b46dd0d1ae5e86cbc8f37e75ceeb6760230c1ca4ffbcb0c97b96dd7d9c464b/\ +bd75b3e080945674c0351f75e0db33d1e90986fa07b318ea7edf776f5eef38d4`); + }); + + it("Should anonymise a location of an unknown screen", async () => { + const location = await getRedactedCurrentLocation( + "https://foo.bar", "#/not_a_screen_name/some/pii", "/", Anonymity.Anonymous); + expect(location).toBe("https://foo.bar/#///"); + }); + + it("Should handle an empty hash", async () => { + const location = await getRedactedCurrentLocation( + "https://foo.bar", "", "/", Anonymity.Anonymous); + expect(location).toBe("https://foo.bar/"); + }); + + it("Should identify the user to posthog if pseudonymous", async () => { + analytics.setAnonymity(Anonymity.Pseudonymous); + await analytics.identifyUser("foo"); + expect(fakePosthog.identify.mock.calls[0][0]) + .toBe("2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"); + }); + + it("Should not identify the user to posthog if anonymous", async () => { + analytics.setAnonymity(Anonymity.Anonymous); + await analytics.identifyUser("foo"); + expect(fakePosthog.identify.mock.calls.length).toBe(0); + }); + }); +}); diff --git a/tsconfig.json b/tsconfig.json index b139e8e8d1..b982d40b07 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,10 +22,15 @@ "es2019", "dom", "dom.iterable" - ] + ], + "paths": { + "posthog-js": [ + "./src/@types/posthog.d.ts" + ] + } }, "include": [ "./src/**/*.ts", "./src/**/*.tsx" - ] + ], } diff --git a/yarn.lock b/yarn.lock index 2a03f640ee..daed6f4377 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3601,6 +3601,11 @@ fbjs@^0.8.4: setimmediate "^1.0.5" ua-parser-js "^0.7.18" +fflate@^0.4.1: + version "0.4.8" + resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.4.8.tgz#f90b82aefbd8ac174213abb338bd7ef848f0f5ae" + integrity sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA== + file-entry-cache@^6.0.0, file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -6249,6 +6254,13 @@ postcss@^8.0.2: nanoid "^3.1.23" source-map-js "^0.6.2" +posthog-js@1.12.1: + version "1.12.1" + resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.12.1.tgz#97834ee2574f34ffb5db2f5b07452c847e3c4d27" + integrity sha512-Y3lzcWkS8xFY6Ryj3I4ees7qWP2WGkLw0Arcbk5xaT0+5YlA6UC2jlL/+fN9bz/Bl62EoN3BML901Cuot/QNjg== + dependencies: + fflate "^0.4.1" + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" From c66d0017de6d0540f428b26cfc66e8bf7461fba5 Mon Sep 17 00:00:00 2001 From: James Salter Date: Tue, 3 Aug 2021 11:32:51 +0100 Subject: [PATCH 2/8] Patch posthog's type definitions using patch-package Remove definitions for sentry and rrweb-snapshot --- package.json | 7 +- patches/posthog-js+1.12.2.patch | 78 ++++ src/@types/posthog.d.ts | 748 -------------------------------- tsconfig.json | 5 - yarn.lock | 102 ++++- 5 files changed, 177 insertions(+), 763 deletions(-) create mode 100644 patches/posthog-js+1.12.2.patch delete mode 100644 src/@types/posthog.d.ts diff --git a/package.json b/package.json index b7e06fe012..e7ea85ccd4 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,8 @@ "lint:style": "stylelint 'res/css/**/*.scss'", "test": "jest", "test:e2e": "./test/end-to-end-tests/run.sh --app-url http://localhost:8080", - "coverage": "yarn test --coverage" + "coverage": "yarn test --coverage", + "postinstall": "patch-package" }, "dependencies": { "@babel/runtime": "^7.12.5", @@ -87,7 +88,7 @@ "pako": "^2.0.3", "parse5": "^6.0.1", "png-chunks-extract": "^1.0.0", - "posthog-js": "1.12.1", + "posthog-js": "1.12.2", "prop-types": "^15.7.2", "qrcode": "^1.4.4", "re-resizable": "^6.9.0", @@ -165,6 +166,8 @@ "matrix-mock-request": "^1.2.3", "matrix-react-test-utils": "^0.2.3", "matrix-web-i18n": "github:matrix-org/matrix-web-i18n", + "patch-package": "^6.4.7", + "postinstall-postinstall": "^2.1.0", "react-test-renderer": "^17.0.2", "rimraf": "^3.0.2", "stylelint": "^13.9.0", diff --git a/patches/posthog-js+1.12.2.patch b/patches/posthog-js+1.12.2.patch new file mode 100644 index 0000000000..430a9f0a62 --- /dev/null +++ b/patches/posthog-js+1.12.2.patch @@ -0,0 +1,78 @@ +diff --git a/node_modules/posthog-js/dist/module.d.ts b/node_modules/posthog-js/dist/module.d.ts +index d3cba02..8c87ef8 100644 +--- a/node_modules/posthog-js/dist/module.d.ts ++++ b/node_modules/posthog-js/dist/module.d.ts +@@ -1,7 +1,5 @@ + // Type definitions for exported methods +- +-import { EventProcessor, Integration } from '@sentry/types' +-import { MaskInputOptions, SlimDOMOptions } from 'rrweb-snapshot' ++// Patched to remove references to sentry and rrweb-snapshot which aren't otherwise SDK dependencies + + declare class posthog { + /** +@@ -485,25 +483,6 @@ declare class posthog { + */ + static reloadFeatureFlags(): void + +- /** +- * Integrate Sentry with PostHog. This will add a direct link to the person in Sentry, and an $exception event in PostHog +- * +- * ### Usage +- * +- * Sentry.init({ +- * dsn: 'https://example', +- * integrations: [ +- * new posthog.SentryIntegration(posthog) +- * ] +- * }) +- * +- * @param {Object} [posthog] The posthog object +- * @param {string} [organization] Optional: The Sentry organization, used to send a direct link from PostHog to Sentry +- * @param {Number} [projectId] Optional: The Sentry project id, used to send a direct link from PostHog to Sentry +- * @param {string} [prefix] Optional: Url of a self-hosted sentry instance (default: https://sentry.io/organizations/) +- */ +- static SentryIntegration: typeof SentryIntegration +- + static toString(): string + + /* Will log all capture requests to the Javascript console, including event properties for easy debugging */ +@@ -585,7 +564,6 @@ declare namespace posthog { + request_batching?: boolean + sanitize_properties?: (properties: posthog.Properties, event_name: string) => posthog.Properties + properties_string_max_length?: number +- session_recording?: SessionRecordingOptions + mask_all_element_attributes?: boolean + mask_all_text?: boolean + advanced_disable_decide?: boolean +@@ -618,17 +596,6 @@ declare namespace posthog { + send_event: boolean + } + +- interface SessionRecordingOptions { +- blockClass?: string | RegExp +- blockSelector?: string +- ignoreClass?: string +- maskAllInputs?: boolean +- maskInputOptions?: MaskInputOptions +- maskInputFn?: (text: string) => string +- slimDOMOptions?: SlimDOMOptions | 'all' | true +- collectFonts?: boolean +- } +- + export class persistence { + static properties(): posthog.Properties + +@@ -768,12 +735,6 @@ declare namespace posthog { + export class feature_flags extends featureFlags {} + } + +-export class SentryIntegration implements Integration { +- constructor(posthog: posthog, organization?: string, projectId?: number, prefix?: string) +- name: string +- setupOnce(addGlobalEventProcessor: (callback: EventProcessor) => void): void +-} +- + export type PostHog = typeof posthog + + export default posthog diff --git a/src/@types/posthog.d.ts b/src/@types/posthog.d.ts deleted file mode 100644 index 1ca475cd3b..0000000000 --- a/src/@types/posthog.d.ts +++ /dev/null @@ -1,748 +0,0 @@ -// A clone of the type definitions from posthog-js, stripped of references to transitive -// dependencies which we don't actually use, so that we don't need to install them. -// -// Original file lives in node_modules/posthog/dist/module.d.ts - -/* eslint-disable @typescript-eslint/member-delimiter-style */ -/* eslint-disable @typescript-eslint/naming-convention */ -/* eslint-disable camelcase */ - -// Type definitions for exported methods - -declare class posthog { - /** - * This function initializes a new instance of the PostHog capturing object. - * All new instances are added to the main posthog object as sub properties (such as - * posthog.library_name) and also returned by this function. To define a - * second instance on the page, you would call: - * - * posthog.init('new token', { your: 'config' }, 'library_name'); - * - * and use it like so: - * - * posthog.library_name.capture(...); - * - * @param {String} token Your PostHog API token - * @param {Object} [config] A dictionary of config options to override. See a list of default config options. - * @param {String} [name] The name for the new posthog instance that you want created - */ - static init(token: string, config?: posthog.Config, name?: string): posthog - - /** - * Clears super properties and generates a new random distinct_id for this instance. - * Useful for clearing data when a user logs out. - */ - static reset(reset_device_id?: boolean): void - - /** - * Capture an event. This is the most important and - * frequently used PostHog function. - * - * ### Usage: - * - * // capture an event named 'Registered' - * posthog.capture('Registered', {'Gender': 'Male', 'Age': 21}); - * - * // capture an event using navigator.sendBeacon - * posthog.capture('Left page', {'duration_seconds': 35}, {transport: 'sendBeacon'}); - * - * @param {String} event_name The name of the event. This can be anything the user does - 'Button Click', 'Sign Up', 'Item Purchased', etc. - * @param {Object} [properties] A set of properties to include with the event you're sending. These describe the user who did the event or details about the event itself. - * @param {Object} [options] Optional configuration for this capture request. - * @param {String} [options.transport] Transport method for network request ('XHR' or 'sendBeacon'). - */ - static capture( - event_name: string, - properties?: posthog.Properties, - options?: { transport: 'XHR' | 'sendBeacon' } - ): posthog.CaptureResult - - /** - * Capture a page view event, which is currently ignored by the server. - * This function is called by default on page load unless the - * capture_pageview configuration variable is false. - * - * @param {String} [page] The url of the page to record. If you don't include this, it defaults to the current url. - * @api private - */ - static capture_pageview(page?: string): void - - /** - * Register a set of super properties, which are included with all - * events. This will overwrite previous super property values. - * - * ### Usage: - * - * // register 'Gender' as a super property - * posthog.register({'Gender': 'Female'}); - * - * // register several super properties when a user signs up - * posthog.register({ - * 'Email': 'jdoe@example.com', - * 'Account Type': 'Free' - * }); - * - * @param {Object} properties An associative array of properties to store about the user - * @param {Number} [days] How many days since the user's last visit to store the super properties - */ - static register(properties: posthog.Properties, days?: number): void - - /** - * Register a set of super properties only once. This will not - * overwrite previous super property values, unlike register(). - * - * ### Usage: - * - * // register a super property for the first time only - * posthog.register_once({ - * 'First Login Date': new Date().toISOString() - * }); - * - * ### Notes: - * - * If default_value is specified, current super properties - * with that value will be overwritten. - * - * @param {Object} properties An associative array of properties to store about the user - * @param {*} [default_value] Value to override if already set in super properties (ex: 'False') Default: 'None' - * @param {Number} [days] How many days since the users last visit to store the super properties - */ - static register_once(properties: posthog.Properties, default_value?: posthog.Property, days?: number): void - - /** - * Delete a super property stored with the current user. - * - * @param {String} property The name of the super property to remove - */ - static unregister(property: string): void - - /** - * Identify a user with a unique ID instead of a PostHog - * randomly generated distinct_id. If the method is never called, - * then unique visitors will be identified by a UUID generated - * the first time they visit the site. - * - * If user properties are passed, they are also sent to posthog. - * - * ### Usage: - * - * posthog.identify('[user unique id]') - * posthog.identify('[user unique id]', { email: 'john@example.com' }) - * posthog.identify('[user unique id]', {}, { referral_code: '12345' }) - * - * ### Notes: - * - * You can call this function to overwrite a previously set - * unique ID for the current user. PostHog cannot translate - * between IDs at this time, so when you change a user's ID - * they will appear to be a new user. - * - * When used alone, posthog.identify will change the user's - * distinct_id to the unique ID provided. When used in tandem - * with posthog.alias, it will allow you to identify based on - * unique ID and map that back to the original, anonymous - * distinct_id given to the user upon her first arrival to your - * site (thus connecting anonymous pre-signup activity to - * post-signup activity). Though the two work together, do not - * call identify() at the same time as alias(). Calling the two - * at the same time can cause a race condition, so it is best - * practice to call identify on the original, anonymous ID - * right after you've aliased it. - * - * @param {String} [unique_id] A string that uniquely identifies a user. If not provided, the distinct_id currently in the persistent store (cookie or localStorage) will be used. - * @param {Object} [userProperties] Optional: An associative array of properties to store about the user - * @param {Object} [userPropertiesToSetOnce] Optional: An associative array of properties to store about the user. If property is previously set, this does not override that value. - */ - static identify( - unique_id?: string, - userPropertiesToSet?: posthog.Properties, - userPropertiesToSetOnce?: posthog.Properties - ): void - - /** - * Create an alias, which PostHog will use to link two distinct_ids going forward (not retroactively). - * Multiple aliases can map to the same original ID, but not vice-versa. Aliases can also be chained - the - * following is a valid scenario: - * - * posthog.alias('new_id', 'existing_id'); - * ... - * posthog.alias('newer_id', 'new_id'); - * - * If the original ID is not passed in, we will use the current distinct_id - probably the auto-generated GUID. - * - * ### Notes: - * - * The best practice is to call alias() when a unique ID is first created for a user - * (e.g., when a user first registers for an account and provides an email address). - * alias() should never be called more than once for a given user, except to - * chain a newer ID to a previously new ID, as described above. - * - * @param {String} alias A unique identifier that you want to use for this user in the future. - * @param {String} [original] The current identifier being used for this user. - */ - static alias(alias: string, original?: string): posthog.CaptureResult | number - - /** - * Update the configuration of a posthog library instance. - * - * The default config is: - * - * { - * // HTTP method for capturing requests - * api_method: 'POST' - * - * // transport for sending requests ('XHR' or 'sendBeacon') - * // NB: sendBeacon should only be used for scenarios such as - * // page unload where a "best-effort" attempt to send is - * // acceptable; the sendBeacon API does not support callbacks - * // or any way to know the result of the request. PostHog - * // capturing via sendBeacon will not support any event- - * // batching or retry mechanisms. - * api_transport: 'XHR' - * - * // Automatically capture clicks, form submissions and change events - * autocapture: true - * - * // Capture rage clicks (beta) - useful for session recording - * rageclick: false - * - * // super properties cookie expiration (in days) - * cookie_expiration: 365 - * - * // super properties span subdomains - * cross_subdomain_cookie: true - * - * // debug mode - * debug: false - * - * // if this is true, the posthog cookie or localStorage entry - * // will be deleted, and no user persistence will take place - * disable_persistence: false - * - * // if this is true, PostHog will automatically determine - * // City, Region and Country data using the IP address of - * //the client - * ip: true - * - * // opt users out of capturing by this PostHog instance by default - * opt_out_capturing_by_default: false - * - * // opt users out of browser data storage by this PostHog instance by default - * opt_out_persistence_by_default: false - * - * // persistence mechanism used by opt-in/opt-out methods - cookie - * // or localStorage - falls back to cookie if localStorage is unavailable - * opt_out_capturing_persistence_type: 'localStorage' - * - * // customize the name of cookie/localStorage set by opt-in/opt-out methods - * opt_out_capturing_cookie_prefix: null - * - * // type of persistent store for super properties (cookie/ - * // localStorage) if set to 'localStorage', any existing - * // posthog cookie value with the same persistence_name - * // will be transferred to localStorage and deleted - * persistence: 'cookie' - * - * // name for super properties persistent store - * persistence_name: '' - * - * // names of properties/superproperties which should never - * // be sent with capture() calls - * property_blacklist: [] - * - * // if this is true, posthog cookies will be marked as - * // secure, meaning they will only be transmitted over https - * secure_cookie: false - * - * // should we capture a page view on page load - * capture_pageview: true - * - * // if you set upgrade to be true, the library will check for - * // a cookie from our old js library and import super - * // properties from it, then the old cookie is deleted - * // The upgrade config option only works in the initialization, - * // so make sure you set it when you create the library. - * upgrade: false - * - * // extra HTTP request headers to set for each API request, in - * // the format {'Header-Name': value} - * xhr_headers: {} - * - * // protocol for fetching in-app message resources, e.g. - * // 'https://' or 'http://'; defaults to '//' (which defers to the - * // current page's protocol) - * inapp_protocol: '//' - * - * // whether to open in-app message link in new tab/window - * inapp_link_new_window: false - * - * // a set of rrweb config options that PostHog users can configure - * // see https://github.com/rrweb-io/rrweb/blob/master/guide.md - * session_recording: { - * blockClass: 'ph-no-capture', - * blockSelector: null, - * ignoreClass: 'ph-ignore-input', - * maskAllInputs: false, - * maskInputOptions: {}, - * maskInputFn: null, - * slimDOMOptions: {}, - * collectFonts: false - * } - * - * // prevent autocapture from capturing any attribute names on elements - * mask_all_element_attributes: false - * - * // prevent autocapture from capturing textContent on all elements - * mask_all_text: false - * - * // will disable requests to the /decide endpoint (please review documentation for details) - * // autocapture, feature flags, compression and session recording will be disabled when set to `true` - * advanced_disable_decide: false - * - * } - * - * - * @param {Object} config A dictionary of new configuration values to update - */ - static set_config(config: posthog.Config): void - - /** - * returns the current config object for the library. - */ - static get_config(prop_name: T): posthog.Config[T] - - /** - * Returns the value of the super property named property_name. If no such - * property is set, get_property() will return the undefined value. - * - * ### Notes: - * - * get_property() can only be called after the PostHog library has finished loading. - * init() has a loaded function available to handle this automatically. For example: - * - * // grab value for 'user_id' after the posthog library has loaded - * posthog.init('YOUR PROJECT TOKEN', { - * loaded: function(posthog) { - * user_id = posthog.get_property('user_id'); - * } - * }); - * - * @param {String} property_name The name of the super property you want to retrieve - */ - static get_property(property_name: string): posthog.Property | undefined - - /** - * Returns the current distinct id of the user. This is either the id automatically - * generated by the library or the id that has been passed by a call to identify(). - * - * ### Notes: - * - * get_distinct_id() can only be called after the PostHog library has finished loading. - * init() has a loaded function available to handle this automatically. For example: - * - * // set distinct_id after the posthog library has loaded - * posthog.init('YOUR PROJECT TOKEN', { - * loaded: function(posthog) { - * distinct_id = posthog.get_distinct_id(); - * } - * }); - */ - static get_distinct_id(): string - - /** - * Opt the user out of data capturing and cookies/localstorage for this PostHog instance - * - * ### Usage - * - * // opt user out - * posthog.opt_out_capturing(); - * - * // opt user out with different cookie configuration from PostHog instance - * posthog.opt_out_capturing({ - * cookie_expiration: 30, - * secure_cookie: true - * }); - * - * @param {Object} [options] A dictionary of config options to override - * @param {boolean} [options.clear_persistence=true] If true, will delete all data stored by the sdk in persistence - * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable - * @param {string} [options.cookie_prefix=__ph_opt_in_out] Custom prefix to be used in the cookie/localstorage name - * @param {Number} [options.cookie_expiration] Number of days until the opt-in cookie expires (overrides value specified in this PostHog instance's config) - * @param {boolean} [options.cross_subdomain_cookie] Whether the opt-in cookie is set as cross-subdomain or not (overrides value specified in this PostHog instance's config) - * @param {boolean} [options.secure_cookie] Whether the opt-in cookie is set as secure or not (overrides value specified in this PostHog instance's config) - */ - static opt_out_capturing(options?: posthog.OptInOutCapturingOptions): void - - /** - * Opt the user in to data capturing and cookies/localstorage for this PostHog instance - * - * ### Usage - * - * // opt user in - * posthog.opt_in_capturing(); - * - * // opt user in with specific event name, properties, cookie configuration - * posthog.opt_in_capturing({ - * capture_event_name: 'User opted in', - * capture_event_properties: { - * 'Email': 'jdoe@example.com' - * }, - * cookie_expiration: 30, - * secure_cookie: true - * }); - * - * @param {Object} [options] A dictionary of config options to override - * @param {function} [options.capture] Function used for capturing a PostHog event to record the opt-in action (default is this PostHog instance's capture method) - * @param {string} [options.capture_event_name=$opt_in] Event name to be used for capturing the opt-in action - * @param {Object} [options.capture_properties] Set of properties to be captured along with the opt-in action - * @param {boolean} [options.enable_persistence=true] If true, will re-enable sdk persistence - * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable - * @param {string} [options.cookie_prefix=__ph_opt_in_out] Custom prefix to be used in the cookie/localstorage name - * @param {Number} [options.cookie_expiration] Number of days until the opt-in cookie expires (overrides value specified in this PostHog instance's config) - * @param {boolean} [options.cross_subdomain_cookie] Whether the opt-in cookie is set as cross-subdomain or not (overrides value specified in this PostHog instance's config) - * @param {boolean} [options.secure_cookie] Whether the opt-in cookie is set as secure or not (overrides value specified in this PostHog instance's config) - */ - static opt_in_capturing(options?: posthog.OptInOutCapturingOptions): void - - /** - * Check whether the user has opted out of data capturing and cookies/localstorage for this PostHog instance - * - * ### Usage - * - * const has_opted_out = posthog.has_opted_out_capturing(); - * // use has_opted_out value - * - * @param {Object} [options] A dictionary of config options to override - * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable - * @param {string} [options.cookie_prefix=__ph_opt_in_out] Custom prefix to be used in the cookie/localstorage name - * @returns {boolean} current opt-out status - */ - static has_opted_out_capturing(options?: posthog.HasOptedInOutCapturingOptions): boolean - - /** - * Check whether the user has opted in to data capturing and cookies/localstorage for this PostHog instance - * - * ### Usage - * - * const has_opted_in = posthog.has_opted_in_capturing(); - * // use has_opted_in value - * - * @param {Object} [options] A dictionary of config options to override - * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable - * @param {string} [options.cookie_prefix=__ph_opt_in_out] Custom prefix to be used in the cookie/localstorage name - * @returns {boolean} current opt-in status - */ - static has_opted_in_capturing(options?: posthog.HasOptedInOutCapturingOptions): boolean - - /** - * Clear the user's opt in/out status of data capturing and cookies/localstorage for this PostHog instance - * - * ### Usage - * - * // clear user's opt-in/out status - * posthog.clear_opt_in_out_capturing(); - * - * // clear user's opt-in/out status with specific cookie configuration - should match - * // configuration used when opt_in_capturing/opt_out_capturing methods were called. - * posthog.clear_opt_in_out_capturing({ - * cookie_expiration: 30, - * secure_cookie: true - * }); - * - * @param {Object} [options] A dictionary of config options to override - * @param {boolean} [options.enable_persistence=true] If true, will re-enable sdk persistence - * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable - * @param {string} [options.cookie_prefix=__ph_opt_in_out] Custom prefix to be used in the cookie/localstorage name - * @param {Number} [options.cookie_expiration] Number of days until the opt-in cookie expires (overrides value specified in this PostHog instance's config) - * @param {boolean} [options.cross_subdomain_cookie] Whether the opt-in cookie is set as cross-subdomain or not (overrides value specified in this PostHog instance's config) - * @param {boolean} [options.secure_cookie] Whether the opt-in cookie is set as secure or not (overrides value specified in this PostHog instance's config) - */ - static clear_opt_in_out_capturing(options?: posthog.ClearOptInOutCapturingOptions): void - - /* - * See if feature flag is enabled for user. - * - * ### Usage: - * - * if(posthog.isFeatureEnabled('beta-feature')) { // do something } - * - * @param {Object|String} prop Key of the feature flag. - * @param {Object|String} options (optional) If {send_event: false}, we won't send an $feature_flag_call event to PostHog. - */ - static isFeatureEnabled(key: string, options?: posthog.isFeatureEnabledOptions): boolean - - /* - * See if feature flags are available. - * - * ### Usage: - * - * posthog.onFeatureFlags(function(featureFlags) { // do something }) - * - * @param {Function} [callback] The callback function will be called once the feature flags are ready. It'll return a list of feature flags enabled for the user. - */ - static onFeatureFlags(callback: (flags: string[]) => void): false | undefined - - /* - * Reload all feature flags for the user. - * - * ### Usage: - * - * posthog.reloadFeatureFlags() - */ - static reloadFeatureFlags(): void - - static toString(): string - - /* Will log all capture requests to the Javascript console, including event properties for easy debugging */ - static debug(): void - - /* - * Starts session recording and updates disable_session_recording to false. - * Used for manual session recording management. By default, session recording is enabled and - * starts automatically. - * - * ### Usage: - * - * posthog.startSessionRecording() - */ - static startSessionRecording(): void - - /* - * Stops session recording and updates disable_session_recording to true. - * - * ### Usage: - * - * posthog.stopSessionRecording() - */ - static stopSessionRecording(): void - - /* - * Check if session recording is currently running. - * - * ### Usage: - * - * const isSessionRecordingOn = posthog.sessionRecordingStarted() - */ - static sessionRecordingStarted(): boolean -} - -declare namespace posthog { - /* eslint-disable @typescript-eslint/no-explicit-any */ - type Property = any; - type Properties = Record; - type CaptureResult = { event: string; properties: Properties } | undefined; - type CaptureCallback = (response: any, data: any) => void; - /* eslint-enable @typescript-eslint/no-explicit-any */ - - interface Config { - api_host?: string - api_method?: string - api_transport?: string - autocapture?: boolean - rageclick?: boolean - cdn?: string - cross_subdomain_cookie?: boolean - persistence?: 'localStorage' | 'cookie' | 'memory' - persistence_name?: string - cookie_name?: string - loaded?: (posthog_instance: typeof posthog) => void - store_google?: boolean - save_referrer?: boolean - test?: boolean - verbose?: boolean - img?: boolean - capture_pageview?: boolean - debug?: boolean - cookie_expiration?: number - upgrade?: boolean - disable_session_recording?: boolean - disable_persistence?: boolean - disable_cookie?: boolean - secure_cookie?: boolean - ip?: boolean - opt_out_capturing_by_default?: boolean - opt_out_persistence_by_default?: boolean - opt_out_capturing_persistence_type?: 'localStorage' | 'cookie' - opt_out_capturing_cookie_prefix?: string | null - respect_dnt?: boolean - property_blacklist?: string[] - xhr_headers?: { [header_name: string]: string } - inapp_protocol?: string - inapp_link_new_window?: boolean - request_batching?: boolean - sanitize_properties?: (properties: posthog.Properties, event_name: string) => posthog.Properties - properties_string_max_length?: number - mask_all_element_attributes?: boolean - mask_all_text?: boolean - advanced_disable_decide?: boolean - } - - interface OptInOutCapturingOptions { - clear_persistence: boolean - persistence_type: string - cookie_prefix: string - cookie_expiration: number - cross_subdomain_cookie: boolean - secure_cookie: boolean - } - - interface HasOptedInOutCapturingOptions { - persistence_type: string - cookie_prefix: string - } - - interface ClearOptInOutCapturingOptions { - enable_persistence: boolean - persistence_type: string - cookie_prefix: string - cookie_expiration: number - cross_subdomain_cookie: boolean - secure_cookie: boolean - } - - interface isFeatureEnabledOptions { - send_event: boolean - } - - export class persistence { - static properties(): posthog.Properties - - static load(): void - - static save(): void - - static remove(): void - - static clear(): void - - /** - * @param {Object} props - * @param {*=} default_value - * @param {number=} days - */ - static register_once(props: Properties, default_value?: Property, days?: number): boolean - - /** - * @param {Object} props - * @param {number=} days - */ - static register(props: posthog.Properties, days?: number): boolean - - static unregister(prop: string): void - - static update_campaign_params(): void - - static update_search_keyword(referrer: string): void - - static update_referrer_info(referrer: string): void - - static get_referrer_info(): posthog.Properties - - static safe_merge(props: posthog.Properties): posthog.Properties - - static update_config(config: posthog.Config): void - - static set_disabled(disabled: boolean): void - - static set_cross_subdomain(cross_subdomain: boolean): void - - static get_cross_subdomain(): boolean - - static set_secure(secure: boolean): void - - static set_event_timer(event_name: string, timestamp: Date): void - - static remove_event_timer(event_name: string): Date | undefined - } - - export class people { - /* - * Set properties on a user record. - * - * ### Usage: - * - * posthog.people.set('gender', 'm'); - * - * // or set multiple properties at once - * posthog.people.set({ - * 'Company': 'Acme', - * 'Plan': 'Premium', - * 'Upgrade date': new Date() - * }); - * // properties can be strings, integers, dates, or lists - * - * @param {Object|String} prop If a string, this is the name of the property. If an object, this is an associative array of names and values. - * @param {*} [to] A value to set on the given property name - * @param {Function} [callback] If provided, the callback will be called after capturing the event. - */ - static set( - prop: posthog.Properties | string, - to?: posthog.Property, - callback?: posthog.CaptureCallback - ): posthog.Properties - - /* - * Set properties on a user record, only if they do not yet exist. - * This will not overwrite previous people property values, unlike - * people.set(). - * - * ### Usage: - * - * posthog.people.set_once('First Login Date', new Date()); - * - * // or set multiple properties at once - * posthog.people.set_once({ - * 'First Login Date': new Date(), - * 'Starting Plan': 'Premium' - * }); - * - * // properties can be strings, integers or dates - * - * @param {Object|String} prop If a string, this is the name of the property. If an object, this is an associative array of names and values. - * @param {*} [to] A value to set on the given property name - * @param {Function} [callback] If provided, the callback will be called after capturing the event. - */ - static set_once( - prop: posthog.Properties | string, - to?: posthog.Property, - callback?: posthog.CaptureCallback - ): posthog.Properties - - static toString(): string - } - - export class featureFlags { - static getFlags(): string[] - - static reloadFeatureFlags(): void - - /* - * See if feature flag is enabled for user. - * - * ### Usage: - * - * if(posthog.isFeatureEnabled('beta-feature')) { // do something } - * - * @param {Object|String} prop Key of the feature flag. - * @param {Object|String} options (optional) If {send_event: false}, we won't send an $feature_flag_call event to PostHog. - */ - static isFeatureEnabled(key: string, options?: { send_event?: boolean }): boolean - - /* - * See if feature flags are available. - * - * ### Usage: - * - * posthog.onFeatureFlags(function(featureFlags) { // do something }) - * - * @param {Function} [callback] The callback function will be called once the feature flags are ready. It'll return a list of feature flags enabled for the user. - */ - static onFeatureFlags(callback: (flags: string[]) => void): false | undefined - } - - export class feature_flags extends featureFlags {} -} - -export type PostHog = typeof posthog; - -export default posthog; diff --git a/tsconfig.json b/tsconfig.json index b982d40b07..2e0131609c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,11 +23,6 @@ "dom", "dom.iterable" ], - "paths": { - "posthog-js": [ - "./src/@types/posthog.d.ts" - ] - } }, "include": [ "./src/**/*.ts", diff --git a/yarn.lock b/yarn.lock index daed6f4377..6bb5654db8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1790,6 +1790,11 @@ object.fromentries "^2.0.0" prop-types "^15.7.0" +"@yarnpkg/lockfile@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" + integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== + abab@^2.0.3, abab@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" @@ -2713,7 +2718,7 @@ cross-fetch@^3.0.4: dependencies: node-fetch "2.6.1" -cross-spawn@^6.0.0: +cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== @@ -3664,6 +3669,13 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" +find-yarn-workspace-root@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd" + integrity sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ== + dependencies: + micromatch "^4.0.2" + flat-cache@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" @@ -3743,6 +3755,15 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" +fs-extra@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-readdir-recursive@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" @@ -3919,7 +3940,7 @@ gonzales-pe@^4.3.0: dependencies: minimist "^1.2.5" -graceful-fs@^4.1.11, graceful-fs@^4.2.4: +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.4: version "4.2.6" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== @@ -4595,7 +4616,7 @@ is-windows@^1.0.2: resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== -is-wsl@^2.2.0: +is-wsl@^2.1.1, is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== @@ -5217,6 +5238,13 @@ json5@^2.1.2: dependencies: minimist "^1.2.5" +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -5266,6 +5294,13 @@ kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== +klaw-sync@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c" + integrity sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ== + dependencies: + graceful-fs "^4.1.11" + kleur@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" @@ -5937,6 +5972,14 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" +open@^7.4.2: + version "7.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" + integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== + dependencies: + is-docker "^2.0.0" + is-wsl "^2.1.1" + optionator@^0.8.1: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" @@ -5966,6 +6009,11 @@ opus-recorder@^8.0.3: resolved "https://registry.yarnpkg.com/opus-recorder/-/opus-recorder-8.0.3.tgz#f7b44f8f68500c9b96a15042a69f915fd9c1716d" integrity sha512-8vXGiRwlJAavT9D3yYzukNVXQ8vEcKHcsQL/zXO24DQtJ0PLXvoPHNQPJrbMCdB4ypJgWDExvHF4JitQDL7dng== +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + p-each-series@^2.1.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.2.0.tgz#105ab0357ce72b202a8a8b94933672657b5e2a9a" @@ -6074,6 +6122,25 @@ pascalcase@^0.1.1: resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= +patch-package@^6.4.7: + version "6.4.7" + resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-6.4.7.tgz#2282d53c397909a0d9ef92dae3fdeb558382b148" + integrity sha512-S0vh/ZEafZ17hbhgqdnpunKDfzHQibQizx9g8yEf5dcVk3KOflOfdufRXQX8CSEkyOQwuM/bNz1GwKvFj54kaQ== + dependencies: + "@yarnpkg/lockfile" "^1.1.0" + chalk "^2.4.2" + cross-spawn "^6.0.5" + find-yarn-workspace-root "^2.0.0" + fs-extra "^7.0.1" + is-ci "^2.0.0" + klaw-sync "^6.0.0" + minimist "^1.2.0" + open "^7.4.2" + rimraf "^2.6.3" + semver "^5.6.0" + slash "^2.0.0" + tmp "^0.0.33" + path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" @@ -6254,13 +6321,18 @@ postcss@^8.0.2: nanoid "^3.1.23" source-map-js "^0.6.2" -posthog-js@1.12.1: - version "1.12.1" - resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.12.1.tgz#97834ee2574f34ffb5db2f5b07452c847e3c4d27" - integrity sha512-Y3lzcWkS8xFY6Ryj3I4ees7qWP2WGkLw0Arcbk5xaT0+5YlA6UC2jlL/+fN9bz/Bl62EoN3BML901Cuot/QNjg== +posthog-js@^1.12.2: + version "1.12.2" + resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.12.2.tgz#ff76e26634067e003f8af7df654d7ea0e647d946" + integrity sha512-I0d6c+Yu2f91PFidz65AIkkqZM219EY9Z1wlbTkW5Zqfq5oXqogBMKS8BaDBOrMc46LjLX7IH67ytCcBFRo1uw== dependencies: fflate "^0.4.1" +postinstall-postinstall@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postinstall-postinstall/-/postinstall-postinstall-2.1.0.tgz#4f7f77441ef539d1512c40bd04c71b06a4704ca3" + integrity sha512-7hQX6ZlZXIoRiWNrbMQaLzUUfH+sSx39u8EJ9HYuDc1kLo9IXKWjM5RSquZN1ad5GnH8CGFM78fsAAQi3OKEEQ== + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -6834,6 +6906,13 @@ rfc4648@^1.4.0: resolved "https://registry.yarnpkg.com/rfc4648/-/rfc4648-1.5.0.tgz#1ba940ec1649685ec4d88788dc57fb8e18855055" integrity sha512-FA6W9lDNeX8WbMY31io1xWg+TpZCbeDKsBo0ocwACZiWnh9TUAyk9CCuBQuOPmYnwwdEQZmraQ2ZK7yJsxErBg== +rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -7520,6 +7599,13 @@ tmatch@^2.0.1: resolved "https://registry.yarnpkg.com/tmatch/-/tmatch-2.0.1.tgz#0c56246f33f30da1b8d3d72895abaf16660f38cf" integrity sha1-DFYkbzPzDaG409colauvFmYPOM8= +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + tmpl@1.0.x: version "1.0.4" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" @@ -7765,7 +7851,7 @@ unist-util-stringify-position@^2.0.0: dependencies: "@types/unist" "^2.0.2" -universalify@^0.1.2: +universalify@^0.1.0, universalify@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== From 612384a6a36bf468cc4575d8fccb9d1cbf941ff0 Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 3 Aug 2021 18:03:46 +0100 Subject: [PATCH 3/8] Switch to new changelog generator allchange is typescript so has a 'prepare' script to tsc it into javascript so it can be a binscript - hopefully this won't cause it to make too much of a pain of itself causing tsc to run on every yarn add/install --- package.json | 1 + yarn.lock | 311 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 309 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 704315ca69..fcb1e9133c 100644 --- a/package.json +++ b/package.json @@ -147,6 +147,7 @@ "@typescript-eslint/eslint-plugin": "^4.17.0", "@typescript-eslint/parser": "^4.17.0", "@wojtekmaj/enzyme-adapter-react-17": "^0.6.1", + "allchange": "github:matrix-org/allchange", "babel-jest": "^26.6.3", "chokidar": "^3.5.1", "concurrently": "^5.3.0", diff --git a/yarn.lock b/yarn.lock index f121112a1b..2b504d2366 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1324,6 +1324,107 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@octokit/auth-token@^2.4.4": + version "2.4.5" + resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.5.tgz#568ccfb8cb46f36441fac094ce34f7a875b197f3" + integrity sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA== + dependencies: + "@octokit/types" "^6.0.3" + +"@octokit/core@^3.5.0": + version "3.5.1" + resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.5.1.tgz#8601ceeb1ec0e1b1b8217b960a413ed8e947809b" + integrity sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw== + dependencies: + "@octokit/auth-token" "^2.4.4" + "@octokit/graphql" "^4.5.8" + "@octokit/request" "^5.6.0" + "@octokit/request-error" "^2.0.5" + "@octokit/types" "^6.0.3" + before-after-hook "^2.2.0" + universal-user-agent "^6.0.0" + +"@octokit/endpoint@^6.0.1": + version "6.0.12" + resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.12.tgz#3b4d47a4b0e79b1027fb8d75d4221928b2d05658" + integrity sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA== + dependencies: + "@octokit/types" "^6.0.3" + is-plain-object "^5.0.0" + universal-user-agent "^6.0.0" + +"@octokit/graphql@^4.5.8": + version "4.6.4" + resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.6.4.tgz#0c3f5bed440822182e972317122acb65d311a5ed" + integrity sha512-SWTdXsVheRmlotWNjKzPOb6Js6tjSqA2a8z9+glDJng0Aqjzti8MEWOtuT8ZSu6wHnci7LZNuarE87+WJBG4vg== + dependencies: + "@octokit/request" "^5.6.0" + "@octokit/types" "^6.0.3" + universal-user-agent "^6.0.0" + +"@octokit/openapi-types@^9.3.0": + version "9.3.0" + resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-9.3.0.tgz#160347858d727527901c6aae7f7d5c2414cc1f2e" + integrity sha512-oz60hhL+mDsiOWhEwrj5aWXTOMVtQgcvP+sRzX4C3cH7WOK9QSAoEtjWh0HdOf6V3qpdgAmUMxnQPluzDWR7Fw== + +"@octokit/plugin-paginate-rest@^2.6.2": + version "2.15.0" + resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.15.0.tgz#9c956c3710b2bd786eb3814eaf5a2b17392c150d" + integrity sha512-/vjcb0w6ggVRtsb8OJBcRR9oEm+fpdo8RJk45khaWw/W0c8rlB2TLCLyZt/knmC17NkX7T9XdyQeEY7OHLSV1g== + dependencies: + "@octokit/types" "^6.23.0" + +"@octokit/plugin-request-log@^1.0.2": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz#5e50ed7083a613816b1e4a28aeec5fb7f1462e85" + integrity sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA== + +"@octokit/plugin-rest-endpoint-methods@5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.6.0.tgz#c28833b88d0f07bf94093405d02d43d73c7de99b" + integrity sha512-2G7lIPwjG9XnTlNhe/TRnpI8yS9K2l68W4RP/ki3wqw2+sVeTK8hItPxkqEI30VeH0UwnzpuksMU/yHxiVVctw== + dependencies: + "@octokit/types" "^6.23.0" + deprecation "^2.3.1" + +"@octokit/request-error@^2.0.5", "@octokit/request-error@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.1.0.tgz#9e150357831bfc788d13a4fd4b1913d60c74d677" + integrity sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg== + dependencies: + "@octokit/types" "^6.0.3" + deprecation "^2.0.0" + once "^1.4.0" + +"@octokit/request@^5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.6.0.tgz#6084861b6e4fa21dc40c8e2a739ec5eff597e672" + integrity sha512-4cPp/N+NqmaGQwbh3vUsYqokQIzt7VjsgTYVXiwpUP2pxd5YiZB2XuTedbb0SPtv9XS7nzAKjAuQxmY8/aZkiA== + dependencies: + "@octokit/endpoint" "^6.0.1" + "@octokit/request-error" "^2.1.0" + "@octokit/types" "^6.16.1" + is-plain-object "^5.0.0" + node-fetch "^2.6.1" + universal-user-agent "^6.0.0" + +"@octokit/rest@^18.6.7": + version "18.8.0" + resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.8.0.tgz#ba24f7ba554f015a7ae2b7cc2aecef5386ddfea5" + integrity sha512-lsuNRhgzGnLMn/NmQTNCit/6jplFWiTUlPXhqN0zCMLwf2/9pseHzsnTW+Cjlp4bLMEJJNPa5JOzSLbSCOahKw== + dependencies: + "@octokit/core" "^3.5.0" + "@octokit/plugin-paginate-rest" "^2.6.2" + "@octokit/plugin-request-log" "^1.0.2" + "@octokit/plugin-rest-endpoint-methods" "5.6.0" + +"@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.23.0": + version "6.23.0" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.23.0.tgz#b39f242b20036e89fa8f34f7962b4e9b7ff8f65b" + integrity sha512-eG3clC31GSS7K3oBK6C6o7wyXPrkP+mu++eus8CSZdpRytJ5PNszYxudOQ0spWZQ3S9KAtoTG6v1WK5prJcJrA== + dependencies: + "@octokit/openapi-types" "^9.3.0" + "@peculiar/asn1-schema@^2.0.27", "@peculiar/asn1-schema@^2.0.32": version "2.0.37" resolved "https://registry.yarnpkg.com/@peculiar/asn1-schema/-/asn1-schema-2.0.37.tgz#700476512ab903d809f64a3040fb1b2fe6fb6d4b" @@ -1850,6 +1951,17 @@ ajv@^8.0.1: require-from-string "^2.0.2" uri-js "^4.2.2" +"allchange@github:matrix-org/allchange": + version "0.0.1" + resolved "https://codeload.github.com/matrix-org/allchange/tar.gz/56b37b06339a3ac3fe771f3ec3d0bff798df8dab" + dependencies: + "@octokit/rest" "^18.6.7" + cli-color "^2.0.0" + js-yaml "^4.1.0" + loglevel "^1.7.1" + semver "^7.3.5" + yargs "^17.0.1" + another-json@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/another-json/-/another-json-0.2.0.tgz#b5f4019c973b6dd5c6506a2d93469cb6d32aeedc" @@ -1867,6 +1979,11 @@ ansi-escapes@^4.2.1: dependencies: type-fest "^0.21.3" +ansi-regex@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + ansi-regex@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" @@ -1914,6 +2031,11 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" @@ -2206,6 +2328,11 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" +before-after-hook@^2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e" + integrity sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ== + binary-extensions@^1.0.0: version "1.13.1" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" @@ -2506,6 +2633,18 @@ classnames@*, classnames@^2.2.6: resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== +cli-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/cli-color/-/cli-color-2.0.0.tgz#11ecfb58a79278cf6035a60c54e338f9d837897c" + integrity sha512-a0VZ8LeraW0jTuCkuAGMNufareGHhyZU9z8OGsW0gXd1hZGi1SRuNRXdbGkraBBKnhyUhyebFWnRbp+dIn0f0A== + dependencies: + ansi-regex "^2.1.1" + d "^1.0.1" + es5-ext "^0.10.51" + es6-iterator "^2.0.3" + memoizee "^0.4.14" + timers-ext "^0.1.7" + cliui@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" @@ -2524,6 +2663,15 @@ cliui@^6.0.0: strip-ansi "^6.0.0" wrap-ansi "^6.2.0" +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + clone-deep@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" @@ -2788,6 +2936,14 @@ csstype@^3.0.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.8.tgz#d2266a792729fb227cd216fb572f43728e1ad340" integrity sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw== +d@1, d@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" + integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== + dependencies: + es5-ext "^0.10.50" + type "^1.0.1" + dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" @@ -2895,6 +3051,11 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= +deprecation@^2.0.0, deprecation@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" + integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== + detect-newline@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" @@ -3191,6 +3352,42 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" +es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@^0.10.51, es5-ext@^0.10.53, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46: + version "0.10.53" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1" + integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q== + dependencies: + es6-iterator "~2.0.3" + es6-symbol "~3.1.3" + next-tick "~1.0.0" + +es6-iterator@^2.0.3, es6-iterator@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-symbol@^3.1.1, es6-symbol@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" + integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== + dependencies: + d "^1.0.1" + ext "^1.1.2" + +es6-weak-map@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.3.tgz#b6da1f16cc2cc0d9be43e6bdbfc5e7dfcdf31d53" + integrity sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA== + dependencies: + d "1" + es5-ext "^0.10.46" + es6-iterator "^2.0.3" + es6-symbol "^3.1.1" + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -3383,6 +3580,14 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +event-emitter@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + integrity sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk= + dependencies: + d "1" + es5-ext "~0.10.14" + events@^3.2.0: version "3.3.0" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" @@ -3478,6 +3683,13 @@ expect@^26.6.2: jest-message-util "^26.6.2" jest-regex-util "^26.0.0" +ext@^1.1.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244" + integrity sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A== + dependencies: + type "^2.0.0" + extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" @@ -3783,7 +3995,7 @@ gensync@^1.0.0-beta.2: resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== -get-caller-file@^2.0.1: +get-caller-file@^2.0.1, get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== @@ -4502,6 +4714,11 @@ is-potential-custom-element-name@^1.0.1: resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== +is-promise@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" + integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== + is-regex@^1.0.3, is-regex@^1.0.5, is-regex@^1.1.2, is-regex@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.3.tgz#d029f9aff6448b93ebbe3f33dac71511fdcbef9f" @@ -5122,6 +5339,13 @@ js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" @@ -5396,6 +5620,13 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lru-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3" + integrity sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM= + dependencies: + es5-ext "~0.10.2" + make-dir@^2.0.0, make-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" @@ -5528,6 +5759,20 @@ memoize-one@^5.1.1: resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== +memoizee@^0.4.14: + version "0.4.15" + resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.15.tgz#e6f3d2da863f318d02225391829a6c5956555b72" + integrity sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ== + dependencies: + d "^1.0.1" + es5-ext "^0.10.53" + es6-weak-map "^2.0.3" + event-emitter "^0.3.5" + is-promise "^2.2.2" + lru-queue "^0.1.0" + next-tick "^1.1.0" + timers-ext "^0.1.7" + meow@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/meow/-/meow-9.0.0.tgz#cd9510bc5cac9dee7d03c73ee1f9ad959f4ea364" @@ -5701,12 +5946,22 @@ nearley@^2.7.10: railroad-diagrams "^1.0.0" randexp "0.4.6" +next-tick@1, next-tick@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" + integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== + +next-tick@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" + integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== -node-fetch@2.6.1: +node-fetch@2.6.1, node-fetch@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== @@ -7498,6 +7753,14 @@ throat@^5.0.0: resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== +timers-ext@^0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/timers-ext/-/timers-ext-0.1.7.tgz#6f57ad8578e07a3fb9f91d9387d65647555e25c6" + integrity sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ== + dependencies: + es5-ext "~0.10.46" + next-tick "1" + tiny-invariant@^1.0.6: version "1.1.0" resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" @@ -7657,6 +7920,16 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== +type@^1.0.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" + integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== + +type@^2.0.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/type/-/type-2.5.0.tgz#0a2e78c2e77907b252abe5f298c1b01c63f0db3d" + integrity sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw== + typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" @@ -7753,6 +8026,11 @@ unist-util-stringify-position@^2.0.0: dependencies: "@types/unist" "^2.0.2" +universal-user-agent@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" + integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== + universalify@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" @@ -8056,6 +8334,15 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -8091,6 +8378,11 @@ y18n@^4.0.0: resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" @@ -8117,7 +8409,7 @@ yargs-parser@^18.1.2: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^20.2.3: +yargs-parser@^20.2.2, yargs-parser@^20.2.3: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== @@ -8155,6 +8447,19 @@ yargs@^15.4.1: y18n "^4.0.0" yargs-parser "^18.1.2" +yargs@^17.0.1: + version "17.0.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.0.1.tgz#6a1ced4ed5ee0b388010ba9fd67af83b9362e0bb" + integrity sha512-xBBulfCc8Y6gLFcrPvtqKz9hz8SO0l1Ni8GgDekvBX2ro0HRQImDGnikfc33cgzcYUSncapnNcZDjVFIH3f6KQ== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + zwitch@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920" From 82c644564870090dc9293bdef86b5fb69d0f6dad Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 30 Jul 2021 21:35:11 +0100 Subject: [PATCH 4/8] Add release_config for changelogging --- release_config.yaml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 release_config.yaml diff --git a/release_config.yaml b/release_config.yaml new file mode 100644 index 0000000000..12e857cbdd --- /dev/null +++ b/release_config.yaml @@ -0,0 +1,4 @@ +subprojects: + matrix-js-sdk: + includeByDefault: false + From 4b78edd65241256351e68b799b05c607de5bd574 Mon Sep 17 00:00:00 2001 From: James Salter Date: Wed, 4 Aug 2021 09:30:04 +0100 Subject: [PATCH 5/8] Remove patch-package and postinstall-postinstall --- package.json | 5 +- patches/posthog-js+1.12.2.patch | 78 --------------------------- yarn.lock | 96 ++------------------------------- 3 files changed, 6 insertions(+), 173 deletions(-) delete mode 100644 patches/posthog-js+1.12.2.patch diff --git a/package.json b/package.json index e7ea85ccd4..8f5459ab99 100644 --- a/package.json +++ b/package.json @@ -51,8 +51,7 @@ "lint:style": "stylelint 'res/css/**/*.scss'", "test": "jest", "test:e2e": "./test/end-to-end-tests/run.sh --app-url http://localhost:8080", - "coverage": "yarn test --coverage", - "postinstall": "patch-package" + "coverage": "yarn test --coverage" }, "dependencies": { "@babel/runtime": "^7.12.5", @@ -166,8 +165,6 @@ "matrix-mock-request": "^1.2.3", "matrix-react-test-utils": "^0.2.3", "matrix-web-i18n": "github:matrix-org/matrix-web-i18n", - "patch-package": "^6.4.7", - "postinstall-postinstall": "^2.1.0", "react-test-renderer": "^17.0.2", "rimraf": "^3.0.2", "stylelint": "^13.9.0", diff --git a/patches/posthog-js+1.12.2.patch b/patches/posthog-js+1.12.2.patch deleted file mode 100644 index 430a9f0a62..0000000000 --- a/patches/posthog-js+1.12.2.patch +++ /dev/null @@ -1,78 +0,0 @@ -diff --git a/node_modules/posthog-js/dist/module.d.ts b/node_modules/posthog-js/dist/module.d.ts -index d3cba02..8c87ef8 100644 ---- a/node_modules/posthog-js/dist/module.d.ts -+++ b/node_modules/posthog-js/dist/module.d.ts -@@ -1,7 +1,5 @@ - // Type definitions for exported methods -- --import { EventProcessor, Integration } from '@sentry/types' --import { MaskInputOptions, SlimDOMOptions } from 'rrweb-snapshot' -+// Patched to remove references to sentry and rrweb-snapshot which aren't otherwise SDK dependencies - - declare class posthog { - /** -@@ -485,25 +483,6 @@ declare class posthog { - */ - static reloadFeatureFlags(): void - -- /** -- * Integrate Sentry with PostHog. This will add a direct link to the person in Sentry, and an $exception event in PostHog -- * -- * ### Usage -- * -- * Sentry.init({ -- * dsn: 'https://example', -- * integrations: [ -- * new posthog.SentryIntegration(posthog) -- * ] -- * }) -- * -- * @param {Object} [posthog] The posthog object -- * @param {string} [organization] Optional: The Sentry organization, used to send a direct link from PostHog to Sentry -- * @param {Number} [projectId] Optional: The Sentry project id, used to send a direct link from PostHog to Sentry -- * @param {string} [prefix] Optional: Url of a self-hosted sentry instance (default: https://sentry.io/organizations/) -- */ -- static SentryIntegration: typeof SentryIntegration -- - static toString(): string - - /* Will log all capture requests to the Javascript console, including event properties for easy debugging */ -@@ -585,7 +564,6 @@ declare namespace posthog { - request_batching?: boolean - sanitize_properties?: (properties: posthog.Properties, event_name: string) => posthog.Properties - properties_string_max_length?: number -- session_recording?: SessionRecordingOptions - mask_all_element_attributes?: boolean - mask_all_text?: boolean - advanced_disable_decide?: boolean -@@ -618,17 +596,6 @@ declare namespace posthog { - send_event: boolean - } - -- interface SessionRecordingOptions { -- blockClass?: string | RegExp -- blockSelector?: string -- ignoreClass?: string -- maskAllInputs?: boolean -- maskInputOptions?: MaskInputOptions -- maskInputFn?: (text: string) => string -- slimDOMOptions?: SlimDOMOptions | 'all' | true -- collectFonts?: boolean -- } -- - export class persistence { - static properties(): posthog.Properties - -@@ -768,12 +735,6 @@ declare namespace posthog { - export class feature_flags extends featureFlags {} - } - --export class SentryIntegration implements Integration { -- constructor(posthog: posthog, organization?: string, projectId?: number, prefix?: string) -- name: string -- setupOnce(addGlobalEventProcessor: (callback: EventProcessor) => void): void --} -- - export type PostHog = typeof posthog - - export default posthog diff --git a/yarn.lock b/yarn.lock index 6bb5654db8..891822a66e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1790,11 +1790,6 @@ object.fromentries "^2.0.0" prop-types "^15.7.0" -"@yarnpkg/lockfile@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" - integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== - abab@^2.0.3, abab@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" @@ -2718,7 +2713,7 @@ cross-fetch@^3.0.4: dependencies: node-fetch "2.6.1" -cross-spawn@^6.0.0, cross-spawn@^6.0.5: +cross-spawn@^6.0.0: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== @@ -3669,13 +3664,6 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" -find-yarn-workspace-root@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd" - integrity sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ== - dependencies: - micromatch "^4.0.2" - flat-cache@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" @@ -3755,15 +3743,6 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" -fs-extra@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" - integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs-readdir-recursive@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" @@ -3940,7 +3919,7 @@ gonzales-pe@^4.3.0: dependencies: minimist "^1.2.5" -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.4: +graceful-fs@^4.1.11, graceful-fs@^4.2.4: version "4.2.6" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== @@ -4616,7 +4595,7 @@ is-windows@^1.0.2: resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== -is-wsl@^2.1.1, is-wsl@^2.2.0: +is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== @@ -5238,13 +5217,6 @@ json5@^2.1.2: dependencies: minimist "^1.2.5" -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -5294,13 +5266,6 @@ kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== -klaw-sync@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c" - integrity sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ== - dependencies: - graceful-fs "^4.1.11" - kleur@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" @@ -5972,14 +5937,6 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" -open@^7.4.2: - version "7.4.2" - resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" - integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== - dependencies: - is-docker "^2.0.0" - is-wsl "^2.1.1" - optionator@^0.8.1: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" @@ -6009,11 +5966,6 @@ opus-recorder@^8.0.3: resolved "https://registry.yarnpkg.com/opus-recorder/-/opus-recorder-8.0.3.tgz#f7b44f8f68500c9b96a15042a69f915fd9c1716d" integrity sha512-8vXGiRwlJAavT9D3yYzukNVXQ8vEcKHcsQL/zXO24DQtJ0PLXvoPHNQPJrbMCdB4ypJgWDExvHF4JitQDL7dng== -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - p-each-series@^2.1.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.2.0.tgz#105ab0357ce72b202a8a8b94933672657b5e2a9a" @@ -6122,25 +6074,6 @@ pascalcase@^0.1.1: resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= -patch-package@^6.4.7: - version "6.4.7" - resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-6.4.7.tgz#2282d53c397909a0d9ef92dae3fdeb558382b148" - integrity sha512-S0vh/ZEafZ17hbhgqdnpunKDfzHQibQizx9g8yEf5dcVk3KOflOfdufRXQX8CSEkyOQwuM/bNz1GwKvFj54kaQ== - dependencies: - "@yarnpkg/lockfile" "^1.1.0" - chalk "^2.4.2" - cross-spawn "^6.0.5" - find-yarn-workspace-root "^2.0.0" - fs-extra "^7.0.1" - is-ci "^2.0.0" - klaw-sync "^6.0.0" - minimist "^1.2.0" - open "^7.4.2" - rimraf "^2.6.3" - semver "^5.6.0" - slash "^2.0.0" - tmp "^0.0.33" - path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" @@ -6321,18 +6254,13 @@ postcss@^8.0.2: nanoid "^3.1.23" source-map-js "^0.6.2" -posthog-js@^1.12.2: +posthog-js@1.12.2: version "1.12.2" resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.12.2.tgz#ff76e26634067e003f8af7df654d7ea0e647d946" integrity sha512-I0d6c+Yu2f91PFidz65AIkkqZM219EY9Z1wlbTkW5Zqfq5oXqogBMKS8BaDBOrMc46LjLX7IH67ytCcBFRo1uw== dependencies: fflate "^0.4.1" -postinstall-postinstall@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/postinstall-postinstall/-/postinstall-postinstall-2.1.0.tgz#4f7f77441ef539d1512c40bd04c71b06a4704ca3" - integrity sha512-7hQX6ZlZXIoRiWNrbMQaLzUUfH+sSx39u8EJ9HYuDc1kLo9IXKWjM5RSquZN1ad5GnH8CGFM78fsAAQi3OKEEQ== - prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -6906,13 +6834,6 @@ rfc4648@^1.4.0: resolved "https://registry.yarnpkg.com/rfc4648/-/rfc4648-1.5.0.tgz#1ba940ec1649685ec4d88788dc57fb8e18855055" integrity sha512-FA6W9lDNeX8WbMY31io1xWg+TpZCbeDKsBo0ocwACZiWnh9TUAyk9CCuBQuOPmYnwwdEQZmraQ2ZK7yJsxErBg== -rimraf@^2.6.3: - version "2.7.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - dependencies: - glob "^7.1.3" - rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -7599,13 +7520,6 @@ tmatch@^2.0.1: resolved "https://registry.yarnpkg.com/tmatch/-/tmatch-2.0.1.tgz#0c56246f33f30da1b8d3d72895abaf16660f38cf" integrity sha1-DFYkbzPzDaG409colauvFmYPOM8= -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - tmpl@1.0.x: version "1.0.4" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" @@ -7851,7 +7765,7 @@ unist-util-stringify-position@^2.0.0: dependencies: "@types/unist" "^2.0.2" -universalify@^0.1.0, universalify@^0.1.2: +universalify@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== From 17b935cbc4d7b9ab86e2a885c5da0bd0ff5a252b Mon Sep 17 00:00:00 2001 From: James Salter Date: Wed, 4 Aug 2021 09:34:12 +0100 Subject: [PATCH 6/8] Add @sentry/types and rrweb-snapshot as dev dependencies This is neccessary to resolve re-exported types referred to by posthog-js' type definitions. This isn't ideal, but * We intend to start using sentry anyway * Discussion with posthog maintainers about rrweb-snapshot at https://github.com/PostHog/posthog-js/issues/252, perhaps we can find another solution soon --- package.json | 2 ++ yarn.lock | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/package.json b/package.json index 8f5459ab99..0bcf86bff0 100644 --- a/package.json +++ b/package.json @@ -124,6 +124,7 @@ "@babel/traverse": "^7.12.12", "@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz", "@peculiar/webcrypto": "^1.1.4", + "@sentry/types": "^6.10.0", "@sinonjs/fake-timers": "^7.0.2", "@types/classnames": "^2.2.11", "@types/commonmark": "^0.27.4", @@ -167,6 +168,7 @@ "matrix-web-i18n": "github:matrix-org/matrix-web-i18n", "react-test-renderer": "^17.0.2", "rimraf": "^3.0.2", + "rrweb-snapshot": "1.1.7", "stylelint": "^13.9.0", "stylelint-config-standard": "^20.0.0", "stylelint-scss": "^3.18.0", diff --git a/yarn.lock b/yarn.lock index 891822a66e..836301b002 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1352,6 +1352,11 @@ tslib "^2.2.0" webcrypto-core "^1.2.0" +"@sentry/types@^6.10.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.10.0.tgz#6b1f44e5ed4dbc2710bead24d1b32fb08daf04e1" + integrity sha512-M7s0JFgG7/6/yNVYoPUbxzaXDhnzyIQYRRJJKRaTD77YO4MHvi4Ke8alBWqD5fer0cPIfcSkBqa9BLdqRqcMWw== + "@sinonjs/commons@^1.7.0": version "1.8.3" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" @@ -6841,6 +6846,11 @@ rimraf@^3.0.0, rimraf@^3.0.2: dependencies: glob "^7.1.3" +rrweb-snapshot@1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/rrweb-snapshot/-/rrweb-snapshot-1.1.7.tgz#92a3b47b1112a1b566c2fae2edb02fa48a6f6653" + integrity sha512-+f2kCCvIQ1hbEeCWnV7mPVPDEdWEExqwcYqMd/r1nfK52QE7qU52jefUOyTe85Vy67rZGqWnfK/B25e/OTSgYg== + rst-selector-parser@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz#81b230ea2fcc6066c89e3472de794285d9b03d91" From 7cb21c845faa2ef835414dd647999479877c9b9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Wed, 4 Aug 2021 10:33:37 +0200 Subject: [PATCH 7/8] Fix indent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/HtmlUtils.tsx | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index 27556a4012..2eee5214af 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -57,10 +57,33 @@ const BIGEMOJI_REGEX = new RegExp(`^(${EMOJIBASE_REGEX.source})+$`, 'i'); const COLOR_REGEX = /^#[0-9a-fA-F]{6}$/; -export const PERMITTED_URL_SCHEMES = ["bitcoin", "ftp", "geo", "http", "https", "im", "irc", - "ircs", "magnet", "mailto", "matrix", "mms", "news", - "nntp", "openpgp4fpr", "sip", "sftp", "sms", "smsto", - "ssh", "tel", "urn", "webcal", "wtai", "xmpp"]; +export const PERMITTED_URL_SCHEMES = [ + "bitcoin", + "ftp", + "geo", + "http", + "https", + "im", + "irc", + "ircs", + "magnet", + "mailto", + "matrix", + "mms", + "news", + "nntp", + "openpgp4fpr", + "sip", + "sftp", + "sms", + "smsto", + "ssh", + "tel", + "urn", + "webcal", + "wtai", + "xmpp", +]; const MEDIA_API_MXC_REGEX = /\/_matrix\/media\/r0\/(?:download|thumbnail)\/(.+?)\/(.+?)(?:[?/]|$)/; From c9c8177f58353fc4b71aa39cb6b8d40ee74d4779 Mon Sep 17 00:00:00 2001 From: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> Date: Wed, 4 Aug 2021 09:46:39 +0100 Subject: [PATCH 8/8] Start a call immediately after creating a room via the dial pad (#6529) --- src/CallHandler.tsx | 2 ++ test/CallHandler-test.ts | 6 +++++- test/test-utils.js | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/CallHandler.tsx b/src/CallHandler.tsx index caf010200a..30fcf46790 100644 --- a/src/CallHandler.tsx +++ b/src/CallHandler.tsx @@ -930,6 +930,8 @@ export default class CallHandler extends EventEmitter { action: 'view_room', room_id: roomId, }); + + await this.placeCall(roomId, PlaceCallType.Voice, null); } private async startTransferToPhoneNumber(call: MatrixCall, destination: string, consultFirst: boolean) { diff --git a/test/CallHandler-test.ts b/test/CallHandler-test.ts index 4c3dd25fb4..1a4560ad4a 100644 --- a/test/CallHandler-test.ts +++ b/test/CallHandler-test.ts @@ -156,13 +156,14 @@ describe('CallHandler', () => { DMRoomMap.setShared(null); // @ts-ignore window.mxCallHandler = null; + fakeCall = null; MatrixClientPeg.unset(); document.body.removeChild(audioElement); SdkConfig.unset(); }); - it('should look up the correct user and open the room when a phone number is dialled', async () => { + it('should look up the correct user and start a call in the room when a phone number is dialled', async () => { MatrixClientPeg.get().getThirdpartyUser = jest.fn().mockResolvedValue([{ userid: '@user2:example.org', protocol: "im.vector.protocol.sip_native", @@ -179,6 +180,9 @@ describe('CallHandler', () => { const viewRoomPayload = await untilDispatch('view_room'); expect(viewRoomPayload.room_id).toEqual(MAPPED_ROOM_ID); + + // Check that a call was started + expect(fakeCall.roomId).toEqual(MAPPED_ROOM_ID); }); it('should move calls between rooms when remote asserted identity changes', async () => { diff --git a/test/test-utils.js b/test/test-utils.js index 217c399443..bbab47589a 100644 --- a/test/test-utils.js +++ b/test/test-utils.js @@ -78,6 +78,7 @@ export function createTestClient() { }, mxcUrlToHttp: (mxc) => 'http://this.is.a.url/', setAccountData: jest.fn(), + setRoomAccountData: jest.fn(), sendTyping: jest.fn().mockResolvedValue({}), sendMessage: () => jest.fn().mockResolvedValue({}), getSyncState: () => "SYNCING",