mirror of
https://github.com/BillyOutlast/posthog.git
synced 2026-02-04 03:01:23 +01:00
feat(msg): add worker threads to behavioural events consumer (#35860)
This commit is contained in:
@@ -96,6 +96,7 @@
|
||||
"p-limit": "3.1.0",
|
||||
"pg": "^8.6.0",
|
||||
"pino": "^8.6.0",
|
||||
"piscina": "^5.1.3",
|
||||
"posthog-node": "4.14.0",
|
||||
"pretty-bytes": "^5.6.0",
|
||||
"prom-client": "^14.2.0",
|
||||
|
||||
@@ -8,7 +8,7 @@ import { BehavioralCounterRepository } from '../../utils/db/cassandra/behavioura
|
||||
import { closeHub, createHub } from '../../utils/db/hub'
|
||||
import { createIncomingEvent } from '../_tests/fixtures'
|
||||
import { convertClickhouseRawEventToFilterGlobals } from '../utils/hog-function-filtering'
|
||||
import { BehavioralEvent, CdpBehaviouralEventsConsumer, counterEventsDropped } from './cdp-behavioural-events.consumer'
|
||||
import { BehavioralEvent, CdpBehaviouralEventsConsumer } from './cdp-behavioural-events.consumer'
|
||||
|
||||
class TestCdpBehaviouralEventsConsumer extends CdpBehaviouralEventsConsumer {
|
||||
public getCassandraClient(): CassandraClient | null {
|
||||
@@ -349,45 +349,6 @@ describe('CdpBehaviouralEventsConsumer', () => {
|
||||
|
||||
expect(counter).toBeNull()
|
||||
})
|
||||
|
||||
it('should drop events with missing person ID at parsing stage', async () => {
|
||||
// Create a raw event without person_id (simulating what comes from Kafka)
|
||||
const rawEventWithoutPersonId = {
|
||||
uuid: '12345',
|
||||
event: '$pageview',
|
||||
team_id: team.id,
|
||||
properties: JSON.stringify({ $browser: 'Chrome' }),
|
||||
// person_id is undefined
|
||||
}
|
||||
|
||||
// Get initial metric value
|
||||
const initialDroppedCount = await counterEventsDropped.get()
|
||||
const initialMissingPersonIdCount =
|
||||
initialDroppedCount.values.find((v) => v.labels.reason === 'missing_person_id')?.value || 0
|
||||
|
||||
const messages = [
|
||||
{
|
||||
value: Buffer.from(JSON.stringify(rawEventWithoutPersonId)),
|
||||
},
|
||||
] as any[]
|
||||
|
||||
// Act - parse the batch (should drop the event)
|
||||
const parsedEvents = await (processor as any)._parseKafkaBatch(messages)
|
||||
|
||||
// Assert - no events should be parsed due to missing person_id
|
||||
expect(parsedEvents).toHaveLength(0)
|
||||
|
||||
// Assert - metric should be incremented
|
||||
const finalDroppedCount = await counterEventsDropped.get()
|
||||
const finalMissingPersonIdCount =
|
||||
finalDroppedCount.values.find((v) => v.labels.reason === 'missing_person_id')?.value || 0
|
||||
expect(finalMissingPersonIdCount).toBe(initialMissingPersonIdCount + 1)
|
||||
|
||||
// Assert - no counter should be written to Cassandra since event was dropped
|
||||
const counters = await repository.getCountersForTeam(team.id)
|
||||
|
||||
expect(counters).toHaveLength(0)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { Client as CassandraClient } from 'cassandra-driver'
|
||||
import { createHash } from 'crypto'
|
||||
import { Message } from 'node-rdkafka'
|
||||
import { Counter } from 'prom-client'
|
||||
import { join } from 'path'
|
||||
import Piscina from 'piscina'
|
||||
import { Counter, Histogram } from 'prom-client'
|
||||
|
||||
import { KAFKA_EVENTS_JSON } from '../../config/kafka-topics'
|
||||
import { KafkaConsumer } from '../../kafka/consumer'
|
||||
@@ -12,7 +14,6 @@ import { BehavioralCounterRepository, CounterUpdate } from '../../utils/db/cassa
|
||||
import { parseJSON } from '../../utils/json-parse'
|
||||
import { logger } from '../../utils/logger'
|
||||
import { HogFunctionFilterGlobals } from '../types'
|
||||
import { execHog } from '../utils/hog-exec'
|
||||
import { convertClickhouseRawEventToFilterGlobals } from '../utils/hog-function-filtering'
|
||||
import { CdpConsumerBase } from './cdp-base.consumer'
|
||||
|
||||
@@ -22,26 +23,35 @@ export type BehavioralEvent = {
|
||||
personId: string
|
||||
}
|
||||
|
||||
export const counterParseError = new Counter({
|
||||
name: 'cdp_behavioural_function_parse_error',
|
||||
help: 'A behavioural function invocation was parsed with an error',
|
||||
labelNames: ['error'],
|
||||
export const histogramWorkerPoolExecution = new Histogram({
|
||||
name: 'cdp_behavioural_worker_pool_execution_duration_ms',
|
||||
help: 'Time spent executing bytecode in worker pool',
|
||||
buckets: [1, 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000],
|
||||
})
|
||||
|
||||
export const counterEventsDropped = new Counter({
|
||||
name: 'cdp_behavioural_events_dropped_total',
|
||||
help: 'Total number of events dropped due to missing personId or other validation errors',
|
||||
labelNames: ['reason'],
|
||||
export const histogramActionLoading = new Histogram({
|
||||
name: 'cdp_behavioural_action_loading_duration_ms',
|
||||
help: 'Time spent loading actions for teams',
|
||||
buckets: [1, 5, 10, 25, 50, 100, 250, 500],
|
||||
})
|
||||
|
||||
export const counterEventsConsumed = new Counter({
|
||||
name: 'cdp_behavioural_events_consumed_total',
|
||||
help: 'Total number of events consumed by the behavioural consumer',
|
||||
export const counterWorkerPoolTasks = new Counter({
|
||||
name: 'cdp_behavioural_worker_pool_tasks_total',
|
||||
help: 'Total number of tasks submitted to worker pool',
|
||||
labelNames: ['status'],
|
||||
})
|
||||
|
||||
export const counterEventsMatchedTotal = new Counter({
|
||||
name: 'cdp_behavioural_events_matched_total',
|
||||
help: 'Total number of events that matched at least one action filter',
|
||||
export const histogramBatchProcessingSteps = new Histogram({
|
||||
name: 'cdp_behavioural_batch_processing_steps_duration_ms',
|
||||
help: 'Time spent in different batch processing steps',
|
||||
labelNames: ['step'],
|
||||
buckets: [1, 5, 10, 25, 50, 100, 250, 500, 1000, 2500],
|
||||
})
|
||||
|
||||
export const histogramActionsPerTeam = new Histogram({
|
||||
name: 'cdp_behavioural_actions_per_team',
|
||||
help: 'Number of actions loaded per team',
|
||||
buckets: [0, 1, 2, 5, 10, 20, 50, 100, 200, 500],
|
||||
})
|
||||
|
||||
export class CdpBehaviouralEventsConsumer extends CdpConsumerBase {
|
||||
@@ -50,11 +60,23 @@ export class CdpBehaviouralEventsConsumer extends CdpConsumerBase {
|
||||
protected cassandra: CassandraClient | null
|
||||
protected behavioralCounterRepository: BehavioralCounterRepository | null
|
||||
private filterHashCache = new Map<string, string>()
|
||||
private workerPool: Piscina
|
||||
|
||||
constructor(hub: Hub, topic: string = KAFKA_EVENTS_JSON, groupId: string = 'cdp-behavioural-events-consumer') {
|
||||
super(hub)
|
||||
this.kafkaConsumer = new KafkaConsumer({ groupId, topic })
|
||||
|
||||
// Initialize Piscina worker pool for parallel HOG execution
|
||||
this.workerPool = new Piscina({
|
||||
filename: join(__dirname, '../workers/hog-executor.worker.js'),
|
||||
maxThreads: Math.max(2, Math.floor(require('os').cpus().length * 0.5)),
|
||||
minThreads: 2,
|
||||
resourceLimits: {
|
||||
maxOldGenerationSizeMb: 256,
|
||||
maxYoungGenerationSizeMb: 64,
|
||||
},
|
||||
})
|
||||
|
||||
// Only initialize Cassandra client if the feature is enabled
|
||||
if (hub.WRITE_BEHAVIOURAL_COUNTERS_TO_CASSANDRA) {
|
||||
this.cassandra = new CassandraClient({
|
||||
@@ -79,21 +101,19 @@ export class CdpBehaviouralEventsConsumer extends CdpConsumerBase {
|
||||
return
|
||||
}
|
||||
|
||||
// Track events consumed and matched (absolute numbers)
|
||||
let eventsMatched = 0
|
||||
const counterUpdates: CounterUpdate[] = []
|
||||
|
||||
const results = await Promise.all(events.map((event) => this.processEvent(event, counterUpdates)))
|
||||
eventsMatched = results.reduce((sum, count) => sum + count, 0)
|
||||
// Time event processing
|
||||
const eventProcessingTimer = histogramBatchProcessingSteps.labels({ step: 'event_processing' }).startTimer()
|
||||
await Promise.all(events.map((event) => this.processEvent(event, counterUpdates)))
|
||||
eventProcessingTimer()
|
||||
|
||||
// Batch write all counter updates
|
||||
// Time Cassandra writes
|
||||
if (counterUpdates.length > 0 && this.hub.WRITE_BEHAVIOURAL_COUNTERS_TO_CASSANDRA && this.cassandra) {
|
||||
const cassandraTimer = histogramBatchProcessingSteps.labels({ step: 'cassandra_write' }).startTimer()
|
||||
await this.writeBehavioralCounters(counterUpdates)
|
||||
cassandraTimer()
|
||||
}
|
||||
|
||||
// Update metrics with absolute numbers
|
||||
counterEventsConsumed.inc(events.length)
|
||||
counterEventsMatchedTotal.inc(eventsMatched)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -121,10 +141,14 @@ export class CdpBehaviouralEventsConsumer extends CdpConsumerBase {
|
||||
}
|
||||
|
||||
private async loadActionsForTeam(teamId: number): Promise<Action[]> {
|
||||
const timer = histogramActionLoading.startTimer()
|
||||
try {
|
||||
const actions = await this.hub.actionManagerCDP.getActionsForTeam(teamId)
|
||||
timer()
|
||||
histogramActionsPerTeam.observe(actions.length)
|
||||
return actions
|
||||
} catch (error) {
|
||||
timer()
|
||||
logger.error('Error loading actions for team', { teamId, error })
|
||||
return []
|
||||
}
|
||||
@@ -140,20 +164,25 @@ export class CdpBehaviouralEventsConsumer extends CdpConsumerBase {
|
||||
}
|
||||
|
||||
try {
|
||||
// Execute bytecode directly with the filter globals
|
||||
const execHogOutcome = await execHog(action.bytecode, {
|
||||
globals: event.filterGlobals,
|
||||
telemetry: false,
|
||||
// Execute bytecode in worker thread for better performance
|
||||
const workerTimer = histogramWorkerPoolExecution.startTimer()
|
||||
counterWorkerPoolTasks.labels({ status: 'submitted' }).inc()
|
||||
|
||||
const result = await this.workerPool.run({
|
||||
bytecode: action.bytecode,
|
||||
filterGlobals: event.filterGlobals,
|
||||
})
|
||||
|
||||
if (!execHogOutcome.execResult || execHogOutcome.error || execHogOutcome.execResult.error) {
|
||||
throw execHogOutcome.error ?? execHogOutcome.execResult?.error ?? new Error('Unknown error')
|
||||
workerTimer()
|
||||
|
||||
if (result.error) {
|
||||
counterWorkerPoolTasks.labels({ status: 'error' }).inc()
|
||||
throw result.error
|
||||
}
|
||||
|
||||
const matchedFilter =
|
||||
typeof execHogOutcome.execResult.result === 'boolean' && execHogOutcome.execResult.result
|
||||
counterWorkerPoolTasks.labels({ status: 'success' }).inc()
|
||||
|
||||
if (matchedFilter) {
|
||||
if (result.matched) {
|
||||
const filterHash = this.createFilterHash(action.bytecode!)
|
||||
const date = new Date().toISOString().split('T')[0]
|
||||
counterUpdates.push({
|
||||
@@ -164,9 +193,9 @@ export class CdpBehaviouralEventsConsumer extends CdpConsumerBase {
|
||||
})
|
||||
}
|
||||
|
||||
return matchedFilter
|
||||
return result.matched
|
||||
} catch (error) {
|
||||
logger.error('Error executing action bytecode', {
|
||||
logger.error('Error executing action bytecode in worker', {
|
||||
actionId: String(action.id),
|
||||
error,
|
||||
})
|
||||
@@ -219,7 +248,6 @@ export class CdpBehaviouralEventsConsumer extends CdpConsumerBase {
|
||||
event: clickHouseEvent.event,
|
||||
uuid: clickHouseEvent.uuid,
|
||||
})
|
||||
counterEventsDropped.labels({ reason: 'missing_person_id' }).inc()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -233,7 +261,6 @@ export class CdpBehaviouralEventsConsumer extends CdpConsumerBase {
|
||||
})
|
||||
} catch (e) {
|
||||
logger.error('Error parsing message', e)
|
||||
counterParseError.labels({ error: e.message }).inc()
|
||||
}
|
||||
})
|
||||
// Return Promise.resolve to satisfy runInstrumentedFunction's Promise return type
|
||||
@@ -275,6 +302,9 @@ export class CdpBehaviouralEventsConsumer extends CdpConsumerBase {
|
||||
logger.info('💤', 'Stopping behavioural events consumer...')
|
||||
await this.kafkaConsumer.disconnect()
|
||||
|
||||
// Shutdown worker pool
|
||||
await this.workerPool.destroy()
|
||||
|
||||
// Only shutdown Cassandra if it was initialized
|
||||
if (this.cassandra) {
|
||||
await this.cassandra.shutdown()
|
||||
|
||||
37
plugin-server/src/cdp/workers/hog-executor.worker.js
Normal file
37
plugin-server/src/cdp/workers/hog-executor.worker.js
Normal file
@@ -0,0 +1,37 @@
|
||||
const { exec } = require('@posthog/hogvm')
|
||||
const crypto = require('crypto')
|
||||
const RE2 = require('re2')
|
||||
|
||||
module.exports = function execBehavioralActionWorker(task) {
|
||||
const { bytecode, filterGlobals } = task
|
||||
const now = performance.now()
|
||||
let execResult
|
||||
let error
|
||||
let matched = false
|
||||
|
||||
try {
|
||||
execResult = exec(bytecode, {
|
||||
timeout: 30000,
|
||||
maxAsyncSteps: 0,
|
||||
globals: filterGlobals,
|
||||
telemetry: false,
|
||||
external: {
|
||||
regex: { match: (regex, str) => new RE2(regex).test(str) },
|
||||
crypto,
|
||||
},
|
||||
})
|
||||
|
||||
if (execResult && !execResult.error) {
|
||||
matched = typeof execResult.result === 'boolean' && execResult.result
|
||||
}
|
||||
} catch (e) {
|
||||
error = e
|
||||
}
|
||||
|
||||
return {
|
||||
execResult,
|
||||
error,
|
||||
durationMs: performance.now() - now,
|
||||
matched,
|
||||
}
|
||||
}
|
||||
282
pnpm-lock.yaml
generated
282
pnpm-lock.yaml
generated
@@ -1383,6 +1383,9 @@ importers:
|
||||
pino:
|
||||
specifier: ^8.6.0
|
||||
version: 8.11.0
|
||||
piscina:
|
||||
specifier: ^5.1.3
|
||||
version: 5.1.3
|
||||
posthog-node:
|
||||
specifier: 4.14.0
|
||||
version: 4.14.0
|
||||
@@ -2016,7 +2019,7 @@ importers:
|
||||
version: 0.26.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
'@posthog/lemon-ui':
|
||||
specifier: '*'
|
||||
version: 0.0.0(antd@5.26.0(date-fns@2.30.0)(luxon@3.5.0)(moment@2.29.4)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(kea-router@3.3.0(kea@3.1.5(react@18.2.0)))(kea@3.1.5(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
version: 0.0.0(antd@5.26.0(date-fns@2.30.0)(luxon@3.5.0)(moment@2.29.4)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(kea-router@3.3.1(kea@3.1.5(react@18.2.0)))(kea@3.1.5(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
'@types/react':
|
||||
specifier: '*'
|
||||
version: 17.0.52
|
||||
@@ -4513,6 +4516,106 @@ packages:
|
||||
resolution: {integrity: sha512-N8x7eSLGcmUFNWZRxT1vsHvypzIRgQYdG0rJey/rZCy6zT/30qDt8Joj7FxzGNLSwXbeZqJOMqDurp7ra4hgbw==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
'@napi-rs/nice-android-arm-eabi@1.0.4':
|
||||
resolution: {integrity: sha512-OZFMYUkih4g6HCKTjqJHhMUlgvPiDuSLZPbPBWHLjKmFTv74COzRlq/gwHtmEVaR39mJQ6ZyttDl2HNMUbLVoA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@napi-rs/nice-android-arm64@1.0.4':
|
||||
resolution: {integrity: sha512-k8u7cjeA64vQWXZcRrPbmwjH8K09CBnNaPnI9L1D5N6iMPL3XYQzLcN6WwQonfcqCDv5OCY3IqX89goPTV4KMw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@napi-rs/nice-darwin-arm64@1.0.4':
|
||||
resolution: {integrity: sha512-GsLdQvUcuVzoyzmtjsThnpaVEizAqH5yPHgnsBmq3JdVoVZHELFo7PuJEdfOH1DOHi2mPwB9sCJEstAYf3XCJA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@napi-rs/nice-darwin-x64@1.0.4':
|
||||
resolution: {integrity: sha512-1y3gyT3e5zUY5SxRl3QDtJiWVsbkmhtUHIYwdWWIQ3Ia+byd/IHIEpqAxOGW1nhhnIKfTCuxBadHQb+yZASVoA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@napi-rs/nice-freebsd-x64@1.0.4':
|
||||
resolution: {integrity: sha512-06oXzESPRdXUuzS8n2hGwhM2HACnDfl3bfUaSqLGImM8TA33pzDXgGL0e3If8CcFWT98aHows5Lk7xnqYNGFeA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@napi-rs/nice-linux-arm-gnueabihf@1.0.4':
|
||||
resolution: {integrity: sha512-CgklZ6g8WL4+EgVVkxkEvvsi2DSLf9QIloxWO0fvQyQBp6VguUSX3eHLeRpqwW8cRm2Hv/Q1+PduNk7VK37VZw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@napi-rs/nice-linux-arm64-gnu@1.0.4':
|
||||
resolution: {integrity: sha512-wdAJ7lgjhAlsANUCv0zi6msRwq+D4KDgU+GCCHssSxWmAERZa2KZXO0H2xdmoJ/0i03i6YfK/sWaZgUAyuW2oQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@napi-rs/nice-linux-arm64-musl@1.0.4':
|
||||
resolution: {integrity: sha512-4b1KYG+sriufhFrpUS9uNOEYYJqSfcbnwGx6uGX7JjrH8tELG90cOpCawz5THNIwlS3DhLgnCOcn0+4p6z26QA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@napi-rs/nice-linux-ppc64-gnu@1.0.4':
|
||||
resolution: {integrity: sha512-iaf3vMRgr23oe1PUaKpxaH3DS0IMN0+N9iEiWVwYPm/U15vZFYdqVegGfN2PzrZLUl5lc8ZxbmEKDfuqslhAMA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@napi-rs/nice-linux-riscv64-gnu@1.0.4':
|
||||
resolution: {integrity: sha512-UXoREY6Yw6rHrGuTwQgBxpfjK34t6mTjibE9/cXbefL9AuUCJ9gEgwNKZiONuR5QGswChqo9cnthjdKkYyAdDg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@napi-rs/nice-linux-s390x-gnu@1.0.4':
|
||||
resolution: {integrity: sha512-eFbgYCRPmsqbYPAlLYU5hYTNbogmIDUvknilehHsFhCH1+0/kN87lP+XaLT0Yeq4V/rpwChSd9vlz4muzFArtw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@napi-rs/nice-linux-x64-gnu@1.0.4':
|
||||
resolution: {integrity: sha512-4T3E6uTCwWT6IPnwuPcWVz3oHxvEp/qbrCxZhsgzwTUBEwu78EGNXGdHfKJQt3soth89MLqZJw+Zzvnhrsg1mQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@napi-rs/nice-linux-x64-musl@1.0.4':
|
||||
resolution: {integrity: sha512-NtbBkAeyBPLvCBkWtwkKXkNSn677eaT0cX3tygq+2qVv71TmHgX4gkX6o9BXjlPzdgPGwrUudavCYPT9tzkEqQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@napi-rs/nice-win32-arm64-msvc@1.0.4':
|
||||
resolution: {integrity: sha512-vubOe3i+YtSJGEk/++73y+TIxbuVHi+W8ZzrRm2eETCjCRwNlgbfToQZ85dSA+4iBB/NJRGNp+O4hfdbbttZWA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@napi-rs/nice-win32-ia32-msvc@1.0.4':
|
||||
resolution: {integrity: sha512-BMOVrUDZeg1RNRKVlh4eyLv5djAAVLiSddfpuuQ47EFjBcklg0NUeKMFKNrKQR4UnSn4HAiACLD7YK7koskwmg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@napi-rs/nice-win32-x64-msvc@1.0.4':
|
||||
resolution: {integrity: sha512-kCNk6HcRZquhw/whwh4rHsdPyOSCQCgnVDVik+Y9cuSVTDy3frpiCJTScJqPPS872h4JgZKkr/+CwcwttNEo9Q==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@napi-rs/nice@1.0.4':
|
||||
resolution: {integrity: sha512-Sqih1YARrmMoHlXGgI9JrrgkzxcaaEso0AH+Y7j8NHonUs+xe4iDsgC3IBIDNdzEewbNpccNN6hip+b5vmyRLw==}
|
||||
engines: {node: '>= 10'}
|
||||
|
||||
'@napi-rs/snappy-android-arm-eabi@7.2.2':
|
||||
resolution: {integrity: sha512-H7DuVkPCK5BlAr1NfSU8bDEN7gYs+R78pSHhDng83QxRnCLmVIZk33ymmIwurmoA1HrdTxbkbuNl+lMvNqnytw==}
|
||||
engines: {node: '>= 10'}
|
||||
@@ -12240,11 +12343,6 @@ packages:
|
||||
peerDependencies:
|
||||
kea: '>= 3'
|
||||
|
||||
kea-router@3.3.0:
|
||||
resolution: {integrity: sha512-lcun+z/MFVaK/FK6rFSr1/Epu/cpHir1X7nW9Cr4XMBbbNS6t0MA0SsgAiKY35eM5Vd6c0Y33uI2BIWg/dXBfA==}
|
||||
peerDependencies:
|
||||
kea: '>= 3'
|
||||
|
||||
kea-router@3.3.1:
|
||||
resolution: {integrity: sha512-SA1RiFbWalvJ1u8pRZf8zACvm2UP1fLIr7Jq8uyIvWQov2V0xyh28pI6TgndJUeSp4i1yoGlA6IMmCHoi0q2nA==}
|
||||
peerDependencies:
|
||||
@@ -13607,6 +13705,10 @@ packages:
|
||||
resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
piscina@5.1.3:
|
||||
resolution: {integrity: sha512-0u3N7H4+hbr40KjuVn2uNhOcthu/9usKhnw5vT3J7ply79v3D3M8naI00el9Klcy16x557VsEkkUQaHCWFXC/g==}
|
||||
engines: {node: '>=20.x'}
|
||||
|
||||
pixelmatch@5.3.0:
|
||||
resolution: {integrity: sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q==}
|
||||
hasBin: true
|
||||
@@ -20415,41 +20517,6 @@ snapshots:
|
||||
jest-util: 29.7.0
|
||||
slash: 3.0.0
|
||||
|
||||
'@jest/core@29.7.0':
|
||||
dependencies:
|
||||
'@jest/console': 29.7.0
|
||||
'@jest/reporters': 29.7.0
|
||||
'@jest/test-result': 29.7.0
|
||||
'@jest/transform': 29.7.0
|
||||
'@jest/types': 29.6.3
|
||||
'@types/node': 22.15.17
|
||||
ansi-escapes: 4.3.2
|
||||
chalk: 4.1.2
|
||||
ci-info: 3.8.0
|
||||
exit: 0.1.2
|
||||
graceful-fs: 4.2.11
|
||||
jest-changed-files: 29.7.0
|
||||
jest-config: 29.7.0(@types/node@22.15.17)(ts-node@10.9.1(@swc/core@1.10.14(@swc/helpers@0.5.15))(@types/node@22.15.17)(typescript@5.2.2))
|
||||
jest-haste-map: 29.7.0
|
||||
jest-message-util: 29.7.0
|
||||
jest-regex-util: 29.6.3
|
||||
jest-resolve: 29.7.0
|
||||
jest-resolve-dependencies: 29.7.0
|
||||
jest-runner: 29.7.0
|
||||
jest-runtime: 29.7.0
|
||||
jest-snapshot: 29.7.0
|
||||
jest-util: 29.7.0
|
||||
jest-validate: 29.7.0
|
||||
jest-watcher: 29.7.0
|
||||
micromatch: 4.0.8
|
||||
pretty-format: 29.7.0
|
||||
slash: 3.0.0
|
||||
strip-ansi: 6.0.1
|
||||
transitivePeerDependencies:
|
||||
- babel-plugin-macros
|
||||
- supports-color
|
||||
- ts-node
|
||||
|
||||
'@jest/core@29.7.0(ts-node@10.9.1(@swc/core@1.10.14(@swc/helpers@0.5.15))(@types/node@22.15.17)(typescript@5.2.2))':
|
||||
dependencies:
|
||||
'@jest/console': 29.7.0
|
||||
@@ -20834,6 +20901,74 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@napi-rs/nice-android-arm-eabi@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/nice-android-arm64@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/nice-darwin-arm64@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/nice-darwin-x64@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/nice-freebsd-x64@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/nice-linux-arm-gnueabihf@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/nice-linux-arm64-gnu@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/nice-linux-arm64-musl@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/nice-linux-ppc64-gnu@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/nice-linux-riscv64-gnu@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/nice-linux-s390x-gnu@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/nice-linux-x64-gnu@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/nice-linux-x64-musl@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/nice-win32-arm64-msvc@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/nice-win32-ia32-msvc@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/nice-win32-x64-msvc@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/nice@1.0.4':
|
||||
optionalDependencies:
|
||||
'@napi-rs/nice-android-arm-eabi': 1.0.4
|
||||
'@napi-rs/nice-android-arm64': 1.0.4
|
||||
'@napi-rs/nice-darwin-arm64': 1.0.4
|
||||
'@napi-rs/nice-darwin-x64': 1.0.4
|
||||
'@napi-rs/nice-freebsd-x64': 1.0.4
|
||||
'@napi-rs/nice-linux-arm-gnueabihf': 1.0.4
|
||||
'@napi-rs/nice-linux-arm64-gnu': 1.0.4
|
||||
'@napi-rs/nice-linux-arm64-musl': 1.0.4
|
||||
'@napi-rs/nice-linux-ppc64-gnu': 1.0.4
|
||||
'@napi-rs/nice-linux-riscv64-gnu': 1.0.4
|
||||
'@napi-rs/nice-linux-s390x-gnu': 1.0.4
|
||||
'@napi-rs/nice-linux-x64-gnu': 1.0.4
|
||||
'@napi-rs/nice-linux-x64-musl': 1.0.4
|
||||
'@napi-rs/nice-win32-arm64-msvc': 1.0.4
|
||||
'@napi-rs/nice-win32-ia32-msvc': 1.0.4
|
||||
'@napi-rs/nice-win32-x64-msvc': 1.0.4
|
||||
optional: true
|
||||
|
||||
'@napi-rs/snappy-android-arm-eabi@7.2.2':
|
||||
optional: true
|
||||
|
||||
@@ -21754,11 +21889,11 @@ snapshots:
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
|
||||
'@posthog/lemon-ui@0.0.0(antd@5.26.0(date-fns@2.30.0)(luxon@3.5.0)(moment@2.29.4)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(kea-router@3.3.0(kea@3.1.5(react@18.2.0)))(kea@3.1.5(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
|
||||
'@posthog/lemon-ui@0.0.0(antd@5.26.0(date-fns@2.30.0)(luxon@3.5.0)(moment@2.29.4)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(kea-router@3.3.1(kea@3.1.5(react@18.2.0)))(kea@3.1.5(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
|
||||
dependencies:
|
||||
antd: 5.26.0(date-fns@2.30.0)(luxon@3.5.0)(moment@2.29.4)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
kea: 3.1.5(react@18.2.0)
|
||||
kea-router: 3.3.0(kea@3.1.5(react@18.2.0))
|
||||
kea-router: 3.3.1(kea@3.1.5(react@18.2.0))
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
|
||||
@@ -24334,7 +24469,7 @@ snapshots:
|
||||
commander: 9.4.1
|
||||
expect-playwright: 0.8.0
|
||||
glob: 10.4.5
|
||||
jest: 29.7.0
|
||||
jest: 29.7.0(@types/node@22.15.17)(ts-node@10.9.1(@swc/core@1.10.14(@swc/helpers@0.5.15))(@types/node@22.15.17)(typescript@5.2.2))
|
||||
jest-circus: 29.7.0
|
||||
jest-environment-node: 29.7.0
|
||||
jest-junit: 16.0.0
|
||||
@@ -27186,21 +27321,6 @@ snapshots:
|
||||
safe-buffer: 5.2.1
|
||||
sha.js: 2.4.11
|
||||
|
||||
create-jest@29.7.0:
|
||||
dependencies:
|
||||
'@jest/types': 29.6.3
|
||||
chalk: 4.1.2
|
||||
exit: 0.1.2
|
||||
graceful-fs: 4.2.11
|
||||
jest-config: 29.7.0(@types/node@22.15.17)(ts-node@10.9.1(@swc/core@1.10.14(@swc/helpers@0.5.15))(@types/node@22.15.17)(typescript@5.2.2))
|
||||
jest-util: 29.7.0
|
||||
prompts: 2.4.2
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- babel-plugin-macros
|
||||
- supports-color
|
||||
- ts-node
|
||||
|
||||
create-jest@29.7.0(@types/node@22.15.17)(ts-node@10.9.1(@swc/core@1.10.14(@swc/helpers@0.5.15))(@types/node@22.15.17)(typescript@5.2.2)):
|
||||
dependencies:
|
||||
'@jest/types': 29.6.3
|
||||
@@ -30184,25 +30304,6 @@ snapshots:
|
||||
- babel-plugin-macros
|
||||
- supports-color
|
||||
|
||||
jest-cli@29.7.0:
|
||||
dependencies:
|
||||
'@jest/core': 29.7.0
|
||||
'@jest/test-result': 29.7.0
|
||||
'@jest/types': 29.6.3
|
||||
chalk: 4.1.2
|
||||
create-jest: 29.7.0
|
||||
exit: 0.1.2
|
||||
import-local: 3.1.0
|
||||
jest-config: 29.7.0(@types/node@22.15.17)(ts-node@10.9.1(@swc/core@1.10.14(@swc/helpers@0.5.15))(@types/node@22.15.17)(typescript@5.2.2))
|
||||
jest-util: 29.7.0
|
||||
jest-validate: 29.7.0
|
||||
yargs: 17.7.1
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- babel-plugin-macros
|
||||
- supports-color
|
||||
- ts-node
|
||||
|
||||
jest-cli@29.7.0(@types/node@22.15.17)(ts-node@10.9.1(@swc/core@1.10.14(@swc/helpers@0.5.15))(@types/node@22.15.17)(typescript@5.2.2)):
|
||||
dependencies:
|
||||
'@jest/core': 29.7.0(ts-node@10.9.1(@swc/core@1.10.14(@swc/helpers@0.5.15))(@types/node@22.15.17)(typescript@5.2.2))
|
||||
@@ -30417,7 +30518,7 @@ snapshots:
|
||||
jest-playwright-preset@4.0.0(jest-circus@29.7.0)(jest-environment-node@29.7.0)(jest-runner@29.7.0)(jest@29.7.0):
|
||||
dependencies:
|
||||
expect-playwright: 0.8.0
|
||||
jest: 29.7.0
|
||||
jest: 29.7.0(@types/node@22.15.17)(ts-node@10.9.1(@swc/core@1.10.14(@swc/helpers@0.5.15))(@types/node@22.15.17)(typescript@5.2.2))
|
||||
jest-circus: 29.7.0
|
||||
jest-environment-node: 29.7.0
|
||||
jest-process-manager: 0.4.0
|
||||
@@ -30575,7 +30676,7 @@ snapshots:
|
||||
dependencies:
|
||||
ansi-escapes: 6.0.0
|
||||
chalk: 5.4.1
|
||||
jest: 29.7.0
|
||||
jest: 29.7.0(@types/node@22.15.17)(ts-node@10.9.1(@swc/core@1.10.14(@swc/helpers@0.5.15))(@types/node@22.15.17)(typescript@5.2.2))
|
||||
jest-regex-util: 29.6.3
|
||||
jest-watcher: 29.7.0
|
||||
slash: 5.1.0
|
||||
@@ -30606,18 +30707,6 @@ snapshots:
|
||||
merge-stream: 2.0.0
|
||||
supports-color: 8.1.1
|
||||
|
||||
jest@29.7.0:
|
||||
dependencies:
|
||||
'@jest/core': 29.7.0
|
||||
'@jest/types': 29.6.3
|
||||
import-local: 3.1.0
|
||||
jest-cli: 29.7.0
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- babel-plugin-macros
|
||||
- supports-color
|
||||
- ts-node
|
||||
|
||||
jest@29.7.0(@types/node@22.15.17)(ts-node@10.9.1(@swc/core@1.10.14(@swc/helpers@0.5.15))(@types/node@22.15.17)(typescript@5.2.2)):
|
||||
dependencies:
|
||||
'@jest/core': 29.7.0(ts-node@10.9.1(@swc/core@1.10.14(@swc/helpers@0.5.15))(@types/node@22.15.17)(typescript@5.2.2))
|
||||
@@ -30817,11 +30906,6 @@ snapshots:
|
||||
dependencies:
|
||||
kea: 3.1.5(react@18.2.0)
|
||||
|
||||
kea-router@3.3.0(kea@3.1.5(react@18.2.0)):
|
||||
dependencies:
|
||||
kea: 3.1.5(react@18.2.0)
|
||||
url-pattern: 1.0.3
|
||||
|
||||
kea-router@3.3.1(kea@3.1.5(react@18.2.0)):
|
||||
dependencies:
|
||||
kea: 3.1.5(react@18.2.0)
|
||||
@@ -32331,6 +32415,10 @@ snapshots:
|
||||
|
||||
pirates@4.0.6: {}
|
||||
|
||||
piscina@5.1.3:
|
||||
optionalDependencies:
|
||||
'@napi-rs/nice': 1.0.4
|
||||
|
||||
pixelmatch@5.3.0:
|
||||
dependencies:
|
||||
pngjs: 6.0.0
|
||||
|
||||
Reference in New Issue
Block a user