@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 CHANGED
@@ -1,11 +1,6 @@
1
- # next-session-inspector
1
+ # Nodus SDK
2
2
 
3
- Next.js 미들웨어에서 세션 쿠키(`nodus_session`)를 발급하고 유지하는 경량 패키지입니다.
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
- 루트의 `middleware.ts`에서 그대로 내보냅니다.
17
+ 브라우저 클라이언트에서 이벤트를 보낼 때는 Next.js public 환경 변수도 사용할 수 있습니다.
19
18
 
20
- ```ts
21
- export { middleware, config } from "@nodus-lib/nodus";
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 middleware(request: NextRequest) {
31
- const response = baseMiddleware(request);
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
- return response;
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 { config } from "@nodus-lib/nodus";
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
- 방문 이벤트를 Nodus로 전송하려면 사이트 키를 설정합니다.
67
+ ## AARRR 퍼널 이벤트
44
68
 
45
- ```env
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
- - 쿠키 이름: `nodus_session`
54
- - 기존 쿠키가 있으면 재사용합니다.
55
- - 쿠키가 없으면 `crypto.randomUUID()`로 새 세션 ID를 생성합니다.
56
- - 쿠키 옵션: `httpOnly`, `sameSite: "lax"`, `secure: true`, `path: "/"`
57
- - 쿠키 최대 수명: 1년
76
+ ```tsx
77
+ "use client";
58
78
 
59
- ## config.matcher
79
+ import { nodus_activation, nodus_revenue } from "@nodus-lib/nodus/client";
60
80
 
61
- 기본 matcher는 정적 자산, API, favicon 등을 제외한 페이지 중심 경로에 적용됩니다.
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
- - `/api`
66
- - `/_next/static`
67
- - `/_next/image`
68
- - `/favicon.ico`
69
- - `/sitemap.xml`
70
- - `/robots.txt`
97
+ - 쿠키 이름: `nodus_session`
98
+ - 쿠키 수명: 1년
99
+ - 쿠키 옵션: `sameSite: "lax"`, `secure: true`, `path: "/"`
100
+ - 서버와 클라이언트는 같은 `nodus_session` 쿠키를 사용합니다.
71
101
 
72
- 필요하면 앱의 `middleware.ts`에서 `config`를 직접 정의해 덮어쓸 수 있습니다.
102
+ 클라이언트 이벤트가 같은 세션을 읽어야 하므로 `nodus_session` 쿠키는 `httpOnly`로 설정하지 않습니다.
73
103
 
74
104
  ## 라이선스
75
105
 
76
- MIT. 자세한 내용은 `LICENSE` 파일을 참고하세요.
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, nodus_manager_1.nodus_session_manager)();
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, nodus_manager_1.nodus_session_manager)();
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): void;
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 sessionId = (0, nodus_manager_1.nodus_session_manager)();
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,4 +1,3 @@
1
1
  export declare const COOKIE_NAME = "nodus_session";
2
2
  export declare const COOKIE_MAX_AGE_SECONDS: number;
3
3
  export declare const nodus_key: string | undefined;
4
- export declare function nodus_session_manager(): string;
@@ -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,2 @@
1
+ import { NextRequest, NextResponse } from "next/server";
2
+ export declare function nodus_request_session_manager(request: NextRequest, response: NextResponse): string;
@@ -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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nodus-lib/nodus",
3
- "version": "0.0.14",
3
+ "version": "0.0.16",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },