mirror of
https://github.com/BillyOutlast/posthog.git
synced 2026-02-04 03:01:23 +01:00
feat(cdp): followup native executor (#34769)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
This commit is contained in:
@@ -123,6 +123,7 @@
|
||||
"@types/adm-zip": "^0.4.34",
|
||||
"@types/babel__core": "^7.1.19",
|
||||
"@types/babel__standalone": "^7.1.4",
|
||||
"@types/chance": "^1.1.7",
|
||||
"@types/faker": "^5.5.7",
|
||||
"@types/generic-pool": "^3.1.9",
|
||||
"@types/ioredis": "^4.26.4",
|
||||
@@ -159,6 +160,7 @@
|
||||
"supertest": "^7.0.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"tsc-alias": "^1.8.16",
|
||||
"chance": "^1.1.13",
|
||||
"tsconfig-paths": "^4.2.0"
|
||||
},
|
||||
"cyclotron": {
|
||||
|
||||
@@ -1,28 +1,111 @@
|
||||
import { template } from './webhook.template'
|
||||
import { SAMPLE_GLOBALS } from '~/cdp/_tests/fixtures'
|
||||
|
||||
import { NATIVE_HOG_FUNCTIONS_BY_ID } from '../../index'
|
||||
import { DestinationTester, generateTestData } from '../../test/test-helpers'
|
||||
|
||||
const template = NATIVE_HOG_FUNCTIONS_BY_ID['native-webhook']
|
||||
|
||||
describe(`${template.name} template`, () => {
|
||||
const tester = new DestinationTester(template!)
|
||||
|
||||
beforeEach(() => {
|
||||
tester.beforeEach()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
tester.afterEach()
|
||||
})
|
||||
|
||||
describe('native webhook template', () => {
|
||||
it('should work with default mapping', async () => {
|
||||
const mockRequest = jest.fn().mockResolvedValue({
|
||||
status: 200,
|
||||
json: () => Promise.resolve({ message: 'Success' }),
|
||||
text: () => Promise.resolve(JSON.stringify({ message: 'Success' })),
|
||||
headers: {},
|
||||
})
|
||||
|
||||
const payload = {
|
||||
url: 'https://example.com/webhook',
|
||||
method: 'POST',
|
||||
body: { event: '{event}', person: '{person}' },
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
debug_mode: true,
|
||||
}
|
||||
const response = await tester.invoke(SAMPLE_GLOBALS, payload)
|
||||
|
||||
await template.perform(mockRequest, { payload })
|
||||
expect(response.logs).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"level": "debug",
|
||||
"message": "config, {"method":"POST","body":{"event":{"uuid":"uuid","event":"test","distinct_id":"distinct_id","properties":{"email":"test@posthog.com"},"timestamp":"","elements_chain":"","url":""},"person":{"id":"person-id","name":"person-name","properties":{"email":"example@posthog.com"},"url":"https://us.posthog.com/projects/1/persons/1234"}},"headers":{"Content-Type":"application/json"},"debug":false,"debug_mode":true,"url":"https://example.com/webhook"}",
|
||||
"timestamp": "2025-01-01T00:00:00.000Z",
|
||||
},
|
||||
{
|
||||
"level": "debug",
|
||||
"message": "endpoint, https://example.com/webhook",
|
||||
"timestamp": "2025-01-01T00:00:00.000Z",
|
||||
},
|
||||
{
|
||||
"level": "debug",
|
||||
"message": "options, {"method":"POST","headers":{"Content-Type":"application/json"},"json":{"event":{"uuid":"uuid","event":"test","distinct_id":"distinct_id","properties":{"email":"test@posthog.com"},"timestamp":"","elements_chain":"","url":""},"person":{"id":"person-id","name":"person-name","properties":{"email":"example@posthog.com"},"url":"https://us.posthog.com/projects/1/persons/1234"}}}",
|
||||
"timestamp": "2025-01-01T00:00:00.000Z",
|
||||
},
|
||||
{
|
||||
"level": "debug",
|
||||
"message": "fetchOptions, {"method":"POST","headers":{"User-Agent":"PostHog.com/1.0","Content-Type":"application/json"},"body":"{\\"event\\":{\\"uuid\\":\\"uuid\\",\\"event\\":\\"test\\",\\"distinct_id\\":\\"distinct_id\\",\\"properties\\":{\\"email\\":\\"test@posthog.com\\"},\\"timestamp\\":\\"\\",\\"elements_chain\\":\\"\\",\\"url\\":\\"\\"},\\"person\\":{\\"id\\":\\"person-id\\",\\"name\\":\\"person-name\\",\\"properties\\":{\\"email\\":\\"example@posthog.com\\"},\\"url\\":\\"https://us.posthog.com/projects/1/persons/1234\\"}}"}",
|
||||
"timestamp": "2025-01-01T00:00:00.000Z",
|
||||
},
|
||||
{
|
||||
"level": "debug",
|
||||
"message": "convertedResponse, 200, {"status":"OK"}, {"status":"OK"}, {"content-type":"application/json"}",
|
||||
"timestamp": "2025-01-01T00:00:00.000Z",
|
||||
},
|
||||
{
|
||||
"level": "info",
|
||||
"message": "Function completed in [REPLACED]",
|
||||
"timestamp": "2025-01-01T00:00:00.000Z",
|
||||
},
|
||||
]
|
||||
`)
|
||||
})
|
||||
|
||||
expect(mockRequest).toHaveBeenCalledTimes(1)
|
||||
expect(mockRequest).toHaveBeenCalledWith('https://example.com/webhook', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
json: { event: '{event}', person: '{person}' },
|
||||
it('should handle a failing request', async () => {
|
||||
const inputs = generateTestData(template.id, template.inputs_schema)
|
||||
|
||||
tester.mockFetchResponse({
|
||||
status: 400,
|
||||
body: { status: 'ERROR' },
|
||||
headers: { 'content-type': 'application/json' },
|
||||
})
|
||||
|
||||
const response = await tester.invoke(SAMPLE_GLOBALS, { ...inputs, debug_mode: true })
|
||||
|
||||
expect(response.logs).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"level": "debug",
|
||||
"message": "config, {"method":"POST","body":{"event":{"uuid":"uuid","event":"test","distinct_id":"distinct_id","properties":{"email":"test@posthog.com"},"timestamp":"","elements_chain":"","url":""},"person":{"id":"person-id","name":"person-name","properties":{"email":"example@posthog.com"},"url":"https://us.posthog.com/projects/1/persons/1234"}},"headers":{"Content-Type":"application/json"},"debug":false,"debug_mode":true,"url":"http://jaj.mu/iroti"}",
|
||||
"timestamp": "2025-01-01T00:00:00.000Z",
|
||||
},
|
||||
{
|
||||
"level": "debug",
|
||||
"message": "endpoint, http://jaj.mu/iroti",
|
||||
"timestamp": "2025-01-01T00:00:00.000Z",
|
||||
},
|
||||
{
|
||||
"level": "debug",
|
||||
"message": "options, {"method":"POST","headers":{"Content-Type":"application/json"},"json":{"event":{"uuid":"uuid","event":"test","distinct_id":"distinct_id","properties":{"email":"test@posthog.com"},"timestamp":"","elements_chain":"","url":""},"person":{"id":"person-id","name":"person-name","properties":{"email":"example@posthog.com"},"url":"https://us.posthog.com/projects/1/persons/1234"}}}",
|
||||
"timestamp": "2025-01-01T00:00:00.000Z",
|
||||
},
|
||||
{
|
||||
"level": "debug",
|
||||
"message": "fetchOptions, {"method":"POST","headers":{"User-Agent":"PostHog.com/1.0","Content-Type":"application/json"},"body":"{\\"event\\":{\\"uuid\\":\\"uuid\\",\\"event\\":\\"test\\",\\"distinct_id\\":\\"distinct_id\\",\\"properties\\":{\\"email\\":\\"test@posthog.com\\"},\\"timestamp\\":\\"\\",\\"elements_chain\\":\\"\\",\\"url\\":\\"\\"},\\"person\\":{\\"id\\":\\"person-id\\",\\"name\\":\\"person-name\\",\\"properties\\":{\\"email\\":\\"example@posthog.com\\"},\\"url\\":\\"https://us.posthog.com/projects/1/persons/1234\\"}}"}",
|
||||
"timestamp": "2025-01-01T00:00:00.000Z",
|
||||
},
|
||||
{
|
||||
"level": "warn",
|
||||
"message": "HTTP request failed with status 400 ({"status":"ERROR"}). ",
|
||||
"timestamp": "2025-01-01T00:00:00.000Z",
|
||||
},
|
||||
{
|
||||
"level": "error",
|
||||
"message": "Function failed: Error executing function on event uuid: Request failed with status 400 ({"status":"ERROR"})",
|
||||
"timestamp": "2025-01-01T00:00:00.000Z",
|
||||
},
|
||||
]
|
||||
`)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -4,7 +4,7 @@ import { HogFunctionTemplate, NativeTemplate } from '../types'
|
||||
import { allComingSoonTemplates } from './_destinations/coming-soon/coming-soon-destinations.template'
|
||||
import { template as googleAdsTemplate } from './_destinations/google_ads/google.template'
|
||||
import { template as linearTemplate } from './_destinations/linear/linear.template'
|
||||
import { template as nativeWebhook } from './_destinations/native-webhook/webhook.template'
|
||||
import { template as nativeWebhookTemplate } from './_destinations/native-webhook/webhook.template'
|
||||
import { template as redditAdsTemplate } from './_destinations/reddit_ads/reddit.template'
|
||||
import { template as snapchatAdsTemplate } from './_destinations/snapchat_ads/snapchat.template'
|
||||
import { template as tiktokAdsTemplate } from './_destinations/tiktok_ads/tiktok.template'
|
||||
@@ -49,7 +49,7 @@ export const HOG_FUNCTION_TEMPLATES_TRANSFORMATIONS: HogFunctionTemplate[] = [
|
||||
urlNormalizationTemplate,
|
||||
]
|
||||
|
||||
export const NATIVE_HOG_FUNCTIONS: NativeTemplate[] = [nativeWebhook].map((plugin) => ({
|
||||
export const NATIVE_HOG_FUNCTIONS: NativeTemplate[] = [nativeWebhookTemplate].map((plugin) => ({
|
||||
...plugin,
|
||||
code_language: 'javascript',
|
||||
code: 'return event;',
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import Chance from 'chance'
|
||||
import merge from 'deepmerge'
|
||||
import { DateTime, Settings } from 'luxon'
|
||||
|
||||
import { NativeDestinationExecutorService } from '~/cdp/services/native-destination-executor.service'
|
||||
import { defaultConfig } from '~/config/config'
|
||||
import { CyclotronInputType } from '~/schema/cyclotron'
|
||||
import { GeoIp, GeoIPService } from '~/utils/geoip'
|
||||
@@ -7,14 +10,17 @@ import { GeoIp, GeoIPService } from '~/utils/geoip'
|
||||
import { Hub } from '../../../types'
|
||||
import { cleanNullValues } from '../../hog-transformations/transformation-functions'
|
||||
import { HogExecutorService } from '../../services/hog-executor.service'
|
||||
import { HogInputsService } from '../../services/hog-inputs.service'
|
||||
import {
|
||||
CyclotronJobInvocationHogFunction,
|
||||
CyclotronJobInvocationResult,
|
||||
HogFunctionInputSchemaType,
|
||||
HogFunctionInvocationGlobals,
|
||||
HogFunctionInvocationGlobalsWithInputs,
|
||||
HogFunctionTemplate,
|
||||
HogFunctionTemplateCompiled,
|
||||
HogFunctionType,
|
||||
NativeTemplate,
|
||||
} from '../../types'
|
||||
import { cloneInvocation } from '../../utils/invocation-utils'
|
||||
import { createInvocation } from '../../utils/invocation-utils'
|
||||
@@ -27,6 +33,87 @@ export type DeepPartialHogFunctionInvocationGlobals = {
|
||||
request?: HogFunctionInvocationGlobals['request']
|
||||
}
|
||||
|
||||
const compileObject = async (obj: any): Promise<any> => {
|
||||
if (Array.isArray(obj)) {
|
||||
return Promise.all(obj.map((item) => compileObject(item)))
|
||||
} else if (typeof obj === 'object') {
|
||||
const res: Record<string, any> = {}
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
res[key] = await compileObject(value)
|
||||
}
|
||||
return res
|
||||
} else if (typeof obj === 'string') {
|
||||
return await compileHog(`return f'${obj}'`)
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
const compileInputs = async (
|
||||
template: HogFunctionTemplate | NativeTemplate,
|
||||
_inputs: Record<string, any>
|
||||
): Promise<Record<string, CyclotronInputType>> => {
|
||||
const defaultInputs = template.inputs_schema.reduce((acc, input) => {
|
||||
if (typeof input.default !== 'undefined') {
|
||||
acc[input.key] = input.default
|
||||
}
|
||||
return acc
|
||||
}, {} as Record<string, CyclotronInputType>)
|
||||
|
||||
const allInputs = { ...defaultInputs, ..._inputs }
|
||||
|
||||
// Don't compile inputs that don't suppport templating
|
||||
const compiledEntries = await Promise.all(
|
||||
Object.entries(allInputs).map(async ([key, value]) => {
|
||||
const schema = template.inputs_schema.find((input) => input.key === key)
|
||||
if (schema?.templating === false) {
|
||||
return [key, value]
|
||||
}
|
||||
return [key, await compileObject(value)]
|
||||
})
|
||||
)
|
||||
|
||||
return compiledEntries.reduce((acc, [key, value]) => {
|
||||
acc[key] = {
|
||||
value: allInputs[key],
|
||||
bytecode: value,
|
||||
}
|
||||
return acc
|
||||
}, {} as Record<string, CyclotronInputType>)
|
||||
}
|
||||
|
||||
const createGlobals = (
|
||||
globals: DeepPartialHogFunctionInvocationGlobals = {}
|
||||
): HogFunctionInvocationGlobalsWithInputs => {
|
||||
return {
|
||||
...globals,
|
||||
inputs: {},
|
||||
project: { id: 1, name: 'project-name', url: 'https://us.posthog.com/projects/1' },
|
||||
event: {
|
||||
uuid: 'event-id',
|
||||
event: 'event-name',
|
||||
distinct_id: 'distinct-id',
|
||||
properties: { $current_url: 'https://example.com', ...globals.event?.properties },
|
||||
timestamp: '2024-01-01T00:00:00Z',
|
||||
elements_chain: '',
|
||||
url: 'https://us.posthog.com/projects/1/events/1234',
|
||||
...globals.event,
|
||||
},
|
||||
person: {
|
||||
id: 'person-id',
|
||||
name: 'person-name',
|
||||
properties: { email: 'example@posthog.com', ...globals.person?.properties },
|
||||
url: 'https://us.posthog.com/projects/1/persons/1234',
|
||||
...globals.person,
|
||||
},
|
||||
source: {
|
||||
url: 'https://us.posthog.com/hog_functions/1234',
|
||||
name: 'hog-function-name',
|
||||
...globals.source,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export class TemplateTester {
|
||||
public template: HogFunctionTemplateCompiled
|
||||
private executor: HogExecutorService
|
||||
@@ -70,79 +157,7 @@ export class TemplateTester {
|
||||
}
|
||||
|
||||
createGlobals(globals: DeepPartialHogFunctionInvocationGlobals = {}): HogFunctionInvocationGlobalsWithInputs {
|
||||
return {
|
||||
...globals,
|
||||
inputs: {},
|
||||
project: { id: 1, name: 'project-name', url: 'https://us.posthog.com/projects/1' },
|
||||
event: {
|
||||
uuid: 'event-id',
|
||||
event: 'event-name',
|
||||
distinct_id: 'distinct-id',
|
||||
properties: { $current_url: 'https://example.com', ...globals.event?.properties },
|
||||
timestamp: '2024-01-01T00:00:00Z',
|
||||
elements_chain: '',
|
||||
url: 'https://us.posthog.com/projects/1/events/1234',
|
||||
...globals.event,
|
||||
},
|
||||
person: {
|
||||
id: 'person-id',
|
||||
name: 'person-name',
|
||||
properties: { email: 'example@posthog.com', ...globals.person?.properties },
|
||||
url: 'https://us.posthog.com/projects/1/persons/1234',
|
||||
...globals.person,
|
||||
},
|
||||
source: {
|
||||
url: 'https://us.posthog.com/hog_functions/1234',
|
||||
name: 'hog-function-name',
|
||||
...globals.source,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
private async compileObject(obj: any): Promise<any> {
|
||||
if (Array.isArray(obj)) {
|
||||
return Promise.all(obj.map((item) => this.compileObject(item)))
|
||||
} else if (typeof obj === 'object') {
|
||||
const res: Record<string, any> = {}
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
res[key] = await this.compileObject(value)
|
||||
}
|
||||
return res
|
||||
} else if (typeof obj === 'string') {
|
||||
return await compileHog(`return f'${obj}'`)
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
private async compileInputs(_inputs: Record<string, any>): Promise<Record<string, CyclotronInputType>> {
|
||||
const defaultInputs = this.template.inputs_schema.reduce((acc, input) => {
|
||||
if (typeof input.default !== 'undefined') {
|
||||
acc[input.key] = input.default
|
||||
}
|
||||
return acc
|
||||
}, {} as Record<string, CyclotronInputType>)
|
||||
|
||||
const allInputs = { ...defaultInputs, ..._inputs }
|
||||
|
||||
// Don't compile inputs that don't suppport templating
|
||||
const compiledEntries = await Promise.all(
|
||||
Object.entries(allInputs).map(async ([key, value]) => {
|
||||
const schema = this.template.inputs_schema.find((input) => input.key === key)
|
||||
if (schema?.templating === false) {
|
||||
return [key, value]
|
||||
}
|
||||
return [key, await this.compileObject(value)]
|
||||
})
|
||||
)
|
||||
|
||||
return compiledEntries.reduce((acc, [key, value]) => {
|
||||
acc[key] = {
|
||||
value: allInputs[key],
|
||||
bytecode: value,
|
||||
}
|
||||
return acc
|
||||
}, {} as Record<string, CyclotronInputType>)
|
||||
return createGlobals(globals)
|
||||
}
|
||||
|
||||
async invoke(
|
||||
@@ -153,7 +168,7 @@ export class TemplateTester {
|
||||
throw new Error('Mapping templates found. Use invokeMapping instead.')
|
||||
}
|
||||
|
||||
const compiledInputs = await this.compileInputs(_inputs)
|
||||
const compiledInputs = await compileInputs(this.template, _inputs)
|
||||
const globals = this.createGlobals(_globals)
|
||||
|
||||
const { code, ...partialTemplate } = this.template
|
||||
@@ -196,7 +211,7 @@ export class TemplateTester {
|
||||
throw new Error('No mapping templates found')
|
||||
}
|
||||
|
||||
const compiledInputs = await this.compileInputs(_inputs)
|
||||
const compiledInputs = await compileInputs(this.template, _inputs)
|
||||
|
||||
const compiledMappingInputs = {
|
||||
...this.template.mapping_templates.find((mapping) => mapping.name === mapping_name),
|
||||
@@ -215,7 +230,7 @@ export class TemplateTester {
|
||||
return {
|
||||
key: input.key,
|
||||
value,
|
||||
bytecode: await this.compileObject(value),
|
||||
bytecode: await compileObject(value),
|
||||
}
|
||||
})
|
||||
)
|
||||
@@ -270,6 +285,95 @@ export class TemplateTester {
|
||||
}
|
||||
}
|
||||
|
||||
export class DestinationTester {
|
||||
private executor: NativeDestinationExecutorService
|
||||
private inputsService: HogInputsService
|
||||
private mockFetch = jest.fn()
|
||||
|
||||
constructor(private template: NativeTemplate) {
|
||||
this.template = template
|
||||
this.executor = new NativeDestinationExecutorService({} as any)
|
||||
this.inputsService = new HogInputsService({} as any)
|
||||
|
||||
this.executor.fetch = this.mockFetch
|
||||
|
||||
this.mockFetch.mockResolvedValue({
|
||||
status: 200,
|
||||
json: () => Promise.resolve({ status: 'OK' }),
|
||||
text: () => Promise.resolve(JSON.stringify({ status: 'OK' })),
|
||||
headers: { 'content-type': 'application/json' },
|
||||
})
|
||||
}
|
||||
|
||||
createGlobals(globals: DeepPartialHogFunctionInvocationGlobals = {}): HogFunctionInvocationGlobalsWithInputs {
|
||||
return createGlobals(globals)
|
||||
}
|
||||
|
||||
mockFetchResponse(response?: { status?: number; body?: Record<string, any>; headers?: Record<string, string> }) {
|
||||
const defaultResponse = {
|
||||
status: 200,
|
||||
body: { status: 'OK' },
|
||||
headers: { 'content-type': 'application/json' },
|
||||
}
|
||||
|
||||
const finalResponse = { ...defaultResponse, ...response }
|
||||
|
||||
this.mockFetch.mockResolvedValue({
|
||||
status: finalResponse.status,
|
||||
json: () => Promise.resolve(finalResponse.body),
|
||||
text: () => Promise.resolve(JSON.stringify(finalResponse.body)),
|
||||
headers: finalResponse.headers,
|
||||
})
|
||||
}
|
||||
|
||||
beforeEach() {
|
||||
Settings.defaultZone = 'UTC'
|
||||
const fixedTime = DateTime.fromISO('2025-01-01T00:00:00Z').toJSDate()
|
||||
jest.spyOn(Date, 'now').mockReturnValue(fixedTime.getTime())
|
||||
}
|
||||
|
||||
afterEach() {
|
||||
Settings.defaultZone = 'system'
|
||||
jest.useRealTimers()
|
||||
}
|
||||
|
||||
async invoke(globals: HogFunctionInvocationGlobals, inputs: Record<string, any>) {
|
||||
const compiledInputs = await compileInputs(this.template, inputs)
|
||||
|
||||
const globalsWithInputs = await this.inputsService.buildInputsWithGlobals(
|
||||
{
|
||||
...this.template,
|
||||
inputs: compiledInputs,
|
||||
} as unknown as HogFunctionType,
|
||||
this.createGlobals(globals)
|
||||
)
|
||||
const invocation = createInvocation(globalsWithInputs, {
|
||||
...this.template,
|
||||
template_id: this.template.id,
|
||||
hog: 'return event',
|
||||
bytecode: [],
|
||||
team_id: 1,
|
||||
enabled: true,
|
||||
created_at: '2024-01-01T00:00:00Z',
|
||||
updated_at: '2024-01-01T00:00:00Z',
|
||||
deleted: false,
|
||||
inputs: compiledInputs,
|
||||
is_addon_required: false,
|
||||
})
|
||||
|
||||
const result = await this.executor.execute(invocation)
|
||||
|
||||
result.logs.forEach((x) => {
|
||||
if (typeof x.message === 'string' && x.message.includes('Function completed in')) {
|
||||
x.message = 'Function completed in [REPLACED]'
|
||||
}
|
||||
})
|
||||
result.invocation.id = 'invocation-id'
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
export const createAdDestinationPayload = (
|
||||
globals?: DeepPartialHogFunctionInvocationGlobals
|
||||
): DeepPartialHogFunctionInvocationGlobals => {
|
||||
@@ -304,3 +408,97 @@ export const createAdDestinationPayload = (
|
||||
|
||||
return defaultPayload
|
||||
}
|
||||
|
||||
export const generateTestData = (
|
||||
seedName: string,
|
||||
input_schema: HogFunctionInputSchemaType[],
|
||||
requiredFieldsOnly: boolean = false
|
||||
): Record<string, any> => {
|
||||
const generateValue = (input: HogFunctionInputSchemaType): any => {
|
||||
const chance = new Chance(seedName)
|
||||
|
||||
if (Array.isArray(input.choices)) {
|
||||
const choice = chance.pickone(input.choices)
|
||||
return choice.value
|
||||
}
|
||||
|
||||
const getFormat = (input: HogFunctionInputSchemaType): string => {
|
||||
if (input.key === 'url') {
|
||||
return 'uri'
|
||||
} else if (input.key === 'email') {
|
||||
return 'email'
|
||||
} else if (input.key === 'uuid') {
|
||||
return 'uuid'
|
||||
} else if (input.key === 'phone') {
|
||||
return 'phone'
|
||||
}
|
||||
return 'string'
|
||||
}
|
||||
|
||||
let val: any
|
||||
switch (input.type) {
|
||||
case 'boolean':
|
||||
val = chance.bool()
|
||||
break
|
||||
case 'number':
|
||||
val = chance.integer()
|
||||
break
|
||||
default:
|
||||
// covers string
|
||||
switch (getFormat(input)) {
|
||||
case 'date': {
|
||||
const d = chance.date()
|
||||
val = [d.getFullYear(), d.getMonth() + 1, d.getDate()]
|
||||
.map((v) => String(v).padStart(2, '0'))
|
||||
.join('-')
|
||||
break
|
||||
}
|
||||
case 'date-time':
|
||||
val = chance.date().toISOString()
|
||||
break
|
||||
case 'email':
|
||||
val = chance.email()
|
||||
break
|
||||
case 'hostname':
|
||||
val = chance.domain()
|
||||
break
|
||||
case 'ipv4':
|
||||
val = chance.ip()
|
||||
break
|
||||
case 'ipv6':
|
||||
val = chance.ipv6()
|
||||
break
|
||||
case 'time': {
|
||||
const d = chance.date()
|
||||
val = [d.getHours(), d.getMinutes(), d.getSeconds()]
|
||||
.map((v) => String(v).padStart(2, '0'))
|
||||
.join(':')
|
||||
break
|
||||
}
|
||||
case 'uri':
|
||||
val = chance.url()
|
||||
break
|
||||
case 'uuid':
|
||||
val = chance.guid()
|
||||
break
|
||||
case 'phone':
|
||||
val = chance.phone()
|
||||
break
|
||||
default:
|
||||
val = chance.string()
|
||||
break
|
||||
}
|
||||
break
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
const inputs = input_schema.reduce((acc, input) => {
|
||||
if (input.required || requiredFieldsOnly === false) {
|
||||
acc[input.key] = input.default ?? generateValue(input)
|
||||
}
|
||||
return acc
|
||||
}, {} as Record<string, any>)
|
||||
|
||||
return inputs
|
||||
}
|
||||
|
||||
86
pnpm-lock.yaml
generated
86
pnpm-lock.yaml
generated
@@ -161,7 +161,7 @@ importers:
|
||||
version: 3.12.1
|
||||
jest:
|
||||
specifier: ^29.7.0
|
||||
version: 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))
|
||||
version: 29.7.0(@types/node@22.15.17)(ts-node@10.9.1(@swc/core@1.11.4(@swc/helpers@0.5.15))(@types/node@22.15.17)(typescript@5.2.2))
|
||||
parcel:
|
||||
specifier: ^2.13.3
|
||||
version: 2.13.3(@swc/helpers@0.5.15)(cssnano@7.0.6(postcss@8.5.6))(postcss@8.5.6)(relateurl@0.2.7)(svgo@3.3.2)(terser@5.19.1)(typescript@5.2.2)
|
||||
@@ -1459,6 +1459,9 @@ importers:
|
||||
'@types/babel__standalone':
|
||||
specifier: ^7.1.4
|
||||
version: 7.1.4
|
||||
'@types/chance':
|
||||
specifier: ^1.1.7
|
||||
version: 1.1.7
|
||||
'@types/faker':
|
||||
specifier: ^5.5.7
|
||||
version: 5.5.9
|
||||
@@ -1516,6 +1519,9 @@ importers:
|
||||
babel-eslint:
|
||||
specifier: ^10.1.0
|
||||
version: 10.1.0(eslint@8.57.0)
|
||||
chance:
|
||||
specifier: ^1.1.13
|
||||
version: 1.1.13
|
||||
deepmerge:
|
||||
specifier: ^4.2.2
|
||||
version: 4.3.1
|
||||
@@ -1923,7 +1929,7 @@ importers:
|
||||
version: 8.57.0
|
||||
jest:
|
||||
specifier: '*'
|
||||
version: 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))
|
||||
version: 29.7.0(@types/node@22.15.17)(ts-node@10.9.1(@swc/core@1.11.4(@swc/helpers@0.5.15))(@types/node@22.15.17)(typescript@5.2.2))
|
||||
kea:
|
||||
specifier: '*'
|
||||
version: 3.1.5(react@18.2.0)
|
||||
@@ -1977,7 +1983,7 @@ importers:
|
||||
version: 3.1.3
|
||||
jest:
|
||||
specifier: '*'
|
||||
version: 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))
|
||||
version: 29.7.0(@types/node@22.15.17)(ts-node@10.9.1(@swc/core@1.11.4(@swc/helpers@0.5.15))(@types/node@22.15.17)(typescript@5.2.2))
|
||||
kea:
|
||||
specifier: '*'
|
||||
version: 3.1.5(react@18.2.0)
|
||||
@@ -7585,6 +7591,9 @@ packages:
|
||||
'@types/caseless@0.12.5':
|
||||
resolution: {integrity: sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==}
|
||||
|
||||
'@types/chance@1.1.7':
|
||||
resolution: {integrity: sha512-40you9610GTQPJyvjMBgmj9wiDO6qXhbfjizNYod/fmvLSfUUxURAJMTD8tjmbcZSsyYE5iEUox61AAcCjW/wQ==}
|
||||
|
||||
'@types/chart.js@2.9.37':
|
||||
resolution: {integrity: sha512-9bosRfHhkXxKYfrw94EmyDQcdjMaQPkU1fH2tDxu8DWXxf1mjzWQAV4laJF51ZbC2ycYwNDvIm1rGez8Bug0vg==}
|
||||
|
||||
@@ -9013,6 +9022,9 @@ packages:
|
||||
resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==}
|
||||
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
|
||||
|
||||
chance@1.1.13:
|
||||
resolution: {integrity: sha512-V6lQCljcLznE7tUYUM9EOAnnKXbctE6j/rdQkYOHIWbfGQbrzTsAXNW9CdU5XCo4ArXQCj/rb6HgxPlmGJcaUg==}
|
||||
|
||||
char-regex@1.0.2:
|
||||
resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -18071,7 +18083,7 @@ snapshots:
|
||||
'@babel/traverse': 7.28.0
|
||||
'@babel/types': 7.28.1
|
||||
convert-source-map: 2.0.0
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
gensync: 1.0.0-beta.2
|
||||
json5: 2.2.3
|
||||
semver: 6.3.1
|
||||
@@ -18181,7 +18193,7 @@ snapshots:
|
||||
'@babel/core': 7.26.0
|
||||
'@babel/helper-compilation-targets': 7.25.9
|
||||
'@babel/helper-plugin-utils': 7.24.7
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
lodash.debounce: 4.0.8
|
||||
resolve: 1.22.8
|
||||
transitivePeerDependencies:
|
||||
@@ -18192,7 +18204,7 @@ snapshots:
|
||||
'@babel/core': 7.28.0
|
||||
'@babel/helper-compilation-targets': 7.25.9
|
||||
'@babel/helper-plugin-utils': 7.24.7
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
lodash.debounce: 4.0.8
|
||||
resolve: 1.22.8
|
||||
transitivePeerDependencies:
|
||||
@@ -18203,7 +18215,7 @@ snapshots:
|
||||
'@babel/core': 7.26.0
|
||||
'@babel/helper-compilation-targets': 7.25.9
|
||||
'@babel/helper-plugin-utils': 7.24.7
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
lodash.debounce: 4.0.8
|
||||
resolve: 1.22.8
|
||||
transitivePeerDependencies:
|
||||
@@ -18214,7 +18226,7 @@ snapshots:
|
||||
'@babel/core': 7.28.0
|
||||
'@babel/helper-compilation-targets': 7.25.9
|
||||
'@babel/helper-plugin-utils': 7.24.7
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
lodash.debounce: 4.0.8
|
||||
resolve: 1.22.8
|
||||
transitivePeerDependencies:
|
||||
@@ -18225,7 +18237,7 @@ snapshots:
|
||||
'@babel/core': 7.26.0
|
||||
'@babel/helper-compilation-targets': 7.25.9
|
||||
'@babel/helper-plugin-utils': 7.24.7
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
lodash.debounce: 4.0.8
|
||||
resolve: 1.22.8
|
||||
transitivePeerDependencies:
|
||||
@@ -18236,7 +18248,7 @@ snapshots:
|
||||
'@babel/core': 7.28.0
|
||||
'@babel/helper-compilation-targets': 7.25.9
|
||||
'@babel/helper-plugin-utils': 7.24.7
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
lodash.debounce: 4.0.8
|
||||
resolve: 1.22.8
|
||||
transitivePeerDependencies:
|
||||
@@ -19675,7 +19687,7 @@ snapshots:
|
||||
'@babel/parser': 7.28.0
|
||||
'@babel/template': 7.27.2
|
||||
'@babel/types': 7.28.1
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -20232,7 +20244,7 @@ snapshots:
|
||||
'@eslint/eslintrc@2.1.4':
|
||||
dependencies:
|
||||
ajv: 6.12.6
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
espree: 9.6.1
|
||||
globals: 13.23.0
|
||||
ignore: 5.2.4
|
||||
@@ -20362,7 +20374,7 @@ snapshots:
|
||||
'@humanwhocodes/config-array@0.11.14':
|
||||
dependencies:
|
||||
'@humanwhocodes/object-schema': 2.0.3
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
minimatch: 3.1.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -20779,7 +20791,7 @@ snapshots:
|
||||
'@open-draft/until': 1.0.3
|
||||
'@types/debug': 4.1.7
|
||||
'@xmldom/xmldom': 0.8.6
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
headers-polyfill: 3.2.5
|
||||
outvariant: 1.4.0
|
||||
strict-event-emitter: 0.2.8
|
||||
@@ -24162,7 +24174,7 @@ snapshots:
|
||||
|
||||
'@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.2.2)(webpack@5.88.2)':
|
||||
dependencies:
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
endent: 2.1.0
|
||||
find-cache-dir: 3.3.2
|
||||
flat-cache: 3.2.0
|
||||
@@ -24966,6 +24978,8 @@ snapshots:
|
||||
|
||||
'@types/caseless@0.12.5': {}
|
||||
|
||||
'@types/chance@1.1.7': {}
|
||||
|
||||
'@types/chart.js@2.9.37':
|
||||
dependencies:
|
||||
moment: 2.29.4
|
||||
@@ -25590,7 +25604,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@typescript-eslint/typescript-estree': 7.1.1(typescript@5.2.2)
|
||||
'@typescript-eslint/utils': 7.1.1(eslint@8.57.0)(typescript@5.2.2)
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
eslint: 8.57.0
|
||||
ts-api-utils: 1.0.2(typescript@5.2.2)
|
||||
optionalDependencies:
|
||||
@@ -25604,7 +25618,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 7.1.1
|
||||
'@typescript-eslint/visitor-keys': 7.1.1
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
globby: 11.1.0
|
||||
is-glob: 4.0.3
|
||||
minimatch: 9.0.3
|
||||
@@ -25842,7 +25856,7 @@ snapshots:
|
||||
|
||||
agent-base@6.0.2:
|
||||
dependencies:
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -25850,7 +25864,7 @@ snapshots:
|
||||
|
||||
agentkeepalive@4.3.0:
|
||||
dependencies:
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
depd: 2.0.0
|
||||
humanize-ms: 1.2.1
|
||||
transitivePeerDependencies:
|
||||
@@ -26715,6 +26729,8 @@ snapshots:
|
||||
|
||||
chalk@5.4.1: {}
|
||||
|
||||
chance@1.1.13: {}
|
||||
|
||||
char-regex@1.0.2: {}
|
||||
|
||||
char-regex@2.0.1: {}
|
||||
@@ -27815,7 +27831,7 @@ snapshots:
|
||||
detect-port@1.5.1:
|
||||
dependencies:
|
||||
address: 1.2.2
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -28193,7 +28209,7 @@ snapshots:
|
||||
|
||||
esbuild-register@3.5.0(esbuild@0.18.20):
|
||||
dependencies:
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
esbuild: 0.18.20
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -28767,7 +28783,7 @@ snapshots:
|
||||
dependencies:
|
||||
chalk: 4.1.2
|
||||
commander: 5.1.0
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -29542,14 +29558,14 @@ snapshots:
|
||||
dependencies:
|
||||
'@tootallnate/once': 2.0.0
|
||||
agent-base: 6.0.2
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
http-proxy-agent@7.0.2:
|
||||
dependencies:
|
||||
agent-base: 7.1.4
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -29562,21 +29578,21 @@ snapshots:
|
||||
https-proxy-agent@4.0.0:
|
||||
dependencies:
|
||||
agent-base: 5.1.1
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
https-proxy-agent@5.0.1:
|
||||
dependencies:
|
||||
agent-base: 6.0.2
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
https-proxy-agent@7.0.6:
|
||||
dependencies:
|
||||
agent-base: 7.1.4
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -30053,7 +30069,7 @@ snapshots:
|
||||
|
||||
istanbul-lib-source-maps@4.0.1:
|
||||
dependencies:
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
istanbul-lib-coverage: 3.2.0
|
||||
source-map: 0.6.1
|
||||
transitivePeerDependencies:
|
||||
@@ -30930,7 +30946,7 @@ snapshots:
|
||||
dependencies:
|
||||
chalk: 5.4.1
|
||||
commander: 13.1.0
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
execa: 8.0.1
|
||||
lilconfig: 3.1.3
|
||||
listr2: 8.3.3
|
||||
@@ -31321,7 +31337,7 @@ snapshots:
|
||||
|
||||
micromark@2.11.4:
|
||||
dependencies:
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
parse-entities: 2.0.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -33235,7 +33251,7 @@ snapshots:
|
||||
puppeteer-core@2.1.1:
|
||||
dependencies:
|
||||
'@types/mime-types': 2.1.1
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
extract-zip: 1.7.0
|
||||
https-proxy-agent: 4.0.0
|
||||
mime: 2.6.0
|
||||
@@ -34209,7 +34225,7 @@ snapshots:
|
||||
|
||||
retry-request@4.2.2:
|
||||
dependencies:
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
extend: 3.0.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -34646,7 +34662,7 @@ snapshots:
|
||||
socks-proxy-agent@8.0.5:
|
||||
dependencies:
|
||||
agent-base: 7.1.4
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
socks: 2.8.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -35095,7 +35111,7 @@ snapshots:
|
||||
dependencies:
|
||||
component-emitter: 1.3.1
|
||||
cookiejar: 2.1.4
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
fast-safe-stringify: 2.1.1
|
||||
form-data: 4.0.1
|
||||
formidable: 3.5.1
|
||||
@@ -35984,7 +36000,7 @@ snapshots:
|
||||
dependencies:
|
||||
chalk: 2.4.2
|
||||
commander: 3.0.2
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
debug: 4.4.1(supports-color@5.5.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
|
||||
Reference in New Issue
Block a user