mirror of
https://github.com/hanzoai/insights-js.git
synced 2026-10-30 18:34:19 +00:00
We own the ingestion server (hanzoai/insights: Django + rust/capture + nodejs plugin) AND this SDK, so there is no external wire contract to preserve. The server is already 100% posthog-free; this SDK was the last laggard. - $last_posthog_reset -> $last_insights_reset. This FIXES A LIVE MISMATCH: the server taxonomy (insights/taxonomy/taxonomy.py, insights/insightsql/ai.py) already expected the insights form while the SDK emitted the posthog form. - __PosthogExtensions__ -> __InsightsExtensions__; all PostHog/posthog/POSTHOG identifiers -> Insights/insights/INSIGHTS (src, tests, playground, playwright, scripts, rrweb subpackages, package.json keywords). - Hosts: DEFAULT_PLUGIN_HOST + DEFAULT_NUXT_HOST + the core host default pointed at PostHog's cloud (us.i.posthog.com) — a real bug. All -> insights.hanzo.ai. - Removed the us-assets/eu-assets CDN split in getRemoteConfig (PostHog-specific; Hanzo serves remote config from the same host) — it had degenerated to a no-op. - Fixed generate-docs writing to a stray references/@hanzo/ subdir. - Renamed the 3 posthog-named test files; dropped 58MB of stale reference snapshots named for upstream posthog versions we never shipped (they are generated output — references/ is now gitignored). Verified: typecheck errors 42 (HEAD) -> 18 (all pre-existing test-mock looseness); types package 0; every package.json valid with @hanzo/* names. Guard: grep -rioE 'posthog' packages ... | wc -l => 0
456 lines
19 KiB
JavaScript
456 lines
19 KiB
JavaScript
import babel from '@rollup/plugin-babel'
|
|
import json from '@rollup/plugin-json'
|
|
import resolve from '@rollup/plugin-node-resolve'
|
|
import typescript from '@rollup/plugin-typescript'
|
|
import { dts } from 'rollup-plugin-dts'
|
|
import terser from '@rollup/plugin-terser'
|
|
import { visualizer } from 'rollup-plugin-visualizer'
|
|
import commonjs from '@rollup/plugin-commonjs'
|
|
import postcss from 'rollup-plugin-postcss'
|
|
import postcssImport from 'postcss-import'
|
|
import postcssNesting from 'postcss-nesting'
|
|
import cssnano from 'cssnano'
|
|
import fs from 'fs'
|
|
import path from 'path'
|
|
|
|
const WRITE_MANGLED_PROPERTIES = process.env.WRITE_MANGLED_PROPERTIES
|
|
const nameCachePath = './terser-mangled-names.json'
|
|
let nameCache = {}
|
|
|
|
// Shared across all entries so mangled property names are consistent between
|
|
// module.slim.js and extension-bundles.js — see #3313.
|
|
// Only property names (props) are shared; top-level variable names (vars) are
|
|
// reset per-entry by the plugin below since each module has its own scope.
|
|
|
|
const plugins = (es5, noExternal) => [
|
|
{
|
|
name: 'reset-vars-name-cache',
|
|
buildStart() {
|
|
nameCache.vars = { props: {} }
|
|
},
|
|
},
|
|
json(),
|
|
resolve({ browser: true }),
|
|
typescript({ sourceMap: true, outDir: './dist', module: 'es2015' }),
|
|
commonjs(),
|
|
postcss({
|
|
plugins: [
|
|
postcssImport(),
|
|
postcssNesting(),
|
|
cssnano({
|
|
preset: [
|
|
'default',
|
|
{
|
|
discardComments: { removeAll: true },
|
|
discardDuplicates: true,
|
|
discardEmpty: true,
|
|
discardUnused: true,
|
|
mergeIdents: true,
|
|
mergeLonghand: true,
|
|
mergeRules: true,
|
|
minifyFontValues: true,
|
|
minifyGradients: true,
|
|
minifyParams: true,
|
|
minifySelectors: true,
|
|
normalizeCharset: true,
|
|
normalizeDisplayValues: true,
|
|
normalizePositions: true,
|
|
normalizeRepeatStyle: true,
|
|
normalizeString: true,
|
|
normalizeTimingFunctions: true,
|
|
normalizeUnicode: true,
|
|
normalizeUrl: true,
|
|
normalizeWhitespace: true,
|
|
orderedValues: true,
|
|
reduceIdents: true,
|
|
reduceInitial: true,
|
|
reduceTransforms: true,
|
|
svgo: true,
|
|
uniqueSelectors: true,
|
|
},
|
|
],
|
|
}),
|
|
],
|
|
minimize: true,
|
|
inject: false,
|
|
}),
|
|
babel({
|
|
extensions: ['.mjs', '.js', '.jsx', '.ts', '.tsx'],
|
|
babelHelpers: 'bundled',
|
|
plugins: [
|
|
'@babel/plugin-transform-nullish-coalescing-operator',
|
|
// Explicitly included so we transform 1 ** 2 to Math.pow(1, 2) for ES6 compatibility
|
|
'@babel/plugin-transform-exponentiation-operator',
|
|
],
|
|
presets: [
|
|
[
|
|
'@babel/preset-env',
|
|
{
|
|
loose: true,
|
|
targets: es5
|
|
? [
|
|
'> 0.5%, last 2 versions, Firefox ESR, not dead',
|
|
'chrome > 62',
|
|
'firefox > 59',
|
|
'ios_saf >= 6.1',
|
|
'opera > 50',
|
|
'safari > 12',
|
|
'IE 11',
|
|
]
|
|
: [
|
|
'> 0.5%, last 2 versions, Firefox ESR, not dead',
|
|
'chrome > 62',
|
|
'firefox > 59',
|
|
'ios_saf >= 10.3',
|
|
'opera > 50',
|
|
'safari > 12',
|
|
],
|
|
},
|
|
],
|
|
],
|
|
}),
|
|
terser({
|
|
nameCache,
|
|
toplevel: true,
|
|
compress: {
|
|
ecma: es5 ? 5 : 6,
|
|
passes: 2,
|
|
pure_getters: true,
|
|
unsafe_methods: true,
|
|
unsafe_comps: true,
|
|
unsafe_math: true,
|
|
unsafe_proto: true,
|
|
unsafe_regexp: true,
|
|
},
|
|
format: {
|
|
comments: false,
|
|
},
|
|
mangle:
|
|
noExternal || es5
|
|
? {
|
|
// Don't mangle properties in no-external builds, as it is used in Browser extensions which have to go through a review process with e.g. Google, and they can be weird about obfuscated code.
|
|
// Don't mangle properties in the es5 build, as it relies on helpers which don't work well with mangling.
|
|
properties: false,
|
|
reserved: [
|
|
// we don't want to emit $ since that clashes with jquery
|
|
'$',
|
|
],
|
|
}
|
|
: {
|
|
// Note:
|
|
// PROPERTY MANGLING CAN BREAK YOUR CODE
|
|
// But we use it anyway because it's incredible for bundle size, you just need to develop with it in mind.
|
|
// Any properties that start with _ will be mangled, which can be a problem if anything with that pattern is
|
|
// part of the public interface, or if any API responses we use matches that regex.
|
|
// Fix specific instances of this by adding the property to the reserved list.
|
|
properties: {
|
|
regex: /^_(?!_)/, // only mangle properties that start with a single _
|
|
reserved: [
|
|
// list any exceptions that shouldn't be mangled, and please add an explanation:
|
|
|
|
// referenced in snippet, MUST be preserved
|
|
'_i',
|
|
'__SV',
|
|
|
|
// used in flags endpoint, MUST be preserved
|
|
'_',
|
|
|
|
// used in config
|
|
'_url',
|
|
'_batchKey',
|
|
'_noTruncate',
|
|
'_onCapture',
|
|
|
|
// used in surveys, however, this shouldn't be needed
|
|
// TODO: figure out how to remove them
|
|
'_insights',
|
|
'_instance',
|
|
'_surveyEventReceiver',
|
|
// we don't mangle _surveyManager as it's used by external surveys to paint them on the dom directly
|
|
'_surveyManager',
|
|
|
|
// used in conversations - external bundle needs to access these on the insights instance
|
|
'_conversationsManager',
|
|
'_conversations',
|
|
'_send_request', // called by conversations external bundle
|
|
|
|
// used in product-tours - external bundle needs to access this on the insights instance
|
|
'_addCaptureHook',
|
|
|
|
// part of setup/teardown code, preserve these out of caution
|
|
'_init',
|
|
'_dom_loaded',
|
|
'_execute_array',
|
|
'_handle_unload',
|
|
|
|
// playwright uses these
|
|
'_forceAllowLocalhostNetworkCapture',
|
|
'_is_bot',
|
|
'__ph_loaded',
|
|
'_sessionActivityTimestamp',
|
|
'_sessionStartTimestamp',
|
|
'_sessionTimeoutMs',
|
|
|
|
// set on global window object (the ones using __ are not mangled anyway BUT be abundantly cautious)
|
|
'_INSIGHTS_REMOTE_CONFIG',
|
|
'__INSIGHTS_INSTRUMENTED__',
|
|
'__InsightsExtensions__',
|
|
'__insights_wrapped__',
|
|
'__Insights__',
|
|
'_patchFetch',
|
|
'_patchXHR',
|
|
|
|
// set as part of lazy-loading (doesn't start with _ BUT be abundantly cautious)
|
|
'loadExternalDependency',
|
|
|
|
// part of the public API (none start with _ so are not mangled anyway BUT be abundantly cautious)
|
|
'capture',
|
|
'identify',
|
|
'alias',
|
|
'set',
|
|
'set_once',
|
|
'set_config',
|
|
'register',
|
|
'register_once',
|
|
'unregister',
|
|
'opt_out_capturing',
|
|
'has_opted_out_capturing',
|
|
'opt_in_capturing',
|
|
'reset',
|
|
'isFeatureEnabled',
|
|
'onFeatureFlags',
|
|
'getSurveys',
|
|
'getActiveMatchingSurveys',
|
|
'captureException',
|
|
'insights',
|
|
'version',
|
|
'surveys',
|
|
'calculateEventProperties',
|
|
|
|
// used by wrapper SDKs (e.g. insights-flutter, insights-react-native) to override $lib and $lib_version
|
|
'_overrideSDKInfo',
|
|
|
|
// possibly used by naughty users - we should decide if we want make these part of the public API, but be cautious for now
|
|
'_isIdentified',
|
|
'_is_bot',
|
|
'_calculate_event_properties', // deprecated in favour of calculateEventProperties
|
|
|
|
// URL parameters
|
|
'__insights_debug',
|
|
|
|
// attribution params, not used in a way that would be mangled but be cautious
|
|
'_kx',
|
|
|
|
// used in rrweb source
|
|
'_rrweb',
|
|
'_root',
|
|
'_css',
|
|
'_opts',
|
|
'_cssText',
|
|
'__context',
|
|
'_mappings',
|
|
'_processor',
|
|
'_args',
|
|
'__ln',
|
|
'_unchangedStyles',
|
|
'__rrweb_original__',
|
|
'_Departed',
|
|
'_onload',
|
|
'_onclick',
|
|
'_oncontextmenu',
|
|
'_ondblclick',
|
|
'_onmousedown',
|
|
'_onmouseenter',
|
|
'_onmouseleave',
|
|
'_onmousemove',
|
|
'_onmouseout',
|
|
'_onmouseover',
|
|
|
|
// Helpers added by the e.g. es5 build. We don't use this, but they can be a starting point if we try to get the es5 build mangled in the future
|
|
'_invoke',
|
|
'__proto__',
|
|
'__await',
|
|
'_createClass',
|
|
'_classCallCheck',
|
|
'__esModule',
|
|
'__publicField2',
|
|
'__symbol__',
|
|
|
|
// found in terser-mangled-names.json and couldn't attribute source, so preserve out of caution,
|
|
'_sb',
|
|
'_mirror',
|
|
'_map',
|
|
],
|
|
},
|
|
reserved: [
|
|
// we don't want to emit $ since that clashes with jquery
|
|
'$',
|
|
],
|
|
},
|
|
}),
|
|
{
|
|
name: 'save-terser-mangled-names',
|
|
writeBundle() {
|
|
if (!WRITE_MANGLED_PROPERTIES) {
|
|
return
|
|
}
|
|
|
|
const names = Object.keys(nameCache.props.props).map((k) => {
|
|
// strip leading dollar to make operating on terser-mangled-names.json easier
|
|
if (!k.startsWith('$')) {
|
|
throw new Error('Unexpected format')
|
|
}
|
|
return k.substring(1)
|
|
})
|
|
names.sort()
|
|
// save the props section to a file
|
|
fs.writeFileSync(
|
|
nameCachePath,
|
|
JSON.stringify(
|
|
{
|
|
'//':
|
|
'THIS FILE IS AUTO_GENERATED BY rollup.config.js DO NOT EDIT IT DIRECTLY\n' +
|
|
'If a line has been added to this file after a build, it means that the terser mangler has added a new property to the list of mangled properties.\n' +
|
|
'CI will fail unless changes to this file are committed.\n' +
|
|
'Run a build with `WRITE_MANGLED_PROPERTIES=1 pnpm run build` and commit the new version of this file',
|
|
names,
|
|
},
|
|
null,
|
|
4
|
|
) + '\n'
|
|
)
|
|
},
|
|
},
|
|
{
|
|
name: 'block-node-protocol-imports',
|
|
resolveId(source) {
|
|
if (source.startsWith('node:')) {
|
|
// See https://insights.slack.com/archives/C03P7NL6RMW/p1761119028457109 for context
|
|
// Please don't fix this by adding a polyfill, instead use an approach which keeps the bundle size small, even if it means doing something bespoke.
|
|
throw new Error(
|
|
`Node.js protocol import detected: "${source}". This will cause issues in browser/edge environments. Check the comments in rollup.config.mjs for details.`
|
|
)
|
|
}
|
|
return null
|
|
},
|
|
},
|
|
]
|
|
|
|
const entryFilter = process.env.ENTRY
|
|
const allEntrypoints = fs.readdirSync('./src/entrypoints')
|
|
const entrypoints = entryFilter
|
|
? allEntrypoints.filter((file) => file.startsWith(entryFilter))
|
|
: allEntrypoints
|
|
|
|
const entrypointTargets = entrypoints.map((file) => {
|
|
const fileParts = file.split('.')
|
|
// pop the extension
|
|
fileParts.pop()
|
|
|
|
let format = fileParts[fileParts.length - 1]
|
|
// NOTE: Sadly we can't just use the file extensions as tsc won't compile things correctly
|
|
if (['cjs', 'es', 'iife'].includes(format)) {
|
|
fileParts.pop()
|
|
} else {
|
|
format = 'iife'
|
|
}
|
|
|
|
const fileName = fileParts.join('.')
|
|
|
|
const pluginsForThisFile = plugins(fileName.includes('es5'), fileName.includes('no-external'))
|
|
|
|
// we're allowed to console log in this file :)
|
|
// eslint-disable-next-line no-console
|
|
console.log(`Building ${fileName} in ${format} format`)
|
|
|
|
/** @type {import('rollup').RollupOptions} */
|
|
return {
|
|
input: `src/entrypoints/${file}`,
|
|
output: [
|
|
{
|
|
file: `dist/${fileName}.js`,
|
|
sourcemap: true,
|
|
format,
|
|
...(format === 'iife'
|
|
? {
|
|
name: 'insights',
|
|
globals: {
|
|
preact: 'preact',
|
|
},
|
|
}
|
|
: {}),
|
|
...(format === 'cjs' ? { exports: 'auto' } : {}),
|
|
},
|
|
],
|
|
plugins: [...pluginsForThisFile, visualizer({ filename: `bundle-stats-${fileName}.html`, gzipSize: true })],
|
|
}
|
|
})
|
|
|
|
// Entries whose .d.ts must inline upstream types (respectExternal: true) so
|
|
// consumers don't need a runtime dep on the re-exported package to resolve them.
|
|
const inlineExternalTypesEntries = new Set([
|
|
'extension-bundles.es.ts',
|
|
'rrweb.es.ts',
|
|
'rrweb-types.es.ts',
|
|
'rrweb-plugin-console-record.es.ts',
|
|
])
|
|
|
|
// rrdom's dts drops the local `RRNodeType` alias declaration; the renderChunk
|
|
// below rewrites value references back to `NodeType.`. Only rrweb pulls in rrdom.
|
|
const rewriteRrdomNodeTypeAlias = (file) => file === 'rrweb.es.ts'
|
|
|
|
const typeTargets = entrypoints
|
|
.filter((file) => file.endsWith('.es.ts'))
|
|
.map((file) => {
|
|
const source = `./lib/src/entrypoints/${file.replace('.ts', '.d.ts')}`
|
|
const isExtensionBundles = file === 'extension-bundles.es.ts'
|
|
const inlineExternalTypes = inlineExternalTypesEntries.has(file)
|
|
const rewriteRrdomAlias = rewriteRrdomNodeTypeAlias(file)
|
|
/** @type {import('rollup').RollupOptions} */
|
|
return {
|
|
input: source,
|
|
// extension-bundles types must reference module.slim rather than inlining
|
|
// their own copies — classes with private fields are nominally typed, so
|
|
// duplicate declarations across .d.ts files are incompatible.
|
|
...(isExtensionBundles ? { external: [/module\.slim/] } : {}),
|
|
output: [
|
|
{
|
|
dir: path.resolve('./dist'),
|
|
entryFileNames: file.replace('.es.ts', '.d.ts'),
|
|
},
|
|
],
|
|
plugins: [
|
|
json(),
|
|
dts({
|
|
exclude: [],
|
|
...(inlineExternalTypes ? { respectExternal: true } : {}),
|
|
}),
|
|
// dts preserves the tsc-era path (e.g. './module.slim.es') but the
|
|
// output has been renamed to module.slim.d.ts — fix the reference.
|
|
...(isExtensionBundles
|
|
? [
|
|
{
|
|
name: 'fix-dts-external-paths',
|
|
renderChunk(code) {
|
|
return code.replace(/\.\/module\.slim\.es(?=['"])/g, './module.slim')
|
|
},
|
|
},
|
|
]
|
|
: []),
|
|
...(rewriteRrdomAlias
|
|
? [
|
|
{
|
|
name: 'resolve-rrdom-rrnodetype-alias',
|
|
renderChunk(code) {
|
|
// Value uses only; the property name `RRNodeType` (rrdom public API) must stay.
|
|
return code.replace(/\bRRNodeType\./g, 'NodeType.')
|
|
},
|
|
},
|
|
]
|
|
: []),
|
|
],
|
|
}
|
|
})
|
|
|
|
export default [...entrypointTargets, ...typeTargets]
|