Add event_data base.
parent
72af76a417
commit
15c5cc065e
|
@ -48,7 +48,8 @@
|
||||||
"import/no-anonymous-default-export": "off",
|
"import/no-anonymous-default-export": "off",
|
||||||
"@next/next/no-img-element": "off",
|
"@next/next/no-img-element": "off",
|
||||||
"@typescript-eslint/no-empty-function": "off",
|
"@typescript-eslint/no-empty-function": "off",
|
||||||
"@typescript-eslint/no-explicit-any": "off"
|
"@typescript-eslint/no-explicit-any": "off",
|
||||||
|
"@typescript-eslint/no-var-requires": "off"
|
||||||
},
|
},
|
||||||
"globals": {
|
"globals": {
|
||||||
"React": "writable"
|
"React": "writable"
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { Button, Column, Row, Dropdown, Item } from 'react-basics';
|
import WebsiteSelect from 'components/input/WebsiteSelect';
|
||||||
import Head from 'next/head';
|
|
||||||
import Link from 'next/link';
|
|
||||||
import { useRouter } from 'next/router';
|
|
||||||
import Page from 'components/layout/Page';
|
import Page from 'components/layout/Page';
|
||||||
import PageHeader from 'components/layout/PageHeader';
|
import PageHeader from 'components/layout/PageHeader';
|
||||||
import EventsChart from 'components/metrics/EventsChart';
|
import EventsChart from 'components/metrics/EventsChart';
|
||||||
import WebsiteChart from 'components/metrics/WebsiteChart';
|
import WebsiteChart from 'components/metrics/WebsiteChart';
|
||||||
import WebsiteSelect from 'components/input/WebsiteSelect';
|
|
||||||
import useApi from 'hooks/useApi';
|
import useApi from 'hooks/useApi';
|
||||||
|
import Head from 'next/head';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
import { Button, Column, Row } from 'react-basics';
|
||||||
import styles from './TestConsole.module.css';
|
import styles from './TestConsole.module.css';
|
||||||
|
|
||||||
export default function TestConsole() {
|
export default function TestConsole() {
|
||||||
|
@ -27,7 +27,11 @@ export default function TestConsole() {
|
||||||
window.umami('umami-default');
|
window.umami('umami-default');
|
||||||
window.umami.trackView('/page-view', 'https://www.google.com');
|
window.umami.trackView('/page-view', 'https://www.google.com');
|
||||||
window.umami.trackEvent('track-event-no-data');
|
window.umami.trackEvent('track-event-no-data');
|
||||||
window.umami.trackEvent('track-event-with-data', { test: 'test-data', time: Date.now() });
|
window.umami.trackEvent('track-event-with-data', {
|
||||||
|
test: 'test-data',
|
||||||
|
time: new Date(),
|
||||||
|
time2: new Date().toISOString(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
|
|
|
@ -5,7 +5,7 @@ CREATE TABLE event
|
||||||
(
|
(
|
||||||
website_id UUID,
|
website_id UUID,
|
||||||
session_id UUID,
|
session_id UUID,
|
||||||
event_id Nullable(UUID),
|
event_id UUID,
|
||||||
rev_id UInt32,
|
rev_id UInt32,
|
||||||
--session
|
--session
|
||||||
hostname LowCardinality(String),
|
hostname LowCardinality(String),
|
||||||
|
@ -34,7 +34,7 @@ CREATE TABLE event
|
||||||
CREATE TABLE event_queue (
|
CREATE TABLE event_queue (
|
||||||
website_id UUID,
|
website_id UUID,
|
||||||
session_id UUID,
|
session_id UUID,
|
||||||
event_id Nullable(UUID),
|
event_id UUID,
|
||||||
rev_id UInt32,
|
rev_id UInt32,
|
||||||
--session
|
--session
|
||||||
hostname LowCardinality(String),
|
hostname LowCardinality(String),
|
||||||
|
@ -86,3 +86,56 @@ SELECT website_id,
|
||||||
event_name,
|
event_name,
|
||||||
created_at
|
created_at
|
||||||
FROM event_queue;
|
FROM event_queue;
|
||||||
|
|
||||||
|
CREATE TABLE event_data
|
||||||
|
(
|
||||||
|
website_id UUID,
|
||||||
|
session_id UUID,
|
||||||
|
event_id UUID,
|
||||||
|
rev_id UInt32,
|
||||||
|
event_name String,
|
||||||
|
event_key String,
|
||||||
|
event_string_value Nullable(String),
|
||||||
|
event_numeric_value Nullable(UInt32),
|
||||||
|
event_date_value Nullable(DateTime('UTC')),
|
||||||
|
event_data_type UInt32,
|
||||||
|
created_at DateTime('UTC')
|
||||||
|
)
|
||||||
|
engine = MergeTree
|
||||||
|
ORDER BY (website_id, session_id, created_at)
|
||||||
|
SETTINGS index_granularity = 8192;
|
||||||
|
|
||||||
|
CREATE TABLE event_data_queue (
|
||||||
|
website_id UUID,
|
||||||
|
session_id UUID,
|
||||||
|
event_id UUID,
|
||||||
|
rev_id UInt32,
|
||||||
|
event_name String,
|
||||||
|
event_key String,
|
||||||
|
event_string_value Nullable(String),
|
||||||
|
event_numeric_value Nullable(UInt64),
|
||||||
|
event_date_value Nullable(DateTime('UTC')),
|
||||||
|
event_data_type UInt32,
|
||||||
|
created_at DateTime('UTC')
|
||||||
|
)
|
||||||
|
ENGINE = Kafka
|
||||||
|
SETTINGS kafka_broker_list = 'domain:9092,domain:9093,domain:9094', -- input broker list
|
||||||
|
kafka_topic_list = 'event_data',
|
||||||
|
kafka_group_name = 'event_data_consumer_group',
|
||||||
|
kafka_format = 'JSONEachRow',
|
||||||
|
kafka_max_block_size = 1048576,
|
||||||
|
kafka_skip_broken_messages = 1;
|
||||||
|
|
||||||
|
CREATE MATERIALIZED VIEW event_data_queue_mv TO event_data AS
|
||||||
|
SELECT website_id,
|
||||||
|
session_id,
|
||||||
|
event_id,
|
||||||
|
rev_id,
|
||||||
|
event_name,
|
||||||
|
event_key,
|
||||||
|
event_string_value,
|
||||||
|
event_numeric_value,
|
||||||
|
event_date_value,
|
||||||
|
event_data_type,
|
||||||
|
created_at
|
||||||
|
FROM event_data_queue;
|
|
@ -38,6 +38,19 @@ export const EVENT_TYPE = {
|
||||||
customEvent: 2,
|
customEvent: 2,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
export const EVENT_DATA_TYPE = {
|
||||||
|
string: 1,
|
||||||
|
number: 2,
|
||||||
|
boolean: 3,
|
||||||
|
date: 4,
|
||||||
|
array: 5,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const KAFKA_TOPIC = {
|
||||||
|
event: 'event',
|
||||||
|
eventData: 'event_data',
|
||||||
|
} as const;
|
||||||
|
|
||||||
export const ROLES = {
|
export const ROLES = {
|
||||||
admin: 'admin',
|
admin: 'admin',
|
||||||
user: 'user',
|
user: 'user',
|
||||||
|
|
|
@ -79,10 +79,10 @@ export async function getClientInfo(req, { screen }) {
|
||||||
const userAgent = req.headers['user-agent'];
|
const userAgent = req.headers['user-agent'];
|
||||||
const ip = getIpAddress(req);
|
const ip = getIpAddress(req);
|
||||||
const location = await getLocation(ip);
|
const location = await getLocation(ip);
|
||||||
const country = location.country;
|
const country = location?.country;
|
||||||
const subdivision1 = location.subdivision1;
|
const subdivision1 = location?.subdivision1;
|
||||||
const subdivision2 = location.subdivision2;
|
const subdivision2 = location?.subdivision2;
|
||||||
const city = location.city;
|
const city = location?.city;
|
||||||
const browser = browserName(userAgent);
|
const browser = browserName(userAgent);
|
||||||
const os = detectOS(userAgent);
|
const os = detectOS(userAgent);
|
||||||
const device = getDevice(screen, browser, os);
|
const device = getDevice(screen, browser, os);
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
import { isValid, parseISO } from 'date-fns';
|
||||||
|
import { EVENT_DATA_TYPE } from './constants';
|
||||||
|
import { EventDataTypes } from './types';
|
||||||
|
|
||||||
|
export function flattenJSON(
|
||||||
|
eventData: { [key: string]: any },
|
||||||
|
keyValues: { key: string; value: any; eventDataType: EventDataTypes }[] = [],
|
||||||
|
parentKey = '',
|
||||||
|
): { key: string; value: any; eventDataType: EventDataTypes }[] {
|
||||||
|
return Object.keys(eventData).reduce(
|
||||||
|
(acc, key) => {
|
||||||
|
const value = eventData[key];
|
||||||
|
const type = typeof eventData[key];
|
||||||
|
|
||||||
|
// nested object
|
||||||
|
if (value && type === 'object' && !Array.isArray(value) && !isValid(value)) {
|
||||||
|
flattenJSON(value, acc.keyValues, getKeyName(key, parentKey));
|
||||||
|
} else {
|
||||||
|
createKey(getKeyName(key, parentKey), value, acc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{ keyValues, parentKey },
|
||||||
|
).keyValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createKey(key, value, acc: { keyValues: any[]; parentKey: string }) {
|
||||||
|
const type = isValid(value) || isValid(parseISO(value)) ? 'date' : typeof value;
|
||||||
|
|
||||||
|
let eventDataType = null;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 'number':
|
||||||
|
eventDataType = EVENT_DATA_TYPE.number;
|
||||||
|
break;
|
||||||
|
case 'string':
|
||||||
|
eventDataType = EVENT_DATA_TYPE.string;
|
||||||
|
break;
|
||||||
|
case 'boolean':
|
||||||
|
eventDataType = EVENT_DATA_TYPE.boolean;
|
||||||
|
break;
|
||||||
|
case 'date':
|
||||||
|
eventDataType = EVENT_DATA_TYPE.date;
|
||||||
|
break;
|
||||||
|
case 'object':
|
||||||
|
eventDataType = EVENT_DATA_TYPE.array;
|
||||||
|
value = JSON.stringify(value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
eventDataType = EVENT_DATA_TYPE.string;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
acc.keyValues.push({ key, value, eventDataType });
|
||||||
|
}
|
||||||
|
|
||||||
|
function getKeyName(key, parentKey) {
|
||||||
|
if (!parentKey) {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${parentKey}.${key}`;
|
||||||
|
}
|
|
@ -1,19 +1,20 @@
|
||||||
import { Kafka, logLevel } from 'kafkajs';
|
|
||||||
import dateFormat from 'dateformat';
|
import dateFormat from 'dateformat';
|
||||||
import debug from 'debug';
|
import debug from 'debug';
|
||||||
|
import { Kafka, Mechanism, Producer, RecordMetadata, SASLOptions, logLevel } from 'kafkajs';
|
||||||
import { KAFKA, KAFKA_PRODUCER } from 'lib/db';
|
import { KAFKA, KAFKA_PRODUCER } from 'lib/db';
|
||||||
|
import * as tls from 'tls';
|
||||||
|
|
||||||
const log = debug('umami:kafka');
|
const log = debug('umami:kafka');
|
||||||
|
|
||||||
let kafka;
|
let kafka: Kafka;
|
||||||
let producer;
|
let producer: Producer;
|
||||||
const enabled = Boolean(process.env.KAFKA_URL && process.env.KAFKA_BROKER);
|
const enabled = Boolean(process.env.KAFKA_URL && process.env.KAFKA_BROKER);
|
||||||
|
|
||||||
function getClient() {
|
function getClient() {
|
||||||
const { username, password } = new URL(process.env.KAFKA_URL);
|
const { username, password } = new URL(process.env.KAFKA_URL);
|
||||||
const brokers = process.env.KAFKA_BROKER.split(',');
|
const brokers = process.env.KAFKA_BROKER.split(',');
|
||||||
|
|
||||||
const ssl =
|
const ssl: { ssl?: tls.ConnectionOptions | boolean; sasl?: SASLOptions | Mechanism } =
|
||||||
username && password
|
username && password
|
||||||
? {
|
? {
|
||||||
ssl: {
|
ssl: {
|
||||||
|
@ -30,7 +31,7 @@ function getClient() {
|
||||||
}
|
}
|
||||||
: {};
|
: {};
|
||||||
|
|
||||||
const client = new Kafka({
|
const client: Kafka = new Kafka({
|
||||||
clientId: 'umami',
|
clientId: 'umami',
|
||||||
brokers: brokers,
|
brokers: brokers,
|
||||||
connectionTimeout: 3000,
|
connectionTimeout: 3000,
|
||||||
|
@ -47,7 +48,7 @@ function getClient() {
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getProducer() {
|
async function getProducer(): Promise<Producer> {
|
||||||
const producer = kafka.producer();
|
const producer = kafka.producer();
|
||||||
await producer.connect();
|
await producer.connect();
|
||||||
|
|
||||||
|
@ -60,25 +61,40 @@ async function getProducer() {
|
||||||
return producer;
|
return producer;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDateFormat(date) {
|
function getDateFormat(date): string {
|
||||||
return dateFormat(date, 'UTC:yyyy-mm-dd HH:MM:ss');
|
return dateFormat(date, 'UTC:yyyy-mm-dd HH:MM:ss');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function sendMessage(params, topic) {
|
async function sendMessage(
|
||||||
|
message: { [key: string]: string | number },
|
||||||
|
topic: string,
|
||||||
|
): Promise<RecordMetadata[]> {
|
||||||
|
await connect();
|
||||||
|
|
||||||
|
return producer.send({
|
||||||
|
topic,
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
value: JSON.stringify(message),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
acks: -1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendMessages(messages: { [key: string]: string | number }[], topic: string) {
|
||||||
await connect();
|
await connect();
|
||||||
|
|
||||||
await producer.send({
|
await producer.send({
|
||||||
topic,
|
topic,
|
||||||
messages: [
|
messages: messages.map(a => {
|
||||||
{
|
return { value: JSON.stringify(a) };
|
||||||
value: JSON.stringify(params),
|
}),
|
||||||
},
|
|
||||||
],
|
|
||||||
acks: 1,
|
acks: 1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function connect() {
|
async function connect(): Promise<Kafka> {
|
||||||
if (!kafka) {
|
if (!kafka) {
|
||||||
kafka = process.env.KAFKA_URL && process.env.KAFKA_BROKER && (global[KAFKA] || getClient());
|
kafka = process.env.KAFKA_URL && process.env.KAFKA_BROKER && (global[KAFKA] || getClient());
|
||||||
|
|
||||||
|
@ -98,4 +114,5 @@ export default {
|
||||||
connect,
|
connect,
|
||||||
getDateFormat,
|
getDateFormat,
|
||||||
sendMessage,
|
sendMessage,
|
||||||
|
sendMessages,
|
||||||
};
|
};
|
11
lib/types.ts
11
lib/types.ts
|
@ -1,10 +1,19 @@
|
||||||
import { NextApiRequest } from 'next';
|
import { NextApiRequest } from 'next';
|
||||||
import { ROLES } from './constants';
|
import { EVENT_DATA_TYPE, EVENT_TYPE, KAFKA_TOPIC, ROLES } from './constants';
|
||||||
|
|
||||||
type ObjectValues<T> = T[keyof T];
|
type ObjectValues<T> = T[keyof T];
|
||||||
|
|
||||||
export type Roles = ObjectValues<typeof ROLES>;
|
export type Roles = ObjectValues<typeof ROLES>;
|
||||||
|
|
||||||
|
export type EventTypes = ObjectValues<typeof EVENT_TYPE>;
|
||||||
|
|
||||||
|
export type EventDataTypes = ObjectValues<typeof EVENT_DATA_TYPE>;
|
||||||
|
|
||||||
|
export type KafkaTopics = ObjectValues<typeof KAFKA_TOPIC>;
|
||||||
|
|
||||||
|
export interface EventData {
|
||||||
|
[key: string]: number | string | EventData | number[] | string[] | EventData[];
|
||||||
|
}
|
||||||
export interface Auth {
|
export interface Auth {
|
||||||
user?: {
|
user?: {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
|
@ -12,7 +12,7 @@ function customCollectEndpoint(req) {
|
||||||
const { pathname } = url;
|
const { pathname } = url;
|
||||||
|
|
||||||
if (pathname.endsWith(collectEndpoint)) {
|
if (pathname.endsWith(collectEndpoint)) {
|
||||||
url.pathname = '/api/collect';
|
url.pathname = '/api/send';
|
||||||
return NextResponse.rewrite(url);
|
return NextResponse.rewrite(url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,6 +143,7 @@
|
||||||
"stylelint-config-prettier": "^9.0.3",
|
"stylelint-config-prettier": "^9.0.3",
|
||||||
"stylelint-config-recommended": "^9.0.0",
|
"stylelint-config-recommended": "^9.0.0",
|
||||||
"tar": "^6.1.2",
|
"tar": "^6.1.2",
|
||||||
|
"ts-node": "^10.9.1",
|
||||||
"typescript": "^4.9.5"
|
"typescript": "^4.9.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,9 +34,14 @@ export default async (req: NextApiRequestCollect, res: NextApiResponse) => {
|
||||||
|
|
||||||
const { type, payload } = getJsonBody(req);
|
const { type, payload } = getJsonBody(req);
|
||||||
|
|
||||||
const { referrer, eventName, pageTitle } = payload;
|
const { referrer, eventName, eventData, pageTitle } = payload;
|
||||||
let { url } = payload;
|
let { url } = payload;
|
||||||
|
|
||||||
|
// Validate eventData is JSON
|
||||||
|
if (eventData && !(typeof eventData === 'object' && !Array.isArray(eventData))) {
|
||||||
|
return badRequest(res, 'Event Data must be in the form of a JSON Object.');
|
||||||
|
}
|
||||||
|
|
||||||
const ignoreIps = process.env.IGNORE_IP;
|
const ignoreIps = process.env.IGNORE_IP;
|
||||||
const ignoreHostnames = process.env.IGNORE_HOSTNAME;
|
const ignoreHostnames = process.env.IGNORE_HOSTNAME;
|
||||||
|
|
||||||
|
@ -96,6 +101,7 @@ export default async (req: NextApiRequestCollect, res: NextApiResponse) => {
|
||||||
referrer,
|
referrer,
|
||||||
pageTitle,
|
pageTitle,
|
||||||
eventName,
|
eventName,
|
||||||
|
eventData,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return badRequest(res);
|
return badRequest(res);
|
||||||
|
|
|
@ -4,6 +4,7 @@ import kafka from 'lib/kafka';
|
||||||
import prisma from 'lib/prisma';
|
import prisma from 'lib/prisma';
|
||||||
import { uuid } from 'lib/crypto';
|
import { uuid } from 'lib/crypto';
|
||||||
import cache from 'lib/cache';
|
import cache from 'lib/cache';
|
||||||
|
import { saveEventData } from '../eventData/saveEventData';
|
||||||
|
|
||||||
export async function saveEvent(args: {
|
export async function saveEvent(args: {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -12,6 +13,7 @@ export async function saveEvent(args: {
|
||||||
referrer?: string;
|
referrer?: string;
|
||||||
pageTitle?: string;
|
pageTitle?: string;
|
||||||
eventName?: string;
|
eventName?: string;
|
||||||
|
eventData?: any;
|
||||||
hostname?: string;
|
hostname?: string;
|
||||||
browser?: string;
|
browser?: string;
|
||||||
os?: string;
|
os?: string;
|
||||||
|
@ -36,6 +38,7 @@ async function relationalQuery(data: {
|
||||||
referrer?: string;
|
referrer?: string;
|
||||||
pageTitle?: string;
|
pageTitle?: string;
|
||||||
eventName?: string;
|
eventName?: string;
|
||||||
|
eventData?: any;
|
||||||
}) {
|
}) {
|
||||||
const { websiteId, id: sessionId, url, eventName, referrer, pageTitle } = data;
|
const { websiteId, id: sessionId, url, eventName, referrer, pageTitle } = data;
|
||||||
|
|
||||||
|
@ -60,6 +63,7 @@ async function clickhouseQuery(data: {
|
||||||
referrer?: string;
|
referrer?: string;
|
||||||
pageTitle?: string;
|
pageTitle?: string;
|
||||||
eventName?: string;
|
eventName?: string;
|
||||||
|
eventData?: any;
|
||||||
hostname?: string;
|
hostname?: string;
|
||||||
browser?: string;
|
browser?: string;
|
||||||
os?: string;
|
os?: string;
|
||||||
|
@ -77,6 +81,7 @@ async function clickhouseQuery(data: {
|
||||||
url,
|
url,
|
||||||
pageTitle,
|
pageTitle,
|
||||||
eventName,
|
eventName,
|
||||||
|
eventData,
|
||||||
country,
|
country,
|
||||||
subdivision1,
|
subdivision1,
|
||||||
subdivision2,
|
subdivision2,
|
||||||
|
@ -85,11 +90,13 @@ async function clickhouseQuery(data: {
|
||||||
} = data;
|
} = data;
|
||||||
const { getDateFormat, sendMessage } = kafka;
|
const { getDateFormat, sendMessage } = kafka;
|
||||||
const website = await cache.fetchWebsite(websiteId);
|
const website = await cache.fetchWebsite(websiteId);
|
||||||
|
const eventId = uuid();
|
||||||
|
const createdAt = getDateFormat(new Date());
|
||||||
|
|
||||||
const message = {
|
const message = {
|
||||||
website_id: websiteId,
|
website_id: websiteId,
|
||||||
session_id: sessionId,
|
session_id: sessionId,
|
||||||
event_id: uuid(),
|
event_id: eventId,
|
||||||
country: country ? country : null,
|
country: country ? country : null,
|
||||||
subdivision1: subdivision1 ? subdivision1 : null,
|
subdivision1: subdivision1 ? subdivision1 : null,
|
||||||
subdivision2: subdivision2 ? subdivision2 : null,
|
subdivision2: subdivision2 ? subdivision2 : null,
|
||||||
|
@ -99,11 +106,23 @@ async function clickhouseQuery(data: {
|
||||||
event_type: EVENT_TYPE.customEvent,
|
event_type: EVENT_TYPE.customEvent,
|
||||||
event_name: eventName?.substring(0, EVENT_NAME_LENGTH),
|
event_name: eventName?.substring(0, EVENT_NAME_LENGTH),
|
||||||
rev_id: website?.revId || 0,
|
rev_id: website?.revId || 0,
|
||||||
created_at: getDateFormat(new Date()),
|
created_at: createdAt,
|
||||||
...args,
|
...args,
|
||||||
};
|
};
|
||||||
|
|
||||||
await sendMessage(message, 'event');
|
await sendMessage(message, 'event');
|
||||||
|
|
||||||
|
if (eventData) {
|
||||||
|
await saveEventData({
|
||||||
|
websiteId,
|
||||||
|
sessionId,
|
||||||
|
eventId,
|
||||||
|
revId: website?.revId,
|
||||||
|
eventName: eventName?.substring(0, EVENT_NAME_LENGTH),
|
||||||
|
eventData,
|
||||||
|
createdAt,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
import { EVENT_DATA_TYPE } from 'lib/constants';
|
||||||
|
import { CLICKHOUSE, PRISMA, runQuery } from 'lib/db';
|
||||||
|
import { flattenJSON } from 'lib/eventData';
|
||||||
|
import kafka from 'lib/kafka';
|
||||||
|
import { EventData } from 'lib/types';
|
||||||
|
|
||||||
|
export async function saveEventData(args: {
|
||||||
|
websiteId: string;
|
||||||
|
sessionId: string;
|
||||||
|
eventId: string;
|
||||||
|
revId: number;
|
||||||
|
eventName: string;
|
||||||
|
eventData: EventData;
|
||||||
|
createdAt: string;
|
||||||
|
}) {
|
||||||
|
return runQuery({
|
||||||
|
[PRISMA]: () => relationalQuery(args),
|
||||||
|
[CLICKHOUSE]: () => clickhouseQuery(args),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function relationalQuery(data: {
|
||||||
|
websiteId: string;
|
||||||
|
sessionId: string;
|
||||||
|
eventId: string;
|
||||||
|
revId: number;
|
||||||
|
eventName: string;
|
||||||
|
eventData: EventData;
|
||||||
|
createdAt: string;
|
||||||
|
}) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function clickhouseQuery(data: {
|
||||||
|
websiteId: string;
|
||||||
|
sessionId: string;
|
||||||
|
eventId: string;
|
||||||
|
revId: number;
|
||||||
|
eventName: string;
|
||||||
|
eventData: EventData;
|
||||||
|
createdAt: string;
|
||||||
|
}) {
|
||||||
|
const { websiteId, sessionId, eventId, revId, eventName, eventData, createdAt } = data;
|
||||||
|
|
||||||
|
const { getDateFormat, sendMessages } = kafka;
|
||||||
|
|
||||||
|
const jsonKeys = flattenJSON(eventData);
|
||||||
|
|
||||||
|
const messages = jsonKeys.map(a => ({
|
||||||
|
website_id: websiteId,
|
||||||
|
session_id: sessionId,
|
||||||
|
event_id: eventId,
|
||||||
|
rev_id: revId,
|
||||||
|
event_name: eventName,
|
||||||
|
event_key: a.key,
|
||||||
|
event_string_value:
|
||||||
|
a.eventDataType === EVENT_DATA_TYPE.string ||
|
||||||
|
a.eventDataType === EVENT_DATA_TYPE.boolean ||
|
||||||
|
a.eventDataType === EVENT_DATA_TYPE.array
|
||||||
|
? a.value
|
||||||
|
: null,
|
||||||
|
event_numeric_value: a.eventDataType === EVENT_DATA_TYPE.number ? a.value : null,
|
||||||
|
event_date_value: a.eventDataType === EVENT_DATA_TYPE.date ? getDateFormat(a.value) : null,
|
||||||
|
event_data_type: a.eventDataType,
|
||||||
|
created_at: createdAt,
|
||||||
|
}));
|
||||||
|
|
||||||
|
await sendMessages(messages, 'event_data');
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
|
@ -85,6 +85,7 @@ async function clickhouseQuery(data: {
|
||||||
const message = {
|
const message = {
|
||||||
website_id: websiteId,
|
website_id: websiteId,
|
||||||
session_id: sessionId,
|
session_id: sessionId,
|
||||||
|
event_id: uuid(),
|
||||||
rev_id: website?.revId || 0,
|
rev_id: website?.revId || 0,
|
||||||
country: country ? country : null,
|
country: country ? country : null,
|
||||||
subdivision1: subdivision1 ? subdivision1 : null,
|
subdivision1: subdivision1 ? subdivision1 : null,
|
||||||
|
|
|
@ -11,7 +11,7 @@ export default {
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
replace({
|
replace({
|
||||||
'/api/collect': process.env.COLLECT_API_ENDPOINT || '/api/collect',
|
'/api/send': process.env.COLLECT_API_ENDPOINT || '/api/send',
|
||||||
delimiters: ['', ''],
|
delimiters: ['', ''],
|
||||||
preventAssignment: true,
|
preventAssignment: true,
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -5,7 +5,7 @@ const isCI = require('is-ci');
|
||||||
const pkg = require('../package.json');
|
const pkg = require('../package.json');
|
||||||
|
|
||||||
const dest = path.resolve(__dirname, '../.next/cache/umami.json');
|
const dest = path.resolve(__dirname, '../.next/cache/umami.json');
|
||||||
const url = 'https://telemetry.umami.is/api/collect';
|
const url = 'https://telemetry.umami.is/api/send';
|
||||||
|
|
||||||
async function sendTelemetry(action) {
|
async function sendTelemetry(action) {
|
||||||
let json = {};
|
let json = {};
|
||||||
|
|
|
@ -12,7 +12,7 @@ if (endPoint) {
|
||||||
|
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
path.resolve(file),
|
path.resolve(file),
|
||||||
tracker.toString().replace(/"\/api\/collect"/g, `"${endPoint}"`),
|
tracker.toString().replace(/"\/api\/send"/g, `"${endPoint}"`),
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(`Updated tracker endpoint: ${endPoint}.`);
|
console.log(`Updated tracker endpoint: ${endPoint}.`);
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
const root = hostUrl
|
const root = hostUrl
|
||||||
? hostUrl.replace(/\/$/, '')
|
? hostUrl.replace(/\/$/, '')
|
||||||
: currentScript.src.split('/').slice(0, -1).join('/');
|
: currentScript.src.split('/').slice(0, -1).join('/');
|
||||||
const endpoint = `${root}/api/collect`;
|
const endpoint = `${root}/api/send`;
|
||||||
const screen = `${width}x${height}`;
|
const screen = `${width}x${height}`;
|
||||||
const eventClass = /^umami--([a-z]+)--([\w]+[\w-]*)$/;
|
const eventClass = /^umami--([a-z]+)--([\w]+[\w-]*)$/;
|
||||||
const eventSelect = "[class*='umami--']";
|
const eventSelect = "[class*='umami--']";
|
||||||
|
@ -73,7 +73,7 @@
|
||||||
let cache;
|
let cache;
|
||||||
|
|
||||||
if (currentRef.substring(0, 4) === 'http') {
|
if (currentRef.substring(0, 4) === 'http') {
|
||||||
if ((currentRef = currentRef.split('/')[2].split(':')[0] === hostname)) {
|
if (currentRef.split('/')[2].split(':')[0] === hostname) {
|
||||||
currentRef = '/' + currentRef.split('/').splice(3).join('/');
|
currentRef = '/' + currentRef.split('/').splice(3).join('/');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,6 +118,7 @@
|
||||||
|
|
||||||
const trackEvent = (
|
const trackEvent = (
|
||||||
eventName,
|
eventName,
|
||||||
|
eventData,
|
||||||
url = currentUrl,
|
url = currentUrl,
|
||||||
websiteId = website,
|
websiteId = website,
|
||||||
pageTitle = currentPageTitle,
|
pageTitle = currentPageTitle,
|
||||||
|
@ -128,7 +129,8 @@
|
||||||
website: websiteId,
|
website: websiteId,
|
||||||
url,
|
url,
|
||||||
pageTitle,
|
pageTitle,
|
||||||
eventName: eventName,
|
eventName,
|
||||||
|
eventData,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
101
yarn.lock
101
yarn.lock
|
@ -1403,6 +1403,13 @@
|
||||||
"@babel/helper-validator-identifier" "^7.18.6"
|
"@babel/helper-validator-identifier" "^7.18.6"
|
||||||
to-fast-properties "^2.0.0"
|
to-fast-properties "^2.0.0"
|
||||||
|
|
||||||
|
"@cspotcode/source-map-support@^0.8.0":
|
||||||
|
version "0.8.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1"
|
||||||
|
integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==
|
||||||
|
dependencies:
|
||||||
|
"@jridgewell/trace-mapping" "0.3.9"
|
||||||
|
|
||||||
"@csstools/postcss-cascade-layers@^1.1.1":
|
"@csstools/postcss-cascade-layers@^1.1.1":
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz#8a997edf97d34071dd2e37ea6022447dd9e795ad"
|
resolved "https://registry.yarnpkg.com/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz#8a997edf97d34071dd2e37ea6022447dd9e795ad"
|
||||||
|
@ -1714,7 +1721,7 @@
|
||||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||||
"@jridgewell/trace-mapping" "^0.3.9"
|
"@jridgewell/trace-mapping" "^0.3.9"
|
||||||
|
|
||||||
"@jridgewell/resolve-uri@3.1.0":
|
"@jridgewell/resolve-uri@3.1.0", "@jridgewell/resolve-uri@^3.0.3":
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
|
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
|
||||||
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
|
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
|
||||||
|
@ -1737,6 +1744,14 @@
|
||||||
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
|
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
|
||||||
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
|
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
|
||||||
|
|
||||||
|
"@jridgewell/trace-mapping@0.3.9":
|
||||||
|
version "0.3.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9"
|
||||||
|
integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==
|
||||||
|
dependencies:
|
||||||
|
"@jridgewell/resolve-uri" "^3.0.3"
|
||||||
|
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||||
|
|
||||||
"@jridgewell/trace-mapping@^0.3.9":
|
"@jridgewell/trace-mapping@^0.3.9":
|
||||||
version "0.3.17"
|
version "0.3.17"
|
||||||
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985"
|
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985"
|
||||||
|
@ -2420,6 +2435,26 @@
|
||||||
resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
|
resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
|
||||||
integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
|
integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
|
||||||
|
|
||||||
|
"@tsconfig/node10@^1.0.7":
|
||||||
|
version "1.0.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2"
|
||||||
|
integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==
|
||||||
|
|
||||||
|
"@tsconfig/node12@^1.0.7":
|
||||||
|
version "1.0.11"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d"
|
||||||
|
integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==
|
||||||
|
|
||||||
|
"@tsconfig/node14@^1.0.0":
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1"
|
||||||
|
integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==
|
||||||
|
|
||||||
|
"@tsconfig/node16@^1.0.2":
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e"
|
||||||
|
integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==
|
||||||
|
|
||||||
"@types/babel__core@^7.1.7":
|
"@types/babel__core@^7.1.7":
|
||||||
version "7.1.18"
|
version "7.1.18"
|
||||||
resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz"
|
resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz"
|
||||||
|
@ -2856,21 +2891,26 @@ acorn-jsx@^5.2.0, acorn-jsx@^5.3.2:
|
||||||
resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
|
resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
|
||||||
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
|
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
|
||||||
|
|
||||||
|
acorn-walk@^8.1.1:
|
||||||
|
version "8.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
|
||||||
|
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
|
||||||
|
|
||||||
acorn@^6.4.1:
|
acorn@^6.4.1:
|
||||||
version "6.4.2"
|
version "6.4.2"
|
||||||
resolved "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz"
|
resolved "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz"
|
||||||
integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==
|
integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==
|
||||||
|
|
||||||
|
acorn@^8.4.1, acorn@^8.8.0:
|
||||||
|
version "8.8.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a"
|
||||||
|
integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
|
||||||
|
|
||||||
acorn@^8.5.0:
|
acorn@^8.5.0:
|
||||||
version "8.7.1"
|
version "8.7.1"
|
||||||
resolved "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz"
|
resolved "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz"
|
||||||
integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==
|
integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==
|
||||||
|
|
||||||
acorn@^8.8.0:
|
|
||||||
version "8.8.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a"
|
|
||||||
integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
|
|
||||||
|
|
||||||
agent-base@6:
|
agent-base@6:
|
||||||
version "6.0.2"
|
version "6.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
|
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
|
||||||
|
@ -2979,6 +3019,11 @@ arch@^2.2.0:
|
||||||
resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11"
|
resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11"
|
||||||
integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==
|
integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==
|
||||||
|
|
||||||
|
arg@^4.1.0:
|
||||||
|
version "4.1.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
|
||||||
|
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
|
||||||
|
|
||||||
argparse@^1.0.7:
|
argparse@^1.0.7:
|
||||||
version "1.0.10"
|
version "1.0.10"
|
||||||
resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz"
|
resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz"
|
||||||
|
@ -3607,6 +3652,11 @@ cosmiconfig@^7.0.1, cosmiconfig@^7.1.0:
|
||||||
path-type "^4.0.0"
|
path-type "^4.0.0"
|
||||||
yaml "^1.10.0"
|
yaml "^1.10.0"
|
||||||
|
|
||||||
|
create-require@^1.1.0:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
|
||||||
|
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
|
||||||
|
|
||||||
cross-env@^7.0.3:
|
cross-env@^7.0.3:
|
||||||
version "7.0.3"
|
version "7.0.3"
|
||||||
resolved "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz"
|
resolved "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz"
|
||||||
|
@ -3957,6 +4007,11 @@ detect-libc@^2.0.0, detect-libc@^2.0.1:
|
||||||
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.1.tgz#e1897aa88fa6ad197862937fbc0441ef352ee0cd"
|
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.1.tgz#e1897aa88fa6ad197862937fbc0441ef352ee0cd"
|
||||||
integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==
|
integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==
|
||||||
|
|
||||||
|
diff@^4.0.1:
|
||||||
|
version "4.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
|
||||||
|
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
|
||||||
|
|
||||||
dir-glob@^3.0.1:
|
dir-glob@^3.0.1:
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
|
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
|
||||||
|
@ -5904,6 +5959,11 @@ make-dir@^3.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
semver "^6.0.0"
|
semver "^6.0.0"
|
||||||
|
|
||||||
|
make-error@^1.1.1:
|
||||||
|
version "1.3.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
|
||||||
|
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
|
||||||
|
|
||||||
map-obj@^1.0.0:
|
map-obj@^1.0.0:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
|
resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
|
||||||
|
@ -8274,6 +8334,25 @@ trim-newlines@^3.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144"
|
resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144"
|
||||||
integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==
|
integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==
|
||||||
|
|
||||||
|
ts-node@^10.9.1:
|
||||||
|
version "10.9.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b"
|
||||||
|
integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==
|
||||||
|
dependencies:
|
||||||
|
"@cspotcode/source-map-support" "^0.8.0"
|
||||||
|
"@tsconfig/node10" "^1.0.7"
|
||||||
|
"@tsconfig/node12" "^1.0.7"
|
||||||
|
"@tsconfig/node14" "^1.0.0"
|
||||||
|
"@tsconfig/node16" "^1.0.2"
|
||||||
|
acorn "^8.4.1"
|
||||||
|
acorn-walk "^8.1.1"
|
||||||
|
arg "^4.1.0"
|
||||||
|
create-require "^1.1.0"
|
||||||
|
diff "^4.0.1"
|
||||||
|
make-error "^1.1.1"
|
||||||
|
v8-compile-cache-lib "^3.0.1"
|
||||||
|
yn "3.1.1"
|
||||||
|
|
||||||
tsconfig-paths@^3.14.1:
|
tsconfig-paths@^3.14.1:
|
||||||
version "3.14.1"
|
version "3.14.1"
|
||||||
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a"
|
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a"
|
||||||
|
@ -8572,6 +8651,11 @@ uuid@^8.3.0, uuid@^8.3.2:
|
||||||
resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz"
|
resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz"
|
||||||
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
|
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
|
||||||
|
|
||||||
|
v8-compile-cache-lib@^3.0.1:
|
||||||
|
version "3.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
|
||||||
|
integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==
|
||||||
|
|
||||||
v8-compile-cache@^2.3.0:
|
v8-compile-cache@^2.3.0:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz"
|
resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz"
|
||||||
|
@ -8767,6 +8851,11 @@ yargs-parser@^20.2.3:
|
||||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
|
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
|
||||||
integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
|
integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
|
||||||
|
|
||||||
|
yn@3.1.1:
|
||||||
|
version "3.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
|
||||||
|
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
|
||||||
|
|
||||||
yocto-queue@^0.1.0:
|
yocto-queue@^0.1.0:
|
||||||
version "0.1.0"
|
version "0.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
|
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
|
||||||
|
|
Loading…
Reference in New Issue