fix(fe2): accept invite before onboarding after sign up (#2491)

* explicitly ordering global middlewares

* various subscription fixes & WIP project invite middleware

* SSR invite accept & toast notifs seem to work

* backend support for mixpanel

* mixpanel be logic -> shared

* minor fix

* finissh

* lint fix

* minor comment adjustments

* better adblock handling
This commit is contained in:
Kristaps Fabians Geikins
2024-07-11 11:45:11 +03:00
committed by GitHub
parent 790d97383c
commit ee5ae8af62
43 changed files with 774 additions and 347 deletions
+3 -1
View File
@@ -1,4 +1,4 @@
import { isNull, isNumber, isUndefined } from '#lodash'
import { isNull, isNumber, isUndefined, noop } from '#lodash'
import type {
MaybeAsync,
NonNullableProperties,
@@ -144,3 +144,5 @@ export const removeNullOrUndefinedKeys = <T extends Record<string, unknown>>(
export const isArrayOf = <T>(arr: unknown, guard: (v: unknown) => v is T): arr is T[] =>
Array.isArray(arr) && arr.every(guard)
export const waitForever = (): Promise<never> => new Promise<never>(noop)
@@ -0,0 +1,101 @@
/* eslint-disable camelcase */
import Mixpanel from 'mixpanel'
import type { IncomingHttpHeaders } from 'node:http'
import type { Optional } from '../core/helpers/utilityTypes.js'
import UAParser from 'ua-parser-js'
import { resolveMixpanelServerId } from '../core/helpers/tracking.js'
export const buildServerMixpanelClient = (params: {
tokenId: string
apiHostname: string
debug?: boolean
}) => {
const { tokenId, apiHostname, debug } = params
const client = Mixpanel.init(tokenId, {
host: apiHostname,
debug
})
return client
}
export const buildBasePropertiesPayload = (params: {
/**
* Host app identifier
*/
hostApp: string
/**
* The public origin (URL) of the server
*/
serverOrigin: string
speckleVersion: string
}) => {
const { hostApp, serverOrigin, speckleVersion } = params
return {
server_id: resolveMixpanelServerId(new URL(serverOrigin).hostname),
hostApp,
speckleVersion
}
}
export const buildPropertiesPayload = (params: {
/**
* User's distinctId. If not provided, the user will be treated as anonymous
*/
distinctId?: string
headers?: IncomingHttpHeaders
query?: Record<string, unknown>
/**
* User's IP address from request
*/
remoteAddress?: string
}) => {
const { distinctId, headers, query, remoteAddress } = params
const userProps = distinctId ? { distinct_id: distinctId } : {}
// User agent
const userAgentString = headers?.['user-agent'] as Optional<string>
const uaParser = userAgentString ? new UAParser(userAgentString) : null
const uaProps = uaParser
? {
$browser: uaParser.getBrowser().name,
$device: uaParser.getDevice().model,
$os: uaParser.getOS().name
}
: {}
// Referer
const refererHeader = headers?.['referer'] as Optional<string>
const refererDomain = refererHeader ? new URL(refererHeader).host : null
const refererProps = {
...(refererHeader ? { $referrer: refererHeader } : {}),
...(refererDomain ? { $referring_domain: refererDomain } : {})
}
// Utm
const utmKeys = [
'utm_source',
'utm_medium',
'utm_campaign',
'utm_content',
'utm_term'
]
const utmProps = utmKeys.reduce((acc, key) => {
const value = query?.[key] as Optional<string>
return value ? { ...acc, [key]: value } : acc
}, {})
// Remote addr
const remoteAddr = (headers?.['x-forwarded-for'] as Optional<string>) || remoteAddress
const remoteAddrProps = remoteAddr ? { ip: remoteAddr } : {}
return {
...userProps,
...uaProps,
...refererProps,
...utmProps,
...remoteAddrProps
}
}