@zalkera/client 0.17.1 → 0.19.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/README.md +12 -7
- package/bin/validate-storefront.mjs +540 -10
- package/contracts/aeo-surface-guarantees.json +4 -4
- package/dist/index.cjs +35 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +142 -130
- package/dist/index.d.ts +142 -130
- package/dist/index.js +35 -17
- package/dist/index.js.map +1 -1
- package/llms.txt +163 -78
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -47,7 +47,7 @@ export const zalkera = createZalkeraClient({
|
|
|
47
47
|
```ts
|
|
48
48
|
const posts = await zalkera.listPosts({size: 10, sort: "publishedAt,desc"});
|
|
49
49
|
const post = await zalkera.getPost("hello-world");
|
|
50
|
-
const
|
|
50
|
+
const site = await zalkera.getSiteConfig({tags: ["site-config"]});
|
|
51
51
|
const product = await zalkera.getProduct("tee", {tags: ["product:tee"]});
|
|
52
52
|
await zalkera.submitInquiry({name, email, subject, message}, {clientIp});
|
|
53
53
|
```
|
|
@@ -83,13 +83,13 @@ await zalkera.submitInquiry({name, email, subject, message}, {clientIp});
|
|
|
83
83
|
| `listPosts(params?)` | `GET /api/public/posts` | `Paginated<PostSummary>` |
|
|
84
84
|
| `getPost(slug)` | `GET /api/public/posts/{slug}` | `PostDetail` |
|
|
85
85
|
| `recordPostView(slug, ctx?)` | `POST /api/public/posts/{slug}/view` | `boolean` |
|
|
86
|
-
| `getPage(slug, options?)` | `GET /api/public/pages/{slug}` | `PageContent` |
|
|
87
|
-
| `listPages(params?, options?)` | `GET /api/public/pages` | `Paginated<PageSummary>` |
|
|
88
|
-
| `listMenus(options?)` | `GET /api/public/menus` | `Menu[]` |
|
|
89
86
|
| `getMediaUrl(id)` | `GET /api/public/media/{id}/url` | `MediaUrl` |
|
|
90
87
|
| `submitInquiry(input, ctx?)` | `POST /api/public/inquiries` | `InquiryCreated` |
|
|
91
88
|
| `submitLead(input, ctx?)` | `POST /api/public/leads` | `LeadCreated` |
|
|
92
89
|
|
|
90
|
+
- **고정 페이지·섹션·내비는 API 표면이 아니다.** 사이트의 얼굴은 레포 파일이 정본이라
|
|
91
|
+
(`content/pages/*.json`·`content/nav.json`) 백엔드 왕복이 없다 — 배선은 `llms.txt` §4.8·§9.
|
|
92
|
+
|
|
93
93
|
### 커머스 카탈로그·후기(공개)
|
|
94
94
|
|
|
95
95
|
| 메서드 | 엔드포인트 | 반환 |
|
|
@@ -101,7 +101,6 @@ await zalkera.submitInquiry({name, email, subject, message}, {clientIp});
|
|
|
101
101
|
| `getProductReviewSummary(productId, options?)` | `GET /api/public/products/{id}/reviews/summary` | `RatingSummary` |
|
|
102
102
|
| `createProductReview(productId, input, accessToken)` | `POST /api/shop/products/{id}/reviews` | `Review` |
|
|
103
103
|
|
|
104
|
-
- `listPages`는 **열거 전용**(본문 없음 — sitemap용). `size` 상한 100.
|
|
105
104
|
- 후기 조회는 **숫자 `productId`**(slug 아님) — `getProduct(slug).id`로 획득.
|
|
106
105
|
- 후기 작성은 로그인 필수 + 구매검증(본인·배송완료 이상·상품 일치).
|
|
107
106
|
|
|
@@ -174,14 +173,20 @@ await zalkera.submitInquiry({name, email, subject, message}, {clientIp});
|
|
|
174
173
|
### IP 민감 호출은 방문자 IP를 넘긴다
|
|
175
174
|
|
|
176
175
|
- 대상: `submitInquiry`·`submitLead`·`recordPostView`.
|
|
177
|
-
- 이유: 백엔드 IP 레이트리밋·조회 dedup
|
|
176
|
+
- 이유: 백엔드 IP 레이트리밋·조회 dedup이 이 값을 본다. 안 넘기면 테넌트 서버 IP로 뭉쳐 방문자 전원이 429.
|
|
178
177
|
|
|
179
178
|
```ts
|
|
180
179
|
// route handler 안
|
|
181
|
-
|
|
180
|
+
import {visitorIp} from "@zalkera/client";
|
|
181
|
+
|
|
182
|
+
const ip = visitorIp(req.headers); // 프록시 1단 기준(기본)
|
|
183
|
+
// const ip = visitorIp(req.headers, {trustedHops: 2}); // 예: CDN + 로드밸런서
|
|
182
184
|
await zalkera.submitInquiry(input, {clientIp: ip});
|
|
183
185
|
```
|
|
184
186
|
|
|
187
|
+
- ❌ **`x-forwarded-for` 첫 엔트리 직접 추출 금지**(`xff.split(",")[0]`). 이 헤더는 프록시가 오른쪽에 append하므로 **첫 엔트리는 방문자가 손으로 실은 값**이다 — 그걸로 레이트리밋 버킷을 만들면 요청마다 값을 바꿔 우회된다. `x-real-ip` 폴백도 마찬가지(세우는 주체가 프록시마다 다르다).
|
|
188
|
+
- **보장 경계**: `visitorIp()`는 "부르면 안전"이 아니라 **"선언한 홉 수가 참인 만큼 안전"**을 준다. 실제보다 **크게** 선언하면 위조 엔트리를 채택한다(조용히 뚫린다). 실제보다 **작게** 선언하면 방문자가 뭉쳐 429로 드러난다. **선언은 실제 이하로만.** 리버스 프록시 **0단 직노출** 배포는 미지원(소켓 IP를 플랫폼 수단으로 직접 얻을 것). 잘커라가 서빙하는 사이트는 기본값 1이 구성상 맞다.
|
|
189
|
+
|
|
185
190
|
## 시크릿 키 (`secretKey`)
|
|
186
191
|
|
|
187
192
|
- 역할: `X-Tenant` 무인증 신뢰의 **보안 승격** — 키가 테넌트 신원을 증명(백엔드에선 키가 정본).
|