@zalkera/client 0.14.0 → 0.16.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/contracts/aeo-surface-guarantees.json +3 -5
- package/dist/index.cjs +28 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +26 -3
- package/dist/index.d.ts +26 -3
- package/dist/index.js +28 -17
- package/dist/index.js.map +1 -1
- package/llms.txt +18 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -949,7 +949,7 @@ declare class ZalkeraError extends Error {
|
|
|
949
949
|
* 이 패키지는 그 방언을 읽는 헬퍼([asHandle]·[asHandleArray]·[assetPath]·[readConfig])를 실어 나른다.
|
|
950
950
|
* 그래서 아래 `SECTION_CONTRACT` 리터럴은 rev 3 과 **바이트 동일**하다(동기 스크립트가 확인한다).
|
|
951
951
|
*/
|
|
952
|
-
declare const SECTION_CONTRACT_REV =
|
|
952
|
+
declare const SECTION_CONTRACT_REV = 5;
|
|
953
953
|
/** 업종 분류 — 콘솔 섹션 픽커의 그룹핑에 쓴다(테넌트 업종 필드는 아직 없다·memo102 §5). */
|
|
954
954
|
type SectionVertical = "BEAUTY" | "GENERAL";
|
|
955
955
|
interface SectionSpec {
|
|
@@ -972,6 +972,17 @@ interface SectionSpec {
|
|
|
972
972
|
* **필수성의 집행 지점은 팩/시드뿐이다** — 런타임은 그대로 관용이다(렌더러 스킵·콘솔 raw 편집 허용).
|
|
973
973
|
*/
|
|
974
974
|
readonly requiredRefs: readonly string[];
|
|
975
|
+
/**
|
|
976
|
+
* **참조 그룹**(rev 5) — 각 그룹에서 **하나 이상**이 채워져야 한다.
|
|
977
|
+
*
|
|
978
|
+
* rev 3 은 필수성을 키 하나(`productIds`)에 걸었는데, rev 5 에서 갈래 참조(`categorySlug`)가 같은
|
|
979
|
+
* 역할을 하게 되면서 필수의 단위가 **"참조 존재"**로 옮겨갔다. 막으려는 것은 그대로다 — 아무것도
|
|
980
|
+
* 안 가리킨 채 시드에 들어와 개시 직후 조용히 사라지는 섹션.
|
|
981
|
+
*
|
|
982
|
+
* `requiredRefs`(무조건 필수)와 **함께** 쓴다: 그룹으로 표현되는 섹션은 `requiredRefs` 가 빈 배열이고,
|
|
983
|
+
* 종전처럼 단일 키가 무조건 필수인 섹션은 이 필드가 빈 배열이다. 둘 다 빈 배열이면 참조 요구가 없다.
|
|
984
|
+
*/
|
|
985
|
+
readonly requiredRefsAnyOf: readonly (readonly string[])[];
|
|
975
986
|
}
|
|
976
987
|
/**
|
|
977
988
|
* 아는 섹션 전량. **순서는 콘솔 픽커의 노출 순서**(관행 아크: 주목→가치→신뢰→행동).
|
|
@@ -985,62 +996,74 @@ declare const SECTION_CONTRACT: readonly [{
|
|
|
985
996
|
readonly type: "SERVICE_MENU";
|
|
986
997
|
readonly vertical: "BEAUTY";
|
|
987
998
|
readonly jsonLd: "ItemList";
|
|
988
|
-
readonly requiredRefs: readonly [
|
|
999
|
+
readonly requiredRefs: readonly [];
|
|
1000
|
+
readonly requiredRefsAnyOf: readonly [readonly ["productIds", "categorySlug"]];
|
|
989
1001
|
}, {
|
|
990
1002
|
readonly type: "BEFORE_AFTER_GALLERY";
|
|
991
1003
|
readonly vertical: "BEAUTY";
|
|
992
1004
|
readonly jsonLd: null;
|
|
993
1005
|
readonly requiredRefs: readonly [];
|
|
1006
|
+
readonly requiredRefsAnyOf: readonly [];
|
|
994
1007
|
}, {
|
|
995
1008
|
readonly type: "BOOKING_CTA";
|
|
996
1009
|
readonly vertical: "BEAUTY";
|
|
997
1010
|
readonly jsonLd: null;
|
|
998
|
-
readonly requiredRefs: readonly [
|
|
1011
|
+
readonly requiredRefs: readonly [];
|
|
1012
|
+
readonly requiredRefsAnyOf: readonly [readonly ["productId", "categorySlug"]];
|
|
999
1013
|
}, {
|
|
1000
1014
|
readonly type: "DOCTOR_INTRO";
|
|
1001
1015
|
readonly vertical: "BEAUTY";
|
|
1002
1016
|
readonly jsonLd: null;
|
|
1003
1017
|
readonly requiredRefs: readonly [];
|
|
1018
|
+
readonly requiredRefsAnyOf: readonly [];
|
|
1004
1019
|
}, {
|
|
1005
1020
|
readonly type: "HERO";
|
|
1006
1021
|
readonly vertical: "GENERAL";
|
|
1007
1022
|
readonly jsonLd: null;
|
|
1008
1023
|
readonly requiredRefs: readonly [];
|
|
1024
|
+
readonly requiredRefsAnyOf: readonly [];
|
|
1009
1025
|
}, {
|
|
1010
1026
|
readonly type: "FEATURE_GRID";
|
|
1011
1027
|
readonly vertical: "GENERAL";
|
|
1012
1028
|
readonly jsonLd: null;
|
|
1013
1029
|
readonly requiredRefs: readonly [];
|
|
1030
|
+
readonly requiredRefsAnyOf: readonly [];
|
|
1014
1031
|
}, {
|
|
1015
1032
|
readonly type: "TEXT_MEDIA";
|
|
1016
1033
|
readonly vertical: "GENERAL";
|
|
1017
1034
|
readonly jsonLd: null;
|
|
1018
1035
|
readonly requiredRefs: readonly [];
|
|
1036
|
+
readonly requiredRefsAnyOf: readonly [];
|
|
1019
1037
|
}, {
|
|
1020
1038
|
readonly type: "LOGO_WALL";
|
|
1021
1039
|
readonly vertical: "GENERAL";
|
|
1022
1040
|
readonly jsonLd: null;
|
|
1023
1041
|
readonly requiredRefs: readonly [];
|
|
1042
|
+
readonly requiredRefsAnyOf: readonly [];
|
|
1024
1043
|
}, {
|
|
1025
1044
|
readonly type: "STATS_BAND";
|
|
1026
1045
|
readonly vertical: "GENERAL";
|
|
1027
1046
|
readonly jsonLd: null;
|
|
1028
1047
|
readonly requiredRefs: readonly [];
|
|
1048
|
+
readonly requiredRefsAnyOf: readonly [];
|
|
1029
1049
|
}, {
|
|
1030
1050
|
readonly type: "TESTIMONIALS";
|
|
1031
1051
|
readonly vertical: "GENERAL";
|
|
1032
1052
|
readonly jsonLd: null;
|
|
1033
1053
|
readonly requiredRefs: readonly [];
|
|
1054
|
+
readonly requiredRefsAnyOf: readonly [];
|
|
1034
1055
|
}, {
|
|
1035
1056
|
readonly type: "FAQ_LIST";
|
|
1036
1057
|
readonly vertical: "GENERAL";
|
|
1037
1058
|
readonly jsonLd: "FAQPage";
|
|
1038
1059
|
readonly requiredRefs: readonly [];
|
|
1060
|
+
readonly requiredRefsAnyOf: readonly [];
|
|
1039
1061
|
}, {
|
|
1040
1062
|
readonly type: "LEAD_CTA";
|
|
1041
1063
|
readonly vertical: "GENERAL";
|
|
1042
1064
|
readonly jsonLd: null;
|
|
1043
1065
|
readonly requiredRefs: readonly [];
|
|
1066
|
+
readonly requiredRefsAnyOf: readonly [];
|
|
1044
1067
|
}];
|
|
1045
1068
|
/** 지금 렌더러가 아는 섹션 타입. 이 밖의 값이 와도 정상이다(스킵). */
|
|
1046
1069
|
type KnownSectionType = (typeof SECTION_CONTRACT)[number]["type"];
|
package/dist/index.d.ts
CHANGED
|
@@ -949,7 +949,7 @@ declare class ZalkeraError extends Error {
|
|
|
949
949
|
* 이 패키지는 그 방언을 읽는 헬퍼([asHandle]·[asHandleArray]·[assetPath]·[readConfig])를 실어 나른다.
|
|
950
950
|
* 그래서 아래 `SECTION_CONTRACT` 리터럴은 rev 3 과 **바이트 동일**하다(동기 스크립트가 확인한다).
|
|
951
951
|
*/
|
|
952
|
-
declare const SECTION_CONTRACT_REV =
|
|
952
|
+
declare const SECTION_CONTRACT_REV = 5;
|
|
953
953
|
/** 업종 분류 — 콘솔 섹션 픽커의 그룹핑에 쓴다(테넌트 업종 필드는 아직 없다·memo102 §5). */
|
|
954
954
|
type SectionVertical = "BEAUTY" | "GENERAL";
|
|
955
955
|
interface SectionSpec {
|
|
@@ -972,6 +972,17 @@ interface SectionSpec {
|
|
|
972
972
|
* **필수성의 집행 지점은 팩/시드뿐이다** — 런타임은 그대로 관용이다(렌더러 스킵·콘솔 raw 편집 허용).
|
|
973
973
|
*/
|
|
974
974
|
readonly requiredRefs: readonly string[];
|
|
975
|
+
/**
|
|
976
|
+
* **참조 그룹**(rev 5) — 각 그룹에서 **하나 이상**이 채워져야 한다.
|
|
977
|
+
*
|
|
978
|
+
* rev 3 은 필수성을 키 하나(`productIds`)에 걸었는데, rev 5 에서 갈래 참조(`categorySlug`)가 같은
|
|
979
|
+
* 역할을 하게 되면서 필수의 단위가 **"참조 존재"**로 옮겨갔다. 막으려는 것은 그대로다 — 아무것도
|
|
980
|
+
* 안 가리킨 채 시드에 들어와 개시 직후 조용히 사라지는 섹션.
|
|
981
|
+
*
|
|
982
|
+
* `requiredRefs`(무조건 필수)와 **함께** 쓴다: 그룹으로 표현되는 섹션은 `requiredRefs` 가 빈 배열이고,
|
|
983
|
+
* 종전처럼 단일 키가 무조건 필수인 섹션은 이 필드가 빈 배열이다. 둘 다 빈 배열이면 참조 요구가 없다.
|
|
984
|
+
*/
|
|
985
|
+
readonly requiredRefsAnyOf: readonly (readonly string[])[];
|
|
975
986
|
}
|
|
976
987
|
/**
|
|
977
988
|
* 아는 섹션 전량. **순서는 콘솔 픽커의 노출 순서**(관행 아크: 주목→가치→신뢰→행동).
|
|
@@ -985,62 +996,74 @@ declare const SECTION_CONTRACT: readonly [{
|
|
|
985
996
|
readonly type: "SERVICE_MENU";
|
|
986
997
|
readonly vertical: "BEAUTY";
|
|
987
998
|
readonly jsonLd: "ItemList";
|
|
988
|
-
readonly requiredRefs: readonly [
|
|
999
|
+
readonly requiredRefs: readonly [];
|
|
1000
|
+
readonly requiredRefsAnyOf: readonly [readonly ["productIds", "categorySlug"]];
|
|
989
1001
|
}, {
|
|
990
1002
|
readonly type: "BEFORE_AFTER_GALLERY";
|
|
991
1003
|
readonly vertical: "BEAUTY";
|
|
992
1004
|
readonly jsonLd: null;
|
|
993
1005
|
readonly requiredRefs: readonly [];
|
|
1006
|
+
readonly requiredRefsAnyOf: readonly [];
|
|
994
1007
|
}, {
|
|
995
1008
|
readonly type: "BOOKING_CTA";
|
|
996
1009
|
readonly vertical: "BEAUTY";
|
|
997
1010
|
readonly jsonLd: null;
|
|
998
|
-
readonly requiredRefs: readonly [
|
|
1011
|
+
readonly requiredRefs: readonly [];
|
|
1012
|
+
readonly requiredRefsAnyOf: readonly [readonly ["productId", "categorySlug"]];
|
|
999
1013
|
}, {
|
|
1000
1014
|
readonly type: "DOCTOR_INTRO";
|
|
1001
1015
|
readonly vertical: "BEAUTY";
|
|
1002
1016
|
readonly jsonLd: null;
|
|
1003
1017
|
readonly requiredRefs: readonly [];
|
|
1018
|
+
readonly requiredRefsAnyOf: readonly [];
|
|
1004
1019
|
}, {
|
|
1005
1020
|
readonly type: "HERO";
|
|
1006
1021
|
readonly vertical: "GENERAL";
|
|
1007
1022
|
readonly jsonLd: null;
|
|
1008
1023
|
readonly requiredRefs: readonly [];
|
|
1024
|
+
readonly requiredRefsAnyOf: readonly [];
|
|
1009
1025
|
}, {
|
|
1010
1026
|
readonly type: "FEATURE_GRID";
|
|
1011
1027
|
readonly vertical: "GENERAL";
|
|
1012
1028
|
readonly jsonLd: null;
|
|
1013
1029
|
readonly requiredRefs: readonly [];
|
|
1030
|
+
readonly requiredRefsAnyOf: readonly [];
|
|
1014
1031
|
}, {
|
|
1015
1032
|
readonly type: "TEXT_MEDIA";
|
|
1016
1033
|
readonly vertical: "GENERAL";
|
|
1017
1034
|
readonly jsonLd: null;
|
|
1018
1035
|
readonly requiredRefs: readonly [];
|
|
1036
|
+
readonly requiredRefsAnyOf: readonly [];
|
|
1019
1037
|
}, {
|
|
1020
1038
|
readonly type: "LOGO_WALL";
|
|
1021
1039
|
readonly vertical: "GENERAL";
|
|
1022
1040
|
readonly jsonLd: null;
|
|
1023
1041
|
readonly requiredRefs: readonly [];
|
|
1042
|
+
readonly requiredRefsAnyOf: readonly [];
|
|
1024
1043
|
}, {
|
|
1025
1044
|
readonly type: "STATS_BAND";
|
|
1026
1045
|
readonly vertical: "GENERAL";
|
|
1027
1046
|
readonly jsonLd: null;
|
|
1028
1047
|
readonly requiredRefs: readonly [];
|
|
1048
|
+
readonly requiredRefsAnyOf: readonly [];
|
|
1029
1049
|
}, {
|
|
1030
1050
|
readonly type: "TESTIMONIALS";
|
|
1031
1051
|
readonly vertical: "GENERAL";
|
|
1032
1052
|
readonly jsonLd: null;
|
|
1033
1053
|
readonly requiredRefs: readonly [];
|
|
1054
|
+
readonly requiredRefsAnyOf: readonly [];
|
|
1034
1055
|
}, {
|
|
1035
1056
|
readonly type: "FAQ_LIST";
|
|
1036
1057
|
readonly vertical: "GENERAL";
|
|
1037
1058
|
readonly jsonLd: "FAQPage";
|
|
1038
1059
|
readonly requiredRefs: readonly [];
|
|
1060
|
+
readonly requiredRefsAnyOf: readonly [];
|
|
1039
1061
|
}, {
|
|
1040
1062
|
readonly type: "LEAD_CTA";
|
|
1041
1063
|
readonly vertical: "GENERAL";
|
|
1042
1064
|
readonly jsonLd: null;
|
|
1043
1065
|
readonly requiredRefs: readonly [];
|
|
1066
|
+
readonly requiredRefsAnyOf: readonly [];
|
|
1044
1067
|
}];
|
|
1045
1068
|
/** 지금 렌더러가 아는 섹션 타입. 이 밖의 값이 와도 정상이다(스킵). */
|
|
1046
1069
|
type KnownSectionType = (typeof SECTION_CONTRACT)[number]["type"];
|
package/dist/index.js
CHANGED
|
@@ -104,15 +104,25 @@ function createZalkeraClient(options) {
|
|
|
104
104
|
if (init?.bearer) headers["Authorization"] = `Bearer ${init.bearer}`;
|
|
105
105
|
if (init?.cartSession) headers["X-Cart-Session"] = init.cartSession;
|
|
106
106
|
if (init?.idempotencyKey) headers["Idempotency-Key"] = init.idempotencyKey;
|
|
107
|
+
const method = init?.method ?? "GET";
|
|
108
|
+
const isRead = method === "GET";
|
|
107
109
|
const controller = new AbortController();
|
|
108
110
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
111
|
+
let timedOut = false;
|
|
112
|
+
const deadline = new Promise((_, reject) => {
|
|
113
|
+
setTimeout(() => {
|
|
114
|
+
timedOut = true;
|
|
115
|
+
reject(new Error("AbortError"));
|
|
116
|
+
}, timeoutMs).unref?.();
|
|
117
|
+
});
|
|
109
118
|
let response;
|
|
110
119
|
try {
|
|
111
120
|
const fetchInit = {
|
|
112
|
-
method
|
|
121
|
+
method,
|
|
113
122
|
headers,
|
|
114
123
|
body: init?.body != null ? JSON.stringify(init.body) : void 0,
|
|
115
|
-
signal
|
|
124
|
+
// 읽기는 위 이유로 signal 을 뺀다(메모이제이션 보존).
|
|
125
|
+
...isRead ? {} : { signal: controller.signal },
|
|
116
126
|
// 리다이렉트를 따라가지 않는다 — **보안 불변식이라 스위치를 두지 않는다**(옵션으로 열면
|
|
117
127
|
// 그 옵션이 곧 사고 경로가 된다). 기본값 `follow` 로 크로스오리진 3xx 를 따라가면
|
|
118
128
|
// `X-Storefront-Key`(테넌트 시크릿)·`X-Tenant`·`X-Cart-Session`·`Idempotency-Key` 가
|
|
@@ -122,9 +132,10 @@ function createZalkeraClient(options) {
|
|
|
122
132
|
redirect: "manual"
|
|
123
133
|
};
|
|
124
134
|
if (init?.next) fetchInit.next = init.next;
|
|
125
|
-
|
|
135
|
+
const call = fetchImpl(url.toString(), fetchInit);
|
|
136
|
+
response = isRead ? await Promise.race([call, deadline]) : await call;
|
|
126
137
|
} catch (cause) {
|
|
127
|
-
const aborted = cause instanceof Error && cause.name === "AbortError";
|
|
138
|
+
const aborted = timedOut || cause instanceof Error && cause.name === "AbortError";
|
|
128
139
|
throw new ZalkeraError(
|
|
129
140
|
aborted ? `\uC694\uCCAD \uC2DC\uAC04\uC774 \uCD08\uACFC\uB418\uC5C8\uC2B5\uB2C8\uB2E4 (${timeoutMs}ms)` : "\uB124\uD2B8\uC6CC\uD06C \uC694\uCCAD\uC774 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.",
|
|
130
141
|
{ status: 0, cause }
|
|
@@ -290,7 +301,7 @@ function safeJsonParse(text) {
|
|
|
290
301
|
}
|
|
291
302
|
|
|
292
303
|
// src/sections.ts
|
|
293
|
-
var SECTION_CONTRACT_REV =
|
|
304
|
+
var SECTION_CONTRACT_REV = 5;
|
|
294
305
|
var SECTION_CONTRACT = [
|
|
295
306
|
// 뷰티(memo47) — append-only 계약상 불변
|
|
296
307
|
// SERVICE_MENU 의 ItemList 는 rev 2 에서 올라왔다(memo119 T6-ⓒ): 쇼핑몰 유형엔 상품 목록 표면을
|
|
@@ -298,19 +309,19 @@ var SECTION_CONTRACT = [
|
|
|
298
309
|
// 정위치는 별도 라우트가 아니라 홈의 이 섹션이라, FAQ_LIST→FAQPage 와 같은 형태로 섹션이 직접 낸다.
|
|
299
310
|
// rev 3 에서 productIds 의 `?` 가 떨어졌다 — 목록을 내겠다고 선언한 섹션이 목록을 안 가리키는 상태가
|
|
300
311
|
// 계약상 성립하지 않게 됐다(BOOKING_CTA.productId 는 rev 1 부터 필수였다·비대칭 해소).
|
|
301
|
-
{ type: "SERVICE_MENU", vertical: "BEAUTY", jsonLd: "ItemList", requiredRefs: ["productIds"] },
|
|
302
|
-
{ type: "BEFORE_AFTER_GALLERY", vertical: "BEAUTY", jsonLd: null, requiredRefs: [] },
|
|
303
|
-
{ type: "BOOKING_CTA", vertical: "BEAUTY", jsonLd: null, requiredRefs: ["productId"] },
|
|
304
|
-
{ type: "DOCTOR_INTRO", vertical: "BEAUTY", jsonLd: null, requiredRefs: [] },
|
|
312
|
+
{ type: "SERVICE_MENU", vertical: "BEAUTY", jsonLd: "ItemList", requiredRefs: [], requiredRefsAnyOf: [["productIds", "categorySlug"]] },
|
|
313
|
+
{ type: "BEFORE_AFTER_GALLERY", vertical: "BEAUTY", jsonLd: null, requiredRefs: [], requiredRefsAnyOf: [] },
|
|
314
|
+
{ type: "BOOKING_CTA", vertical: "BEAUTY", jsonLd: null, requiredRefs: [], requiredRefsAnyOf: [["productId", "categorySlug"]] },
|
|
315
|
+
{ type: "DOCTOR_INTRO", vertical: "BEAUTY", jsonLd: null, requiredRefs: [], requiredRefsAnyOf: [] },
|
|
305
316
|
// 기업 마케팅(memo102 §2)
|
|
306
|
-
{ type: "HERO", vertical: "GENERAL", jsonLd: null, requiredRefs: [] },
|
|
307
|
-
{ type: "FEATURE_GRID", vertical: "GENERAL", jsonLd: null, requiredRefs: [] },
|
|
308
|
-
{ type: "TEXT_MEDIA", vertical: "GENERAL", jsonLd: null, requiredRefs: [] },
|
|
309
|
-
{ type: "LOGO_WALL", vertical: "GENERAL", jsonLd: null, requiredRefs: [] },
|
|
310
|
-
{ type: "STATS_BAND", vertical: "GENERAL", jsonLd: null, requiredRefs: [] },
|
|
311
|
-
{ type: "TESTIMONIALS", vertical: "GENERAL", jsonLd: null, requiredRefs: [] },
|
|
312
|
-
{ type: "FAQ_LIST", vertical: "GENERAL", jsonLd: "FAQPage", requiredRefs: [] },
|
|
313
|
-
{ type: "LEAD_CTA", vertical: "GENERAL", jsonLd: null, requiredRefs: [] }
|
|
317
|
+
{ type: "HERO", vertical: "GENERAL", jsonLd: null, requiredRefs: [], requiredRefsAnyOf: [] },
|
|
318
|
+
{ type: "FEATURE_GRID", vertical: "GENERAL", jsonLd: null, requiredRefs: [], requiredRefsAnyOf: [] },
|
|
319
|
+
{ type: "TEXT_MEDIA", vertical: "GENERAL", jsonLd: null, requiredRefs: [], requiredRefsAnyOf: [] },
|
|
320
|
+
{ type: "LOGO_WALL", vertical: "GENERAL", jsonLd: null, requiredRefs: [], requiredRefsAnyOf: [] },
|
|
321
|
+
{ type: "STATS_BAND", vertical: "GENERAL", jsonLd: null, requiredRefs: [], requiredRefsAnyOf: [] },
|
|
322
|
+
{ type: "TESTIMONIALS", vertical: "GENERAL", jsonLd: null, requiredRefs: [], requiredRefsAnyOf: [] },
|
|
323
|
+
{ type: "FAQ_LIST", vertical: "GENERAL", jsonLd: "FAQPage", requiredRefs: [], requiredRefsAnyOf: [] },
|
|
324
|
+
{ type: "LEAD_CTA", vertical: "GENERAL", jsonLd: null, requiredRefs: [], requiredRefsAnyOf: [] }
|
|
314
325
|
];
|
|
315
326
|
function sectionsOfVertical(vertical) {
|
|
316
327
|
return SECTION_CONTRACT.filter((s) => s.vertical === vertical);
|