@sayren/store-sdk 0.50.0 → 0.51.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 +656 -410
- package/dist/index.mjs +333 -10
- package/dist/server.d.mts +3 -1
- package/dist/server.mjs +2 -1
- package/dist/userinfo-n1JYxWAz.d.mts +90 -0
- package/package.json +1 -1
- package/src/client.ts +29 -0
- package/src/index.ts +1 -0
- package/src/member-delegation.ts +4 -0
- package/src/schemas/condition-tree.ts +103 -3
- package/src/schemas/coupon-rules.ts +178 -0
- package/src/schemas/coupon.ts +75 -5
- package/src/schemas/customer-delegation.ts +6 -0
- package/src/schemas/customer.ts +4 -0
- package/src/schemas/userinfo.ts +118 -0
- package/dist/webhook-headers-D6QmPdEJ.d.mts +0 -22
package/src/schemas/coupon.ts
CHANGED
|
@@ -35,17 +35,34 @@ export const couponStatusSchema = z
|
|
|
35
35
|
export type CouponStatus = z.infer<typeof couponStatusSchema>;
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
* 발급 방식 — 코드 입력·셀러 지급·다운로드(구매자가 받기)·회원가입 자동 지급(이슈 #110).
|
|
38
|
+
* 발급 방식 — 코드 입력·셀러 지급·다운로드(구매자가 받기)·회원가입 자동 지급(이슈 #110)·흐름 지급(이슈 #264).
|
|
39
39
|
* 응답(`couponSchema.issueMethod`)은 값이 늘 수 있어 문자열로 받는다. 이 enum은 요청 검증용이다.
|
|
40
40
|
*/
|
|
41
41
|
export const couponIssueMethodSchema = z
|
|
42
|
-
.enum(["CODE", "MANUAL", "DOWNLOAD", "SIGNUP"])
|
|
42
|
+
.enum(["CODE", "MANUAL", "DOWNLOAD", "SIGNUP", "FLOW", "VOUCHER"])
|
|
43
43
|
.describe(
|
|
44
44
|
"발급 방식. `CODE`=구매자가 주문서에 코드를 입력한다, `MANUAL`=셀러가 회원을 골라 지급한다, " +
|
|
45
|
-
"`DOWNLOAD`=구매자가 스토어프론트에서 받는다, `SIGNUP`=회원가입 때 자동으로
|
|
45
|
+
"`DOWNLOAD`=구매자가 스토어프론트에서 받는다, `SIGNUP`=회원가입 때 자동으로 지급한다, " +
|
|
46
|
+
"`FLOW`=주문 흐름의 쿠폰 지급 단계가 그 주문의 구매자에게 지급한다, " +
|
|
47
|
+
"`VOUCHER`=셀러가 1회용 쿠폰 번호를 만들어 나눠 주고 구매자가 번호를 등록하면 지급한다",
|
|
46
48
|
);
|
|
47
49
|
export type CouponIssueMethod = z.infer<typeof couponIssueMethodSchema>;
|
|
48
50
|
|
|
51
|
+
/** 쿠폰 번호 접두어 — 영문·숫자 2~10자, 대문자로 저장한다. 상점 안에서 유일하다 */
|
|
52
|
+
export const VOUCHER_PREFIX_PATTERN = /^[A-Za-z0-9]{2,10}$/;
|
|
53
|
+
/** 쿠폰 번호 한 쿠폰의 최대 개수 */
|
|
54
|
+
export const VOUCHER_COUNT_MAX = 100_000;
|
|
55
|
+
|
|
56
|
+
/** 쿠폰 번호 설정(`VOUCHER`, 이슈 #264) — 만든 뒤에는 바꿀 수 없다 */
|
|
57
|
+
export const couponVoucherInputSchema = z
|
|
58
|
+
.strictObject({
|
|
59
|
+
prefix: z.string().regex(VOUCHER_PREFIX_PATTERN).describe("번호 앞부분(영문·숫자 2~10자)"),
|
|
60
|
+
count: z.number().int().min(1).max(VOUCHER_COUNT_MAX).describe("만들 번호 수(1~100,000)"),
|
|
61
|
+
})
|
|
62
|
+
.describe(
|
|
63
|
+
"쿠폰 번호 설정 — 1회용 번호 `count`개를 만든다. 번호는 `GET /v1/coupons/{couponId}/voucher-codes`로 받는다",
|
|
64
|
+
);
|
|
65
|
+
|
|
49
66
|
/** 코드 형식 — 영문·숫자·`-`·`_` 6~30자. 대소문자를 구분하지 않고 서버가 대문자로 저장한다 */
|
|
50
67
|
export const COUPON_CODE_PATTERN = /^[A-Za-z0-9_-]{6,30}$/;
|
|
51
68
|
|
|
@@ -240,6 +257,7 @@ export const createCouponRequestSchema = strictRequest(
|
|
|
240
257
|
target: couponTargetInputSchema.optional().describe("대상 상품·카테고리. 생략하면 전 상품"),
|
|
241
258
|
issueMethod: couponIssueMethodSchema,
|
|
242
259
|
code: z.string().regex(COUPON_CODE_PATTERN).optional().describe(descriptions.code),
|
|
260
|
+
voucher: couponVoucherInputSchema.optional(),
|
|
243
261
|
startsAt: couponTimeField(descriptions.startsAt),
|
|
244
262
|
endsAt: couponTimeField(descriptions.endsAt),
|
|
245
263
|
validDaysAfterIssue: z
|
|
@@ -270,6 +288,10 @@ export const createCouponRequestSchema = strictRequest(
|
|
|
270
288
|
ctx.addIssue({ code: "custom", path: [path], message });
|
|
271
289
|
if (body.issueMethod === "CODE" && !body.code)
|
|
272
290
|
issue("code", "코드 입력형 쿠폰은 코드가 필요합니다");
|
|
291
|
+
if (body.issueMethod === "VOUCHER" && !body.voucher)
|
|
292
|
+
issue("voucher", "쿠폰 번호 쿠폰은 번호 설정이 필요합니다");
|
|
293
|
+
if (body.issueMethod !== "VOUCHER" && body.voucher)
|
|
294
|
+
issue("voucher", "번호 설정은 쿠폰 번호 쿠폰에만 둡니다");
|
|
273
295
|
if (body.issueMethod !== "CODE" && body.code)
|
|
274
296
|
issue("code", "코드는 코드 입력형 쿠폰에만 둡니다");
|
|
275
297
|
if (body.issueMethod === "CODE" && body.validDaysAfterIssue != null) {
|
|
@@ -348,7 +370,7 @@ export const couponSchema = z.object({
|
|
|
348
370
|
issueMethod: z
|
|
349
371
|
.string()
|
|
350
372
|
.describe(
|
|
351
|
-
"발급 방식. 현재 값은 `CODE`·`MANUAL`·`DOWNLOAD`(구매자가 받기)·`SIGNUP`(회원가입 자동 지급)이고 값이 추가될 수 있어 문자열로 받는다",
|
|
373
|
+
"발급 방식. 현재 값은 `CODE`·`MANUAL`·`DOWNLOAD`(구매자가 받기)·`SIGNUP`(회원가입 자동 지급)·`FLOW`(주문 흐름 지급)·`VOUCHER`(쿠폰 번호)이고 값이 추가될 수 있어 문자열로 받는다",
|
|
352
374
|
),
|
|
353
375
|
code: z.string().nullable().describe("쿠폰 코드(대문자). 코드 입력형이 아니면 null"),
|
|
354
376
|
startsAt: z.string().nullable(),
|
|
@@ -365,6 +387,12 @@ export const couponSchema = z.object({
|
|
|
365
387
|
totalUseLimit: z.number().int().nullable(),
|
|
366
388
|
perMemberIssueLimit: z.number().int().nullable(),
|
|
367
389
|
perMemberUseLimit: z.number().int().nullable(),
|
|
390
|
+
voucher: z
|
|
391
|
+
.object({ prefix: z.string(), count: z.number().int() })
|
|
392
|
+
.nullable()
|
|
393
|
+
.optional()
|
|
394
|
+
.default(null)
|
|
395
|
+
.describe("쿠폰 번호 설정(`VOUCHER`만, 이슈 #264). 다른 발급 방식은 null. 서버는 항상 싣는다"),
|
|
368
396
|
issuedCount: z
|
|
369
397
|
.number()
|
|
370
398
|
.int()
|
|
@@ -444,7 +472,7 @@ export const couponIssueSchema = z.object({
|
|
|
444
472
|
.string()
|
|
445
473
|
.optional()
|
|
446
474
|
.describe(
|
|
447
|
-
"발급 경로(이슈 #110). 현재 값은 `MANUAL`(셀러 지급)·`DOWNLOAD`(구매자가 받음)·`SIGNUP`(회원가입 자동 지급)이고 값이 추가될 수 있다. 서버는 항상 싣는다",
|
|
475
|
+
"발급 경로(이슈 #110). 현재 값은 `MANUAL`(셀러 지급)·`DOWNLOAD`(구매자가 받음)·`SIGNUP`(회원가입 자동 지급)·`FLOW`(주문 흐름 지급)·`VOUCHER`(쿠폰 번호 등록)이고 값이 추가될 수 있다. 서버는 항상 싣는다",
|
|
448
476
|
),
|
|
449
477
|
status: couponIssueStatusSchema,
|
|
450
478
|
validFrom: z.string(),
|
|
@@ -460,6 +488,48 @@ export const couponIssueListQuerySchema = z.object({
|
|
|
460
488
|
...pageQueryShape(),
|
|
461
489
|
});
|
|
462
490
|
|
|
491
|
+
/** `GET /v1/coupons/{couponId}/voucher-codes` — 쿠폰 번호 전체(순번 순). 상점 플랫폼이 CSV로 내려받는다 */
|
|
492
|
+
export const couponVoucherCodesSchema = z
|
|
493
|
+
.object({
|
|
494
|
+
prefix: z.string(),
|
|
495
|
+
count: z.number().int(),
|
|
496
|
+
codes: z.array(z.string()).describe("번호 — 순번 1부터. 등록에 쓴 번호도 싣는다"),
|
|
497
|
+
})
|
|
498
|
+
.describe("쿠폰 번호 목록");
|
|
499
|
+
export type CouponVoucherCodes = z.infer<typeof couponVoucherCodesSchema>;
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* 발급 대상 전원 지급(이슈 #264) — `POST /v1/coupons/{couponId}/distributions`(202)가 만들고 서버가 뒤에서 처리한다. 셀러 지급(`MANUAL`) 쿠폰을
|
|
503
|
+
* 발급 대상 조건에 맞는 회원 모두에게 준다(셀러 지급과 같은 한도 판정). 쿠폰마다 진행 중 작업은 하나다
|
|
504
|
+
*/
|
|
505
|
+
export const couponDistributionSchema = z
|
|
506
|
+
.object({
|
|
507
|
+
distributionId: z.string(),
|
|
508
|
+
couponId: z.string(),
|
|
509
|
+
status: z
|
|
510
|
+
.string()
|
|
511
|
+
.describe(
|
|
512
|
+
"작업 상태. 현재 값은 `QUEUED`(대기)·`RUNNING`(지급 중)·`COMPLETED`(끝남)·`FAILED`(실패)이고 값이 추가될 수 있다",
|
|
513
|
+
),
|
|
514
|
+
processedCount: z.number().int().describe("지금까지 살펴본 회원 수"),
|
|
515
|
+
issuedCount: z.number().int().describe("이 작업이 지급한 장수"),
|
|
516
|
+
skippedCount: z
|
|
517
|
+
.number()
|
|
518
|
+
.int()
|
|
519
|
+
.describe("건너뛴 회원 수 — 발급 대상이 아니거나 1인 발급 한도에 닿은 회원"),
|
|
520
|
+
stopCode: z
|
|
521
|
+
.string()
|
|
522
|
+
.nullable()
|
|
523
|
+
.describe(
|
|
524
|
+
"일찍 끝난 사유. `COUPON_EXHAUSTED`(총 발급 한도)·`COUPON_DAILY_EXHAUSTED`(하루 발급 한도)·`COUPON_NOT_ACTIVE`(중지·종료)·`COUPON_EXPIRED`(사용 기간 끝) 등. 끝까지 돌았으면 null",
|
|
525
|
+
),
|
|
526
|
+
createdAt: z.string(),
|
|
527
|
+
startedAt: z.string().nullable(),
|
|
528
|
+
finishedAt: z.string().nullable(),
|
|
529
|
+
})
|
|
530
|
+
.describe("발급 대상 전원 지급 작업");
|
|
531
|
+
export type CouponDistribution = z.infer<typeof couponDistributionSchema>;
|
|
532
|
+
|
|
463
533
|
/** `POST /v1/coupons/{couponId}/issues` — 셀러 지급. 한 번에 1,000명까지 */
|
|
464
534
|
export const issueCouponRequestSchema = z.strictObject({
|
|
465
535
|
customerIds: z
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as z from "zod";
|
|
2
2
|
import { strictRequest } from "./strict";
|
|
3
|
+
import { customerUserinfoInputSchema } from "./userinfo";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* 구매자 위임 REST(`POST /v1/customers/delegations`, #71) — 계정 토큰(또는 관리 API 토큰) + `X-Store-Id`로 부른다(`customer:rw`).
|
|
@@ -31,6 +32,11 @@ export const customerDelegationRequestSchema = strictRequest(
|
|
|
31
32
|
.describe(
|
|
32
33
|
"사용자가 셀러 서비스에서 실제로 로그인한 시각(uid 위임만). 주면 구매자 토큰의 인증 시각이 된다",
|
|
33
34
|
),
|
|
35
|
+
userinfo: customerUserinfoInputSchema
|
|
36
|
+
.optional()
|
|
37
|
+
.describe(
|
|
38
|
+
"OIDC 클레임(이슈 #264) — 위임할 때마다 준 클레임만 바뀌고 null은 지운다. `email_verified`를 생략하면 위임으로 만든 구매자의 이메일은 확인된 것으로 본다",
|
|
39
|
+
),
|
|
34
40
|
})
|
|
35
41
|
.refine((value) => Boolean(value.uid || value.email), {
|
|
36
42
|
message: "uid 또는 email이 필요합니다",
|
package/src/schemas/customer.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as z from "zod";
|
|
2
2
|
import { orderItemStatusSchema, pageQueryShape } from "./common";
|
|
3
3
|
import { strictRequest } from "./strict";
|
|
4
|
+
import { customerUserinfoSchema } from "./userinfo";
|
|
4
5
|
|
|
5
6
|
/** 구매자 목록 정렬 */
|
|
6
7
|
export const customerSortSchema = z
|
|
@@ -169,6 +170,9 @@ export const customerDetailSchema = z.object({
|
|
|
169
170
|
"약관·개인정보·마케팅 동의의 현재 상태. 이력은 `GET /v1/customers/{customerId}/consents`",
|
|
170
171
|
),
|
|
171
172
|
addresses: z.array(customerAddressSchema),
|
|
173
|
+
userinfo: customerUserinfoSchema
|
|
174
|
+
.optional()
|
|
175
|
+
.describe("OIDC userinfo 표준 클레임(이슈 #264, 주소는 기본 배송지). 서버는 항상 싣는다"),
|
|
172
176
|
stats: customerStatsSchema.extend({
|
|
173
177
|
canceledOrReturnedCount: z.number().int().describe("취소된 주문 상품 + 완료된 반품 수"),
|
|
174
178
|
reviewCount: z.number().int(),
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 구매자 정보의 OIDC userinfo 표준 클레임(OpenID Connect Core 1.0 5.1, 이슈 #264). 이름은 표준 그대로 snake_case다.
|
|
5
|
+
* 값이 없는 클레임은 응답에서 빠진다. 같은 형식이 스토어프론트 API(storefront-sdk `userinfoSchema`)에도 있다.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** 생일 — `YYYY-MM-DD`, 연도를 모르면 `0000-MM-DD`(표준 형식) */
|
|
9
|
+
export const CUSTOMER_BIRTHDATE_PATTERN = /^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/;
|
|
10
|
+
|
|
11
|
+
export const customerUserinfoAddressSchema = z.object({
|
|
12
|
+
formatted: z.string().optional(),
|
|
13
|
+
street_address: z.string().optional(),
|
|
14
|
+
locality: z.string().optional(),
|
|
15
|
+
region: z.string().optional(),
|
|
16
|
+
postal_code: z.string().optional(),
|
|
17
|
+
country: z.string().optional().describe("ISO 3166-1 alpha-2"),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export const customerUserinfoSchema = z
|
|
21
|
+
.object({
|
|
22
|
+
sub: z.string().describe("구매자 id(상점 안에서 유일)"),
|
|
23
|
+
name: z.string().optional(),
|
|
24
|
+
given_name: z.string().optional(),
|
|
25
|
+
family_name: z.string().optional(),
|
|
26
|
+
middle_name: z.string().optional(),
|
|
27
|
+
nickname: z.string().optional(),
|
|
28
|
+
preferred_username: z.string().optional(),
|
|
29
|
+
profile: z.string().optional(),
|
|
30
|
+
picture: z.string().optional(),
|
|
31
|
+
website: z.string().optional(),
|
|
32
|
+
email: z.string().optional(),
|
|
33
|
+
email_verified: z
|
|
34
|
+
.boolean()
|
|
35
|
+
.optional()
|
|
36
|
+
.describe("이메일 확인 여부 — 인증된 소셜 가입·셀러 위임만 true다. 비밀번호 가입은 false"),
|
|
37
|
+
gender: z.string().optional().describe("표준 값은 `female`·`male`이고 다른 값도 온다"),
|
|
38
|
+
birthdate: z.string().optional().describe("`YYYY-MM-DD`, 연도를 모르면 `0000-MM-DD`"),
|
|
39
|
+
zoneinfo: z.string().optional().describe("IANA 시간대(예: `Asia/Seoul`)"),
|
|
40
|
+
locale: z.string().optional().describe("BCP 47 언어 태그(예: `ko-KR`)"),
|
|
41
|
+
phone_number: z.string().optional().describe("E.164(예: `+821012345678`)"),
|
|
42
|
+
phone_number_verified: z.boolean().optional(),
|
|
43
|
+
address: customerUserinfoAddressSchema.optional().describe("기본 배송지에서 만든다"),
|
|
44
|
+
updated_at: z.number().int().optional().describe("프로필을 바꾼 시각(epoch 초)"),
|
|
45
|
+
})
|
|
46
|
+
.describe("OIDC userinfo 표준 클레임(이슈 #264)");
|
|
47
|
+
export type CustomerUserinfo = z.infer<typeof customerUserinfoSchema>;
|
|
48
|
+
|
|
49
|
+
const text = (max: number) => z.string().trim().min(1).max(max).nullable().optional();
|
|
50
|
+
const httpsUrl = z
|
|
51
|
+
.url({ protocol: /^https$/ })
|
|
52
|
+
.max(2048)
|
|
53
|
+
.nullable()
|
|
54
|
+
.optional()
|
|
55
|
+
.describe("https 주소");
|
|
56
|
+
|
|
57
|
+
/** 시간대·언어 태그 검사 — 런타임(Intl)이 아는 값만 받는다 */
|
|
58
|
+
const zoneinfo = z
|
|
59
|
+
.string()
|
|
60
|
+
.max(64)
|
|
61
|
+
.refine((value) => {
|
|
62
|
+
try {
|
|
63
|
+
new Intl.DateTimeFormat("en", { timeZone: value });
|
|
64
|
+
return true;
|
|
65
|
+
} catch {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}, "IANA 시간대가 아닙니다")
|
|
69
|
+
.nullable()
|
|
70
|
+
.optional();
|
|
71
|
+
const locale = z
|
|
72
|
+
.string()
|
|
73
|
+
.max(35)
|
|
74
|
+
.refine((value) => {
|
|
75
|
+
try {
|
|
76
|
+
return Intl.getCanonicalLocales(value).length === 1;
|
|
77
|
+
} catch {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
}, "BCP 47 언어 태그가 아닙니다")
|
|
81
|
+
.nullable()
|
|
82
|
+
.optional();
|
|
83
|
+
const birthdate = z
|
|
84
|
+
.string()
|
|
85
|
+
.regex(CUSTOMER_BIRTHDATE_PATTERN, "생일은 YYYY-MM-DD(연도를 모르면 0000-MM-DD)입니다")
|
|
86
|
+
.refine((value) => {
|
|
87
|
+
const [y, m, d] = value.split("-").map(Number) as [number, number, number];
|
|
88
|
+
// 연도를 모르면 윤년(2000)으로 날짜만 본다
|
|
89
|
+
const day = new Date(Date.UTC(y === 0 ? 2000 : y, m - 1, d));
|
|
90
|
+
return day.getUTCMonth() === m - 1 && day.getUTCDate() === d;
|
|
91
|
+
}, "없는 날짜입니다")
|
|
92
|
+
.nullable()
|
|
93
|
+
.optional();
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 셀러가 위임으로 바꿀 수 있는 클레임 — 준 클레임만 바뀌고 null은 지운다. `sub`·`email`·`phone_number`·`updated_at`·`address`는 받지 않는다. 확인 여부(`*_verified`)는 셀러가 확인한 값을 받는다
|
|
97
|
+
* (이메일·휴대폰은 각자의 칸, 주소는 배송지가 원천이다)
|
|
98
|
+
*/
|
|
99
|
+
export const customerUserinfoInputSchema = z
|
|
100
|
+
.strictObject({
|
|
101
|
+
/** 셀러가 확인한 값 그대로 받는다 — 셀러 서비스가 인증한 회원이다 */
|
|
102
|
+
email_verified: z.boolean().optional(),
|
|
103
|
+
phone_number_verified: z.boolean().optional(),
|
|
104
|
+
given_name: text(50),
|
|
105
|
+
family_name: text(50),
|
|
106
|
+
middle_name: text(50),
|
|
107
|
+
nickname: text(50),
|
|
108
|
+
preferred_username: text(50),
|
|
109
|
+
profile: httpsUrl,
|
|
110
|
+
picture: httpsUrl,
|
|
111
|
+
website: httpsUrl,
|
|
112
|
+
gender: text(30),
|
|
113
|
+
birthdate,
|
|
114
|
+
zoneinfo,
|
|
115
|
+
locale,
|
|
116
|
+
})
|
|
117
|
+
.describe("바꿀 OIDC 클레임 — 준 것만 바뀌고 null은 지운다");
|
|
118
|
+
export type CustomerUserinfoInput = z.infer<typeof customerUserinfoInputSchema>;
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
//#region src/webhook-headers.d.ts
|
|
2
|
-
/** 웹훅 발송 요청 헤더 상수 (공개 계약). zod 의존 없이 서버 엔트리포인트에서도 가볍게 쓴다 */
|
|
3
|
-
/** 서명 헤더. 형식: `t=<unix초>,v1=<hex>[,v1=<hex>]` */
|
|
4
|
-
declare const WEBHOOK_SIGNATURE_HEADER = "Sayren-Signature";
|
|
5
|
-
/** 이벤트 ID 헤더. 본문 `id`와 같다. 중복 제거 키 */
|
|
6
|
-
declare const WEBHOOK_EVENT_ID_HEADER = "Sayren-Event-Id";
|
|
7
|
-
/** 이벤트 타입 헤더. 본문 `type`과 같다 */
|
|
8
|
-
declare const WEBHOOK_EVENT_TYPE_HEADER = "Sayren-Event-Type";
|
|
9
|
-
/** 전송 기록 ID 헤더. 전송 기록의 `deliveryId`와 같다 */
|
|
10
|
-
declare const WEBHOOK_DELIVERY_ID_HEADER = "Sayren-Delivery-Id";
|
|
11
|
-
/** 발송 요청의 `User-Agent` 값 */
|
|
12
|
-
declare const WEBHOOK_USER_AGENT = "Sayren-Webhooks/1.0";
|
|
13
|
-
/** 수신 측 권장 타임스탬프 허용 오차(초) */
|
|
14
|
-
declare const WEBHOOK_DEFAULT_TOLERANCE_SEC = 300;
|
|
15
|
-
declare const WEBHOOK_HEADERS: {
|
|
16
|
-
readonly signature: "Sayren-Signature";
|
|
17
|
-
readonly eventId: "Sayren-Event-Id";
|
|
18
|
-
readonly eventType: "Sayren-Event-Type";
|
|
19
|
-
readonly deliveryId: "Sayren-Delivery-Id";
|
|
20
|
-
};
|
|
21
|
-
//#endregion
|
|
22
|
-
export { WEBHOOK_HEADERS as a, WEBHOOK_EVENT_TYPE_HEADER as i, WEBHOOK_DELIVERY_ID_HEADER as n, WEBHOOK_SIGNATURE_HEADER as o, WEBHOOK_EVENT_ID_HEADER as r, WEBHOOK_USER_AGENT as s, WEBHOOK_DEFAULT_TOLERANCE_SEC as t };
|