@sayren/store-sdk 0.30.0 → 0.30.2
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 +690 -61
- package/dist/index.mjs +220 -9
- package/package.json +1 -1
- package/src/client.ts +98 -0
- package/src/schemas/commerce-flow.ts +253 -1
- package/src/schemas/misc.ts +2 -0
- package/src/schemas/order.ts +10 -0
- package/src/schemas/webhook-event.ts +26 -0
|
@@ -10,9 +10,14 @@ import { orderItemStatusSchema } from "./common";
|
|
|
10
10
|
|
|
11
11
|
export const flowInputFieldSchema = z.object({
|
|
12
12
|
key: z.string(),
|
|
13
|
-
type: z
|
|
13
|
+
type: z
|
|
14
|
+
.string()
|
|
15
|
+
.describe(
|
|
16
|
+
"text · textarea · number · select · radio · checkbox · boolean · date · datetime · image (늘어날 수 있다). 값: checkbox는 고른 선택지 배열, boolean은 참거짓(필수면 true), date는 `YYYY-MM-DD`, datetime은 오프셋 있는 ISO 8601, image는 https 주소 배열",
|
|
17
|
+
),
|
|
14
18
|
required: z.boolean(),
|
|
15
19
|
label: z.string(),
|
|
20
|
+
placeholder: z.string().optional().describe("입력 안내"),
|
|
16
21
|
maxLength: z.number().int().optional(),
|
|
17
22
|
maxFiles: z.number().int().optional(),
|
|
18
23
|
options: z.array(z.union([z.string(), z.number()])).optional(),
|
|
@@ -62,6 +67,20 @@ export const flowStateSchema = z.object({
|
|
|
62
67
|
.array(z.string())
|
|
63
68
|
.optional()
|
|
64
69
|
.describe("가장 최근 행동이 붙인 첨부 주소(시안 등, #115). 없으면 생략"),
|
|
70
|
+
inputs: z
|
|
71
|
+
.object({
|
|
72
|
+
by: z.string().describe("적은 사람 — seller · buyer"),
|
|
73
|
+
values: z.array(
|
|
74
|
+
z.object({
|
|
75
|
+
key: z.string(),
|
|
76
|
+
label: z.string(),
|
|
77
|
+
type: z.string(),
|
|
78
|
+
value: z.union([z.string(), z.number(), z.boolean(), z.array(z.string())]),
|
|
79
|
+
}),
|
|
80
|
+
),
|
|
81
|
+
})
|
|
82
|
+
.optional()
|
|
83
|
+
.describe("이 상태로 오게 한 행동의 입력값(수정 내용 등, #115). 없으면 생략"),
|
|
65
84
|
progress: z.boolean().optional().describe("진행 단계 표시에 넣는 상태인가"),
|
|
66
85
|
fields: z.record(z.string(), flowFieldValueSchema).describe("보는 사람 공개 범위의 커스텀 필드"),
|
|
67
86
|
});
|
|
@@ -76,9 +95,63 @@ export const orderItemFlowSchema = z.object({
|
|
|
76
95
|
.array(z.object({ key: z.string(), dueAt: z.string(), paused: z.boolean() }))
|
|
77
96
|
.describe("걸린 타이머(셀러 보기)"),
|
|
78
97
|
ended: z.boolean(),
|
|
98
|
+
moveTargets: z
|
|
99
|
+
.array(
|
|
100
|
+
z.object({
|
|
101
|
+
key: z.string(),
|
|
102
|
+
label: z.string().describe("셀러용 상태 이름"),
|
|
103
|
+
coreStatus: orderItemStatusSchema.nullable(),
|
|
104
|
+
}),
|
|
105
|
+
)
|
|
106
|
+
.optional()
|
|
107
|
+
.describe("상태 직접 이동으로 옮길 수 있는 상태(셀러 보기). 흐름이 끝났으면 빈 배열"),
|
|
108
|
+
branches: z
|
|
109
|
+
.array(flowStateSchema)
|
|
110
|
+
.optional()
|
|
111
|
+
.describe(
|
|
112
|
+
"활성 위치가 둘 이상(병렬 가지·하위 흐름)이면 각 위치의 상태. `flowState`는 그 가운데 가장 앞 단계다",
|
|
113
|
+
),
|
|
79
114
|
});
|
|
80
115
|
export type OrderItemFlow = z.infer<typeof orderItemFlowSchema>;
|
|
81
116
|
|
|
117
|
+
/** 상태 직접 이동(#115) — 연결선을 지나지 않고 다른 상태로 옮긴다. 블록(재고·환불·송장)은 실행하지 않는다 */
|
|
118
|
+
export const moveFlowStateRequestSchema = z.object({
|
|
119
|
+
to: z.string().min(1).describe("옮길 상태 키(`moveTargets[].key`)"),
|
|
120
|
+
reason: z.string().trim().max(200).optional().describe("옮긴 사유(실행 기록에 남는다)"),
|
|
121
|
+
});
|
|
122
|
+
export type MoveFlowStateRequest = z.infer<typeof moveFlowStateRequestSchema>;
|
|
123
|
+
|
|
124
|
+
export const flowRunStepSchema = z.object({
|
|
125
|
+
step: z.number().int(),
|
|
126
|
+
block: z.string().describe("실행한 블록 종류"),
|
|
127
|
+
edgeId: z.string(),
|
|
128
|
+
status: z.string(),
|
|
129
|
+
output: z.record(z.string(), z.unknown()).nullable(),
|
|
130
|
+
at: z.string(),
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
/** 흐름 실행 기록 — 사건 하나가 일으킨 전이(시작·행동·사건·시간·이동·취소) */
|
|
134
|
+
export const flowRunSchema = z.object({
|
|
135
|
+
runId: z.string(),
|
|
136
|
+
orderItemId: z.string().optional().describe("조회한 주문상품(묶음 진행이면 그 묶음의 하나)"),
|
|
137
|
+
trigger: z
|
|
138
|
+
.record(z.string(), z.unknown())
|
|
139
|
+
.describe(
|
|
140
|
+
"일으킨 사건 — `type`: start · seller.action · buyer.action · event · timer · move (늘어날 수 있다)",
|
|
141
|
+
),
|
|
142
|
+
status: z.string(),
|
|
143
|
+
fromState: z.string().nullable(),
|
|
144
|
+
fromLabel: z.string().nullable().describe("이전 상태의 셀러용 이름"),
|
|
145
|
+
toState: z.string(),
|
|
146
|
+
toLabel: z.string().describe("새 상태의 셀러용 이름"),
|
|
147
|
+
path: z.array(z.string()).describe("지나간 연결선"),
|
|
148
|
+
error: z.unknown().nullable(),
|
|
149
|
+
startedAt: z.string(),
|
|
150
|
+
finishedAt: z.string().nullable(),
|
|
151
|
+
steps: z.array(flowRunStepSchema).describe("실행한 블록(차례대로)"),
|
|
152
|
+
});
|
|
153
|
+
export type FlowRun = z.infer<typeof flowRunSchema>;
|
|
154
|
+
|
|
82
155
|
export const flowActionRequestSchema = z.object({
|
|
83
156
|
input: z.record(z.string(), z.unknown()).optional().describe("행동 입력 — 행동의 `input` 폼 키"),
|
|
84
157
|
});
|
|
@@ -151,10 +224,45 @@ export const commerceFlowSchema = commerceFlowSummarySchema.extend({
|
|
|
151
224
|
version: z.number().int(),
|
|
152
225
|
status: z.enum(["DRAFT", "ACTIVE", "LEGACY"]),
|
|
153
226
|
publishedAt: z.string().nullable(),
|
|
227
|
+
inProgress: z
|
|
228
|
+
.number()
|
|
229
|
+
.int()
|
|
230
|
+
.optional()
|
|
231
|
+
.describe(
|
|
232
|
+
"이 버전을 따르는 진행 중 주문상품 흐름 수(묶음 진행은 묶음 하나가 1). 서버는 항상 싣는다",
|
|
233
|
+
),
|
|
154
234
|
}),
|
|
155
235
|
),
|
|
156
236
|
});
|
|
157
237
|
export type CommerceFlow = z.infer<typeof commerceFlowSchema>;
|
|
238
|
+
export type CommerceFlowVersionView = z.infer<typeof commerceFlowVersionViewSchema>;
|
|
239
|
+
|
|
240
|
+
/** 진행 중 주문을 활성 버전으로 옮기기(#115) — 한 번에 `limit`개까지. 남으면 다시 부른다 */
|
|
241
|
+
export const migrateFlowVersionRequestSchema = z.object({
|
|
242
|
+
limit: z.number().int().min(1).max(500).optional().describe("한 번에 옮길 흐름 수(기본 100)"),
|
|
243
|
+
});
|
|
244
|
+
export type MigrateFlowVersionRequest = z.infer<typeof migrateFlowVersionRequestSchema>;
|
|
245
|
+
|
|
246
|
+
export const migrateFlowVersionResultSchema = z.object({
|
|
247
|
+
fromVersion: z.number().int(),
|
|
248
|
+
toVersion: z.number().int(),
|
|
249
|
+
migrated: z.number().int().describe("옮긴 흐름 수"),
|
|
250
|
+
skipped: z
|
|
251
|
+
.array(
|
|
252
|
+
z.object({
|
|
253
|
+
orderItemIds: z.array(z.string()),
|
|
254
|
+
state: z.string(),
|
|
255
|
+
reason: z
|
|
256
|
+
.string()
|
|
257
|
+
.describe(
|
|
258
|
+
"STATE_MISSING 새 버전에 같은 상태가 없음 · CHILD_ACTIVE 진행 중 클레임 · EXTERNAL_PENDING 외부 API 응답 대기 (늘어날 수 있다)",
|
|
259
|
+
),
|
|
260
|
+
}),
|
|
261
|
+
)
|
|
262
|
+
.describe("이번에 옮기지 못한 흐름(그 버전에 남는다)"),
|
|
263
|
+
remaining: z.number().int().describe("아직 이 버전에 남은 진행 중 흐름 수(건너뛴 것 포함)"),
|
|
264
|
+
});
|
|
265
|
+
export type MigrateFlowVersionResult = z.infer<typeof migrateFlowVersionResultSchema>;
|
|
158
266
|
|
|
159
267
|
export const createCommerceFlowRequestSchema = z.object({
|
|
160
268
|
key: z
|
|
@@ -228,3 +336,147 @@ export const saveFlowSecretRequestSchema = z.object({
|
|
|
228
336
|
.describe("함께 보낼 헤더(인증 등). 값은 암호화해 두고 다시 보여 주지 않는다"),
|
|
229
337
|
});
|
|
230
338
|
export type SaveFlowSecretRequest = z.input<typeof saveFlowSecretRequestSchema>;
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* 주문 전체 행동 결과(#115) — 같은 행동을 주문의 주문상품마다 실행한다. 한 주문상품의 실패가 다른 주문상품을 되돌리지 않는다(부분 실행).
|
|
342
|
+
* 묶음 진행이면 한 번 실행이 묶음의 주문상품을 함께 움직인다(COMPLETED로 함께 나온다). 그 행동이 없는 주문상품은 SKIPPED다
|
|
343
|
+
*/
|
|
344
|
+
export const orderFlowActionResultSchema = z.object({
|
|
345
|
+
orderId: z.string(),
|
|
346
|
+
key: z.string(),
|
|
347
|
+
results: z.array(
|
|
348
|
+
z.object({
|
|
349
|
+
orderItemId: z.string(),
|
|
350
|
+
status: z
|
|
351
|
+
.enum(["COMPLETED", "SKIPPED", "FAILED"])
|
|
352
|
+
.describe(
|
|
353
|
+
"COMPLETED 실행 · SKIPPED 이 주문상품에는 그 행동이 없다 · FAILED 실행하다 거절됐다",
|
|
354
|
+
),
|
|
355
|
+
reason: z
|
|
356
|
+
.string()
|
|
357
|
+
.optional()
|
|
358
|
+
.describe(
|
|
359
|
+
"SKIPPED·FAILED의 이유 — 꺼진 이유(EXPIRED·CONDITION·NOT_IN_STATE) 또는 오류 코드",
|
|
360
|
+
),
|
|
361
|
+
message: z.string().optional(),
|
|
362
|
+
}),
|
|
363
|
+
),
|
|
364
|
+
});
|
|
365
|
+
export type OrderFlowActionResult = z.infer<typeof orderFlowActionResultSchema>;
|
|
366
|
+
|
|
367
|
+
// ── 시뮬레이터·과거 주문 재생(#115 P2) — 초안을 가상 시계로 돌려 본다. 실제 주문·돈·재고는 건드리지 않는다 ─────────────
|
|
368
|
+
|
|
369
|
+
const simulationEventSchema = z.object({
|
|
370
|
+
type: z
|
|
371
|
+
.enum(["start", "seller.action", "buyer.action", "event", "timer"])
|
|
372
|
+
.describe(
|
|
373
|
+
"start 결제 승인 · seller.action 셀러 버튼 · buyer.action 구매자 버튼 · event 사건 · timer 타이머 키",
|
|
374
|
+
),
|
|
375
|
+
key: z.string().optional().describe("행동·사건·타이머 키(start는 없음)"),
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
export const simulateFlowRequestSchema = z.object({
|
|
379
|
+
startAt: z.iso.datetime({ offset: true }).optional().describe("가상 시계 시작(기본: 지금)"),
|
|
380
|
+
context: z
|
|
381
|
+
.record(z.string(), z.unknown())
|
|
382
|
+
.optional()
|
|
383
|
+
.describe("식이 읽을 값(item·order·buyer·product). 비우면 견본 주문 값"),
|
|
384
|
+
steps: z
|
|
385
|
+
.array(
|
|
386
|
+
z.union([
|
|
387
|
+
z.object({ event: simulationEventSchema }),
|
|
388
|
+
z.object({ advance: z.string().regex(/^P/).describe("시간 경과(ISO 8601 기간)") }),
|
|
389
|
+
]),
|
|
390
|
+
)
|
|
391
|
+
.min(1)
|
|
392
|
+
.max(100),
|
|
393
|
+
});
|
|
394
|
+
export type SimulateFlowRequest = z.infer<typeof simulateFlowRequestSchema>;
|
|
395
|
+
|
|
396
|
+
export const simulationStepSchema = z.object({
|
|
397
|
+
step: z.number().int(),
|
|
398
|
+
input: z.record(z.string(), z.unknown()).describe("넣은 사건(`event`) 또는 시간 경과(`advance`)"),
|
|
399
|
+
at: z.string().describe("이 단계 뒤 가상 시각"),
|
|
400
|
+
node: z.string().nullable(),
|
|
401
|
+
label: z.string().nullable().describe("도착 상태의 셀러용 이름"),
|
|
402
|
+
coreStatus: z.string().optional(),
|
|
403
|
+
ended: z.boolean(),
|
|
404
|
+
path: z.array(z.string()).describe("지나간 연결선"),
|
|
405
|
+
blocks: z.array(z.string()).describe("실행했을 블록 종류"),
|
|
406
|
+
timers: z.array(z.object({ key: z.string(), dueAt: z.string() })),
|
|
407
|
+
leaves: z
|
|
408
|
+
.array(z.object({ node: z.string().nullable(), kind: z.string() }))
|
|
409
|
+
.optional()
|
|
410
|
+
.describe("활성 위치가 둘 이상(병렬 가지·하위 흐름)이면 각 위치"),
|
|
411
|
+
error: z.string().optional().describe("사건이 거절된 이유(NO_TRANSITION 등). 위치는 그대로다"),
|
|
412
|
+
});
|
|
413
|
+
export type SimulationStep = z.infer<typeof simulationStepSchema>;
|
|
414
|
+
|
|
415
|
+
export const simulateFlowResultSchema = z.object({
|
|
416
|
+
compiled: z.boolean().describe("초안이 컴파일됐는가. false면 trace가 비고 errors를 고친다"),
|
|
417
|
+
errors: z.array(flowIssueSchema),
|
|
418
|
+
trace: z.array(simulationStepSchema),
|
|
419
|
+
});
|
|
420
|
+
export type SimulateFlowResult = z.infer<typeof simulateFlowResultSchema>;
|
|
421
|
+
|
|
422
|
+
export const replayFlowRequestSchema = z.object({
|
|
423
|
+
orderItemId: z.string().describe("재생할 주문상품 — 그 흐름의 실행 기록을 초안으로 다시 돌린다"),
|
|
424
|
+
});
|
|
425
|
+
export type ReplayFlowRequest = z.infer<typeof replayFlowRequestSchema>;
|
|
426
|
+
|
|
427
|
+
export const replayFlowResultSchema = z.object({
|
|
428
|
+
orderItemId: z.string(),
|
|
429
|
+
compiled: z.boolean(),
|
|
430
|
+
errors: z.array(flowIssueSchema),
|
|
431
|
+
steps: z.array(
|
|
432
|
+
z.object({
|
|
433
|
+
runId: z.string(),
|
|
434
|
+
trigger: z.record(z.string(), z.unknown()),
|
|
435
|
+
recordedState: z.string().describe("실제로 간 상태"),
|
|
436
|
+
simulatedState: z.string().nullable().describe("초안으로 돌렸을 때 간 상태"),
|
|
437
|
+
match: z.boolean(),
|
|
438
|
+
error: z.string().optional(),
|
|
439
|
+
}),
|
|
440
|
+
),
|
|
441
|
+
divergedAt: z
|
|
442
|
+
.number()
|
|
443
|
+
.int()
|
|
444
|
+
.nullable()
|
|
445
|
+
.describe("처음 갈라진 단계(steps 인덱스). 끝까지 같으면 null"),
|
|
446
|
+
unsupported: z
|
|
447
|
+
.number()
|
|
448
|
+
.int()
|
|
449
|
+
.describe(
|
|
450
|
+
"재생할 수 없는 기록(상태 직접 이동·버전 옮기기·엔진 밖 취소) 수 — 그 앞까지만 돌린다",
|
|
451
|
+
),
|
|
452
|
+
});
|
|
453
|
+
export type ReplayFlowResult = z.infer<typeof replayFlowResultSchema>;
|
|
454
|
+
|
|
455
|
+
/** 노드·블록 종류 목록(#115) — 흐름을 API·AI로 짤 때 쓸 수 있는 종류와 설정 형식(JSON Schema) */
|
|
456
|
+
export const flowNodeTypesSchema = z.object({
|
|
457
|
+
nodes: z.array(
|
|
458
|
+
z.object({
|
|
459
|
+
type: z.string(),
|
|
460
|
+
version: z.number().int(),
|
|
461
|
+
kind: z
|
|
462
|
+
.string()
|
|
463
|
+
.describe("state 머묾 · wait 결과를 기다림 · end 종료 · transient 즉시 갈라짐"),
|
|
464
|
+
outputs: z
|
|
465
|
+
.array(z.string())
|
|
466
|
+
.nullable()
|
|
467
|
+
.describe("고정 결과 이름. 설정에서 나오면(셀러 확인의 버튼) null"),
|
|
468
|
+
configSchema: z.record(z.string(), z.unknown()).describe("설정 형식(JSON Schema)"),
|
|
469
|
+
}),
|
|
470
|
+
),
|
|
471
|
+
blocks: z.array(
|
|
472
|
+
z.object({
|
|
473
|
+
type: z.string(),
|
|
474
|
+
version: z.number().int(),
|
|
475
|
+
effect: z
|
|
476
|
+
.string()
|
|
477
|
+
.describe("local 같은 트랜잭션 · afterCommit 커밋 뒤 · external 트랜잭션 밖"),
|
|
478
|
+
configSchema: z.record(z.string(), z.unknown()),
|
|
479
|
+
}),
|
|
480
|
+
),
|
|
481
|
+
});
|
|
482
|
+
export type FlowNodeTypes = z.infer<typeof flowNodeTypesSchema>;
|
package/src/schemas/misc.ts
CHANGED
|
@@ -160,6 +160,8 @@ export const eventTypeSchema = z
|
|
|
160
160
|
"PRODUCT.OUT_OF_STOCK",
|
|
161
161
|
// 커머스 플로우 알림 블록(이슈 #115). 플로우에 알림 블록을 둔 상점의 구독자에게만 간다
|
|
162
162
|
"ORDER.FLOW_NOTIFICATION",
|
|
163
|
+
// 커머스 플로우 상태 변경(이슈 #115). 흐름 단계가 바뀔 때마다 간다
|
|
164
|
+
"ORDER.FLOW_STATE_CHANGED",
|
|
163
165
|
])
|
|
164
166
|
.describe(
|
|
165
167
|
"웹훅 이벤트 타입. `ORDER.ADDRESS_CHANGE_REQUESTED`는 현재 발송하지 않음(호환을 위해 값만 남았고, 구독해도 이벤트가 오지 않는다)",
|
package/src/schemas/order.ts
CHANGED
|
@@ -15,6 +15,11 @@ export const orderSummarySchema = z.object({
|
|
|
15
15
|
itemCount: z.number().int(),
|
|
16
16
|
totalAmount: z.number().int(),
|
|
17
17
|
representativeStatus: orderItemStatusSchema,
|
|
18
|
+
progressStatus: orderItemStatusSchema
|
|
19
|
+
.optional()
|
|
20
|
+
.describe(
|
|
21
|
+
"진행 중 주문상품 가운데 가장 앞 단계(취소 제외, 모두 취소면 CANCELED, #115). 섞인 주문에서 아직 기다리는 단계다. 서버는 항상 싣는다",
|
|
22
|
+
),
|
|
18
23
|
orderedAt: z.string(),
|
|
19
24
|
testPayment: z
|
|
20
25
|
.boolean()
|
|
@@ -162,6 +167,11 @@ export type OrderDiscount = z.infer<typeof orderDiscountSchema>;
|
|
|
162
167
|
|
|
163
168
|
export const orderSchema = z.object({
|
|
164
169
|
orderId: z.string(),
|
|
170
|
+
progressStatus: orderItemStatusSchema
|
|
171
|
+
.optional()
|
|
172
|
+
.describe(
|
|
173
|
+
"진행 중 주문상품 가운데 가장 앞 단계(취소 제외, 모두 취소면 CANCELED, #115). 섞인 주문에서 아직 기다리는 단계다. 서버는 항상 싣는다",
|
|
174
|
+
),
|
|
165
175
|
orderNo: commerceNumberField(
|
|
166
176
|
"주문번호(이슈 #107) — 숫자 14자리(YYMMDD KST + 난수 8자리), 전역 유일, 생성 후 바뀌지 않습니다. 전화 CS·ARS용 번호이고 API 경로의 식별자는 여전히 `orderId`입니다. 화면 표기는 `formatOrderNo`(4자리 하이픈)를 쓰십시오",
|
|
167
177
|
),
|
|
@@ -399,6 +399,31 @@ export const flowNotificationWebhookEventSchema = z.object({
|
|
|
399
399
|
data: flowNotificationWebhookEventDataSchema,
|
|
400
400
|
});
|
|
401
401
|
|
|
402
|
+
/**
|
|
403
|
+
* 흐름 상태 변경(이슈 #115) — 주문상품의 흐름 상태(노드)가 바뀔 때마다 온다. 공개 상태(`ORDER.*`)가 같아도 상점 흐름의 단계가 바뀌면 온다
|
|
404
|
+
* (시안 확인 → 제작중). 묶음 진행이면 `orderItemIds`가 여럿이다. 개인정보는 싣지 않는다
|
|
405
|
+
*/
|
|
406
|
+
export const flowStateChangedWebhookEventDataSchema = z.object({
|
|
407
|
+
orderId: z.string().describe("주문 ID"),
|
|
408
|
+
orderItemIds: z.array(z.string()).describe("상태가 바뀐 주문상품(묶음 진행이면 여럿)"),
|
|
409
|
+
flowId: z.string(),
|
|
410
|
+
flowVersion: z.number().int(),
|
|
411
|
+
from: z.string().nullable().describe("이전 상태 키. 흐름이 막 시작했으면 null"),
|
|
412
|
+
to: z.string().describe("새 상태 키"),
|
|
413
|
+
label: z.string().describe("새 상태의 셀러용 이름"),
|
|
414
|
+
coreStatus: z
|
|
415
|
+
.string()
|
|
416
|
+
.nullable()
|
|
417
|
+
.describe("새 상태의 공개 상태. 공개 상태를 바꾸지 않는 단계면 null"),
|
|
418
|
+
changedAt: z.string().describe("바뀐 시각"),
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
export const flowStateChangedWebhookEventSchema = z.object({
|
|
422
|
+
...envelopeFields,
|
|
423
|
+
type: z.literal("ORDER.FLOW_STATE_CHANGED"),
|
|
424
|
+
data: flowStateChangedWebhookEventDataSchema,
|
|
425
|
+
});
|
|
426
|
+
|
|
402
427
|
/** 웹훅 요청 본문. `type`으로 판별하며 `data` 형태가 타입별로 다르다 */
|
|
403
428
|
export const webhookEventSchema = z
|
|
404
429
|
.discriminatedUnion("type", [
|
|
@@ -410,6 +435,7 @@ export const webhookEventSchema = z
|
|
|
410
435
|
reviewWebhookEventSchema,
|
|
411
436
|
productOutOfStockWebhookEventSchema,
|
|
412
437
|
flowNotificationWebhookEventSchema,
|
|
438
|
+
flowStateChangedWebhookEventSchema,
|
|
413
439
|
])
|
|
414
440
|
.describe(
|
|
415
441
|
"웹훅 요청 본문 (얇은 이벤트). 개인정보를 싣지 않으며 `data`의 id로 관리 API를 조회한다",
|