@nodus-lib/nodus 0.0.14 → 0.0.16
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/README.md +71 -41
- package/dist/next/nodus_client.js +3 -2
- package/dist/next/nodus_server.d.ts +2 -2
- package/dist/next/nodus_server.js +5 -1
- package/dist/session/nodus-client-manager.d.ts +1 -0
- package/dist/session/nodus-client-manager.js +22 -0
- package/dist/session/nodus-manager.d.ts +0 -1
- package/dist/session/nodus-manager.js +0 -19
- package/dist/session/nodus-server-manager.d.ts +2 -0
- package/dist/session/nodus-server-manager.js +18 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Nodus SDK
|
|
2
2
|
|
|
3
|
-
Next.js
|
|
4
|
-
|
|
5
|
-
## 요구 사항
|
|
6
|
-
|
|
7
|
-
- Node.js `>=18.18.0`
|
|
8
|
-
- Next.js `>=14` (peer dependency)
|
|
3
|
+
Next.js에서 방문, 활성화, 매출 이벤트를 Nodus 서버로 전송하는 SDK입니다.
|
|
9
4
|
|
|
10
5
|
## 설치
|
|
11
6
|
|
|
@@ -13,64 +8,99 @@ Next.js 미들웨어에서 세션 쿠키(`nodus_session`)를 발급하고 유지
|
|
|
13
8
|
npm install @nodus-lib/nodus
|
|
14
9
|
```
|
|
15
10
|
|
|
16
|
-
##
|
|
11
|
+
## 환경 변수
|
|
12
|
+
|
|
13
|
+
```env
|
|
14
|
+
NODUS_SITE_KEY=site_xxx
|
|
15
|
+
```
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
브라우저 클라이언트에서 이벤트를 보낼 때는 Next.js public 환경 변수도 사용할 수 있습니다.
|
|
19
18
|
|
|
20
|
-
```
|
|
21
|
-
|
|
19
|
+
```env
|
|
20
|
+
NEXT_PUBLIC_NODUS_SITE_KEY=site_xxx
|
|
22
21
|
```
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
## 방문 로그 설정
|
|
24
|
+
|
|
25
|
+
방문 로그는 Next.js 요청 정보를 사용하므로 서버의 Proxy 또는 Middleware에서 설정합니다.
|
|
26
|
+
|
|
27
|
+
### Next.js 16 이상
|
|
28
|
+
|
|
29
|
+
Next.js 16부터 `middleware.ts`는 `proxy.ts`로 이름이 변경되었습니다.
|
|
25
30
|
|
|
26
31
|
```ts
|
|
32
|
+
import { nodus_visit } from "@nodus-lib/nodus/server";
|
|
27
33
|
import type { NextRequest } from "next/server";
|
|
28
|
-
import { middleware as baseMiddleware } from "@nodus-lib/nodus";
|
|
29
34
|
|
|
30
|
-
export function
|
|
31
|
-
|
|
35
|
+
export function proxy(request: NextRequest) {
|
|
36
|
+
return nodus_visit(request);
|
|
37
|
+
}
|
|
32
38
|
|
|
33
|
-
|
|
39
|
+
export const config = {
|
|
40
|
+
matcher: [
|
|
41
|
+
"/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)",
|
|
42
|
+
],
|
|
43
|
+
};
|
|
44
|
+
```
|
|
34
45
|
|
|
35
|
-
|
|
46
|
+
### Next.js 15 이하
|
|
47
|
+
|
|
48
|
+
Next.js 15 이하에서는 `middleware.ts`를 사용합니다.
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import { nodus_visit } from "@nodus-lib/nodus/server";
|
|
52
|
+
import type { NextRequest } from "next/server";
|
|
53
|
+
|
|
54
|
+
export function middleware(request: NextRequest) {
|
|
55
|
+
return nodus_visit(request);
|
|
36
56
|
}
|
|
37
57
|
|
|
38
|
-
export
|
|
58
|
+
export const config = {
|
|
59
|
+
matcher: [
|
|
60
|
+
"/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)",
|
|
61
|
+
],
|
|
62
|
+
};
|
|
39
63
|
```
|
|
40
64
|
|
|
41
|
-
|
|
65
|
+
`nodus_visit`은 `nodus_session` 쿠키를 생성하거나 재사용하고, 현재 URL과 referer를 방문 이벤트로 전송합니다.
|
|
42
66
|
|
|
43
|
-
|
|
67
|
+
## AARRR 퍼널 이벤트
|
|
44
68
|
|
|
45
|
-
|
|
46
|
-
NODUS_SITE_KEY=site_xxx
|
|
47
|
-
```
|
|
69
|
+
`nodus_activation`과 `nodus_revenue`는 AARRR 퍼널 분석에서 참고한 이벤트입니다.
|
|
48
70
|
|
|
49
|
-
|
|
71
|
+
- `nodus_activation`: 사용자가 핵심 기능을 경험했을 때 기록합니다.
|
|
72
|
+
- `nodus_revenue`: 결제, 구매, 구독 전환처럼 매출과 관련된 행동을 기록합니다.
|
|
50
73
|
|
|
51
|
-
|
|
74
|
+
이 함수들은 브라우저에서 실행되는 클라이언트 전용 함수입니다. React 컴포넌트에서 사용할 때는 `"use client"`가 필요합니다.
|
|
52
75
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
- 쿠키가 없으면 `crypto.randomUUID()`로 새 세션 ID를 생성합니다.
|
|
56
|
-
- 쿠키 옵션: `httpOnly`, `sameSite: "lax"`, `secure: true`, `path: "/"`
|
|
57
|
-
- 쿠키 최대 수명: 1년
|
|
76
|
+
```tsx
|
|
77
|
+
"use client";
|
|
58
78
|
|
|
59
|
-
|
|
79
|
+
import { nodus_activation, nodus_revenue } from "@nodus-lib/nodus/client";
|
|
60
80
|
|
|
61
|
-
|
|
81
|
+
export function PricingActions() {
|
|
82
|
+
return (
|
|
83
|
+
<>
|
|
84
|
+
<button onClick={() => nodus_activation("무료_체험_시작_클릭")}>
|
|
85
|
+
Start
|
|
86
|
+
</button>
|
|
87
|
+
<button onClick={() => nodus_revenue("결제_완료")}>
|
|
88
|
+
Paid
|
|
89
|
+
</button>
|
|
90
|
+
</>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
```
|
|
62
94
|
|
|
63
|
-
|
|
95
|
+
## 세션
|
|
64
96
|
|
|
65
|
-
-
|
|
66
|
-
-
|
|
67
|
-
-
|
|
68
|
-
-
|
|
69
|
-
- `/sitemap.xml`
|
|
70
|
-
- `/robots.txt`
|
|
97
|
+
- 쿠키 이름: `nodus_session`
|
|
98
|
+
- 쿠키 수명: 1년
|
|
99
|
+
- 쿠키 옵션: `sameSite: "lax"`, `secure: true`, `path: "/"`
|
|
100
|
+
- 서버와 클라이언트는 같은 `nodus_session` 쿠키를 사용합니다.
|
|
71
101
|
|
|
72
|
-
|
|
102
|
+
클라이언트 이벤트가 같은 세션을 읽어야 하므로 `nodus_session` 쿠키는 `httpOnly`로 설정하지 않습니다.
|
|
73
103
|
|
|
74
104
|
## 라이선스
|
|
75
105
|
|
|
76
|
-
MIT
|
|
106
|
+
MIT
|
|
@@ -3,9 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.nodus_activation = nodus_activation;
|
|
4
4
|
exports.nodus_revenue = nodus_revenue;
|
|
5
5
|
const nodus_server_caller_1 = require("../logger/nodus-server-caller");
|
|
6
|
+
const nodus_client_manager_1 = require("../session/nodus-client-manager");
|
|
6
7
|
const nodus_manager_1 = require("../session/nodus-manager");
|
|
7
8
|
function nodus_activation(feature) {
|
|
8
|
-
const sessionId = (0,
|
|
9
|
+
const sessionId = (0, nodus_client_manager_1.nodus_session_manager)();
|
|
9
10
|
if (nodus_manager_1.nodus_key) {
|
|
10
11
|
(0, nodus_server_caller_1.nodus_server_caller)({
|
|
11
12
|
data: {
|
|
@@ -19,7 +20,7 @@ function nodus_activation(feature) {
|
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
22
|
function nodus_revenue(tag) {
|
|
22
|
-
const sessionId = (0,
|
|
23
|
+
const sessionId = (0, nodus_client_manager_1.nodus_session_manager)();
|
|
23
24
|
if (nodus_manager_1.nodus_key) {
|
|
24
25
|
(0, nodus_server_caller_1.nodus_server_caller)({
|
|
25
26
|
data: {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { NextRequest } from "next/server";
|
|
2
|
-
export declare function nodus_visit(request: NextRequest):
|
|
1
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
2
|
+
export declare function nodus_visit(request: NextRequest): NextResponse<unknown>;
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.nodus_visit = nodus_visit;
|
|
4
|
+
const server_1 = require("next/server");
|
|
4
5
|
const nodus_server_caller_1 = require("../logger/nodus-server-caller");
|
|
5
6
|
const nodus_manager_1 = require("../session/nodus-manager");
|
|
7
|
+
const nodus_server_manager_1 = require("../session/nodus-server-manager");
|
|
6
8
|
function nodus_visit(request) {
|
|
7
|
-
const
|
|
9
|
+
const response = server_1.NextResponse.next();
|
|
10
|
+
const sessionId = (0, nodus_server_manager_1.nodus_request_session_manager)(request, response);
|
|
8
11
|
if (nodus_manager_1.nodus_key) {
|
|
9
12
|
(0, nodus_server_caller_1.nodus_server_caller)({
|
|
10
13
|
data: {
|
|
@@ -16,4 +19,5 @@ function nodus_visit(request) {
|
|
|
16
19
|
key: nodus_manager_1.nodus_key,
|
|
17
20
|
});
|
|
18
21
|
}
|
|
22
|
+
return response;
|
|
19
23
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function nodus_session_manager(): string;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.nodus_session_manager = nodus_session_manager;
|
|
4
|
+
const nodus_manager_1 = require("./nodus-manager");
|
|
5
|
+
function nodus_session_manager() {
|
|
6
|
+
const existingSession = get_cookie(nodus_manager_1.COOKIE_NAME);
|
|
7
|
+
if (existingSession) {
|
|
8
|
+
return existingSession;
|
|
9
|
+
}
|
|
10
|
+
const sessionId = crypto.randomUUID() + "-" + Date.now();
|
|
11
|
+
set_cookie(nodus_manager_1.COOKIE_NAME, sessionId);
|
|
12
|
+
return sessionId;
|
|
13
|
+
}
|
|
14
|
+
function get_cookie(name) {
|
|
15
|
+
const cookie = document.cookie
|
|
16
|
+
.split("; ")
|
|
17
|
+
.find((row) => row.startsWith(`${name}=`));
|
|
18
|
+
return cookie ? decodeURIComponent(cookie.split("=")[1] ?? "") : null;
|
|
19
|
+
}
|
|
20
|
+
function set_cookie(name, value) {
|
|
21
|
+
document.cookie = `${name}=${encodeURIComponent(value)}; path=/; max-age=${nodus_manager_1.COOKIE_MAX_AGE_SECONDS}; samesite=lax; secure`;
|
|
22
|
+
}
|
|
@@ -1,25 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.nodus_key = exports.COOKIE_MAX_AGE_SECONDS = exports.COOKIE_NAME = void 0;
|
|
4
|
-
exports.nodus_session_manager = nodus_session_manager;
|
|
5
4
|
exports.COOKIE_NAME = "nodus_session";
|
|
6
5
|
exports.COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
|
|
7
6
|
exports.nodus_key = process.env.NODUS_SITE_KEY ?? process.env.NEXT_PUBLIC_NODUS_SITE_KEY;
|
|
8
|
-
function nodus_session_manager() {
|
|
9
|
-
const existingSession = get_cookie(exports.COOKIE_NAME);
|
|
10
|
-
if (existingSession) {
|
|
11
|
-
return existingSession;
|
|
12
|
-
}
|
|
13
|
-
const sessionId = crypto.randomUUID() + "-" + Date.now();
|
|
14
|
-
set_cookie(exports.COOKIE_NAME, sessionId);
|
|
15
|
-
return sessionId;
|
|
16
|
-
}
|
|
17
|
-
function get_cookie(name) {
|
|
18
|
-
const cookie = document.cookie
|
|
19
|
-
.split("; ")
|
|
20
|
-
.find((row) => row.startsWith(`${name}=`));
|
|
21
|
-
return cookie ? decodeURIComponent(cookie.split("=")[1] ?? "") : null;
|
|
22
|
-
}
|
|
23
|
-
function set_cookie(name, value) {
|
|
24
|
-
document.cookie = `${name}=${encodeURIComponent(value)}; path=/; max-age=${exports.COOKIE_MAX_AGE_SECONDS}; samesite=lax; secure`;
|
|
25
|
-
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.nodus_request_session_manager = nodus_request_session_manager;
|
|
4
|
+
const nodus_manager_1 = require("./nodus-manager");
|
|
5
|
+
function nodus_request_session_manager(request, response) {
|
|
6
|
+
const existingSession = request.cookies.get(nodus_manager_1.COOKIE_NAME)?.value;
|
|
7
|
+
if (existingSession) {
|
|
8
|
+
return existingSession;
|
|
9
|
+
}
|
|
10
|
+
const sessionId = crypto.randomUUID() + "-" + Date.now();
|
|
11
|
+
response.cookies.set(nodus_manager_1.COOKIE_NAME, sessionId, {
|
|
12
|
+
sameSite: "lax",
|
|
13
|
+
secure: true,
|
|
14
|
+
path: "/",
|
|
15
|
+
maxAge: nodus_manager_1.COOKIE_MAX_AGE_SECONDS,
|
|
16
|
+
});
|
|
17
|
+
return sessionId;
|
|
18
|
+
}
|