@sayren/store-sdk 0.67.0 → 0.69.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.
@@ -1,8 +1,7 @@
1
1
  import * as z from "zod";
2
2
 
3
3
  /**
4
- * 요금제·구독 — `GET /v1/store/subscription`(스코프 `store:r`). 구독 단위는 상점이다.
5
- * 결제 수단·청구 금액은 싣지 않는다. 요금제 변경은 상점 플랫폼에서만 한다.
4
+ * 요금제 코드와 요금제 오류의 `error.details`. 요금제 비교표·구독 조회는 공개 계약이 아니다(0.69.0에서 뺐다).
6
5
  */
7
6
 
8
7
  /** 요금제 코드 — 이름(`plan.name`)이 바뀌어도 코드는 바뀌지 않는다. 값은 추가만 한다 */
@@ -22,107 +21,6 @@ export const responsePlanCodeSchema = z
22
21
  .describe(planCodeSchema.description ?? "요금제 코드");
23
22
  export type ResponsePlanCode = PlanCode | (string & {});
24
23
 
25
- export const subscriptionStatusSchema = z
26
- .enum(["ACTIVE", "PAST_DUE", "CANCELED", "INCOMPLETE"])
27
- .describe(
28
- "구독 상태. `ACTIVE`=이용 중, `PAST_DUE`=결제 실패 후 유예 중, `CANCELED`=해지됨, `INCOMPLETE`=첫 결제 대기",
29
- );
30
- export type SubscriptionStatus = z.infer<typeof subscriptionStatusSchema>;
31
-
32
- const limit = (description: string) =>
33
- z.number().int().nullable().describe(`${description}. null이면 한도 없음`);
34
-
35
- export const subscriptionLimitsSchema = z.object({
36
- liveOrdersMonthly: limit("더 쓰지 않는다 — 라이브 주문 수로 요금제를 나누지 않아 항상 null"),
37
- seatsIncluded: limit("구성원 석 — 구성원은 모든 요금제에서 무료·무제한이라 null"),
38
- aiActionsMonthly: limit("MCP(에이전트) 쓰기(AI 작업) 월 한도"),
39
- aiReadsMonthly: limit("MCP(에이전트) 읽기 월 한도"),
40
- customDomains: limit("내 도메인 수"),
41
- webhooks: limit("웹훅 구독 수(0이면 쓸 수 없다)"),
42
- socialProviders: limit("더 쓰지 않는다 — 소셜 로그인 공급자 수로 요금제를 나누지 않아 항상 null"),
43
- emailsMonthly: limit("더 쓰지 않는다 — 메일 한도가 없어 항상 null"),
44
- storefrontRequestsMonthly: limit("스토어프론트 월 트래픽(요청 수, 넘어도 막지 않고 안내만)"),
45
- apiLogRetentionDays: limit("API 로그 보관 일수(0이면 API 로그 없음)"),
46
- auditLogRetentionDays: limit("감사 로그 보관 일수"),
47
- storefrontPreviewHoursMonthly: limit("스토어프론트 편집 미리보기 월 시간"),
48
- storefrontBuildMinutesMonthly: limit("스토어프론트 빌드 월 분"),
49
- adminApiRequestsMonthly: limit("관리 API 요청 월 포함량(넘으면 속도만 낮춘다, 주문 처리 제외)"),
50
- publicApps: limit("공개 앱(앱 스토어에 게시된 앱) 설치 수").optional(),
51
- privateApps: limit("비공개 앱(이 상점 전용 앱) 설치 수(0이면 설치할 수 없다)").optional(),
52
- });
53
- export type SubscriptionLimits = z.infer<typeof subscriptionLimitsSchema>;
54
-
55
- export const subscriptionUsageSchema = z.object({
56
- liveOrders: z.number().int().describe("이번 기간 라이브 주문 수(테스트 결제 주문 제외)"),
57
- aiActions: z.number().int().describe("이번 기간 MCP(에이전트) 쓰기(AI 작업) 수"),
58
- aiReads: z.number().int().describe("이번 기간 MCP(에이전트) 읽기 수"),
59
- storefrontRequests: z.number().int().describe("이번 기간 스토어프론트 요청 수"),
60
- adminApiRequests: z
61
- .number()
62
- .int()
63
- .describe("이번 기간 관리 API 요청 수(API 토큰·앱·에이전트 호출, 상점 플랫폼 제외)"),
64
- emails: z.number().int().describe("이번 기간 초대·양도 알림 메일 수(한도 없음, 표시만)"),
65
- storefrontPreviewMinutes: z.number().int().describe("이번 기간 편집 미리보기 분(끝난 세션)"),
66
- storefrontBuildMinutes: z.number().int().describe("이번 기간 빌드 분(끝난 빌드)"),
67
- seats: z.number().int().describe("현재 석 수 — 구성원(OWNER 포함) + 대기 중 초대"),
68
- customDomains: z.number().int().describe("현재 내 도메인 수(해제한 도메인 제외)"),
69
- webhooks: z.number().int().describe("현재 웹훅 구독 수"),
70
- publicApps: z.number().int().optional().describe("현재 설치한 공개 앱 수"),
71
- privateApps: z.number().int().optional().describe("현재 설치한 비공개 앱 수"),
72
- });
73
- export type SubscriptionUsage = z.infer<typeof subscriptionUsageSchema>;
74
-
75
- export const storeSubscriptionSchema = z.object({
76
- plan: z.object({
77
- code: responsePlanCodeSchema,
78
- name: z.string().describe("요금제 표시 이름(예: 프로)"),
79
- }),
80
- status: subscriptionStatusSchema,
81
- interval: z
82
- .enum(["MONTH"])
83
- .nullable()
84
- .describe("결제 주기. `MONTH`=월간. 요금을 내지 않는 요금제(베타·무료)는 null"),
85
- cancelAtPeriodEnd: z.boolean().describe("기간 끝에 해지 예정인가"),
86
- period: z
87
- .object({
88
- start: z.string().describe("사용량 기간 시작(ISO 8601)"),
89
- end: z.string().describe("사용량 기간 끝(ISO 8601, 이 시각에 사용량이 초기화된다)"),
90
- })
91
- .describe("사용량을 세는 기간. 요금을 내지 않는 요금제는 한국 시간 달력 월이다"),
92
- limits: subscriptionLimitsSchema,
93
- features: z.object({
94
- adminApi: z.boolean().describe("관리 API(개인 액세스 토큰·외부 앱 토큰 호출)를 쓸 수 있다"),
95
- analytics: z.boolean().describe("애널리틱스 조회를 쓸 수 있다"),
96
- members: z
97
- .boolean()
98
- .optional()
99
- .describe("소유자 외 구성원이 상점에 접근할 수 있다(false면 소유자만, 구성원 목록은 남는다)"),
100
- aiAssistant: z
101
- .boolean()
102
- .optional()
103
- .describe("AI 상점 도우미를 쓸 수 있다(false면 새 실행을 시작할 수 없다)"),
104
- storeClone: z.boolean().describe("더 쓰지 않는다 — 상점 복제 기능을 없애 항상 false"),
105
- removeBadge: z.boolean().describe("더 쓰지 않는다 — 배지 키를 없애 항상 false"),
106
- }),
107
- usage: subscriptionUsageSchema,
108
- aiActions: z
109
- .object({
110
- limit: z.number().int().nullable(),
111
- used: z.number().int(),
112
- resetsAt: z.string().describe("한도가 초기화되는 시각(ISO 8601)"),
113
- })
114
- .describe("AI 작업(MCP 쓰기) 한도 요약 — 에이전트가 남은 작업 수를 판단할 때 쓴다"),
115
- aiReads: z
116
- .object({
117
- limit: z.number().int().nullable(),
118
- used: z.number().int(),
119
- resetsAt: z.string().describe("한도가 초기화되는 시각(ISO 8601)"),
120
- })
121
- .describe("MCP 읽기 한도 요약"),
122
- salesFeePercent: z.literal(0).describe("판매 수수료(%). 모든 요금제 0이다"),
123
- });
124
- export type StoreSubscription = z.infer<typeof storeSubscriptionSchema>;
125
-
126
24
  /**
127
25
  * 요금제 한도 오류의 `error.details` — 기존 오류 코드(`STORE_LIMIT_EXCEEDED`·`STOREFRONT_DOMAIN_LIMIT`·`WEBHOOK_LIMIT_EXCEEDED` 등)와
128
26
  * 요금제 오류(`PLAN_LIMIT_EXCEEDED`·`PLAN_AI_ACTIONS_EXCEEDED`·`PLAN_AI_READS_EXCEEDED`·`PLAN_FEATURE_REQUIRED`·`PLAN_API_QUOTA_EXCEEDED`)가 같은 형식을 싣는다.
@@ -8,12 +8,14 @@ import { strictRequest } from "./strict";
8
8
  * - `description`: 상세설명 본문에 삽입하는 미디어. 동영상과 svg도 받는다.
9
9
  * - `flow-attachment`: 주문 흐름 행동의 첨부(시안 등, 이슈 #115). 구매자에게 보이므로 정지 이미지와 PDF만 받는다.
10
10
  * - `ai-attachment`: 상점 플랫폼 AI 채팅에 붙이는 자료(이슈 #124). 모델이 읽는 정지 이미지와 PDF만 받는다.
11
+ * - `store-icon`: 상점 아이콘(정사각, 이슈 #400). 메일에도 실리므로 메일 클라이언트가 그리는 PNG·JPG만 받는다.
11
12
  */
