landom-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +220 -0
- package/dist/landom-sdk.cjs.js +19 -0
- package/dist/landom-sdk.cjs.js.map +1 -0
- package/dist/landom-sdk.esm.js +19 -0
- package/dist/landom-sdk.esm.js.map +1 -0
- package/dist/landom-sdk.umd.js +19 -0
- package/dist/landom-sdk.umd.js.map +1 -0
- package/dist/types/core/context.d.ts +7 -0
- package/dist/types/core/event-queue.d.ts +30 -0
- package/dist/types/core/sdk.d.ts +27 -0
- package/dist/types/events/click.d.ts +6 -0
- package/dist/types/events/exit.d.ts +7 -0
- package/dist/types/events/input.d.ts +6 -0
- package/dist/types/events/ping.d.ts +7 -0
- package/dist/types/events/replay.d.ts +6 -0
- package/dist/types/events/scroll.d.ts +6 -0
- package/dist/types/events/start.d.ts +6 -0
- package/dist/types/events/visibility.d.ts +6 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/transport/transport.d.ts +23 -0
- package/dist/types/types/index.d.ts +75 -0
- package/dist/types/utils/dom.d.ts +6 -0
- package/dist/types/utils/logger.d.ts +10 -0
- package/dist/types/utils/selector.d.ts +12 -0
- package/dist/types/utils/session.d.ts +18 -0
- package/dist/types/utils/throttle.d.ts +12 -0
- package/package.json +60 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SDKConfig } from '../types';
|
|
2
|
+
import type { Logger } from '../utils/logger';
|
|
3
|
+
import type { EventQueue } from './event-queue';
|
|
4
|
+
export declare function setContext(q: EventQueue, c: SDKConfig, l: Logger): void;
|
|
5
|
+
export declare function getQueue(): EventQueue;
|
|
6
|
+
export declare function getConfig(): SDKConfig;
|
|
7
|
+
export declare function getLogger(): Logger;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { SDKEvent } from '../types';
|
|
2
|
+
import type { Transport } from '../transport/transport';
|
|
3
|
+
import type { Logger } from '../utils/logger';
|
|
4
|
+
/** EventQueue 생성에 필요한 설정 */
|
|
5
|
+
export interface EventQueueConfig {
|
|
6
|
+
flushInterval: number;
|
|
7
|
+
flushQueueSize: number;
|
|
8
|
+
maxQueueSize: number;
|
|
9
|
+
beforeSend?: (event: SDKEvent) => SDKEvent | null;
|
|
10
|
+
transport: Transport;
|
|
11
|
+
logger: Logger;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 이벤트 큐 모듈
|
|
15
|
+
*
|
|
16
|
+
* 이벤트를 배열에 버퍼링하고, 조건 충족 시 배치 전송한다.
|
|
17
|
+
* - flushInterval마다 자동 flush
|
|
18
|
+
* - flushQueueSize 도달 시 즉시 flush
|
|
19
|
+
* - maxQueueSize 초과 시 오래된 이벤트 드롭
|
|
20
|
+
* - beforeSend 훅으로 이벤트 가공/필터링
|
|
21
|
+
*/
|
|
22
|
+
export declare function createEventQueue(config: EventQueueConfig): {
|
|
23
|
+
push: (event: SDKEvent) => void;
|
|
24
|
+
flush: () => Promise<void>;
|
|
25
|
+
flushSync: () => void;
|
|
26
|
+
start: () => void;
|
|
27
|
+
stop: () => void;
|
|
28
|
+
};
|
|
29
|
+
/** createEventQueue 반환 타입 */
|
|
30
|
+
export type EventQueue = ReturnType<typeof createEventQueue>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { SDKOptions, EventType, EventPayload } from '../types';
|
|
2
|
+
/** 이벤트 수집기 인터페이스 (setup/teardown) */
|
|
3
|
+
export interface Collector {
|
|
4
|
+
setup(): void;
|
|
5
|
+
teardown(): void;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* SDK 초기화
|
|
9
|
+
* 싱글턴으로 동작하며, 중복 호출 시 경고만 출력한다.
|
|
10
|
+
* 이벤트 수집기는 registerCollectors()로 별도 등록한다.
|
|
11
|
+
*/
|
|
12
|
+
export declare function init(options: SDKOptions): void;
|
|
13
|
+
/**
|
|
14
|
+
* 이벤트 수집기 일괄 등록 및 시작
|
|
15
|
+
* init() 이후에 호출해야 한다.
|
|
16
|
+
*/
|
|
17
|
+
export declare function registerCollectors(items: Collector[]): void;
|
|
18
|
+
/**
|
|
19
|
+
* 이벤트를 큐에 추가
|
|
20
|
+
* 외부에서 커스텀 이벤트를 보낼 때 사용
|
|
21
|
+
*/
|
|
22
|
+
export declare function capture(type: EventType, payload?: EventPayload): void;
|
|
23
|
+
/**
|
|
24
|
+
* SDK 종료
|
|
25
|
+
* 모든 수집기 해제 + 잔여 이벤트 flush + 상태 초기화
|
|
26
|
+
*/
|
|
27
|
+
export declare function destroy(): void;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { init, capture, destroy } from './core/sdk';
|
|
2
|
+
export type { EventType, EventPayload, StartPayload, VisibilityPayload, ScrollPayload, ClickPayload, InputPayload, ReplayPayload, PingPayload, ExitPayload, CustomPayload, SDKEvent, TransportPayload, SDKConfig, SDKOptions, } from './types';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { TransportPayload } from '../types';
|
|
2
|
+
import type { Logger } from '../utils/logger';
|
|
3
|
+
/** Transport 생성에 필요한 설정 */
|
|
4
|
+
export interface TransportConfig {
|
|
5
|
+
endpoint: string;
|
|
6
|
+
apiKey: string;
|
|
7
|
+
maxRetries: number;
|
|
8
|
+
logger: Logger;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* 이벤트 전송 모듈
|
|
12
|
+
*
|
|
13
|
+
* 두 가지 전송 방식
|
|
14
|
+
* - send(): fetch(keepalive)로 전송. 커스텀 헤더(X-Project-Key) 사용 가능.
|
|
15
|
+
* - sendSync(): navigator.sendBeacon으로 전송. 페이지 이탈 시 사용.
|
|
16
|
+
* sendBeacon은 커스텀 헤더를 설정할 수 없으므로 body에 apiKey를 포함
|
|
17
|
+
*/
|
|
18
|
+
export declare function createTransport(config: TransportConfig): {
|
|
19
|
+
send: (payload: TransportPayload) => Promise<boolean>;
|
|
20
|
+
sendSync: (payload: TransportPayload) => void;
|
|
21
|
+
};
|
|
22
|
+
/** createTransport 반환 타입 */
|
|
23
|
+
export type Transport = ReturnType<typeof createTransport>;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export type EventType = 'start' | 'visibility' | 'scroll' | 'click' | 'input' | 'replay' | 'ping' | 'exit' | 'custom';
|
|
2
|
+
export interface StartPayload {
|
|
3
|
+
}
|
|
4
|
+
export interface VisibilityPayload {
|
|
5
|
+
isVisible: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface ScrollPayload {
|
|
8
|
+
yOffset: number;
|
|
9
|
+
percentage: number;
|
|
10
|
+
}
|
|
11
|
+
export interface ClickPayload {
|
|
12
|
+
targetId: string;
|
|
13
|
+
}
|
|
14
|
+
export interface InputPayload {
|
|
15
|
+
fieldId: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ReplayPayload {
|
|
18
|
+
event: unknown;
|
|
19
|
+
isCheckout: boolean;
|
|
20
|
+
version: 'rrweb';
|
|
21
|
+
}
|
|
22
|
+
export interface CompressedReplayPayload {
|
|
23
|
+
compressed: true;
|
|
24
|
+
compression: 'gzip';
|
|
25
|
+
encoding: 'base64';
|
|
26
|
+
data: string;
|
|
27
|
+
version: 'rrweb';
|
|
28
|
+
}
|
|
29
|
+
export interface PingPayload {
|
|
30
|
+
sectionId: string;
|
|
31
|
+
}
|
|
32
|
+
export interface ExitPayload {
|
|
33
|
+
lastElementId: string;
|
|
34
|
+
maxDepth: number;
|
|
35
|
+
}
|
|
36
|
+
export interface CustomPayload {
|
|
37
|
+
[key: string]: unknown;
|
|
38
|
+
}
|
|
39
|
+
export type EventPayload = StartPayload | VisibilityPayload | ScrollPayload | ClickPayload | InputPayload | ReplayPayload | CompressedReplayPayload | PingPayload | ExitPayload | CustomPayload;
|
|
40
|
+
export interface SDKEvent {
|
|
41
|
+
type: EventType;
|
|
42
|
+
timestamp: number;
|
|
43
|
+
cssSelector: string | null;
|
|
44
|
+
payload: EventPayload;
|
|
45
|
+
}
|
|
46
|
+
export interface TransportPayload {
|
|
47
|
+
sessionId: string;
|
|
48
|
+
userAgent: string;
|
|
49
|
+
url: string;
|
|
50
|
+
events: SDKEvent[];
|
|
51
|
+
}
|
|
52
|
+
export interface SDKConfig {
|
|
53
|
+
apiKey: string;
|
|
54
|
+
endpoint: string;
|
|
55
|
+
flushInterval: number;
|
|
56
|
+
flushQueueSize: number;
|
|
57
|
+
maxQueueSize: number;
|
|
58
|
+
maxRetries: number;
|
|
59
|
+
enableReplay: boolean;
|
|
60
|
+
replayMaskAllInputs: boolean;
|
|
61
|
+
replayBlockClass: string;
|
|
62
|
+
replayBlockSelector?: string;
|
|
63
|
+
replayMaskTextClass: string;
|
|
64
|
+
replayMaskTextSelector?: string;
|
|
65
|
+
replayInlineStylesheet: boolean;
|
|
66
|
+
replayCheckoutEveryNms: number;
|
|
67
|
+
replayMousemoveSampling: number | false;
|
|
68
|
+
replayMousemoveCallbackSampling: number;
|
|
69
|
+
replayScrollSampling: number;
|
|
70
|
+
replayInputSampling: 'all' | 'last';
|
|
71
|
+
beforeSend?: (event: SDKEvent) => SDKEvent | null;
|
|
72
|
+
debug: boolean;
|
|
73
|
+
}
|
|
74
|
+
export type SDKOptions = Partial<SDKConfig> & Pick<SDKConfig, 'apiKey'>;
|
|
75
|
+
export declare const DEFAULT_CONFIG: Omit<SDKConfig, 'apiKey'>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** SDK 내부 로거 인터페이스(디버깅용으로 넣음) */
|
|
2
|
+
export interface Logger {
|
|
3
|
+
log(...args: unknown[]): void;
|
|
4
|
+
warn(...args: unknown[]): void;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* 조건부 로거 생성
|
|
8
|
+
* debug가 true일 때만 콘솔에 [LandOm] 접두사와 함께 출력
|
|
9
|
+
*/
|
|
10
|
+
export declare function createLogger(debug: boolean): Logger;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 요소의 CSS selector를 생성한다.
|
|
3
|
+
* LandOm-LLM의 html_tools/selector_lookup.py:build_css_selector와 동일한 규칙을 따른다.
|
|
4
|
+
* 규칙이 어긋나면 백엔드의 selector→funnel 매핑이 깨지므로 변경 시 LLM 쪽과 동기화 필수.
|
|
5
|
+
*
|
|
6
|
+
* 규칙:
|
|
7
|
+
* 1) id 속성이 있으면 `tag[id="..."]`를 쓰고 더 이상 위로 올라가지 않는다
|
|
8
|
+
* 2) 그 외에는 `tag:nth-of-type(N)` (같은 태그명 형제 중 1-based 위치)
|
|
9
|
+
* 3) 결합자는 ` > ` (직계 자식)
|
|
10
|
+
* 4) root까지만 올라간다 (기본값 document.body)
|
|
11
|
+
*/
|
|
12
|
+
export declare function buildCssSelector(node: Element, root?: Element): string;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** sessionStorage에 저장되는 세션 데이터 */
|
|
2
|
+
interface SessionData {
|
|
3
|
+
sessionId: string;
|
|
4
|
+
startedAt: number;
|
|
5
|
+
lastActivityAt: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* UUIDv7 생성
|
|
9
|
+
* 상위 48비트에 밀리초 타임스탬프를 담아 시간순 정렬
|
|
10
|
+
*/
|
|
11
|
+
export declare function generateUUIDv7(): string;
|
|
12
|
+
/** 기존 세션 반환, 없거나 만료되었으면 새로 생성 */
|
|
13
|
+
export declare function getOrCreateSession(): SessionData;
|
|
14
|
+
/** 마지막 활동 시간 갱신 */
|
|
15
|
+
export declare function touchSession(): void;
|
|
16
|
+
/** 현재 세션 ID 반환 (활동 시간도 갱신) */
|
|
17
|
+
export declare function getSessionId(): string;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trailing-edge throttle
|
|
3
|
+
* 마지막 호출 기준으로 ms 간격마다 한 번씩 실행한다
|
|
4
|
+
* 스크롤 등 고빈도 이벤트의 호출 횟수를 제한할 때 사용
|
|
5
|
+
*
|
|
6
|
+
* 예시 (ms = 500):
|
|
7
|
+
* 0ms → 스크롤 100px 들어옴 → lastArgs = 100, 타이머 시작
|
|
8
|
+
* 50ms → 스크롤 200px 들어옴 → lastArgs = 200, 타이머 있으니 무시
|
|
9
|
+
* 100ms → 스크롤 350px 들어옴 → lastArgs = 350, 타이머 있으니 무시
|
|
10
|
+
* 500ms → 타이머 만료 → fn(350) 실행 (마지막 값만 사용됨)
|
|
11
|
+
*/
|
|
12
|
+
export declare function throttle<T extends (...args: any[]) => void>(fn: T, ms: number): T;
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "landom-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Lightweight SDK that auto-captures landing page user behavior (clicks, scrolls, inputs, exits, rrweb session replay) and ships it to your analytics backend.",
|
|
5
|
+
"main": "dist/landom-sdk.cjs.js",
|
|
6
|
+
"module": "dist/landom-sdk.esm.js",
|
|
7
|
+
"browser": "dist/landom-sdk.umd.js",
|
|
8
|
+
"types": "dist/types/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/types/index.d.ts",
|
|
12
|
+
"import": "./dist/landom-sdk.esm.js",
|
|
13
|
+
"require": "./dist/landom-sdk.cjs.js",
|
|
14
|
+
"default": "./dist/landom-sdk.umd.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"sideEffects": false,
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"LICENSE",
|
|
21
|
+
"README.md"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "rollup -c && tsc -p tsconfig.json",
|
|
25
|
+
"dev": "rollup -c -w",
|
|
26
|
+
"test": "jest --passWithNoTests",
|
|
27
|
+
"lint": "eslint src/",
|
|
28
|
+
"format": "prettier --write src/",
|
|
29
|
+
"prepublishOnly": "npm run build"
|
|
30
|
+
},
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "git+https://github.com/DontYouKnowFunnel/LandOm-SDK.git"
|
|
37
|
+
},
|
|
38
|
+
"keywords": [
|
|
39
|
+
"analytics",
|
|
40
|
+
"landing-page",
|
|
41
|
+
"user-behavior",
|
|
42
|
+
"sdk",
|
|
43
|
+
"event-tracking"
|
|
44
|
+
],
|
|
45
|
+
"author": "Kim Seongmin",
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"bugs": {
|
|
48
|
+
"url": "https://github.com/DontYouKnowFunnel/LandOm-SDK/issues"
|
|
49
|
+
},
|
|
50
|
+
"homepage": "https://github.com/DontYouKnowFunnel/LandOm-SDK#readme",
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
53
|
+
"rollup": "^4.60.0",
|
|
54
|
+
"rollup-plugin-esbuild": "^6.2.1",
|
|
55
|
+
"typescript": "^6.0.2"
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"rrweb": "^2.0.0-alpha.4"
|
|
59
|
+
}
|
|
60
|
+
}
|