@sayren/store-sdk 0.36.0 → 0.37.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 +450 -177
- package/dist/index.mjs +250 -161
- package/package.json +1 -1
- package/src/client.ts +48 -1
- package/src/index.ts +1 -0
- package/src/schemas/plans.ts +104 -0
- package/src/schemas/storefront-hosting.ts +141 -4
- package/src/schemas/subscription.ts +34 -87
package/src/client.ts
CHANGED
|
@@ -280,6 +280,7 @@ import {
|
|
|
280
280
|
type VerifyPaymentProviderRequest,
|
|
281
281
|
verifyPaymentProviderRequestSchema,
|
|
282
282
|
} from "./schemas/payment";
|
|
283
|
+
import { publicPlansSchema } from "./schemas/plans";
|
|
283
284
|
import {
|
|
284
285
|
customerPointsSchema,
|
|
285
286
|
type PointAdjustmentRequest,
|
|
@@ -369,12 +370,14 @@ import {
|
|
|
369
370
|
addStorefrontDomainRequestSchema,
|
|
370
371
|
type ChangeStorefrontSlugRequest,
|
|
371
372
|
type ChangeStorefrontTemplateRequest,
|
|
373
|
+
type ConnectStorefrontGitRequest,
|
|
372
374
|
type CreateStorefrontEditPreviewLinkRequest,
|
|
373
375
|
type CreateStorefrontPreviewLinkRequest,
|
|
374
376
|
type CreateStorefrontSiteRequest,
|
|
375
377
|
type CreateStorefrontVersionRequest,
|
|
376
378
|
changeStorefrontSlugRequestSchema,
|
|
377
379
|
changeStorefrontTemplateRequestSchema,
|
|
380
|
+
connectStorefrontGitRequestSchema,
|
|
378
381
|
createStorefrontEditPreviewLinkRequestSchema,
|
|
379
382
|
createStorefrontPreviewLinkRequestSchema,
|
|
380
383
|
createStorefrontSiteRequestSchema,
|
|
@@ -383,6 +386,8 @@ import {
|
|
|
383
386
|
type DisableStorefrontHostingRequest,
|
|
384
387
|
deleteStorefrontFileRequestSchema,
|
|
385
388
|
disableStorefrontHostingRequestSchema,
|
|
389
|
+
type LinkStorefrontGitInstallationRequest,
|
|
390
|
+
linkStorefrontGitInstallationRequestSchema,
|
|
386
391
|
type MoveStorefrontFileRequest,
|
|
387
392
|
moveStorefrontFileRequestSchema,
|
|
388
393
|
type PublishStorefrontVersionRequest,
|
|
@@ -394,8 +399,10 @@ import {
|
|
|
394
399
|
rollbackStorefrontRequestSchema,
|
|
395
400
|
runStorefrontCheckRequestSchema,
|
|
396
401
|
type SearchStorefrontFilesRequest,
|
|
402
|
+
type SetStorefrontDeployApprovalRequest,
|
|
397
403
|
type SetStorefrontVisibilityRequest,
|
|
398
404
|
searchStorefrontFilesRequestSchema,
|
|
405
|
+
setStorefrontDeployApprovalRequestSchema,
|
|
399
406
|
setStorefrontVisibilityRequestSchema,
|
|
400
407
|
storefrontBuildSchema,
|
|
401
408
|
storefrontCheckSchema,
|
|
@@ -407,6 +414,9 @@ import {
|
|
|
407
414
|
storefrontFileMoveResultSchema,
|
|
408
415
|
storefrontFileSearchResultSchema,
|
|
409
416
|
storefrontFileWriteResultSchema,
|
|
417
|
+
storefrontGitConnectStateSchema,
|
|
418
|
+
storefrontGitRepositorySchema,
|
|
419
|
+
storefrontGitStatusSchema,
|
|
410
420
|
storefrontHostingSchema,
|
|
411
421
|
storefrontPreviewLinkSchema,
|
|
412
422
|
storefrontSiteDomainSchema,
|
|
@@ -430,7 +440,7 @@ import {
|
|
|
430
440
|
type WriteStorefrontFilesRequest,
|
|
431
441
|
writeStorefrontFilesRequestSchema,
|
|
432
442
|
} from "./schemas/storefront-hosting";
|
|
433
|
-
import {
|
|
443
|
+
import { storeSubscriptionSchema } from "./schemas/subscription";
|
|
434
444
|
import {
|
|
435
445
|
type UploadPurpose,
|
|
436
446
|
type UploadRequest,
|
|
@@ -2327,6 +2337,43 @@ export function createStoreClient(options: StoreClientOptions) {
|
|
|
2327
2337
|
storeHttp.request("PUT", "/storefront/site/source", storefrontSourceReplacedSchema, {
|
|
2328
2338
|
body: replaceStorefrontSourceRequestSchema.parse(body),
|
|
2329
2339
|
}),
|
|
2340
|
+
/** `PUT /v1/storefront/site/deploy-approval` — 승인 없이 배포(상점 플랫폼 OWNER·ADMIN 전용) */
|
|
2341
|
+
setDeployApproval: (body: SetStorefrontDeployApprovalRequest) =>
|
|
2342
|
+
storeHttp.request("PUT", "/storefront/site/deploy-approval", storefrontSiteSchema, {
|
|
2343
|
+
body: setStorefrontDeployApprovalRequestSchema.parse(body),
|
|
2344
|
+
}),
|
|
2345
|
+
/** `GET /v1/storefront/site/git` — Git 원천(발행 소스를 둔 저장소)과 상태(#138) */
|
|
2346
|
+
getGit: () => storeHttp.request("GET", "/storefront/site/git", storefrontGitStatusSchema),
|
|
2347
|
+
/** `POST /v1/storefront/site/git/installations/state` — GitHub 설치 화면에 싣는 1회용 state(상점 플랫폼 전용) */
|
|
2348
|
+
createGitConnectState: () =>
|
|
2349
|
+
storeHttp.request(
|
|
2350
|
+
"POST",
|
|
2351
|
+
"/storefront/site/git/installations/state",
|
|
2352
|
+
storefrontGitConnectStateSchema,
|
|
2353
|
+
),
|
|
2354
|
+
/** `POST /v1/storefront/site/git/installations` — GitHub App 설치 확인(상점 플랫폼 전용) → 그 설치의 저장소 */
|
|
2355
|
+
linkGitInstallation: (body: LinkStorefrontGitInstallationRequest) =>
|
|
2356
|
+
storeHttp.request(
|
|
2357
|
+
"POST",
|
|
2358
|
+
"/storefront/site/git/installations",
|
|
2359
|
+
z.array(storefrontGitRepositorySchema),
|
|
2360
|
+
{ body: linkStorefrontGitInstallationRequestSchema.parse(body) },
|
|
2361
|
+
),
|
|
2362
|
+
/** `GET /v1/storefront/site/git/installations/{installationId}/repositories` — 확인한 설치의 저장소(상점 플랫폼 전용) */
|
|
2363
|
+
listGitRepositories: (installationId: number) =>
|
|
2364
|
+
storeHttp.request(
|
|
2365
|
+
"GET",
|
|
2366
|
+
`/storefront/site/git/installations/${encodeURIComponent(String(installationId))}/repositories`,
|
|
2367
|
+
z.array(storefrontGitRepositorySchema),
|
|
2368
|
+
),
|
|
2369
|
+
/** `POST /v1/storefront/site/git/connect` — 셀러 GitHub 저장소 연결(상점 플랫폼 전용) */
|
|
2370
|
+
connectGit: (body: ConnectStorefrontGitRequest) =>
|
|
2371
|
+
storeHttp.request("POST", "/storefront/site/git/connect", storefrontGitStatusSchema, {
|
|
2372
|
+
body: connectStorefrontGitRequestSchema.parse(body),
|
|
2373
|
+
}),
|
|
2374
|
+
/** `POST /v1/storefront/site/git/disconnect` — 연결 해제(sayren 저장소로 되돌림, 상점 플랫폼 전용) */
|
|
2375
|
+
disconnectGit: () =>
|
|
2376
|
+
storeHttp.request("POST", "/storefront/site/git/disconnect", storefrontGitStatusSchema),
|
|
2330
2377
|
},
|
|
2331
2378
|
|
|
2332
2379
|
subscription: {
|
package/src/index.ts
CHANGED
|
@@ -42,6 +42,7 @@ export * from "./schemas/market";
|
|
|
42
42
|
export * from "./schemas/misc";
|
|
43
43
|
export * from "./schemas/order";
|
|
44
44
|
export * from "./schemas/payment";
|
|
45
|
+
export * from "./schemas/plans";
|
|
45
46
|
export * from "./schemas/points";
|
|
46
47
|
export * from "./schemas/product";
|
|
47
48
|
export * from "./schemas/product-info";
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { responsePlanCodeSchema } from "./subscription";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 요금제 비교표 — `GET /v1/public/plans`(인증 없음). 요금제마다 가격과 기능 키 값을 준다. 값은 서버가 관리하고(사내 어드민 게시) 언제든
|
|
6
|
+
* 바뀔 수 있으니 코드에 요금제 수치를 두지 않는다. 상점 하나의 구독·사용량은 `subscription.ts`다
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const limitOrContract = (description: string) =>
|
|
10
|
+
z.number().int().nullable().describe(`${description}. null이면 계약(엔터프라이즈)·한도 없음`);
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 요금제 기능 키 값 — 요금제 비교표·상점 플랫폼 요금제 화면이 쓴다. 키는 서버 판정의 기능 키와 같다(추가만 한다). 상위 요금제는 하위 요금제
|
|
14
|
+
* 기능을 모두 포함한다
|
|
15
|
+
*/
|
|
16
|
+
export const planEntitlementsSchema = z
|
|
17
|
+
.object({
|
|
18
|
+
"features.members": z
|
|
19
|
+
.boolean()
|
|
20
|
+
.describe("소유자 외 구성원(관리자·직원)의 초대와 상점 접근. false면 소유자만 쓴다"),
|
|
21
|
+
"features.admin_api": z
|
|
22
|
+
.boolean()
|
|
23
|
+
.describe(
|
|
24
|
+
"관리 API(개인 액세스 토큰·외부 앱 토큰 호출). 상점 플랫폼·CLI·MCP는 모든 요금제에서 쓴다",
|
|
25
|
+
),
|
|
26
|
+
"features.analytics": z.boolean().describe("애널리틱스 화면·조회 API"),
|
|
27
|
+
"limits.ai_reads_monthly": limitOrContract("MCP 읽기 월 한도"),
|
|
28
|
+
"limits.ai_actions_monthly": limitOrContract(
|
|
29
|
+
"MCP 쓰기(AI 작업) 월 한도 — 주문 처리는 막지 않는다",
|
|
30
|
+
),
|
|
31
|
+
"limits.custom_domains": limitOrContract("내 도메인 수"),
|
|
32
|
+
"limits.webhooks": limitOrContract("웹훅 구독 수(0이면 쓸 수 없다)"),
|
|
33
|
+
"limits.public_apps": limitOrContract("공개 앱(앱 스토어 게시 앱) 설치 수"),
|
|
34
|
+
"limits.private_apps": limitOrContract(
|
|
35
|
+
"비공개 앱(이 상점 전용 앱) 설치 수(0이면 설치할 수 없다)",
|
|
36
|
+
),
|
|
37
|
+
"limits.ai_credits_monthly": limitOrContract(
|
|
38
|
+
"AI 상점 도우미 월 크레딧(1 크레딧 = 모델 원가 $0.01, 이월 없음)",
|
|
39
|
+
),
|
|
40
|
+
"limits.storefront_preview_hours_monthly": limitOrContract("편집 환경 시간(월, 시간)"),
|
|
41
|
+
"limits.storefront_build_minutes_monthly": limitOrContract("빌드 시간(월, 분)"),
|
|
42
|
+
"limits.storefront_requests_monthly": limitOrContract(
|
|
43
|
+
"스토어프론트 월 트래픽(요청 수) — 넘어도 막지 않고 안내만 한다",
|
|
44
|
+
),
|
|
45
|
+
"limits.admin_api_requests_monthly": limitOrContract(
|
|
46
|
+
"관리 API 월 요청 — 넘으면 속도만 낮춘다(주문 처리 제외)",
|
|
47
|
+
),
|
|
48
|
+
"rate_limit.admin_api": z
|
|
49
|
+
.number()
|
|
50
|
+
.nullable()
|
|
51
|
+
.describe("관리 API 분당 속도 배수(기본 분당 600 × 배수)"),
|
|
52
|
+
"storefront.cpu_ms": z.number().int().describe("스토어프론트 사이트 요청당 CPU 상한(ms)"),
|
|
53
|
+
"storefront.subrequests": z
|
|
54
|
+
.number()
|
|
55
|
+
.int()
|
|
56
|
+
.describe("스토어프론트 사이트 요청당 하위 요청 상한"),
|
|
57
|
+
"storefront.rate_limit_per_minute": z
|
|
58
|
+
.number()
|
|
59
|
+
.int()
|
|
60
|
+
.describe("스토어프론트 남용 방지 요청 속도 상한(사이트당 분당)"),
|
|
61
|
+
"seats.included": limitOrContract(
|
|
62
|
+
"포함 구성원 석 — 구성원은 모든 요금제에서 무료·무제한이라 null",
|
|
63
|
+
),
|
|
64
|
+
"retention.analytics_days": z.number().int().describe("애널리틱스 보관 일수"),
|
|
65
|
+
"retention.api_logs_days": limitOrContract("API 로그 보관 일수(0이면 API 로그 없음)"),
|
|
66
|
+
"retention.audit_days": limitOrContract("감사 로그 보관 일수"),
|
|
67
|
+
"support.tier": z
|
|
68
|
+
.union([z.enum(["COMMUNITY", "EMAIL", "EMAIL_PRIORITY", "DEDICATED", "SLA"]), z.string()])
|
|
69
|
+
.describe(
|
|
70
|
+
"지원 등급(`COMMUNITY`·`EMAIL`·`EMAIL_PRIORITY`·`DEDICATED`·`SLA`, 새 등급이 더해질 수 있다)",
|
|
71
|
+
),
|
|
72
|
+
})
|
|
73
|
+
.describe("요금제 기능 키 값");
|
|
74
|
+
export type PlanEntitlementValues = z.infer<typeof planEntitlementsSchema>;
|
|
75
|
+
|
|
76
|
+
/** 공개 요금제 한 줄 — `GET /v1/public/plans` */
|
|
77
|
+
export const publicPlanSchema = z.object({
|
|
78
|
+
code: responsePlanCodeSchema,
|
|
79
|
+
name: z.string().describe("표시 이름(Free·Pro·프리미엄·엔터프라이즈)"),
|
|
80
|
+
version: z.number().int().describe("요금제 버전 — 값이 바뀌면 새 버전이 게시된다"),
|
|
81
|
+
sort: z.number().int(),
|
|
82
|
+
purchasable: z
|
|
83
|
+
.boolean()
|
|
84
|
+
.describe("셀프 결제로 고를 수 있는가(Free·엔터프라이즈는 아니다 — 엔터프라이즈는 계약)"),
|
|
85
|
+
prices: z.object({
|
|
86
|
+
currency: z.literal("KRW"),
|
|
87
|
+
monthly: z.number().int().nullable().describe("월 가격(공급가, 부가세 별도)"),
|
|
88
|
+
startingAt: z.boolean().describe("「부터」 가격(엔터프라이즈 계약)"),
|
|
89
|
+
vatIncluded: z
|
|
90
|
+
.object({
|
|
91
|
+
monthly: z.number().int().nullable(),
|
|
92
|
+
})
|
|
93
|
+
.describe("표시 가격(부가세 포함) — 요금제 비교표는 이 값을 보인다"),
|
|
94
|
+
}),
|
|
95
|
+
entitlements: planEntitlementsSchema,
|
|
96
|
+
});
|
|
97
|
+
export type PublicPlan = z.infer<typeof publicPlanSchema>;
|
|
98
|
+
|
|
99
|
+
/** 요금제 비교표 — `GET /v1/public/plans`(인증 없음, 캐시 가능). 값은 서버가 관리하고 언제든 바뀔 수 있다 */
|
|
100
|
+
export const publicPlansSchema = z.object({
|
|
101
|
+
vatPercent: z.number().int().describe("부가세율(%)"),
|
|
102
|
+
plans: z.array(publicPlanSchema).describe("공개 요금제의 지금 버전 — 정렬 순"),
|
|
103
|
+
});
|
|
104
|
+
export type PublicPlans = z.infer<typeof publicPlansSchema>;
|
|
@@ -46,7 +46,8 @@ import { RESERVED_STORE_CODES } from "./store";
|
|
|
46
46
|
* - 502 `STOREFRONT_SANDBOX_UNAVAILABLE` — 편집 Sandbox 호출이 실패했다. 잠시 뒤 다시 한다
|
|
47
47
|
*
|
|
48
48
|
* 소스 내려받기·올리기(#60, `/v1/storefront/site/source/**`, `sayren` CLI):
|
|
49
|
-
* - 409 `SOURCE_CHANGED` — 작업 트리가 내려받은 뒤(`expectedBaseRef`)
|
|
49
|
+
* - 409 `SOURCE_CHANGED` — 작업 트리가 내려받은 뒤(`expectedBaseRef`) 바뀌었고 같은 파일을 서로 다르게 고쳤다(상점 플랫폼·AI 편집). 겹치지 않으면 서버가
|
|
50
|
+
* 3-way 병합한다(응답 `merged`). `error.details.currentRef`·`conflicts`(충돌 파일)
|
|
50
51
|
* - 409 `EDIT_SESSION_OPEN` — 편집 환경이 열려 있다. `endEditSession: true`로 끄고 진행할 수 있다
|
|
51
52
|
* - 409 `SOURCE_BLOBS_MISSING` — 올리지 않은 파일 내용이 있다(`error.details.hashes`). `POST source/blobs`로 올리고 다시 한다
|
|
52
53
|
* - 409 `DEPENDENCY_REJECTED` — 쓸 수 없는 npm 의존성이다(`error.details.rejected: [{ name, version, reason, detail }]`)
|
|
@@ -272,8 +273,18 @@ export const storefrontVersionSchema = z.object({
|
|
|
272
273
|
.nullable()
|
|
273
274
|
.optional()
|
|
274
275
|
.describe(
|
|
275
|
-
"만든 경로 (`CONSOLE` 상점 플랫폼 · `AI` AI 에이전트(MCP) · `CLI` `sayren` CLI · `API` 관리 API · `SYSTEM` 자동). 늘어날 수 있다",
|
|
276
|
+
"만든 경로 (`CONSOLE` 상점 플랫폼 · `AI` AI 에이전트(MCP) · `CLI` `sayren` CLI · `API` 관리 API · `SYSTEM` 자동 · `GIT` 연결한 저장소 push). 늘어날 수 있다",
|
|
276
277
|
),
|
|
278
|
+
gitRef: z
|
|
279
|
+
.string()
|
|
280
|
+
.nullable()
|
|
281
|
+
.optional()
|
|
282
|
+
.describe("연결한 저장소의 push로 만든 버전의 브랜치. 그 밖은 null"),
|
|
283
|
+
commitSha: z
|
|
284
|
+
.string()
|
|
285
|
+
.nullable()
|
|
286
|
+
.optional()
|
|
287
|
+
.describe("이 버전 소스를 담은 저장소 커밋(Git 원천 사이트). 저장소에 없는 버전은 null"),
|
|
277
288
|
createdAt: z.string().describe("만든 시각 (ISO 8601)"),
|
|
278
289
|
previewable: z
|
|
279
290
|
.boolean()
|
|
@@ -362,6 +373,12 @@ export type StorefrontSiteSnapshot = z.infer<typeof storefrontSiteSnapshotSchema
|
|
|
362
373
|
|
|
363
374
|
export const storefrontSiteSchema = z.object({
|
|
364
375
|
siteId: z.string(),
|
|
376
|
+
deployWithoutApproval: z
|
|
377
|
+
.boolean()
|
|
378
|
+
.optional()
|
|
379
|
+
.describe(
|
|
380
|
+
"승인 없이 배포 — 켜져 있으면 AI 에이전트의 발행·되돌리기가 승인 없이 실행된다. 상점 플랫폼에서 OWNER·ADMIN만 바꾼다",
|
|
381
|
+
),
|
|
365
382
|
slug: z.string().describe("주소 슬러그"),
|
|
366
383
|
hostname: z.string().describe("대표 호스트 이름"),
|
|
367
384
|
url: z.string().describe("대표 주소 (`https://{hostname}`)"),
|
|
@@ -1475,7 +1492,7 @@ export const replaceStorefrontSourceRequestSchema = z.object({
|
|
|
1475
1492
|
expectedBaseRef: storefrontSourceRefSchema
|
|
1476
1493
|
.optional()
|
|
1477
1494
|
.describe(
|
|
1478
|
-
"내려받은 작업 트리.
|
|
1495
|
+
"내려받은 작업 트리. 그 뒤 작업 트리가 바뀌었으면 이 트리를 기준으로 3-way 병합하고, 같은 곳을 고쳤으면 409 `SOURCE_CHANGED`다. 생략하면 조건 없이 덮어쓴다",
|
|
1479
1496
|
),
|
|
1480
1497
|
files: z
|
|
1481
1498
|
.array(
|
|
@@ -1510,15 +1527,135 @@ export const replaceStorefrontSourceRequestSchema = z.object({
|
|
|
1510
1527
|
export type ReplaceStorefrontSourceRequest = z.infer<typeof replaceStorefrontSourceRequestSchema>;
|
|
1511
1528
|
|
|
1512
1529
|
export const storefrontSourceReplacedSchema = z.object({
|
|
1513
|
-
sourceRef: storefrontSourceRefSchema.describe(
|
|
1530
|
+
sourceRef: storefrontSourceRefSchema.describe(
|
|
1531
|
+
"새 작업 트리(버전 만들기의 `expectedSourceRef`). 다음 올리기의 기준은 `uploadedRef`다",
|
|
1532
|
+
),
|
|
1514
1533
|
previousRef: z.string().describe("바꾸기 전 작업 트리"),
|
|
1515
1534
|
treeSha256: z.string(),
|
|
1516
1535
|
files: z.number().int().min(0),
|
|
1517
1536
|
bytes: z.number().int().min(0),
|
|
1518
1537
|
changed: z.boolean().describe("내용이 바뀌었는가 (같은 트리를 다시 올리면 false)"),
|
|
1538
|
+
merged: z
|
|
1539
|
+
.boolean()
|
|
1540
|
+
.optional()
|
|
1541
|
+
.describe(
|
|
1542
|
+
"내려받은 뒤 바뀐 작업 트리와 3-way 병합해 결과가 올린 목록과 다른가(서버 쪽 변경이 함께 남는다). 같은 곳을 고쳤으면 409 `SOURCE_CHANGED`(`details.conflicts` 충돌 파일)",
|
|
1543
|
+
),
|
|
1544
|
+
uploadedRef: storefrontSourceRefSchema
|
|
1545
|
+
.optional()
|
|
1546
|
+
.describe(
|
|
1547
|
+
"올린 목록 그대로의 트리 — 다음 올리기의 `expectedBaseRef`(클라이언트가 가진 트리). 병합하지 않았으면 `sourceRef`와 같다",
|
|
1548
|
+
),
|
|
1519
1549
|
endedEditSession: z.boolean().describe("열린 편집 환경을 끄고 진행했는가"),
|
|
1520
1550
|
dependencyWarnings: z
|
|
1521
1551
|
.array(storefrontDependencyFindingSchema)
|
|
1522
1552
|
.describe("배포를 막지 않는 의존성 경고 (보안 권고 등)"),
|
|
1523
1553
|
});
|
|
1524
1554
|
export type StorefrontSourceReplaced = z.infer<typeof storefrontSourceReplacedSchema>;
|
|
1555
|
+
|
|
1556
|
+
// ─── Git 원천 (#138 G5) ───────────────────────────────────
|
|
1557
|
+
|
|
1558
|
+
/**
|
|
1559
|
+
* `GET /v1/storefront/site/git` — 사이트의 Git 원천. 발행한 소스는 GitHub 저장소 main에 있다(사내 저장소 또는 셀러가 연결한 저장소).
|
|
1560
|
+
* 연결 전이면 필드가 null이다
|
|
1561
|
+
*/
|
|
1562
|
+
export const storefrontGitStatusSchema = z.object({
|
|
1563
|
+
provider: z.enum(["GITHUB"]).nullable().describe("Git 원천이 켜져 있으면 `GITHUB`, 아니면 null"),
|
|
1564
|
+
owner: z
|
|
1565
|
+
.enum(["SAYREN", "SELLER"])
|
|
1566
|
+
.nullable()
|
|
1567
|
+
.describe("`SAYREN` sayren이 관리하는 저장소 · `SELLER` 셀러가 연결한 저장소"),
|
|
1568
|
+
repository: z
|
|
1569
|
+
.string()
|
|
1570
|
+
.nullable()
|
|
1571
|
+
.describe("연결한 셀러 저장소(`owner/name`). sayren 저장소면 null"),
|
|
1572
|
+
productionBranch: z.string().nullable().describe("운영 배포 브랜치"),
|
|
1573
|
+
rootDirectory: z.string().nullable().describe("저장소 안 사이트 루트(빈 문자열 = 저장소 루트)"),
|
|
1574
|
+
connectedAt: z.string().nullable().describe("원천이 켜진 시각 (ISO 8601)"),
|
|
1575
|
+
headCommitSha: z.string().nullable().describe("운영 브랜치의 마지막 커밋"),
|
|
1576
|
+
mainChanged: z
|
|
1577
|
+
.boolean()
|
|
1578
|
+
.describe(
|
|
1579
|
+
"발행 전 작업이 지금 운영 브랜치 위가 아니다 — 발행하려면 최신 운영 브랜치를 합친 버전을 만든다(아니면 409 `STOREFRONT_MAIN_CHANGED`)",
|
|
1580
|
+
),
|
|
1581
|
+
autoPromotePaused: z
|
|
1582
|
+
.boolean()
|
|
1583
|
+
.describe(
|
|
1584
|
+
"되돌린 상태 — 저장소 push는 빌드만 하고 운영을 바꾸지 않는다. 버전을 발행하면 다시 켜진다",
|
|
1585
|
+
),
|
|
1586
|
+
publishPending: z.boolean().describe("발행한 버전을 운영 브랜치에 올리는 중"),
|
|
1587
|
+
publishErrorCode: z
|
|
1588
|
+
.string()
|
|
1589
|
+
.nullable()
|
|
1590
|
+
.describe(
|
|
1591
|
+
"마지막 발행을 운영 브랜치에 올리지 못한 이유(브랜치 보호 등). 운영과 저장소가 다를 수 있다",
|
|
1592
|
+
),
|
|
1593
|
+
archivedWorkRef: z
|
|
1594
|
+
.string()
|
|
1595
|
+
.nullable()
|
|
1596
|
+
.describe("셀러 저장소를 연결할 때 보관한 발행 전 작업 트리(연결 전 편집). 없으면 null"),
|
|
1597
|
+
});
|
|
1598
|
+
export type StorefrontGitStatus = z.infer<typeof storefrontGitStatusSchema>;
|
|
1599
|
+
|
|
1600
|
+
export const storefrontGitRepositorySchema = z.object({
|
|
1601
|
+
repoId: z.number().int().describe("GitHub 저장소 id"),
|
|
1602
|
+
fullName: z.string().describe("`owner/name`"),
|
|
1603
|
+
defaultBranch: z.string(),
|
|
1604
|
+
});
|
|
1605
|
+
export type StorefrontGitRepository = z.infer<typeof storefrontGitRepositorySchema>;
|
|
1606
|
+
|
|
1607
|
+
/** `POST /v1/storefront/site/git/installations` — GitHub App 설치 화면에서 돌아온 값(`installation_id`·`code`) */
|
|
1608
|
+
export const linkStorefrontGitInstallationRequestSchema = z.object({
|
|
1609
|
+
installationId: z.number().int().positive(),
|
|
1610
|
+
code: z
|
|
1611
|
+
.string()
|
|
1612
|
+
.min(1)
|
|
1613
|
+
.max(200)
|
|
1614
|
+
.describe("설치 화면이 돌려준 GitHub 사용자 인증 코드(한 번만 쓴다)"),
|
|
1615
|
+
state: z
|
|
1616
|
+
.string()
|
|
1617
|
+
.min(1)
|
|
1618
|
+
.max(200)
|
|
1619
|
+
.describe(
|
|
1620
|
+
"설치 화면으로 보내기 전에 받은 연결 state(`POST …/git/installations/state`, 한 번만 쓴다)",
|
|
1621
|
+
),
|
|
1622
|
+
});
|
|
1623
|
+
|
|
1624
|
+
/** `POST /v1/storefront/site/git/installations/state` — GitHub 설치 화면에 싣는 1회용 state(이 상점·사용자, 10분) */
|
|
1625
|
+
export const storefrontGitConnectStateSchema = z.object({
|
|
1626
|
+
state: z.string(),
|
|
1627
|
+
expiresAt: z.string(),
|
|
1628
|
+
});
|
|
1629
|
+
export type StorefrontGitConnectState = z.infer<typeof storefrontGitConnectStateSchema>;
|
|
1630
|
+
export type LinkStorefrontGitInstallationRequest = z.infer<
|
|
1631
|
+
typeof linkStorefrontGitInstallationRequestSchema
|
|
1632
|
+
>;
|
|
1633
|
+
|
|
1634
|
+
/** `POST /v1/storefront/site/git/connect` */
|
|
1635
|
+
export const connectStorefrontGitRequestSchema = z.object({
|
|
1636
|
+
installationId: z.number().int().positive(),
|
|
1637
|
+
repoId: z.number().int().positive(),
|
|
1638
|
+
productionBranch: z
|
|
1639
|
+
.string()
|
|
1640
|
+
.min(1)
|
|
1641
|
+
.max(200)
|
|
1642
|
+
.regex(/^[A-Za-z0-9._-]+(\/[A-Za-z0-9._-]+)*$/)
|
|
1643
|
+
.optional()
|
|
1644
|
+
.describe("운영 배포 브랜치(생략하면 저장소 기본 브랜치)"),
|
|
1645
|
+
rootDirectory: z
|
|
1646
|
+
.string()
|
|
1647
|
+
.max(200)
|
|
1648
|
+
.regex(/^$|^[A-Za-z0-9._-]+(\/[A-Za-z0-9._-]+)*$/)
|
|
1649
|
+
.refine((v) => !v.split("/").some((seg) => seg === "." || seg === ".."), "상대 경로만")
|
|
1650
|
+
.optional()
|
|
1651
|
+
.describe("저장소 안 사이트 루트(생략하면 저장소 루트)"),
|
|
1652
|
+
});
|
|
1653
|
+
export type ConnectStorefrontGitRequest = z.infer<typeof connectStorefrontGitRequestSchema>;
|
|
1654
|
+
|
|
1655
|
+
/** `PUT /v1/storefront/site/deploy-approval` — 승인 없이 배포(#138) */
|
|
1656
|
+
export const setStorefrontDeployApprovalRequestSchema = z.object({
|
|
1657
|
+
deployWithoutApproval: z.boolean(),
|
|
1658
|
+
});
|
|
1659
|
+
export type SetStorefrontDeployApprovalRequest = z.infer<
|
|
1660
|
+
typeof setStorefrontDeployApprovalRequestSchema
|
|
1661
|
+
>;
|
|
@@ -47,6 +47,9 @@ export const subscriptionLimitsSchema = z.object({
|
|
|
47
47
|
storefrontPreviewHoursMonthly: limit("스토어프론트 편집 미리보기 월 시간"),
|
|
48
48
|
storefrontBuildMinutesMonthly: limit("스토어프론트 빌드 월 분"),
|
|
49
49
|
adminApiRequestsMonthly: limit("관리 API 요청 월 포함량(넘으면 속도만 낮춘다, 주문 처리 제외)"),
|
|
50
|
+
publicApps: limit("공개 앱(앱 스토어에 게시된 앱) 설치 수").optional(),
|
|
51
|
+
privateApps: limit("비공개 앱(이 상점 전용 앱) 설치 수(0이면 설치할 수 없다)").optional(),
|
|
52
|
+
aiCreditsMonthly: limit("AI 상점 도우미 월 크레딧").optional(),
|
|
50
53
|
});
|
|
51
54
|
export type SubscriptionLimits = z.infer<typeof subscriptionLimitsSchema>;
|
|
52
55
|
|
|
@@ -65,6 +68,8 @@ export const subscriptionUsageSchema = z.object({
|
|
|
65
68
|
seats: z.number().int().describe("현재 석 수 — 구성원(OWNER 포함) + 대기 중 초대"),
|
|
66
69
|
customDomains: z.number().int().describe("현재 내 도메인 수(해제한 도메인 제외)"),
|
|
67
70
|
webhooks: z.number().int().describe("현재 웹훅 구독 수"),
|
|
71
|
+
publicApps: z.number().int().optional().describe("현재 설치한 공개 앱 수"),
|
|
72
|
+
privateApps: z.number().int().optional().describe("현재 설치한 비공개 앱 수"),
|
|
68
73
|
});
|
|
69
74
|
export type SubscriptionUsage = z.infer<typeof subscriptionUsageSchema>;
|
|
70
75
|
|
|
@@ -89,6 +94,10 @@ export const storeSubscriptionSchema = z.object({
|
|
|
89
94
|
features: z.object({
|
|
90
95
|
adminApi: z.boolean().describe("관리 API(개인 액세스 토큰·외부 앱 토큰 호출)를 쓸 수 있다"),
|
|
91
96
|
analytics: z.boolean().describe("애널리틱스 조회를 쓸 수 있다"),
|
|
97
|
+
members: z
|
|
98
|
+
.boolean()
|
|
99
|
+
.optional()
|
|
100
|
+
.describe("소유자 외 구성원이 상점에 접근할 수 있다(false면 소유자만, 구성원 목록은 남는다)"),
|
|
92
101
|
storeClone: z.boolean().describe("더 쓰지 않는다 — 상점 복제 기능을 없애 항상 false"),
|
|
93
102
|
removeBadge: z.boolean().describe("더 쓰지 않는다 — 배지 키를 없애 항상 false"),
|
|
94
103
|
}),
|
|
@@ -107,6 +116,31 @@ export const storeSubscriptionSchema = z.object({
|
|
|
107
116
|
resetsAt: z.string().describe("한도가 초기화되는 시각(ISO 8601)"),
|
|
108
117
|
})
|
|
109
118
|
.describe("MCP 읽기 한도 요약"),
|
|
119
|
+
aiCredits: z
|
|
120
|
+
.object({
|
|
121
|
+
monthly: z.number().int().nullable().describe("요금제 월 크레딧. null이면 한도 없음"),
|
|
122
|
+
granted: z.number().int().describe("이번 기간에 쓸 수 있는 추가 지급 크레딧"),
|
|
123
|
+
used: z.number().int().describe("이번 기간 사용한 크레딧"),
|
|
124
|
+
monthlyUsed: z.number().int().optional().describe("이번 기간 월 크레딧에서 쓴 양"),
|
|
125
|
+
purchased: z
|
|
126
|
+
.number()
|
|
127
|
+
.int()
|
|
128
|
+
.optional()
|
|
129
|
+
.describe("남은 구매 크레딧 — 구매일부터 1년, 월 크레딧이 초기화돼도 남는다"),
|
|
130
|
+
complimentary: z.number().int().optional().describe("남은 무상 지급 크레딧(이벤트·보상)"),
|
|
131
|
+
remaining: z
|
|
132
|
+
.number()
|
|
133
|
+
.int()
|
|
134
|
+
.nullable()
|
|
135
|
+
.describe("남은 크레딧(월 + 구매 + 무상). null이면 한도 없음"),
|
|
136
|
+
resetsAt: z
|
|
137
|
+
.string()
|
|
138
|
+
.describe("월 크레딧이 초기화되는 시각(ISO 8601). 월 크레딧은 이월하지 않는다"),
|
|
139
|
+
})
|
|
140
|
+
.optional()
|
|
141
|
+
.describe(
|
|
142
|
+
"AI 상점 도우미 크레딧 — 1 크레딧은 모델 원가 $0.01. 남은 크레딧이 없으면 새 실행을 만들 수 없다",
|
|
143
|
+
),
|
|
110
144
|
salesFeePercent: z.literal(0).describe("판매 수수료(%). 모든 요금제 0이다"),
|
|
111
145
|
});
|
|
112
146
|
export type StoreSubscription = z.infer<typeof storeSubscriptionSchema>;
|
|
@@ -133,90 +167,3 @@ export const planErrorDetailsSchema = z
|
|
|
133
167
|
})
|
|
134
168
|
.loose();
|
|
135
169
|
export type PlanErrorDetails = z.infer<typeof planErrorDetailsSchema>;
|
|
136
|
-
|
|
137
|
-
const limitOrContract = (description: string) =>
|
|
138
|
-
z.number().int().nullable().describe(`${description}. null이면 계약(엔터프라이즈)·한도 없음`);
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* 요금제 기능 키 값 — 요금제 비교표·상점 플랫폼 요금제 화면이 쓴다. 키는 서버 판정의 기능 키와 같다(추가만 한다). 상위 요금제는 하위 요금제
|
|
142
|
-
* 기능을 모두 포함한다
|
|
143
|
-
*/
|
|
144
|
-
export const planEntitlementsSchema = z
|
|
145
|
-
.object({
|
|
146
|
-
"features.admin_api": z
|
|
147
|
-
.boolean()
|
|
148
|
-
.describe(
|
|
149
|
-
"관리 API(개인 액세스 토큰·외부 앱 토큰 호출). 상점 플랫폼·CLI·MCP는 모든 요금제에서 쓴다",
|
|
150
|
-
),
|
|
151
|
-
"features.analytics": z.boolean().describe("애널리틱스 화면·조회 API"),
|
|
152
|
-
"limits.ai_reads_monthly": limitOrContract("MCP 읽기 월 한도"),
|
|
153
|
-
"limits.ai_actions_monthly": limitOrContract(
|
|
154
|
-
"MCP 쓰기(AI 작업) 월 한도 — 주문 처리는 막지 않는다",
|
|
155
|
-
),
|
|
156
|
-
"limits.custom_domains": limitOrContract("내 도메인 수"),
|
|
157
|
-
"limits.webhooks": limitOrContract("웹훅 구독 수(0이면 쓸 수 없다)"),
|
|
158
|
-
"limits.storefront_preview_hours_monthly": limitOrContract("편집 환경 시간(월, 시간)"),
|
|
159
|
-
"limits.storefront_build_minutes_monthly": limitOrContract("빌드 시간(월, 분)"),
|
|
160
|
-
"limits.storefront_requests_monthly": limitOrContract(
|
|
161
|
-
"스토어프론트 월 트래픽(요청 수) — 넘어도 막지 않고 안내만 한다",
|
|
162
|
-
),
|
|
163
|
-
"limits.admin_api_requests_monthly": limitOrContract(
|
|
164
|
-
"관리 API 월 요청 — 넘으면 속도만 낮춘다(주문 처리 제외)",
|
|
165
|
-
),
|
|
166
|
-
"rate_limit.admin_api": z
|
|
167
|
-
.number()
|
|
168
|
-
.nullable()
|
|
169
|
-
.describe("관리 API 분당 속도 배수(기본 분당 600 × 배수)"),
|
|
170
|
-
"storefront.cpu_ms": z.number().int().describe("스토어프론트 사이트 요청당 CPU 상한(ms)"),
|
|
171
|
-
"storefront.subrequests": z
|
|
172
|
-
.number()
|
|
173
|
-
.int()
|
|
174
|
-
.describe("스토어프론트 사이트 요청당 하위 요청 상한"),
|
|
175
|
-
"storefront.rate_limit_per_minute": z
|
|
176
|
-
.number()
|
|
177
|
-
.int()
|
|
178
|
-
.describe("스토어프론트 남용 방지 요청 속도 상한(사이트당 분당)"),
|
|
179
|
-
"seats.included": limitOrContract(
|
|
180
|
-
"포함 구성원 석 — 구성원은 모든 요금제에서 무료·무제한이라 null",
|
|
181
|
-
),
|
|
182
|
-
"retention.analytics_days": z.number().int().describe("애널리틱스 보관 일수"),
|
|
183
|
-
"retention.api_logs_days": limitOrContract("API 로그 보관 일수(0이면 API 로그 없음)"),
|
|
184
|
-
"retention.audit_days": limitOrContract("감사 로그 보관 일수"),
|
|
185
|
-
"support.tier": z
|
|
186
|
-
.union([z.enum(["COMMUNITY", "EMAIL", "EMAIL_PRIORITY", "DEDICATED", "SLA"]), z.string()])
|
|
187
|
-
.describe(
|
|
188
|
-
"지원 등급(`COMMUNITY`·`EMAIL`·`EMAIL_PRIORITY`·`DEDICATED`·`SLA`, 새 등급이 더해질 수 있다)",
|
|
189
|
-
),
|
|
190
|
-
})
|
|
191
|
-
.describe("요금제 기능 키 값");
|
|
192
|
-
export type PlanEntitlementValues = z.infer<typeof planEntitlementsSchema>;
|
|
193
|
-
|
|
194
|
-
/** 공개 요금제 한 줄 — `GET /v1/public/plans` */
|
|
195
|
-
export const publicPlanSchema = z.object({
|
|
196
|
-
code: responsePlanCodeSchema,
|
|
197
|
-
name: z.string().describe("표시 이름(Free·Pro·프리미엄·엔터프라이즈)"),
|
|
198
|
-
version: z.number().int().describe("요금제 버전 — 값이 바뀌면 새 버전이 게시된다"),
|
|
199
|
-
sort: z.number().int(),
|
|
200
|
-
purchasable: z
|
|
201
|
-
.boolean()
|
|
202
|
-
.describe("셀프 결제로 고를 수 있는가(Free·엔터프라이즈는 아니다 — 엔터프라이즈는 계약)"),
|
|
203
|
-
prices: z.object({
|
|
204
|
-
currency: z.literal("KRW"),
|
|
205
|
-
monthly: z.number().int().nullable().describe("월 가격(공급가, 부가세 별도)"),
|
|
206
|
-
startingAt: z.boolean().describe("「부터」 가격(엔터프라이즈 계약)"),
|
|
207
|
-
vatIncluded: z
|
|
208
|
-
.object({
|
|
209
|
-
monthly: z.number().int().nullable(),
|
|
210
|
-
})
|
|
211
|
-
.describe("표시 가격(부가세 포함) — 요금제 비교표는 이 값을 보인다"),
|
|
212
|
-
}),
|
|
213
|
-
entitlements: planEntitlementsSchema,
|
|
214
|
-
});
|
|
215
|
-
export type PublicPlan = z.infer<typeof publicPlanSchema>;
|
|
216
|
-
|
|
217
|
-
/** 요금제 비교표 — `GET /v1/public/plans`(인증 없음, 캐시 가능). 값은 서버가 관리하고 언제든 바뀔 수 있다 */
|
|
218
|
-
export const publicPlansSchema = z.object({
|
|
219
|
-
vatPercent: z.number().int().describe("부가세율(%)"),
|
|
220
|
-
plans: z.array(publicPlanSchema).describe("공개 요금제의 지금 버전 — 정렬 순"),
|
|
221
|
-
});
|
|
222
|
-
export type PublicPlans = z.infer<typeof publicPlansSchema>;
|