@sayren/storefront-sdk 0.2.1 → 0.3.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/dist/analytics/index.mjs +2 -1
- package/dist/{analytics-ids-o0a07Ohr.mjs → analytics-CgD70OqH.mjs} +1 -37
- package/dist/analytics-ids-COElZiI3.mjs +38 -0
- package/dist/auth/index.d.mts +43 -0
- package/dist/auth/index.mjs +58 -0
- package/dist/client-Xb-2tNKT.mjs +776 -0
- package/dist/http-DWaRhLfG.d.mts +55 -0
- package/dist/index.d.mts +7 -43
- package/dist/index.mjs +4 -762
- package/package.json +6 -1
- package/src/auth/index.ts +74 -0
- package/src/client.ts +8 -1
- package/src/schemas/auth.ts +15 -0
package/dist/analytics/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { i as
|
|
1
|
+
import { i as ANALYTICS_VISITOR_COOKIE, n as ANALYTICS_SESSION_COOKIE } from "../analytics-CgD70OqH.mjs";
|
|
2
|
+
import { n as safeDecode } from "../analytics-ids-COElZiI3.mjs";
|
|
2
3
|
//#region src/analytics/index.ts
|
|
3
4
|
const VISITOR_MAX_AGE_SEC = 31536e3;
|
|
4
5
|
const SESSION_MAX_AGE_SEC = 1800;
|
|
@@ -87,40 +87,4 @@ webdriver: z.boolean().optional() }).optional()
|
|
|
87
87
|
/** 배치 본문 상한(바이트) — 서버가 넘는 요청을 거부한다 */
|
|
88
88
|
const ANALYTICS_MAX_BATCH_BYTES = 32768;
|
|
89
89
|
//#endregion
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* 요청의 Cookie 헤더에서 방문자·세션 ID를 읽는다 — SSR 서버가 스토어프론트 API를 부를 때 쓴다.
|
|
93
|
-
* 브라우저 모듈(`@sayren/storefront-sdk/analytics`)이 셀러 도메인에 남긴 쿠키다. 형식이 틀린 값은 버린다.
|
|
94
|
-
*
|
|
95
|
-
* ```ts
|
|
96
|
-
* const ids = analyticsIdsFromCookie(request.headers.get("cookie"));
|
|
97
|
-
* createStorefrontClient({ baseUrl, storeCode, ...ids });
|
|
98
|
-
* ```
|
|
99
|
-
*/
|
|
100
|
-
function analyticsIdsFromCookie(cookieHeader) {
|
|
101
|
-
if (!cookieHeader) return {};
|
|
102
|
-
const pick = (name) => {
|
|
103
|
-
for (const part of cookieHeader.split(";")) {
|
|
104
|
-
const [key, ...rest] = part.trim().split("=");
|
|
105
|
-
if (key !== name) continue;
|
|
106
|
-
const value = safeDecode(rest.join("="));
|
|
107
|
-
return value !== null && analyticsIdSchema.safeParse(value).success ? value : void 0;
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
const visitorId = pick(ANALYTICS_VISITOR_COOKIE);
|
|
111
|
-
const sessionId = pick(ANALYTICS_SESSION_COOKIE);
|
|
112
|
-
return {
|
|
113
|
-
...visitorId ? { visitorId } : {},
|
|
114
|
-
...sessionId ? { sessionId } : {}
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
/** 잘못된 퍼센트 인코딩(`%E0%A4`)은 URIError를 던진다 — 쿠키 하나 때문에 SSR 전체가 500이 되지 않게 버린다 */
|
|
118
|
-
function safeDecode(value) {
|
|
119
|
-
try {
|
|
120
|
-
return decodeURIComponent(value);
|
|
121
|
-
} catch {
|
|
122
|
-
return null;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
//#endregion
|
|
126
|
-
export { ANALYTICS_SESSION_HEADER as a, analyticsBatchSchema as c, analyticsIdSchema as d, analyticsServerEventNameSchema as f, ANALYTICS_SESSION_COOKIE as i, analyticsClientEventNameSchema as l, safeDecode as n, ANALYTICS_VISITOR_COOKIE as o, ANALYTICS_MAX_BATCH_BYTES as r, ANALYTICS_VISITOR_HEADER as s, analyticsIdsFromCookie as t, analyticsClientEventSchema as u };
|
|
90
|
+
export { ANALYTICS_VISITOR_HEADER as a, analyticsClientEventSchema as c, ANALYTICS_VISITOR_COOKIE as i, analyticsIdSchema as l, ANALYTICS_SESSION_COOKIE as n, analyticsBatchSchema as o, ANALYTICS_SESSION_HEADER as r, analyticsClientEventNameSchema as s, ANALYTICS_MAX_BATCH_BYTES as t, analyticsServerEventNameSchema as u };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { i as ANALYTICS_VISITOR_COOKIE, l as analyticsIdSchema, n as ANALYTICS_SESSION_COOKIE } from "./analytics-CgD70OqH.mjs";
|
|
2
|
+
//#region src/analytics-ids.ts
|
|
3
|
+
/**
|
|
4
|
+
* 요청의 Cookie 헤더에서 방문자·세션 ID를 읽는다 — SSR 서버가 스토어프론트 API를 부를 때 쓴다.
|
|
5
|
+
* 브라우저 모듈(`@sayren/storefront-sdk/analytics`)이 셀러 도메인에 남긴 쿠키다. 형식이 틀린 값은 버린다.
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* const ids = analyticsIdsFromCookie(request.headers.get("cookie"));
|
|
9
|
+
* createStorefrontClient({ baseUrl, storeCode, ...ids });
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
function analyticsIdsFromCookie(cookieHeader) {
|
|
13
|
+
if (!cookieHeader) return {};
|
|
14
|
+
const pick = (name) => {
|
|
15
|
+
for (const part of cookieHeader.split(";")) {
|
|
16
|
+
const [key, ...rest] = part.trim().split("=");
|
|
17
|
+
if (key !== name) continue;
|
|
18
|
+
const value = safeDecode(rest.join("="));
|
|
19
|
+
return value !== null && analyticsIdSchema.safeParse(value).success ? value : void 0;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const visitorId = pick(ANALYTICS_VISITOR_COOKIE);
|
|
23
|
+
const sessionId = pick(ANALYTICS_SESSION_COOKIE);
|
|
24
|
+
return {
|
|
25
|
+
...visitorId ? { visitorId } : {},
|
|
26
|
+
...sessionId ? { sessionId } : {}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** 잘못된 퍼센트 인코딩(`%E0%A4`)은 URIError를 던진다 — 쿠키 하나 때문에 SSR 전체가 500이 되지 않게 버린다 */
|
|
30
|
+
function safeDecode(value) {
|
|
31
|
+
try {
|
|
32
|
+
return decodeURIComponent(value);
|
|
33
|
+
} catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
export { safeDecode as n, analyticsIdsFromCookie as t };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { a as AnonymousSession, c as TokenPair, o as LoginRequest, s as SignupRequest, t as ApiError } from "../http-DWaRhLfG.mjs";
|
|
2
|
+
//#region src/auth/index.d.ts
|
|
3
|
+
export interface StorefrontAuthOptions {
|
|
4
|
+
/** 예: https://api.sayren.app/storefront/v1 */
|
|
5
|
+
baseUrl: string;
|
|
6
|
+
/** 테넌트 스토어 코드 — `X-Store-Code` 헤더로 보낸다 */
|
|
7
|
+
storeCode: string;
|
|
8
|
+
fetch?: typeof globalThis.fetch;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* 구매자 인증 — 화면은 스토어프런트가 그리고, 계정 저장과 인증 처리는 sayren이 한다.
|
|
12
|
+
* 어느 방식으로 로그인해도 결과는 같은 구매자 토큰(`TokenPair`)이고 `/me/*`·장바구니·주문 API에 그대로 쓴다.
|
|
13
|
+
*
|
|
14
|
+
* 토큰 보관은 앱 몫이다. 서버(loader·action)에서 호출하고 httpOnly 쿠키에 두기를 권한다.
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* const auth = createStorefrontAuth({ baseUrl, storeCode });
|
|
18
|
+
* const guest = await auth.anonymous(); // 비회원: 장바구니 토큰
|
|
19
|
+
* const tokens = await auth.session({ email, password, cartToken: guest.cartToken });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare function createStorefrontAuth(options: StorefrontAuthOptions): {
|
|
23
|
+
/**
|
|
24
|
+
* 비회원 익명 세션 — 구매자 계정을 만들지 않는다. `cartToken`을 `X-Cart-Token`으로 보내면 장바구니·
|
|
25
|
+
* 비회원 주문이 쌓이고, `session()`·`signUp()`에 실으면 회원 장바구니로 병합된 뒤 닫힌다.
|
|
26
|
+
* 마지막 활동 후 30일이 지나면 만료된다.
|
|
27
|
+
*/
|
|
28
|
+
anonymous(): Promise<AnonymousSession>;
|
|
29
|
+
/** 이메일·비밀번호 로그인. `cartToken`을 주면 비회원 장바구니를 병합한다 */
|
|
30
|
+
session(body: LoginRequest): Promise<TokenPair>;
|
|
31
|
+
/** 회원가입 — 가입과 동시에 로그인 토큰을 받는다. `cartToken`을 주면 장바구니를 병합한다 */
|
|
32
|
+
signUp(body: SignupRequest): Promise<TokenPair>;
|
|
33
|
+
/** 토큰 갱신 — refreshToken은 한 번 쓰면 폐기되고 새 쌍이 온다(회전) */
|
|
34
|
+
refresh(refreshToken: string): Promise<TokenPair>;
|
|
35
|
+
/**
|
|
36
|
+
* 로그아웃 — 이 구매자의 refreshToken을 모두 폐기한다. 앱은 보관한 토큰을 지운다.
|
|
37
|
+
* 액세스 토큰이 이미 만료됐으면(401) 서버에서 할 일이 없으므로 성공으로 본다.
|
|
38
|
+
*/
|
|
39
|
+
signOut(accessToken: string): Promise<void>;
|
|
40
|
+
};
|
|
41
|
+
export type StorefrontAuth = ReturnType<typeof createStorefrontAuth>;
|
|
42
|
+
//#endregion
|
|
43
|
+
export { type AnonymousSession, ApiError, type LoginRequest, type SignupRequest, type TokenPair };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { t as createStorefrontClient, tt as ApiError } from "../client-Xb-2tNKT.mjs";
|
|
2
|
+
//#region src/auth/index.ts
|
|
3
|
+
/**
|
|
4
|
+
* 구매자 인증 — 화면은 스토어프런트가 그리고, 계정 저장과 인증 처리는 sayren이 한다.
|
|
5
|
+
* 어느 방식으로 로그인해도 결과는 같은 구매자 토큰(`TokenPair`)이고 `/me/*`·장바구니·주문 API에 그대로 쓴다.
|
|
6
|
+
*
|
|
7
|
+
* 토큰 보관은 앱 몫이다. 서버(loader·action)에서 호출하고 httpOnly 쿠키에 두기를 권한다.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* const auth = createStorefrontAuth({ baseUrl, storeCode });
|
|
11
|
+
* const guest = await auth.anonymous(); // 비회원: 장바구니 토큰
|
|
12
|
+
* const tokens = await auth.session({ email, password, cartToken: guest.cartToken });
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
function createStorefrontAuth(options) {
|
|
16
|
+
const client = (accessToken) => createStorefrontClient({
|
|
17
|
+
baseUrl: options.baseUrl,
|
|
18
|
+
storeCode: options.storeCode,
|
|
19
|
+
accessToken,
|
|
20
|
+
fetch: options.fetch
|
|
21
|
+
});
|
|
22
|
+
return {
|
|
23
|
+
/**
|
|
24
|
+
* 비회원 익명 세션 — 구매자 계정을 만들지 않는다. `cartToken`을 `X-Cart-Token`으로 보내면 장바구니·
|
|
25
|
+
* 비회원 주문이 쌓이고, `session()`·`signUp()`에 실으면 회원 장바구니로 병합된 뒤 닫힌다.
|
|
26
|
+
* 마지막 활동 후 30일이 지나면 만료된다.
|
|
27
|
+
*/
|
|
28
|
+
anonymous() {
|
|
29
|
+
return client().auth.anonymous();
|
|
30
|
+
},
|
|
31
|
+
/** 이메일·비밀번호 로그인. `cartToken`을 주면 비회원 장바구니를 병합한다 */
|
|
32
|
+
session(body) {
|
|
33
|
+
return client().auth.login(body);
|
|
34
|
+
},
|
|
35
|
+
/** 회원가입 — 가입과 동시에 로그인 토큰을 받는다. `cartToken`을 주면 장바구니를 병합한다 */
|
|
36
|
+
signUp(body) {
|
|
37
|
+
return client().auth.signup(body);
|
|
38
|
+
},
|
|
39
|
+
/** 토큰 갱신 — refreshToken은 한 번 쓰면 폐기되고 새 쌍이 온다(회전) */
|
|
40
|
+
refresh(refreshToken) {
|
|
41
|
+
return client().auth.refresh(refreshToken);
|
|
42
|
+
},
|
|
43
|
+
/**
|
|
44
|
+
* 로그아웃 — 이 구매자의 refreshToken을 모두 폐기한다. 앱은 보관한 토큰을 지운다.
|
|
45
|
+
* 액세스 토큰이 이미 만료됐으면(401) 서버에서 할 일이 없으므로 성공으로 본다.
|
|
46
|
+
*/
|
|
47
|
+
async signOut(accessToken) {
|
|
48
|
+
try {
|
|
49
|
+
await client(accessToken).auth.logout();
|
|
50
|
+
} catch (error) {
|
|
51
|
+
if (error instanceof ApiError && error.status === 401) return;
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
export { ApiError, createStorefrontAuth };
|