@sayren/store-sdk 0.17.0 → 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/dist/index.d.mts +1957 -301
- package/dist/index.mjs +521 -102
- package/package.json +1 -1
- package/src/client.ts +102 -4
- package/src/index.ts +1 -0
- package/src/schemas/fulfillment.ts +431 -0
- package/src/schemas/order.ts +6 -16
- package/src/schemas/product.ts +81 -221
- package/src/schemas/refund-policy.ts +16 -26
- package/src/schemas/scope.ts +3 -0
- package/src/schemas/shipping-policy.ts +1 -2
- package/src/schemas/storefront-hosting.ts +283 -0
- package/src/schemas/webhook-event.ts +16 -14
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { RESERVED_STORE_CODES } from "./store";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 스토어프론트 호스팅 (이슈 #53, M1: 템플릿 발행) — 관리 API `/v1/storefront/**`의 계약이다.
|
|
6
|
+
*
|
|
7
|
+
* 셀러는 템플릿을 골라 사이트를 만들고 `{slug}.{호스팅 도메인}` 주소를 받는다. 발행은 버전 단위이고,
|
|
8
|
+
* 되돌리기는 이전 버전을 다시 발행하는 것이다(재빌드 없음). 상태의 원천은 api DB이고 Cloudflare 쪽 반영
|
|
9
|
+
* (라우팅 표·사이트 Worker)은 커밋 뒤 비동기다 — 반영 상태는 `provisioning`으로 본다.
|
|
10
|
+
*
|
|
11
|
+
* 스코프는 조회 `storefront:r`, 쓰기 `storefront:rw`(역할 OWNER·ADMIN)다. 에이전트(MCP)의 발행·되돌리기·템플릿 변경·
|
|
12
|
+
* 공개 전환·슬러그 변경·호스팅 끄기는 승인(`APPROVAL_REQUIRED`)이다 — 구매자가 보는 화면을 바꾸는 쓰기다.
|
|
13
|
+
*
|
|
14
|
+
* 오류 코드:
|
|
15
|
+
* - 403 `STOREFRONT_HOSTING_DISABLED` — 플랫폼 스위치가 꺼져 새 사이트를 만들 수 없다
|
|
16
|
+
* - 404 `STOREFRONT_SITE_NOT_FOUND` · `STOREFRONT_TEMPLATE_NOT_FOUND` · `STOREFRONT_VERSION_NOT_FOUND`
|
|
17
|
+
* - 409 `STOREFRONT_SITE_EXISTS` — 이미 사이트가 있다(스토어당 1개)
|
|
18
|
+
* - 409 `STOREFRONT_SLUG_TAKEN` — 다른 사이트가 쓰거나 보류 중인 슬러그다
|
|
19
|
+
* - 409 `STOREFRONT_SLUG_CHANGE_LIMIT` — 슬러그는 스토어당 30일에 3번까지 바꾼다
|
|
20
|
+
* - 409 `STOREFRONT_SITE_CREATE_LIMIT` — 사이트는 스토어당 30일에 3번까지 만든다
|
|
21
|
+
* - 409 `STOREFRONT_SITE_CHANGED` — 읽은 상태(`expected*`)와 현재 상태가 다르다. 다시 읽고 시도한다
|
|
22
|
+
* - 409 `STOREFRONT_SITE_NOT_ACTIVE` — 정지(`SUSPENDED`)된 사이트는 바꾸거나 끌 수 없다
|
|
23
|
+
* - 409 `STOREFRONT_VERSION_NOT_READY` — 빌드가 끝나지 않았거나 실패한 버전은 발행할 수 없다
|
|
24
|
+
* - 409 `STOREFRONT_NO_ROLLBACK_TARGET` — 되돌릴 이전 발행 버전이 없다
|
|
25
|
+
* - 400 `STOREFRONT_SLUG_CONFIRM_MISMATCH` — 호스팅 끄기 확인 입력이 현재 슬러그와 다르다
|
|
26
|
+
* - 503 `STOREFRONT_PREVIEW_NOT_CONFIGURED` — 미리보기 서명 키가 설정되지 않았다
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
// ─── 슬러그 ───────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 슬러그 형식 — 스토어 코드와 같은 DNS 라벨 규칙(소문자·숫자·하이픈 3~30자, 하이픈으로 시작·끝 불가)에
|
|
33
|
+
* 연속 하이픈 금지를 더한다. `--`는 버전 미리보기 주소(`v3--{slug}`)와 punycode(`xn--`)가 쓰는 구분자다.
|
|
34
|
+
*/
|
|
35
|
+
export const STOREFRONT_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]{1,28}[a-z0-9])$/;
|
|
36
|
+
|
|
37
|
+
/** 호스팅 도메인에서 플랫폼이 쓰거나 쓸 이름 — 스토어 코드 예약어에 호스팅 전용 이름을 더한다 */
|
|
38
|
+
export const RESERVED_STOREFRONT_SLUGS: readonly string[] = [
|
|
39
|
+
...RESERVED_STORE_CODES,
|
|
40
|
+
"mcp",
|
|
41
|
+
"preview",
|
|
42
|
+
"previews",
|
|
43
|
+
"sayren",
|
|
44
|
+
"shop",
|
|
45
|
+
"shops",
|
|
46
|
+
"abuse",
|
|
47
|
+
"security",
|
|
48
|
+
"closed",
|
|
49
|
+
"coming-soon",
|
|
50
|
+
"suspended",
|
|
51
|
+
"dispatch",
|
|
52
|
+
"control",
|
|
53
|
+
"outbound",
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
export function isReservedStorefrontSlug(slug: string): boolean {
|
|
57
|
+
return RESERVED_STOREFRONT_SLUGS.includes(slug.toLowerCase());
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export const storefrontSlugSchema = z
|
|
61
|
+
.string()
|
|
62
|
+
.regex(
|
|
63
|
+
STOREFRONT_SLUG_PATTERN,
|
|
64
|
+
"소문자·숫자·하이픈 3~30자여야 하고 하이픈으로 시작하거나 끝날 수 없습니다",
|
|
65
|
+
)
|
|
66
|
+
.refine((slug) => !slug.includes("--"), "하이픈을 연달아 쓸 수 없습니다")
|
|
67
|
+
.refine((slug) => !isReservedStorefrontSlug(slug), "플랫폼이 쓰는 이름이라 쓸 수 없습니다")
|
|
68
|
+
.describe("주소 슬러그. `{slug}.{호스팅 도메인}`이 사이트 주소가 된다");
|
|
69
|
+
|
|
70
|
+
/** 바꾼 슬러그를 다른 사이트가 가져가지 못하게 막는 기간(일). 보류 동안 옛 주소는 새 주소로 301한다 */
|
|
71
|
+
export const STOREFRONT_SLUG_HOLD_DAYS = 90;
|
|
72
|
+
/** 슬러그 변경 한도 — 이 기간(일) 안에 */
|
|
73
|
+
export const STOREFRONT_SLUG_CHANGE_WINDOW_DAYS = 30;
|
|
74
|
+
/** 슬러그 변경 한도 — 횟수(스토어 단위. 끄고 다시 만들어도 이어서 센다) */
|
|
75
|
+
export const STOREFRONT_SLUG_CHANGE_LIMIT = 3;
|
|
76
|
+
/** 사이트 만들기 한도 — 같은 창(30일) 안의 횟수(스토어 단위). 끄고 만들기를 되풀이해 이름을 묶어 두지 못하게 한다 */
|
|
77
|
+
export const STOREFRONT_SITE_CREATE_LIMIT = 3;
|
|
78
|
+
|
|
79
|
+
// ─── 템플릿 ───────────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
export const storefrontTemplateSchema = z.object({
|
|
82
|
+
templateId: z.string().describe("템플릿 id (예: `basic`)"),
|
|
83
|
+
name: z.string().describe("템플릿 이름"),
|
|
84
|
+
industry: z.string().describe("업종 (예: `general`·`fashion`·`food`). 목록 필터에 쓴다"),
|
|
85
|
+
description: z.string().describe("템플릿 설명"),
|
|
86
|
+
thumbnailUrl: z.string().nullable().describe("썸네일 이미지 주소. 없으면 null"),
|
|
87
|
+
version: z.string().describe("현재 템플릿 버전. 새 사이트·템플릿 변경은 이 버전으로 만든다"),
|
|
88
|
+
isDefault: z.boolean().describe("기본 템플릿인가 (스토어 생성 시 자동 생성에 쓴다)"),
|
|
89
|
+
});
|
|
90
|
+
export type StorefrontTemplate = z.infer<typeof storefrontTemplateSchema>;
|
|
91
|
+
|
|
92
|
+
// ─── 버전 ─────────────────────────────────────────────────
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 버전 상태 — M1은 템플릿 빌드 산출물을 그대로 쓰므로 만들 때 곧바로 `READY`다. `BUILDING`·`FAILED`는
|
|
96
|
+
* 셀러 편집 빌드(M2)가 쓴다. 발행 여부는 상태가 아니라 사이트의 발행 포인터가 원천이다(`published`).
|
|
97
|
+
*/
|
|
98
|
+
export const storefrontVersionStatusSchema = z
|
|
99
|
+
.enum(["BUILDING", "READY", "FAILED"])
|
|
100
|
+
.describe("`BUILDING` 빌드 중 · `READY` 발행 가능 · `FAILED` 빌드 실패");
|
|
101
|
+
export type StorefrontVersionStatus = z.infer<typeof storefrontVersionStatusSchema>;
|
|
102
|
+
|
|
103
|
+
export const storefrontVersionSchema = z.object({
|
|
104
|
+
versionId: z.string(),
|
|
105
|
+
number: z.number().int().min(1).describe("사이트 안에서 1부터 늘어나는 번호 (v1, v2…)"),
|
|
106
|
+
templateId: z.string().describe("이 버전의 기준 템플릿"),
|
|
107
|
+
templateVersion: z.string().describe("이 버전의 기준 템플릿 버전"),
|
|
108
|
+
status: storefrontVersionStatusSchema,
|
|
109
|
+
published: z.boolean().describe("지금 발행된 버전인가"),
|
|
110
|
+
publishedAt: z
|
|
111
|
+
.string()
|
|
112
|
+
.nullable()
|
|
113
|
+
.describe("마지막으로 발행한 시각 (ISO 8601). 발행한 적 없으면 null"),
|
|
114
|
+
message: z.string().nullable().describe("버전 메모"),
|
|
115
|
+
createdByType: z
|
|
116
|
+
.string()
|
|
117
|
+
.describe("만든 행위자 유형 (`USER`·`AGENT`·`APP`·`TOKEN`·`SYSTEM`). 늘어날 수 있다"),
|
|
118
|
+
createdAt: z.string().describe("만든 시각 (ISO 8601)"),
|
|
119
|
+
});
|
|
120
|
+
export type StorefrontVersion = z.infer<typeof storefrontVersionSchema>;
|
|
121
|
+
|
|
122
|
+
// ─── 사이트 ───────────────────────────────────────────────
|
|
123
|
+
|
|
124
|
+
export const storefrontSiteStatusSchema = z
|
|
125
|
+
.enum(["ACTIVE", "SUSPENDED", "CLOSED"])
|
|
126
|
+
.describe("`ACTIVE` 운영 중 · `SUSPENDED` 운영자 정지 · `CLOSED` 호스팅 끔·스토어 폐쇄");
|
|
127
|
+
export type StorefrontSiteStatus = z.infer<typeof storefrontSiteStatusSchema>;
|
|
128
|
+
|
|
129
|
+
export const storefrontVisibilitySchema = z
|
|
130
|
+
.enum(["COMING_SOON", "PUBLIC"])
|
|
131
|
+
.describe("`COMING_SOON` 오픈 준비 중(방문자에게 준비 중 페이지) · `PUBLIC` 공개");
|
|
132
|
+
export type StorefrontVisibility = z.infer<typeof storefrontVisibilitySchema>;
|
|
133
|
+
|
|
134
|
+
export const storefrontSourceModeSchema = z
|
|
135
|
+
.enum(["MANAGED", "CUSTOM"])
|
|
136
|
+
.describe("`MANAGED` 템플릿 그대로 · `CUSTOM` 한 번이라도 편집함");
|
|
137
|
+
|
|
138
|
+
export const storefrontDomainSchema = z.object({
|
|
139
|
+
hostname: z.string().describe("호스트 이름 (예: `mystore.sayren.co`)"),
|
|
140
|
+
kind: z.enum(["PLATFORM", "CUSTOM"]).describe("`PLATFORM` 슬러그 주소 · `CUSTOM` 내 도메인"),
|
|
141
|
+
status: z
|
|
142
|
+
.enum(["ACTIVE", "HELD"])
|
|
143
|
+
.describe("`ACTIVE` 사용 중 · `HELD` 슬러그를 바꿔 보류 중(새 주소로 301)"),
|
|
144
|
+
isPrimary: z.boolean().describe("대표 주소인가 (`Store.storefrontUrl`)"),
|
|
145
|
+
holdUntil: z.string().nullable().describe("보류가 끝나는 시각 (ISO 8601). 보류가 아니면 null"),
|
|
146
|
+
});
|
|
147
|
+
export type StorefrontDomain = z.infer<typeof storefrontDomainSchema>;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* 호스팅 반영 상태 — 발행·슬러그·공개 전환은 DB에 먼저 확정되고 Cloudflare 반영은 커밋 뒤에 한다.
|
|
151
|
+
* `PENDING`이면 반영 중이거나 재시도 대기다(잡이 다시 한다). 반영 뒤에도 라우팅 전파에 최대 1분이 걸린다.
|
|
152
|
+
*/
|
|
153
|
+
export const storefrontProvisioningSchema = z.object({
|
|
154
|
+
status: z
|
|
155
|
+
.enum(["SYNCED", "PENDING", "FAILED"])
|
|
156
|
+
.describe(
|
|
157
|
+
"`SYNCED` 반영됨 · `PENDING` 반영 대기 · `FAILED` 반영이 여러 번 실패함(자동 재시도는 계속한다)",
|
|
158
|
+
),
|
|
159
|
+
lastErrorCode: z.string().nullable().describe("마지막 반영 실패 코드. 없으면 null"),
|
|
160
|
+
syncedAt: z.string().nullable().describe("마지막으로 반영한 시각 (ISO 8601)"),
|
|
161
|
+
});
|
|
162
|
+
export type StorefrontProvisioning = z.infer<typeof storefrontProvisioningSchema>;
|
|
163
|
+
|
|
164
|
+
export const storefrontSiteSchema = z.object({
|
|
165
|
+
siteId: z.string(),
|
|
166
|
+
slug: z.string().describe("주소 슬러그"),
|
|
167
|
+
hostname: z.string().describe("대표 호스트 이름"),
|
|
168
|
+
url: z.string().describe("대표 주소 (`https://{hostname}`)"),
|
|
169
|
+
domains: z.array(storefrontDomainSchema).describe("사용 중·보류 중인 호스트 이름"),
|
|
170
|
+
templateId: z.string().describe("지금 발행된 버전의 템플릿 (발행 전이면 만든 템플릿)"),
|
|
171
|
+
sourceMode: storefrontSourceModeSchema,
|
|
172
|
+
status: storefrontSiteStatusSchema,
|
|
173
|
+
visibility: storefrontVisibilitySchema,
|
|
174
|
+
publishedVersion: storefrontVersionSchema.nullable().describe("지금 발행된 버전"),
|
|
175
|
+
provisioning: storefrontProvisioningSchema,
|
|
176
|
+
slugChangesRemaining: z
|
|
177
|
+
.number()
|
|
178
|
+
.int()
|
|
179
|
+
.min(0)
|
|
180
|
+
.describe(`최근 ${STOREFRONT_SLUG_CHANGE_WINDOW_DAYS}일 기준 남은 슬러그 변경 횟수`),
|
|
181
|
+
createdAt: z.string(),
|
|
182
|
+
updatedAt: z.string(),
|
|
183
|
+
});
|
|
184
|
+
export type StorefrontSite = z.infer<typeof storefrontSiteSchema>;
|
|
185
|
+
|
|
186
|
+
/** `GET /v1/storefront/site` — 스위치 상태와 현재 사이트(없으면 null. 끈 사이트는 싣지 않는다) */
|
|
187
|
+
export const storefrontHostingSchema = z.object({
|
|
188
|
+
enabled: z.boolean().describe("새 사이트를 만들 수 있는가 (플랫폼 스위치)"),
|
|
189
|
+
domain: z.string().describe("호스팅 도메인 (예: `sayren.co`). 사이트 주소는 `{slug}.{domain}`"),
|
|
190
|
+
site: storefrontSiteSchema.nullable(),
|
|
191
|
+
});
|
|
192
|
+
export type StorefrontHosting = z.infer<typeof storefrontHostingSchema>;
|
|
193
|
+
|
|
194
|
+
export const storefrontSlugAvailabilitySchema = z.object({
|
|
195
|
+
slug: z.string(),
|
|
196
|
+
available: z.boolean(),
|
|
197
|
+
reason: z
|
|
198
|
+
.enum(["INVALID", "RESERVED", "TAKEN", "CURRENT"])
|
|
199
|
+
.nullable()
|
|
200
|
+
.describe(
|
|
201
|
+
"쓸 수 없는 이유. `INVALID` 형식 · `RESERVED` 예약어 · `TAKEN` 사용·보류 중 · `CURRENT` 지금 내 슬러그",
|
|
202
|
+
),
|
|
203
|
+
});
|
|
204
|
+
export type StorefrontSlugAvailability = z.infer<typeof storefrontSlugAvailabilitySchema>;
|
|
205
|
+
|
|
206
|
+
// ─── 요청 ─────────────────────────────────────────────────
|
|
207
|
+
|
|
208
|
+
export const createStorefrontSiteRequestSchema = z.object({
|
|
209
|
+
templateId: z.string().min(1).max(64).describe("템플릿 id"),
|
|
210
|
+
slug: storefrontSlugSchema.optional().describe("주소 슬러그. 생략하면 스토어 코드"),
|
|
211
|
+
});
|
|
212
|
+
export type CreateStorefrontSiteRequest = z.infer<typeof createStorefrontSiteRequestSchema>;
|
|
213
|
+
|
|
214
|
+
export const changeStorefrontTemplateRequestSchema = z.object({
|
|
215
|
+
templateId: z.string().min(1).max(64).describe("바꿀 템플릿 id"),
|
|
216
|
+
publish: z
|
|
217
|
+
.boolean()
|
|
218
|
+
.optional()
|
|
219
|
+
.describe("새 버전을 곧바로 발행하는가 (기본 true). false면 버전만 만든다"),
|
|
220
|
+
message: z.string().max(200).optional().describe("버전 메모"),
|
|
221
|
+
});
|
|
222
|
+
export type ChangeStorefrontTemplateRequest = z.infer<typeof changeStorefrontTemplateRequestSchema>;
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* 발행·되돌리기 — 발행은 사이트의 발행 포인터를 바꾸는 조건부 쓰기다. `expectedPublishedVersionId`를 주면
|
|
226
|
+
* 지금 발행 버전이 그 값일 때만 바꾼다(화면을 본 뒤 다른 사람이 바꿨으면 409 `STOREFRONT_SITE_CHANGED`).
|
|
227
|
+
* 이미 그 버전이 발행돼 있으면 아무것도 바꾸지 않고 200이다(같은 요청의 재실행이 안전하다).
|
|
228
|
+
*/
|
|
229
|
+
export const publishStorefrontVersionRequestSchema = z.object({
|
|
230
|
+
expectedPublishedVersionId: z
|
|
231
|
+
.string()
|
|
232
|
+
.nullable()
|
|
233
|
+
.optional()
|
|
234
|
+
.describe("화면에서 본 발행 버전 id (발행 전이었으면 null). 생략하면 확인하지 않는다"),
|
|
235
|
+
});
|
|
236
|
+
export type PublishStorefrontVersionRequest = z.infer<typeof publishStorefrontVersionRequestSchema>;
|
|
237
|
+
|
|
238
|
+
export const rollbackStorefrontRequestSchema = z.object({
|
|
239
|
+
versionId: z.string().optional().describe("되돌릴 버전. 생략하면 지금 버전 직전에 발행했던 버전"),
|
|
240
|
+
expectedPublishedVersionId: z.string().nullable().optional(),
|
|
241
|
+
});
|
|
242
|
+
export type RollbackStorefrontRequest = z.infer<typeof rollbackStorefrontRequestSchema>;
|
|
243
|
+
|
|
244
|
+
export const changeStorefrontSlugRequestSchema = z.object({
|
|
245
|
+
slug: storefrontSlugSchema,
|
|
246
|
+
});
|
|
247
|
+
export type ChangeStorefrontSlugRequest = z.infer<typeof changeStorefrontSlugRequestSchema>;
|
|
248
|
+
|
|
249
|
+
export const setStorefrontVisibilityRequestSchema = z.object({
|
|
250
|
+
visibility: storefrontVisibilitySchema,
|
|
251
|
+
expectedVisibility: storefrontVisibilitySchema
|
|
252
|
+
.optional()
|
|
253
|
+
.describe("화면에서 본 공개 상태. 주면 지금 값이 같을 때만 바꾼다"),
|
|
254
|
+
});
|
|
255
|
+
export type SetStorefrontVisibilityRequest = z.infer<typeof setStorefrontVisibilityRequestSchema>;
|
|
256
|
+
|
|
257
|
+
/** 호스팅 끄기 — 사이트를 닫고(`CLOSED`) 슬러그를 보류한다. 확인 입력은 현재 슬러그다 */
|
|
258
|
+
export const disableStorefrontHostingRequestSchema = z.object({
|
|
259
|
+
confirmSlug: z.string().min(1).describe("확인 입력 — 현재 슬러그"),
|
|
260
|
+
});
|
|
261
|
+
export type DisableStorefrontHostingRequest = z.infer<typeof disableStorefrontHostingRequestSchema>;
|
|
262
|
+
|
|
263
|
+
export const storefrontSlugAvailabilityQuerySchema = z.object({
|
|
264
|
+
slug: z.string().describe("확인할 슬러그"),
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* 오픈 준비 중 미리보기 링크 — 콘솔에서 로그인한 OWNER·ADMIN만 받는다(PAT·에이전트 불가). 링크는 5분 안에 한 번 열면
|
|
269
|
+
* 그 브라우저에 12시간짜리 미리보기 쿠키가 생기고 오픈 준비 중인 사이트의 실제 화면을 본다. 링크를 남에게 넘기면 그 사람도
|
|
270
|
+
* 볼 수 있으므로 공유하지 않는다.
|
|
271
|
+
*/
|
|
272
|
+
export const createStorefrontPreviewLinkRequestSchema = z.object({
|
|
273
|
+
path: z.string().max(512).optional().describe("열 경로 (`/`로 시작). 생략하면 `/`"),
|
|
274
|
+
});
|
|
275
|
+
export type CreateStorefrontPreviewLinkRequest = z.infer<
|
|
276
|
+
typeof createStorefrontPreviewLinkRequestSchema
|
|
277
|
+
>;
|
|
278
|
+
|
|
279
|
+
export const storefrontPreviewLinkSchema = z.object({
|
|
280
|
+
url: z.string().describe("미리보기 링크 — 5분 안에 연다"),
|
|
281
|
+
expiresAt: z.string().describe("링크 만료 시각 (ISO 8601)"),
|
|
282
|
+
});
|
|
283
|
+
export type StorefrontPreviewLink = z.infer<typeof storefrontPreviewLinkSchema>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { claimStatusSchema, claimTypeSchema } from "./claim";
|
|
3
3
|
import { orderItemStatusSchema } from "./common";
|
|
4
|
+
import { orderItemFulfillmentSnapshotResponseSchema } from "./fulfillment";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* 웹훅 발송 형식 (공개 계약). 본문은 얇은 이벤트다. 개인정보를 싣지 않으며
|
|
@@ -59,13 +60,11 @@ export const orderWebhookEventDataSchema = z.object({
|
|
|
59
60
|
"이벤트를 만든 주문상품 ID. 비실물 상품 제공으로 보내는 `ORDER.DELIVERED`에만 실린다. " +
|
|
60
61
|
"택배 배송완료와 그 밖의 주문 이벤트에는 없다",
|
|
61
62
|
),
|
|
62
|
-
|
|
63
|
-
.string()
|
|
63
|
+
fulfillmentSnapshot: orderItemFulfillmentSnapshotResponseSchema
|
|
64
64
|
.optional()
|
|
65
65
|
.describe(
|
|
66
|
-
"이벤트를 만든 주문상품의
|
|
67
|
-
"
|
|
68
|
-
"비실물 제공이 아닌 이벤트에는 없고, 없으면 `SHIPPING`으로 읽는다",
|
|
66
|
+
"이벤트를 만든 주문상품의 주문 시점 이행 스냅샷(주문상품 응답의 `fulfillmentSnapshot`과 같다, 이슈 #57). " +
|
|
67
|
+
"비실물 상품의 제공 완료는 `ORDER.DELIVERED`로도 오고 `type`이 `SHIPPING`이 아니다. `orderItemId`가 있는 이벤트에만 실린다",
|
|
69
68
|
),
|
|
70
69
|
});
|
|
71
70
|
export type OrderWebhookEventData = z.infer<typeof orderWebhookEventDataSchema>;
|
|
@@ -79,15 +78,18 @@ export const orderFulfilledWebhookEventDataSchema = z.object({
|
|
|
79
78
|
orderId: z.string().describe("주문 ID"),
|
|
80
79
|
orderItemId: z.string().describe("제공한 주문상품 ID"),
|
|
81
80
|
status: orderItemStatusSchema.describe("이벤트 발생 시점의 주문 대표 상태"),
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
81
|
+
fulfillmentSnapshot: orderItemFulfillmentSnapshotResponseSchema.describe(
|
|
82
|
+
"제공한 주문상품의 주문 시점 이행 스냅샷(주문상품 응답의 `fulfillmentSnapshot`과 같다, 이슈 #57)",
|
|
83
|
+
),
|
|
84
|
+
fulfillment: z
|
|
85
|
+
.object({
|
|
86
|
+
mode: z
|
|
87
|
+
.string()
|
|
88
|
+
.describe(
|
|
89
|
+
"실제 제공 방식. `AUTO`(결제 확정과 함께)·`MANUAL`(셀러 제공 처리). 주문상품 제공 기록의 `mode`와 같다",
|
|
90
|
+
),
|
|
91
|
+
})
|
|
92
|
+
.describe("제공 기록"),
|
|
91
93
|
fulfilledAt: z.string().describe("제공 시각 (ISO 8601). 주문상품의 `deliveredAt`과 같다"),
|
|
92
94
|
testPayment: z
|
|
93
95
|
.boolean()
|