12
13
  export const uploadPurposeSchema = z.enum([
13
14
  "product-image",
14
15
  "description",
15
16
  "flow-attachment",
16
17
  "ai-attachment",
18
+ "store-icon",
17
19
  ]);
18
20
 
19
21
  export type UploadPurpose = z.infer<typeof uploadPurposeSchema>;
@@ -51,6 +53,10 @@ export const UPLOAD_PURPOSE_LIMITS: Record<UploadPurpose, UploadPurposeLimit> =
51
53
  extensions: ["jpg", "jpeg", "png", "webp", "gif", "pdf"],
52
54
  maxBytes: 10 * MB,
53
55
  },
56
+ "store-icon": {
57
+ extensions: ["jpg", "jpeg", "png"],
58
+ maxBytes: 5 * MB,
59
+ },
54
60
  };
55
61
 
56
62
  /** 파일명의 소문자 확장자. 확장자가 없으면 `""` */
@@ -1,105 +0,0 @@
1
- import * as 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
- * 요금제 기능 키 값 — 요금제 비교표·상점 플랫폼 요금제 화면이 쓴다. 키는 서버 판정의 기능 키와 같다(추가만 한다 — 예외는 0.53에서 지운
14
- * `limits.ai_credits_monthly`). 상위 요금제는 하위 요금제 기능을 모두 포함한다
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
- "features.ai_assistant": z
28
- .boolean()
29
- .optional()
30
- .describe("AI 상점 도우미. false면 새 실행을 시작할 수 없다(403 `PLAN_FEATURE_REQUIRED`)"),
31
- "limits.ai_reads_monthly": limitOrContract("MCP 읽기 월 한도"),
32
- "limits.ai_actions_monthly": limitOrContract(
33
- "MCP 쓰기(AI 작업) 월 한도 — 주문 처리는 막지 않는다",
34
- ),
35
- "limits.custom_domains": limitOrContract("내 도메인 수"),
36
- "limits.webhooks": limitOrContract("웹훅 구독 수(0이면 쓸 수 없다)"),
37
- "limits.public_apps": limitOrContract("공개 앱(앱 스토어 게시 앱) 설치 수"),
38
- "limits.private_apps": limitOrContract(
39
- "비공개 앱(이 상점 전용 앱) 설치 수(0이면 설치할 수 없다)",
40
- ),
41
- "limits.storefront_preview_hours_monthly": limitOrContract("편집 환경 시간(월, 시간)"),
42
- "limits.storefront_build_minutes_monthly": limitOrContract("빌드 시간(월, 분)"),
43
- "limits.storefront_requests_monthly": limitOrContract(
44
- "스토어프론트 월 트래픽(요청 수) — 넘어도 막지 않고 안내만 한다",
45
- ),
46
- "limits.admin_api_requests_monthly": limitOrContract(
47
- "관리 API 월 요청 — 넘으면 속도만 낮춘다(주문 처리 제외)",
48
- ),
49
- "rate_limit.admin_api": z
50
- .number()
51
- .nullable()
52
- .describe("관리 API 분당 속도 배수(기본 분당 600 × 배수)"),
53
- "storefront.cpu_ms": z.number().int().describe("스토어프론트 사이트 요청당 CPU 상한(ms)"),
54
- "storefront.subrequests": z
55
- .number()
56
- .int()
57
- .describe("스토어프론트 사이트 요청당 하위 요청 상한"),
58
- "storefront.rate_limit_per_minute": z
59
- .number()
60
- .int()
61
- .describe("스토어프론트 남용 방지 요청 속도 상한(사이트당 분당)"),
62
- "seats.included": limitOrContract(
63
- "포함 구성원 석 — 구성원은 모든 요금제에서 무료·무제한이라 null",
64
- ),
65
- "retention.analytics_days": z.number().int().describe("애널리틱스 보관 일수"),
66
- "retention.api_logs_days": limitOrContract("API 로그 보관 일수(0이면 API 로그 없음)"),
67
- "retention.audit_days": limitOrContract("감사 로그 보관 일수"),
68
- "support.tier": z
69
- .union([z.enum(["COMMUNITY", "EMAIL", "EMAIL_PRIORITY", "DEDICATED", "SLA"]), z.string()])
70
- .describe(
71
- "지원 등급(`COMMUNITY`·`EMAIL`·`EMAIL_PRIORITY`·`DEDICATED`·`SLA`, 새 등급이 더해질 수 있다)",
72
- ),
73
- })
74
- .describe("요금제 기능 키 값");
75
- export type PlanEntitlementValues = z.infer<typeof planEntitlementsSchema>;
76
-
77
- /** 공개 요금제 한 줄 — `GET /v1/public/plans` */
78
- export const publicPlanSchema = z.object({
79
- code: responsePlanCodeSchema,
80
- name: z.string().describe("표시 이름(Free·Pro·프리미엄·엔터프라이즈)"),
81
- version: z.number().int().describe("요금제 버전 — 값이 바뀌면 새 버전이 게시된다"),
82
- sort: z.number().int(),
83
- purchasable: z
84
- .boolean()
85
- .describe("셀프 결제로 고를 수 있는가(Free·엔터프라이즈는 아니다 — 엔터프라이즈는 계약)"),
86
- prices: z.object({
87
- currency: z.literal("KRW"),
88
- monthly: z.number().int().nullable().describe("월 가격(공급가, 부가세 별도)"),
89
- startingAt: z.boolean().describe("「부터」 가격(엔터프라이즈 계약)"),
90
- vatIncluded: z
91
- .object({
92
- monthly: z.number().int().nullable(),
93
- })
94
- .describe("표시 가격(부가세 포함) — 요금제 비교표는 이 값을 보인다"),
95
- }),
96
- entitlements: planEntitlementsSchema,
97
- });
98
- export type PublicPlan = z.infer<typeof publicPlanSchema>;
99
-
100
- /** 요금제 비교표 — `GET /v1/public/plans`(인증 없음, 캐시 가능). 값은 서버가 관리하고 언제든 바뀔 수 있다 */
101
- export const publicPlansSchema = z.object({
102
- vatPercent: z.number().int().describe("부가세율(%)"),
103
- plans: z.array(publicPlanSchema).describe("공개 요금제의 지금 버전 — 정렬 순"),
104
- });
105
- export type PublicPlans = z.infer<typeof publicPlansSchema>;