@sayren/store-sdk 0.1.1 → 0.2.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 +369 -3
- package/dist/index.mjs +148 -2
- package/package.json +1 -1
- package/src/client.ts +34 -0
- package/src/index.ts +1 -0
- package/src/schemas/analytics.ts +200 -0
- package/src/schemas/scope.ts +4 -1
package/dist/index.d.mts
CHANGED
|
@@ -16,6 +16,270 @@ type TokenSource = string | null | undefined | (() => string | null | undefined)
|
|
|
16
16
|
type Query = Record<string, string | number | boolean | undefined>;
|
|
17
17
|
export declare function buildQuery(query?: Query): string;
|
|
18
18
|
//#endregion
|
|
19
|
+
//#region src/schemas/analytics.d.ts
|
|
20
|
+
export declare const analyticsRangeQuerySchema: z.ZodObject<{
|
|
21
|
+
from: z.ZodString;
|
|
22
|
+
to: z.ZodString;
|
|
23
|
+
includeTest: z.ZodOptional<z.ZodEnum<{
|
|
24
|
+
true: "true";
|
|
25
|
+
false: "false";
|
|
26
|
+
}>>;
|
|
27
|
+
}, z.core.$strip>;
|
|
28
|
+
export type AnalyticsRangeParams = z.infer<typeof analyticsRangeQuerySchema>;
|
|
29
|
+
export declare const analyticsTotalsSchema: z.ZodObject<{
|
|
30
|
+
visitors: z.ZodNumber;
|
|
31
|
+
sessions: z.ZodNumber;
|
|
32
|
+
engagedSessions: z.ZodNumber;
|
|
33
|
+
pageViews: z.ZodNumber;
|
|
34
|
+
engagementSeconds: z.ZodNumber;
|
|
35
|
+
productViews: z.ZodNumber;
|
|
36
|
+
productViewSessions: z.ZodNumber;
|
|
37
|
+
addToCartSessions: z.ZodNumber;
|
|
38
|
+
beginCheckoutSessions: z.ZodNumber;
|
|
39
|
+
purchaseSessions: z.ZodNumber;
|
|
40
|
+
purchases: z.ZodNumber;
|
|
41
|
+
revenue: z.ZodNumber;
|
|
42
|
+
engagementRate: z.ZodNullable<z.ZodNumber>;
|
|
43
|
+
conversionRate: z.ZodNullable<z.ZodNumber>;
|
|
44
|
+
}, z.core.$strip>;
|
|
45
|
+
export type AnalyticsTotals = z.infer<typeof analyticsTotalsSchema>;
|
|
46
|
+
export declare const analyticsFunnelStepSchema: z.ZodObject<{
|
|
47
|
+
step: z.ZodEnum<{
|
|
48
|
+
SESSION: "SESSION";
|
|
49
|
+
PRODUCT_VIEW: "PRODUCT_VIEW";
|
|
50
|
+
ADD_TO_CART: "ADD_TO_CART";
|
|
51
|
+
BEGIN_CHECKOUT: "BEGIN_CHECKOUT";
|
|
52
|
+
PURCHASE: "PURCHASE";
|
|
53
|
+
}>;
|
|
54
|
+
sessions: z.ZodNumber;
|
|
55
|
+
rateFromPrevious: z.ZodNullable<z.ZodNumber>;
|
|
56
|
+
}, z.core.$strip>;
|
|
57
|
+
export type AnalyticsFunnelStep = z.infer<typeof analyticsFunnelStepSchema>;
|
|
58
|
+
export declare const analyticsOverviewSchema: z.ZodObject<{
|
|
59
|
+
summary: z.ZodObject<{
|
|
60
|
+
visitors: z.ZodNumber;
|
|
61
|
+
sessions: z.ZodNumber;
|
|
62
|
+
engagedSessions: z.ZodNumber;
|
|
63
|
+
pageViews: z.ZodNumber;
|
|
64
|
+
engagementSeconds: z.ZodNumber;
|
|
65
|
+
productViews: z.ZodNumber;
|
|
66
|
+
productViewSessions: z.ZodNumber;
|
|
67
|
+
addToCartSessions: z.ZodNumber;
|
|
68
|
+
beginCheckoutSessions: z.ZodNumber;
|
|
69
|
+
purchaseSessions: z.ZodNumber;
|
|
70
|
+
purchases: z.ZodNumber;
|
|
71
|
+
revenue: z.ZodNumber;
|
|
72
|
+
engagementRate: z.ZodNullable<z.ZodNumber>;
|
|
73
|
+
conversionRate: z.ZodNullable<z.ZodNumber>;
|
|
74
|
+
}, z.core.$strip>;
|
|
75
|
+
funnel: z.ZodArray<z.ZodObject<{
|
|
76
|
+
step: z.ZodEnum<{
|
|
77
|
+
SESSION: "SESSION";
|
|
78
|
+
PRODUCT_VIEW: "PRODUCT_VIEW";
|
|
79
|
+
ADD_TO_CART: "ADD_TO_CART";
|
|
80
|
+
BEGIN_CHECKOUT: "BEGIN_CHECKOUT";
|
|
81
|
+
PURCHASE: "PURCHASE";
|
|
82
|
+
}>;
|
|
83
|
+
sessions: z.ZodNumber;
|
|
84
|
+
rateFromPrevious: z.ZodNullable<z.ZodNumber>;
|
|
85
|
+
}, z.core.$strip>>;
|
|
86
|
+
rows: z.ZodArray<z.ZodObject<{
|
|
87
|
+
visitors: z.ZodNumber;
|
|
88
|
+
sessions: z.ZodNumber;
|
|
89
|
+
engagedSessions: z.ZodNumber;
|
|
90
|
+
pageViews: z.ZodNumber;
|
|
91
|
+
engagementSeconds: z.ZodNumber;
|
|
92
|
+
productViews: z.ZodNumber;
|
|
93
|
+
productViewSessions: z.ZodNumber;
|
|
94
|
+
addToCartSessions: z.ZodNumber;
|
|
95
|
+
beginCheckoutSessions: z.ZodNumber;
|
|
96
|
+
purchaseSessions: z.ZodNumber;
|
|
97
|
+
purchases: z.ZodNumber;
|
|
98
|
+
revenue: z.ZodNumber;
|
|
99
|
+
engagementRate: z.ZodNullable<z.ZodNumber>;
|
|
100
|
+
conversionRate: z.ZodNullable<z.ZodNumber>;
|
|
101
|
+
date: z.ZodString;
|
|
102
|
+
}, z.core.$strip>>;
|
|
103
|
+
from: z.ZodString;
|
|
104
|
+
to: z.ZodString;
|
|
105
|
+
timezone: z.ZodLiteral<"Asia/Seoul">;
|
|
106
|
+
currency: z.ZodLiteral<"KRW">;
|
|
107
|
+
includeTest: z.ZodBoolean;
|
|
108
|
+
lastComputedAt: z.ZodNullable<z.ZodString>;
|
|
109
|
+
}, z.core.$strip>;
|
|
110
|
+
export type AnalyticsOverview = z.infer<typeof analyticsOverviewSchema>;
|
|
111
|
+
export declare const analyticsProductSortSchema: z.ZodEnum<{
|
|
112
|
+
VIEWS: "VIEWS";
|
|
113
|
+
ADD_TO_CARTS: "ADD_TO_CARTS";
|
|
114
|
+
PURCHASES: "PURCHASES";
|
|
115
|
+
REVENUE: "REVENUE";
|
|
116
|
+
IMPRESSIONS: "IMPRESSIONS";
|
|
117
|
+
}>;
|
|
118
|
+
export type AnalyticsProductSort = z.infer<typeof analyticsProductSortSchema>;
|
|
119
|
+
export declare const analyticsProductsQuerySchema: z.ZodObject<{
|
|
120
|
+
from: z.ZodString;
|
|
121
|
+
to: z.ZodString;
|
|
122
|
+
includeTest: z.ZodOptional<z.ZodEnum<{
|
|
123
|
+
true: "true";
|
|
124
|
+
false: "false";
|
|
125
|
+
}>>;
|
|
126
|
+
sort: z.ZodOptional<z.ZodEnum<{
|
|
127
|
+
VIEWS: "VIEWS";
|
|
128
|
+
ADD_TO_CARTS: "ADD_TO_CARTS";
|
|
129
|
+
PURCHASES: "PURCHASES";
|
|
130
|
+
REVENUE: "REVENUE";
|
|
131
|
+
IMPRESSIONS: "IMPRESSIONS";
|
|
132
|
+
}>>;
|
|
133
|
+
limit: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
134
|
+
}, z.core.$strip>;
|
|
135
|
+
export type AnalyticsProductsParams = z.infer<typeof analyticsProductsQuerySchema>;
|
|
136
|
+
export declare const analyticsProductRowSchema: z.ZodObject<{
|
|
137
|
+
productId: z.ZodString;
|
|
138
|
+
productName: z.ZodNullable<z.ZodString>;
|
|
139
|
+
impressions: z.ZodNumber;
|
|
140
|
+
views: z.ZodNumber;
|
|
141
|
+
viewSessions: z.ZodNumber;
|
|
142
|
+
addToCarts: z.ZodNumber;
|
|
143
|
+
purchases: z.ZodNumber;
|
|
144
|
+
quantity: z.ZodNumber;
|
|
145
|
+
revenue: z.ZodNumber;
|
|
146
|
+
purchaseRate: z.ZodNullable<z.ZodNumber>;
|
|
147
|
+
}, z.core.$strip>;
|
|
148
|
+
export type AnalyticsProductRow = z.infer<typeof analyticsProductRowSchema>;
|
|
149
|
+
export declare const analyticsProductsSchema: z.ZodObject<{
|
|
150
|
+
sort: z.ZodEnum<{
|
|
151
|
+
VIEWS: "VIEWS";
|
|
152
|
+
ADD_TO_CARTS: "ADD_TO_CARTS";
|
|
153
|
+
PURCHASES: "PURCHASES";
|
|
154
|
+
REVENUE: "REVENUE";
|
|
155
|
+
IMPRESSIONS: "IMPRESSIONS";
|
|
156
|
+
}>;
|
|
157
|
+
rows: z.ZodArray<z.ZodObject<{
|
|
158
|
+
productId: z.ZodString;
|
|
159
|
+
productName: z.ZodNullable<z.ZodString>;
|
|
160
|
+
impressions: z.ZodNumber;
|
|
161
|
+
views: z.ZodNumber;
|
|
162
|
+
viewSessions: z.ZodNumber;
|
|
163
|
+
addToCarts: z.ZodNumber;
|
|
164
|
+
purchases: z.ZodNumber;
|
|
165
|
+
quantity: z.ZodNumber;
|
|
166
|
+
revenue: z.ZodNumber;
|
|
167
|
+
purchaseRate: z.ZodNullable<z.ZodNumber>;
|
|
168
|
+
}, z.core.$strip>>;
|
|
169
|
+
from: z.ZodString;
|
|
170
|
+
to: z.ZodString;
|
|
171
|
+
timezone: z.ZodLiteral<"Asia/Seoul">;
|
|
172
|
+
currency: z.ZodLiteral<"KRW">;
|
|
173
|
+
includeTest: z.ZodBoolean;
|
|
174
|
+
lastComputedAt: z.ZodNullable<z.ZodString>;
|
|
175
|
+
}, z.core.$strip>;
|
|
176
|
+
export type AnalyticsProducts = z.infer<typeof analyticsProductsSchema>;
|
|
177
|
+
export declare const analyticsChannelSchema: z.ZodEnum<{
|
|
178
|
+
PAID: "PAID";
|
|
179
|
+
DIRECT: "DIRECT";
|
|
180
|
+
CAMPAIGN: "CAMPAIGN";
|
|
181
|
+
ORGANIC_SEARCH: "ORGANIC_SEARCH";
|
|
182
|
+
SOCIAL: "SOCIAL";
|
|
183
|
+
EMAIL: "EMAIL";
|
|
184
|
+
REFERRAL: "REFERRAL";
|
|
185
|
+
UNKNOWN: "UNKNOWN";
|
|
186
|
+
}>;
|
|
187
|
+
export type AnalyticsChannel = z.infer<typeof analyticsChannelSchema>;
|
|
188
|
+
export declare const analyticsSourceGroupBySchema: z.ZodEnum<{
|
|
189
|
+
CHANNEL: "CHANNEL";
|
|
190
|
+
SOURCE: "SOURCE";
|
|
191
|
+
CAMPAIGN: "CAMPAIGN";
|
|
192
|
+
DEVICE: "DEVICE";
|
|
193
|
+
}>;
|
|
194
|
+
export type AnalyticsSourceGroupBy = z.infer<typeof analyticsSourceGroupBySchema>;
|
|
195
|
+
export declare const analyticsSourcesQuerySchema: z.ZodObject<{
|
|
196
|
+
from: z.ZodString;
|
|
197
|
+
to: z.ZodString;
|
|
198
|
+
includeTest: z.ZodOptional<z.ZodEnum<{
|
|
199
|
+
true: "true";
|
|
200
|
+
false: "false";
|
|
201
|
+
}>>;
|
|
202
|
+
groupBy: z.ZodOptional<z.ZodEnum<{
|
|
203
|
+
CHANNEL: "CHANNEL";
|
|
204
|
+
SOURCE: "SOURCE";
|
|
205
|
+
CAMPAIGN: "CAMPAIGN";
|
|
206
|
+
DEVICE: "DEVICE";
|
|
207
|
+
}>>;
|
|
208
|
+
}, z.core.$strip>;
|
|
209
|
+
export type AnalyticsSourcesParams = z.infer<typeof analyticsSourcesQuerySchema>;
|
|
210
|
+
export declare const analyticsSourceRowSchema: z.ZodObject<{
|
|
211
|
+
channel: z.ZodNullable<z.ZodEnum<{
|
|
212
|
+
PAID: "PAID";
|
|
213
|
+
DIRECT: "DIRECT";
|
|
214
|
+
CAMPAIGN: "CAMPAIGN";
|
|
215
|
+
ORGANIC_SEARCH: "ORGANIC_SEARCH";
|
|
216
|
+
SOCIAL: "SOCIAL";
|
|
217
|
+
EMAIL: "EMAIL";
|
|
218
|
+
REFERRAL: "REFERRAL";
|
|
219
|
+
UNKNOWN: "UNKNOWN";
|
|
220
|
+
}>>;
|
|
221
|
+
source: z.ZodNullable<z.ZodString>;
|
|
222
|
+
medium: z.ZodNullable<z.ZodString>;
|
|
223
|
+
campaign: z.ZodNullable<z.ZodString>;
|
|
224
|
+
device: z.ZodNullable<z.ZodEnum<{
|
|
225
|
+
unknown: "unknown";
|
|
226
|
+
desktop: "desktop";
|
|
227
|
+
mobile: "mobile";
|
|
228
|
+
tablet: "tablet";
|
|
229
|
+
}>>;
|
|
230
|
+
sessions: z.ZodNumber;
|
|
231
|
+
visitors: z.ZodNumber;
|
|
232
|
+
engagedSessions: z.ZodNumber;
|
|
233
|
+
purchaseSessions: z.ZodNumber;
|
|
234
|
+
purchases: z.ZodNumber;
|
|
235
|
+
revenue: z.ZodNumber;
|
|
236
|
+
conversionRate: z.ZodNullable<z.ZodNumber>;
|
|
237
|
+
}, z.core.$strip>;
|
|
238
|
+
export type AnalyticsSourceRow = z.infer<typeof analyticsSourceRowSchema>;
|
|
239
|
+
export declare const analyticsSourcesSchema: z.ZodObject<{
|
|
240
|
+
groupBy: z.ZodEnum<{
|
|
241
|
+
CHANNEL: "CHANNEL";
|
|
242
|
+
SOURCE: "SOURCE";
|
|
243
|
+
CAMPAIGN: "CAMPAIGN";
|
|
244
|
+
DEVICE: "DEVICE";
|
|
245
|
+
}>;
|
|
246
|
+
rows: z.ZodArray<z.ZodObject<{
|
|
247
|
+
channel: z.ZodNullable<z.ZodEnum<{
|
|
248
|
+
PAID: "PAID";
|
|
249
|
+
DIRECT: "DIRECT";
|
|
250
|
+
CAMPAIGN: "CAMPAIGN";
|
|
251
|
+
ORGANIC_SEARCH: "ORGANIC_SEARCH";
|
|
252
|
+
SOCIAL: "SOCIAL";
|
|
253
|
+
EMAIL: "EMAIL";
|
|
254
|
+
REFERRAL: "REFERRAL";
|
|
255
|
+
UNKNOWN: "UNKNOWN";
|
|
256
|
+
}>>;
|
|
257
|
+
source: z.ZodNullable<z.ZodString>;
|
|
258
|
+
medium: z.ZodNullable<z.ZodString>;
|
|
259
|
+
campaign: z.ZodNullable<z.ZodString>;
|
|
260
|
+
device: z.ZodNullable<z.ZodEnum<{
|
|
261
|
+
unknown: "unknown";
|
|
262
|
+
desktop: "desktop";
|
|
263
|
+
mobile: "mobile";
|
|
264
|
+
tablet: "tablet";
|
|
265
|
+
}>>;
|
|
266
|
+
sessions: z.ZodNumber;
|
|
267
|
+
visitors: z.ZodNumber;
|
|
268
|
+
engagedSessions: z.ZodNumber;
|
|
269
|
+
purchaseSessions: z.ZodNumber;
|
|
270
|
+
purchases: z.ZodNumber;
|
|
271
|
+
revenue: z.ZodNumber;
|
|
272
|
+
conversionRate: z.ZodNullable<z.ZodNumber>;
|
|
273
|
+
}, z.core.$strip>>;
|
|
274
|
+
from: z.ZodString;
|
|
275
|
+
to: z.ZodString;
|
|
276
|
+
timezone: z.ZodLiteral<"Asia/Seoul">;
|
|
277
|
+
currency: z.ZodLiteral<"KRW">;
|
|
278
|
+
includeTest: z.ZodBoolean;
|
|
279
|
+
lastComputedAt: z.ZodNullable<z.ZodString>;
|
|
280
|
+
}, z.core.$strip>;
|
|
281
|
+
export type AnalyticsSources = z.infer<typeof analyticsSourcesSchema>;
|
|
282
|
+
//#endregion
|
|
19
283
|
//#region src/schemas/api-client.d.ts
|
|
20
284
|
/**
|
|
21
285
|
* 앱(OAuth 클라이언트) 관리 — `/v1/store/api-clients` (auth-spec 부록 B-13).
|
|
@@ -4318,6 +4582,106 @@ export declare function createStoreClient(options: StoreClientOptions): {
|
|
|
4318
4582
|
}[];
|
|
4319
4583
|
}>;
|
|
4320
4584
|
};
|
|
4585
|
+
/**
|
|
4586
|
+
* 방문 분석 — 스코프 `analytics:r`. 스토어프런트가 `@sayren/storefront-sdk`로 수집한 이벤트를 Asia/Seoul 날짜별로
|
|
4587
|
+
* 집계한 값이다. 집계는 주기적으로 갱신되고 응답 `lastComputedAt`이 마지막 집계 시각이다. 봇 세션은 빠진다.
|
|
4588
|
+
* 기간은 양끝 포함 최대 92일이고, 테스트 결제 구매는 `includeTest: "true"`일 때만 포함한다.
|
|
4589
|
+
*/
|
|
4590
|
+
analytics: {
|
|
4591
|
+
/** `GET /v1/analytics/overview` — 합계·세션 퍼널·날짜별 값 */
|
|
4592
|
+
overview: (params: AnalyticsRangeParams) => Promise<{
|
|
4593
|
+
summary: {
|
|
4594
|
+
visitors: number;
|
|
4595
|
+
sessions: number;
|
|
4596
|
+
engagedSessions: number;
|
|
4597
|
+
pageViews: number;
|
|
4598
|
+
engagementSeconds: number;
|
|
4599
|
+
productViews: number;
|
|
4600
|
+
productViewSessions: number;
|
|
4601
|
+
addToCartSessions: number;
|
|
4602
|
+
beginCheckoutSessions: number;
|
|
4603
|
+
purchaseSessions: number;
|
|
4604
|
+
purchases: number;
|
|
4605
|
+
revenue: number;
|
|
4606
|
+
engagementRate: number | null;
|
|
4607
|
+
conversionRate: number | null;
|
|
4608
|
+
};
|
|
4609
|
+
funnel: {
|
|
4610
|
+
step: "SESSION" | "PRODUCT_VIEW" | "ADD_TO_CART" | "BEGIN_CHECKOUT" | "PURCHASE";
|
|
4611
|
+
sessions: number;
|
|
4612
|
+
rateFromPrevious: number | null;
|
|
4613
|
+
}[];
|
|
4614
|
+
rows: {
|
|
4615
|
+
visitors: number;
|
|
4616
|
+
sessions: number;
|
|
4617
|
+
engagedSessions: number;
|
|
4618
|
+
pageViews: number;
|
|
4619
|
+
engagementSeconds: number;
|
|
4620
|
+
productViews: number;
|
|
4621
|
+
productViewSessions: number;
|
|
4622
|
+
addToCartSessions: number;
|
|
4623
|
+
beginCheckoutSessions: number;
|
|
4624
|
+
purchaseSessions: number;
|
|
4625
|
+
purchases: number;
|
|
4626
|
+
revenue: number;
|
|
4627
|
+
engagementRate: number | null;
|
|
4628
|
+
conversionRate: number | null;
|
|
4629
|
+
date: string;
|
|
4630
|
+
}[];
|
|
4631
|
+
from: string;
|
|
4632
|
+
to: string;
|
|
4633
|
+
timezone: "Asia/Seoul";
|
|
4634
|
+
currency: "KRW";
|
|
4635
|
+
includeTest: boolean;
|
|
4636
|
+
lastComputedAt: string | null;
|
|
4637
|
+
}>;
|
|
4638
|
+
/** `GET /v1/analytics/products` — 상품별 노출·조회·장바구니·구매 */
|
|
4639
|
+
products: (params: AnalyticsProductsParams) => Promise<{
|
|
4640
|
+
sort: "VIEWS" | "ADD_TO_CARTS" | "PURCHASES" | "REVENUE" | "IMPRESSIONS";
|
|
4641
|
+
rows: {
|
|
4642
|
+
productId: string;
|
|
4643
|
+
productName: string | null;
|
|
4644
|
+
impressions: number;
|
|
4645
|
+
views: number;
|
|
4646
|
+
viewSessions: number;
|
|
4647
|
+
addToCarts: number;
|
|
4648
|
+
purchases: number;
|
|
4649
|
+
quantity: number;
|
|
4650
|
+
revenue: number;
|
|
4651
|
+
purchaseRate: number | null;
|
|
4652
|
+
}[];
|
|
4653
|
+
from: string;
|
|
4654
|
+
to: string;
|
|
4655
|
+
timezone: "Asia/Seoul";
|
|
4656
|
+
currency: "KRW";
|
|
4657
|
+
includeTest: boolean;
|
|
4658
|
+
lastComputedAt: string | null;
|
|
4659
|
+
}>;
|
|
4660
|
+
/** `GET /v1/analytics/sources` — 채널·소스·캠페인·기기별 세션과 구매 */
|
|
4661
|
+
sources: (params: AnalyticsSourcesParams) => Promise<{
|
|
4662
|
+
groupBy: "CHANNEL" | "SOURCE" | "CAMPAIGN" | "DEVICE";
|
|
4663
|
+
rows: {
|
|
4664
|
+
channel: "PAID" | "DIRECT" | "CAMPAIGN" | "ORGANIC_SEARCH" | "SOCIAL" | "EMAIL" | "REFERRAL" | "UNKNOWN" | null;
|
|
4665
|
+
source: string | null;
|
|
4666
|
+
medium: string | null;
|
|
4667
|
+
campaign: string | null;
|
|
4668
|
+
device: "unknown" | "desktop" | "mobile" | "tablet" | null;
|
|
4669
|
+
sessions: number;
|
|
4670
|
+
visitors: number;
|
|
4671
|
+
engagedSessions: number;
|
|
4672
|
+
purchaseSessions: number;
|
|
4673
|
+
purchases: number;
|
|
4674
|
+
revenue: number;
|
|
4675
|
+
conversionRate: number | null;
|
|
4676
|
+
}[];
|
|
4677
|
+
from: string;
|
|
4678
|
+
to: string;
|
|
4679
|
+
timezone: "Asia/Seoul";
|
|
4680
|
+
currency: "KRW";
|
|
4681
|
+
includeTest: boolean;
|
|
4682
|
+
lastComputedAt: string | null;
|
|
4683
|
+
}>;
|
|
4684
|
+
};
|
|
4321
4685
|
/**
|
|
4322
4686
|
* 결제 내역 — 스코프 `settlement:r`. 결제 건(세션) 단위이고 주문 목록과 다르다. 주문이 만들어지지 않은
|
|
4323
4687
|
* 결제(카드 거절·결제창 이탈·승인 결과 확인 중)도 그대로 나온다.
|
|
@@ -5438,7 +5802,7 @@ export declare const scopeAccessSchema: z.ZodEnum<{
|
|
|
5438
5802
|
rw: "rw";
|
|
5439
5803
|
}>;
|
|
5440
5804
|
export type ScopeAccess = z.infer<typeof scopeAccessSchema>;
|
|
5441
|
-
/** 리소스별로 부여 가능한 접근 수준. settlement는 쓰기 API가 없어 `r`만 존재한다 */
|
|
5805
|
+
/** 리소스별로 부여 가능한 접근 수준. settlement·analytics는 쓰기 API가 없어 `r`만 존재한다 */
|
|
5442
5806
|
export declare const STORE_SCOPE_RESOURCES: {
|
|
5443
5807
|
readonly product: readonly ["r", "rw"];
|
|
5444
5808
|
readonly category: readonly ["r", "rw"];
|
|
@@ -5447,6 +5811,7 @@ export declare const STORE_SCOPE_RESOURCES: {
|
|
|
5447
5811
|
readonly inquiry: readonly ["r", "rw"];
|
|
5448
5812
|
readonly review: readonly ["r", "rw"];
|
|
5449
5813
|
readonly settlement: readonly ["r"];
|
|
5814
|
+
readonly analytics: readonly ["r"];
|
|
5450
5815
|
readonly webhook: readonly ["r", "rw"];
|
|
5451
5816
|
readonly store: readonly ["r", "rw"];
|
|
5452
5817
|
readonly member: readonly ["r", "rw"];
|
|
@@ -5460,6 +5825,7 @@ export declare const storeScopeResourceSchema: z.ZodEnum<{
|
|
|
5460
5825
|
inquiry: "inquiry";
|
|
5461
5826
|
review: "review";
|
|
5462
5827
|
settlement: "settlement";
|
|
5828
|
+
analytics: "analytics";
|
|
5463
5829
|
webhook: "webhook";
|
|
5464
5830
|
store: "store";
|
|
5465
5831
|
member: "member";
|
|
@@ -5472,8 +5838,8 @@ export declare function isStoreScope(scope: string): boolean;
|
|
|
5472
5838
|
* 발급 시 지정한 스코프만 갖는다(발급자 보유 스코프 이내).
|
|
5473
5839
|
*/
|
|
5474
5840
|
export declare const STORE_ROLE_SCOPES: {
|
|
5475
|
-
readonly OWNER: readonly ["product:rw", "category:rw", "order:rw", "claim:rw", "inquiry:rw", "review:rw", "settlement:r", "webhook:rw", "store:rw", "member:rw"];
|
|
5476
|
-
readonly ADMIN: readonly ["product:rw", "category:rw", "order:rw", "claim:rw", "inquiry:rw", "review:rw", "webhook:rw", "store:rw", "member:rw"];
|
|
5841
|
+
readonly OWNER: readonly ["product:rw", "category:rw", "order:rw", "claim:rw", "inquiry:rw", "review:rw", "settlement:r", "analytics:r", "webhook:rw", "store:rw", "member:rw"];
|
|
5842
|
+
readonly ADMIN: readonly ["product:rw", "category:rw", "order:rw", "claim:rw", "inquiry:rw", "review:rw", "analytics:r", "webhook:rw", "store:rw", "member:rw"];
|
|
5477
5843
|
readonly STAFF: readonly ["product:rw", "category:rw", "order:rw", "claim:rw", "inquiry:rw", "review:rw"];
|
|
5478
5844
|
};
|
|
5479
5845
|
//#endregion
|
package/dist/index.mjs
CHANGED
|
@@ -146,6 +146,136 @@ function createHttp(options) {
|
|
|
146
146
|
};
|
|
147
147
|
}
|
|
148
148
|
//#endregion
|
|
149
|
+
//#region src/schemas/analytics.ts
|
|
150
|
+
/**
|
|
151
|
+
* 방문 분석 조회 (관리 API `/v1/analytics/*`, 스코프 `analytics:r`).
|
|
152
|
+
*
|
|
153
|
+
* 스토어프런트가 `@sayren/storefront-sdk`로 수집한 이벤트를 서버가 날짜(Asia/Seoul)별로 집계한 값이다. 집계는 주기적으로
|
|
154
|
+
* 갱신되므로 오늘 값은 `lastComputedAt` 시점까지 반영돼 있다. 봇·자동화 브라우저의 세션은 모든 집계에서 빠진다.
|
|
155
|
+
*/
|
|
156
|
+
const reportDate$1 = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "날짜 형식은 YYYY-MM-DD 입니다");
|
|
157
|
+
const includeTest = z.enum(["true", "false"]).optional().describe("테스트 결제(샌드박스 결제)로 만든 구매 포함 여부. 기본 `false`");
|
|
158
|
+
const analyticsRangeQuerySchema = z.object({
|
|
159
|
+
from: reportDate$1.describe("시작일 (YYYY-MM-DD, Asia/Seoul 기준, 포함)"),
|
|
160
|
+
to: reportDate$1.describe("종료일 (YYYY-MM-DD, 포함). from부터 최대 92일"),
|
|
161
|
+
includeTest
|
|
162
|
+
});
|
|
163
|
+
const rangeMeta = {
|
|
164
|
+
from: z.string(),
|
|
165
|
+
to: z.string(),
|
|
166
|
+
timezone: z.literal("Asia/Seoul"),
|
|
167
|
+
currency: z.literal("KRW"),
|
|
168
|
+
includeTest: z.boolean().describe("테스트 결제 구매를 포함했는가"),
|
|
169
|
+
lastComputedAt: z.string().nullable().describe("기간 안에서 가장 최근에 집계한 시각(ISO 8601). 집계된 날이 없으면 null")
|
|
170
|
+
};
|
|
171
|
+
/**
|
|
172
|
+
* 비율(0 이상). 단계가 세션 안에서 꼭 이어지지는 않아 1을 넘을 수 있다 — 예: 조회 없이 장바구니에서 바로 산 구매,
|
|
173
|
+
* 자정을 넘겨 다음 날 확정된 구매.
|
|
174
|
+
*/
|
|
175
|
+
const rate = (description) => z.number().min(0).nullable().describe(description);
|
|
176
|
+
const analyticsTotalsSchema = z.object({
|
|
177
|
+
visitors: z.number().int().describe("방문자 수 — 날짜별 순방문자의 합. 여러 날 방문한 사람은 날마다 센다"),
|
|
178
|
+
sessions: z.number().int().describe("세션 수. 30분 동안 활동이 없거나 다른 캠페인으로 들어오면 새 세션"),
|
|
179
|
+
engagedSessions: z.number().int().describe("참여 세션 수 — 페이지뷰 2개 이상, 체류 10초 이상, 장바구니 담기·결제 시작·구매 중 하나"),
|
|
180
|
+
pageViews: z.number().int(),
|
|
181
|
+
engagementSeconds: z.number().int().describe("페이지가 화면에 보인 시간의 합(초). 페이지뷰 하나는 최대 30분, 세션은 세션 길이 + 30분까지 센다"),
|
|
182
|
+
productViews: z.number().int().describe("상품 조회 수"),
|
|
183
|
+
productViewSessions: z.number().int().describe("상품을 조회한 세션 수"),
|
|
184
|
+
addToCartSessions: z.number().int().describe("장바구니에 담은 세션 수"),
|
|
185
|
+
beginCheckoutSessions: z.number().int().describe("주문서를 연 세션 수"),
|
|
186
|
+
purchaseSessions: z.number().int().describe("구매한 세션 수"),
|
|
187
|
+
purchases: z.number().int().describe("구매(주문) 수"),
|
|
188
|
+
revenue: z.number().int().describe("구매 금액 합계 — 주문 결제 금액(배송비 포함). 이후 취소·환불은 빼지 않으므로 매출 리포트의 순매출과 다르다"),
|
|
189
|
+
engagementRate: rate("참여율 = 참여 세션 / 세션. 세션이 없으면 null"),
|
|
190
|
+
conversionRate: rate("전환율 = 구매 세션 / 세션. 세션이 없으면 null")
|
|
191
|
+
});
|
|
192
|
+
const analyticsFunnelStepSchema = z.object({
|
|
193
|
+
step: z.enum([
|
|
194
|
+
"SESSION",
|
|
195
|
+
"PRODUCT_VIEW",
|
|
196
|
+
"ADD_TO_CART",
|
|
197
|
+
"BEGIN_CHECKOUT",
|
|
198
|
+
"PURCHASE"
|
|
199
|
+
]),
|
|
200
|
+
sessions: z.number().int(),
|
|
201
|
+
rateFromPrevious: rate("직전 단계 대비 비율. 첫 단계이거나 직전 단계가 0이면 null")
|
|
202
|
+
});
|
|
203
|
+
const analyticsOverviewSchema = z.object({
|
|
204
|
+
...rangeMeta,
|
|
205
|
+
summary: analyticsTotalsSchema.describe("기간 합계"),
|
|
206
|
+
funnel: z.array(analyticsFunnelStepSchema).describe("세션 기준 구매 퍼널. 각 단계는 그 행동을 한 세션 수이고, 앞 단계를 거쳤는지는 따지지 않는다"),
|
|
207
|
+
rows: z.array(analyticsTotalsSchema.extend({ date: z.string().describe("일자 (YYYY-MM-DD)") })).describe("날짜별 값. 세션이 없는 날은 생략된다")
|
|
208
|
+
});
|
|
209
|
+
const analyticsProductSortSchema = z.enum([
|
|
210
|
+
"VIEWS",
|
|
211
|
+
"ADD_TO_CARTS",
|
|
212
|
+
"PURCHASES",
|
|
213
|
+
"REVENUE",
|
|
214
|
+
"IMPRESSIONS"
|
|
215
|
+
]).describe("정렬 기준(내림차순). 기본 `VIEWS`");
|
|
216
|
+
const analyticsProductsQuerySchema = analyticsRangeQuerySchema.extend({
|
|
217
|
+
sort: analyticsProductSortSchema.optional(),
|
|
218
|
+
limit: z.coerce.number().int().min(1).max(100).optional().describe("최대 행 수. 기본 20, 최대 100")
|
|
219
|
+
});
|
|
220
|
+
const analyticsProductRowSchema = z.object({
|
|
221
|
+
productId: z.string(),
|
|
222
|
+
productName: z.string().nullable().describe("현재 상품명. 삭제된 상품이면 null"),
|
|
223
|
+
impressions: z.number().int().describe("목록 노출 수"),
|
|
224
|
+
views: z.number().int().describe("상세 조회 수"),
|
|
225
|
+
viewSessions: z.number().int().describe("상세를 조회한 세션 수"),
|
|
226
|
+
addToCarts: z.number().int().describe("장바구니 담기 수"),
|
|
227
|
+
purchases: z.number().int().describe("이 상품이 포함된 구매(주문) 수"),
|
|
228
|
+
quantity: z.number().int().describe("구매 수량"),
|
|
229
|
+
revenue: z.number().int().describe("이 상품의 구매 금액 — 주문 상품 금액(할인 반영, 배송비 제외) 합계. 이후 취소·환불은 빼지 않는다"),
|
|
230
|
+
purchaseRate: rate("구매율 = 구매 / 조회 세션. 조회 세션이 없으면 null")
|
|
231
|
+
});
|
|
232
|
+
const analyticsProductsSchema = z.object({
|
|
233
|
+
...rangeMeta,
|
|
234
|
+
sort: analyticsProductSortSchema,
|
|
235
|
+
rows: z.array(analyticsProductRowSchema)
|
|
236
|
+
});
|
|
237
|
+
const analyticsChannelSchema = z.enum([
|
|
238
|
+
"DIRECT",
|
|
239
|
+
"ORGANIC_SEARCH",
|
|
240
|
+
"SOCIAL",
|
|
241
|
+
"PAID",
|
|
242
|
+
"EMAIL",
|
|
243
|
+
"CAMPAIGN",
|
|
244
|
+
"REFERRAL",
|
|
245
|
+
"UNKNOWN"
|
|
246
|
+
]).describe("유입 채널 — 세션 첫 페이지뷰의 utm·리퍼러로 정한다. `PAID`(utm_medium이 cpc·ppc·paid·display 등), `EMAIL`(utm_medium email), `SOCIAL`(SNS 리퍼러·utm_source), `ORGANIC_SEARCH`(검색 엔진 리퍼러), `CAMPAIGN`(그 밖의 utm), `REFERRAL`(그 밖의 리퍼러), `DIRECT`(없음), `UNKNOWN`(페이지뷰 없이 서버 이벤트만 있는 세션)");
|
|
247
|
+
const analyticsSourceGroupBySchema = z.enum([
|
|
248
|
+
"CHANNEL",
|
|
249
|
+
"SOURCE",
|
|
250
|
+
"CAMPAIGN",
|
|
251
|
+
"DEVICE"
|
|
252
|
+
]).describe("행 집계 기준. 기본 `CHANNEL`");
|
|
253
|
+
const analyticsSourcesQuerySchema = analyticsRangeQuerySchema.extend({ groupBy: analyticsSourceGroupBySchema.optional() });
|
|
254
|
+
const analyticsSourceRowSchema = z.object({
|
|
255
|
+
channel: analyticsChannelSchema.nullable().describe("groupBy=CHANNEL일 때만 값"),
|
|
256
|
+
source: z.string().nullable().describe("groupBy=SOURCE·CAMPAIGN일 때 값. utm_source, 없으면 리퍼러 호스트, 둘 다 없으면 `(direct)`"),
|
|
257
|
+
medium: z.string().nullable().describe("groupBy=SOURCE·CAMPAIGN일 때 값. utm_medium, 없으면 `referral`·`(none)`"),
|
|
258
|
+
campaign: z.string().nullable().describe("groupBy=CAMPAIGN일 때 값. utm_campaign, 없으면 `(not set)`"),
|
|
259
|
+
device: z.enum([
|
|
260
|
+
"desktop",
|
|
261
|
+
"mobile",
|
|
262
|
+
"tablet",
|
|
263
|
+
"unknown"
|
|
264
|
+
]).nullable().describe("groupBy=DEVICE일 때만 값"),
|
|
265
|
+
sessions: z.number().int(),
|
|
266
|
+
visitors: z.number().int().describe("날짜별 순방문자의 합"),
|
|
267
|
+
engagedSessions: z.number().int(),
|
|
268
|
+
purchaseSessions: z.number().int(),
|
|
269
|
+
purchases: z.number().int(),
|
|
270
|
+
revenue: z.number().int(),
|
|
271
|
+
conversionRate: rate("전환율 = 구매 세션 / 세션")
|
|
272
|
+
});
|
|
273
|
+
const analyticsSourcesSchema = z.object({
|
|
274
|
+
...rangeMeta,
|
|
275
|
+
groupBy: analyticsSourceGroupBySchema,
|
|
276
|
+
rows: z.array(analyticsSourceRowSchema).describe("세션 수 내림차순")
|
|
277
|
+
});
|
|
278
|
+
//#endregion
|
|
149
279
|
//#region src/schemas/api-client.ts
|
|
150
280
|
/**
|
|
151
281
|
* 앱(OAuth 클라이언트) 관리 — `/v1/store/api-clients` (auth-spec 부록 B-13).
|
|
@@ -1927,6 +2057,19 @@ function createStoreClient(options) {
|
|
|
1927
2057
|
* 400 `INVALID_PARAMETER`(없는 날짜·to<from), 400 `RANGE_TOO_WIDE`(기간 초과)
|
|
1928
2058
|
*/
|
|
1929
2059
|
get: (params) => storeHttp.request("GET", "/sales-report", salesReportSchema, { query: salesReportQuerySchema.parse(params) }) },
|
|
2060
|
+
/**
|
|
2061
|
+
* 방문 분석 — 스코프 `analytics:r`. 스토어프런트가 `@sayren/storefront-sdk`로 수집한 이벤트를 Asia/Seoul 날짜별로
|
|
2062
|
+
* 집계한 값이다. 집계는 주기적으로 갱신되고 응답 `lastComputedAt`이 마지막 집계 시각이다. 봇 세션은 빠진다.
|
|
2063
|
+
* 기간은 양끝 포함 최대 92일이고, 테스트 결제 구매는 `includeTest: "true"`일 때만 포함한다.
|
|
2064
|
+
*/
|
|
2065
|
+
analytics: {
|
|
2066
|
+
/** `GET /v1/analytics/overview` — 합계·세션 퍼널·날짜별 값 */
|
|
2067
|
+
overview: (params) => storeHttp.request("GET", "/analytics/overview", analyticsOverviewSchema, { query: analyticsRangeQuerySchema.parse(params) }),
|
|
2068
|
+
/** `GET /v1/analytics/products` — 상품별 노출·조회·장바구니·구매 */
|
|
2069
|
+
products: (params) => storeHttp.request("GET", "/analytics/products", analyticsProductsSchema, { query: analyticsProductsQuerySchema.parse(params) }),
|
|
2070
|
+
/** `GET /v1/analytics/sources` — 채널·소스·캠페인·기기별 세션과 구매 */
|
|
2071
|
+
sources: (params) => storeHttp.request("GET", "/analytics/sources", analyticsSourcesSchema, { query: analyticsSourcesQuerySchema.parse(params) })
|
|
2072
|
+
},
|
|
1930
2073
|
/**
|
|
1931
2074
|
* 결제 내역 — 스코프 `settlement:r`. 결제 건(세션) 단위이고 주문 목록과 다르다. 주문이 만들어지지 않은
|
|
1932
2075
|
* 결제(카드 거절·결제창 이탈·승인 결과 확인 중)도 그대로 나온다.
|
|
@@ -2162,7 +2305,7 @@ async function exchangeStoreTokenViaOAuth(options) {
|
|
|
2162
2305
|
* 서버 인가가 갈라지지 않는다.
|
|
2163
2306
|
*/
|
|
2164
2307
|
const scopeAccessSchema = z.enum(["r", "rw"]).describe("접근 수준. `r`=읽기, `rw`=읽기+쓰기(r을 함의)");
|
|
2165
|
-
/** 리소스별로 부여 가능한 접근 수준. settlement는 쓰기 API가 없어 `r`만 존재한다 */
|
|
2308
|
+
/** 리소스별로 부여 가능한 접근 수준. settlement·analytics는 쓰기 API가 없어 `r`만 존재한다 */
|
|
2166
2309
|
const STORE_SCOPE_RESOURCES = {
|
|
2167
2310
|
product: ["r", "rw"],
|
|
2168
2311
|
category: ["r", "rw"],
|
|
@@ -2171,6 +2314,7 @@ const STORE_SCOPE_RESOURCES = {
|
|
|
2171
2314
|
inquiry: ["r", "rw"],
|
|
2172
2315
|
review: ["r", "rw"],
|
|
2173
2316
|
settlement: ["r"],
|
|
2317
|
+
analytics: ["r"],
|
|
2174
2318
|
webhook: ["r", "rw"],
|
|
2175
2319
|
store: ["r", "rw"],
|
|
2176
2320
|
member: ["r", "rw"]
|
|
@@ -2196,6 +2340,7 @@ const STORE_ROLE_SCOPES = {
|
|
|
2196
2340
|
"inquiry:rw",
|
|
2197
2341
|
"review:rw",
|
|
2198
2342
|
"settlement:r",
|
|
2343
|
+
"analytics:r",
|
|
2199
2344
|
"webhook:rw",
|
|
2200
2345
|
"store:rw",
|
|
2201
2346
|
"member:rw"
|
|
@@ -2207,6 +2352,7 @@ const STORE_ROLE_SCOPES = {
|
|
|
2207
2352
|
"claim:rw",
|
|
2208
2353
|
"inquiry:rw",
|
|
2209
2354
|
"review:rw",
|
|
2355
|
+
"analytics:r",
|
|
2210
2356
|
"webhook:rw",
|
|
2211
2357
|
"store:rw",
|
|
2212
2358
|
"member:rw"
|
|
@@ -2448,4 +2594,4 @@ function createStoreSession(options) {
|
|
|
2448
2594
|
};
|
|
2449
2595
|
}
|
|
2450
2596
|
//#endregion
|
|
2451
|
-
export { ApiError, MAX_OPTION_GROUPS, MAX_VALUES_PER_GROUP, MAX_VARIANTS, PAYMENT_ROUTING_EXCLUSION_CODES, PORTONE_CHANNEL_NAME_MAX_LENGTH, PORTONE_MAX_CHANNELS, PORTONE_MIN_CHANNELS, RESERVED_STORE_CODES, STORE_CODE_PATTERN, STORE_ROLE_SCOPES, STORE_SCOPE_RESOURCES, STORE_SESSION_KEYS, TOSS_WIDGET_CLIENT_KEY_PATTERN, TOSS_WIDGET_KEY_MESSAGE, TOSS_WIDGET_SECRET_KEY_PATTERN, VARIANT_STOCK_EXCLUSIVE_MESSAGE, WEBHOOK_DEFAULT_TOLERANCE_SEC, WEBHOOK_DELIVERY_ID_HEADER, WEBHOOK_EVENT_ID_HEADER, WEBHOOK_EVENT_TYPE_HEADER, WEBHOOK_HEADERS, WEBHOOK_SIGNATURE_HEADER, WEBHOOK_USER_AGENT, addressChangeRequestListSchema, addressTypeSchema, apiClientListQuerySchema, apiClientSchema, apiClientSecretRotatedSchema, apiClientStatusSchema, apiClientTypeSchema, apiLogErrorSchema, apiLogListQuerySchema, apiLogPageSchema, apiLogPrincipalSchema, apiLogPrincipalTypeSchema, apiLogSchema, apiLogStatusFilterSchema, apiLogSummarySchema, apiTokenCreateRequestSchema, apiTokenCreatedSchema, apiTokenSchema, approveClaimResultSchema, buildAuthorizeUrl, buildQuery, bulkResultSchema, cancelBySellerRequestSchema, cancelBySellerResultSchema, carrierSchema, categoryAttributeSchema, categoryCreateRequestSchema, categoryDeleteQuerySchema, categoryDeleteStrategySchema, categoryListQuerySchema, categoryPatchRequestSchema, categoryProductSortSchema, categorySchema, categorySearchResultSchema, categoryTreeNodeSchema, categoryWithPathSchema, changeTypeSchema, claimDetailSchema, claimHoldResultSchema, claimListQuerySchema, claimReasonSchema, claimSchema, claimStatusSchema, claimTypeSchema, claimWebhookEventDataSchema, claimWebhookEventSchema, clientCredentialsTokenResponseSchema, createPkcePair, createStoreClient, createStoreSession, customerInquiryCategorySchema, customerInquiryListQuerySchema, deliveryInfoSchema, deliveryMethodSchema, deliveryStatusSchema, deliveryTypeSchema, discountRequestSchema, discountSchema, dispatchRequestSchema, effectivePaymentRoutingModeSchema, eventTypeSchema, exchangeAuthorizationCode, exchangeStoreTokenViaOAuth, holdOrderItemRequestSchema, inquiryListQuerySchema, inquirySchema, inquiryWebhookEventDataSchema, inquiryWebhookEventSchema, invitationListQuerySchema, invitationSchema, isReservedStoreCode, isStoreScope, liveGateConditionCodeSchema, liveGateConditionSchema, liveGateErrorDetailsSchema, liveGateSchema, maskedSecretSchema, myAccountSchema, myStoreSchema, oauthClientRegistrationRequestSchema, oauthClientRegistrationResponseSchema, oauthTokenResponseSchema, optionGroupRequestSchema, optionGroupSchema, optionModelRequestSchema, optionModelSchema, optionValueRequestSchema, optionValueSchema, orderItemListQuerySchema, orderItemMemoResultSchema, orderItemPageSchema, orderItemSchema, orderItemStatusSchema, orderListQuerySchema, orderSchema, orderSummaryPageSchema, orderSummarySchema, orderWebhookEventDataSchema, orderWebhookEventSchema, pageInfoSchema, pageQueryShape, pageSchema, paymentAttemptRecordSchema, paymentAttemptStatusSchema, paymentCredentialSetSchema, paymentListQuerySchema, paymentProviderSchema, paymentProviderVerificationSchema, paymentRecordDetailSchema, paymentRecordPageSchema, paymentRecordSchema, paymentRecordStatusSchema, paymentRefundRecordSchema, paymentRoutingModeSchema, paymentSettingsSchema, pgEnvironmentSchema, pgPaymentMethodSchema, pgProviderSchema, pgVerificationResultSchema, portOneChannelSchema, portOneCredentialsInputSchema, productCreateRequestSchema, productImageUploadResultSchema, productListQuerySchema, productOutOfStockWebhookEventDataSchema, productOutOfStockWebhookEventSchema, productPatchRequestSchema, productSchema, productSortSchema, productStatusSchema, productSummarySchema, productVariantRequestSchema, productVariantSchema, purchaseDecisionExtendResultSchema, purchaseDecisionRequestResultSchema, refreshUserToken, rejectClaimRequestSchema, reviewListQuerySchema, reviewReportResultSchema, reviewSchema, reviewSortSchema, reviewWebhookEventDataSchema, reviewWebhookEventSchema, salesReportGroupBySchema, salesReportQuerySchema, salesReportRowSchema, salesReportSchema, salesTotalsSchema, scopeAccessSchema, sellerAddressListQuerySchema, sellerAddressRequestSchema, sellerAddressSchema, sellerCustomerInquirySchema, settlementDetailQuerySchema, settlementDetailSchema, settlementListQuerySchema, settlementStatusSchema, settlementSummarySchema, settlementWithDetailsSchema, shippingAddressSchema, storeCodeSchema, storeMemberRoleUpdatedSchema, storeMemberSchema, storeRoleSchema, storeSchema, storeScopeResourceSchema, storeTokenResponseSchema, tossPaymentsCredentialsInputSchema, trackingUpdateResultSchema, updatePaymentProviderRequestSchema, updatePaymentSettingsRequestSchema, uploadRequestSchema, uploadTicketSchema, upsertPortOneProviderRequestSchema, upsertTossPaymentsProviderRequestSchema, userTokenResponseSchema, variantStockRequestSchema, variantStockSchema, verifyPaymentProviderRequestSchema, webhookCreatedSchema, webhookDeliveryErrorCodeSchema, webhookDeliveryListQuerySchema, webhookDeliverySchema, webhookDeliveryStatusSchema, webhookEventSchema, webhookRedeliverFailedResultSchema, webhookRequestSchema, webhookSchema, webhookSecretRotatedSchema, webhookStatusSchema, webhookTestRequestSchema, webhookTestResultSchema };
|
|
2597
|
+
export { ApiError, MAX_OPTION_GROUPS, MAX_VALUES_PER_GROUP, MAX_VARIANTS, PAYMENT_ROUTING_EXCLUSION_CODES, PORTONE_CHANNEL_NAME_MAX_LENGTH, PORTONE_MAX_CHANNELS, PORTONE_MIN_CHANNELS, RESERVED_STORE_CODES, STORE_CODE_PATTERN, STORE_ROLE_SCOPES, STORE_SCOPE_RESOURCES, STORE_SESSION_KEYS, TOSS_WIDGET_CLIENT_KEY_PATTERN, TOSS_WIDGET_KEY_MESSAGE, TOSS_WIDGET_SECRET_KEY_PATTERN, VARIANT_STOCK_EXCLUSIVE_MESSAGE, WEBHOOK_DEFAULT_TOLERANCE_SEC, WEBHOOK_DELIVERY_ID_HEADER, WEBHOOK_EVENT_ID_HEADER, WEBHOOK_EVENT_TYPE_HEADER, WEBHOOK_HEADERS, WEBHOOK_SIGNATURE_HEADER, WEBHOOK_USER_AGENT, addressChangeRequestListSchema, addressTypeSchema, analyticsChannelSchema, analyticsFunnelStepSchema, analyticsOverviewSchema, analyticsProductRowSchema, analyticsProductSortSchema, analyticsProductsQuerySchema, analyticsProductsSchema, analyticsRangeQuerySchema, analyticsSourceGroupBySchema, analyticsSourceRowSchema, analyticsSourcesQuerySchema, analyticsSourcesSchema, analyticsTotalsSchema, apiClientListQuerySchema, apiClientSchema, apiClientSecretRotatedSchema, apiClientStatusSchema, apiClientTypeSchema, apiLogErrorSchema, apiLogListQuerySchema, apiLogPageSchema, apiLogPrincipalSchema, apiLogPrincipalTypeSchema, apiLogSchema, apiLogStatusFilterSchema, apiLogSummarySchema, apiTokenCreateRequestSchema, apiTokenCreatedSchema, apiTokenSchema, approveClaimResultSchema, buildAuthorizeUrl, buildQuery, bulkResultSchema, cancelBySellerRequestSchema, cancelBySellerResultSchema, carrierSchema, categoryAttributeSchema, categoryCreateRequestSchema, categoryDeleteQuerySchema, categoryDeleteStrategySchema, categoryListQuerySchema, categoryPatchRequestSchema, categoryProductSortSchema, categorySchema, categorySearchResultSchema, categoryTreeNodeSchema, categoryWithPathSchema, changeTypeSchema, claimDetailSchema, claimHoldResultSchema, claimListQuerySchema, claimReasonSchema, claimSchema, claimStatusSchema, claimTypeSchema, claimWebhookEventDataSchema, claimWebhookEventSchema, clientCredentialsTokenResponseSchema, createPkcePair, createStoreClient, createStoreSession, customerInquiryCategorySchema, customerInquiryListQuerySchema, deliveryInfoSchema, deliveryMethodSchema, deliveryStatusSchema, deliveryTypeSchema, discountRequestSchema, discountSchema, dispatchRequestSchema, effectivePaymentRoutingModeSchema, eventTypeSchema, exchangeAuthorizationCode, exchangeStoreTokenViaOAuth, holdOrderItemRequestSchema, inquiryListQuerySchema, inquirySchema, inquiryWebhookEventDataSchema, inquiryWebhookEventSchema, invitationListQuerySchema, invitationSchema, isReservedStoreCode, isStoreScope, liveGateConditionCodeSchema, liveGateConditionSchema, liveGateErrorDetailsSchema, liveGateSchema, maskedSecretSchema, myAccountSchema, myStoreSchema, oauthClientRegistrationRequestSchema, oauthClientRegistrationResponseSchema, oauthTokenResponseSchema, optionGroupRequestSchema, optionGroupSchema, optionModelRequestSchema, optionModelSchema, optionValueRequestSchema, optionValueSchema, orderItemListQuerySchema, orderItemMemoResultSchema, orderItemPageSchema, orderItemSchema, orderItemStatusSchema, orderListQuerySchema, orderSchema, orderSummaryPageSchema, orderSummarySchema, orderWebhookEventDataSchema, orderWebhookEventSchema, pageInfoSchema, pageQueryShape, pageSchema, paymentAttemptRecordSchema, paymentAttemptStatusSchema, paymentCredentialSetSchema, paymentListQuerySchema, paymentProviderSchema, paymentProviderVerificationSchema, paymentRecordDetailSchema, paymentRecordPageSchema, paymentRecordSchema, paymentRecordStatusSchema, paymentRefundRecordSchema, paymentRoutingModeSchema, paymentSettingsSchema, pgEnvironmentSchema, pgPaymentMethodSchema, pgProviderSchema, pgVerificationResultSchema, portOneChannelSchema, portOneCredentialsInputSchema, productCreateRequestSchema, productImageUploadResultSchema, productListQuerySchema, productOutOfStockWebhookEventDataSchema, productOutOfStockWebhookEventSchema, productPatchRequestSchema, productSchema, productSortSchema, productStatusSchema, productSummarySchema, productVariantRequestSchema, productVariantSchema, purchaseDecisionExtendResultSchema, purchaseDecisionRequestResultSchema, refreshUserToken, rejectClaimRequestSchema, reviewListQuerySchema, reviewReportResultSchema, reviewSchema, reviewSortSchema, reviewWebhookEventDataSchema, reviewWebhookEventSchema, salesReportGroupBySchema, salesReportQuerySchema, salesReportRowSchema, salesReportSchema, salesTotalsSchema, scopeAccessSchema, sellerAddressListQuerySchema, sellerAddressRequestSchema, sellerAddressSchema, sellerCustomerInquirySchema, settlementDetailQuerySchema, settlementDetailSchema, settlementListQuerySchema, settlementStatusSchema, settlementSummarySchema, settlementWithDetailsSchema, shippingAddressSchema, storeCodeSchema, storeMemberRoleUpdatedSchema, storeMemberSchema, storeRoleSchema, storeSchema, storeScopeResourceSchema, storeTokenResponseSchema, tossPaymentsCredentialsInputSchema, trackingUpdateResultSchema, updatePaymentProviderRequestSchema, updatePaymentSettingsRequestSchema, uploadRequestSchema, uploadTicketSchema, upsertPortOneProviderRequestSchema, upsertTossPaymentsProviderRequestSchema, userTokenResponseSchema, variantStockRequestSchema, variantStockSchema, verifyPaymentProviderRequestSchema, webhookCreatedSchema, webhookDeliveryErrorCodeSchema, webhookDeliveryListQuerySchema, webhookDeliverySchema, webhookDeliveryStatusSchema, webhookEventSchema, webhookRedeliverFailedResultSchema, webhookRequestSchema, webhookSchema, webhookSecretRotatedSchema, webhookStatusSchema, webhookTestRequestSchema, webhookTestResultSchema };
|
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { base64Utf8 } from "./base64";
|
|
3
3
|
import { createHttp, path, type Query, resolveToken, type TokenSource, unwrapData } from "./http";
|
|
4
|
+
import {
|
|
5
|
+
type AnalyticsProductsParams,
|
|
6
|
+
type AnalyticsRangeParams,
|
|
7
|
+
type AnalyticsSourcesParams,
|
|
8
|
+
analyticsOverviewSchema,
|
|
9
|
+
analyticsProductsQuerySchema,
|
|
10
|
+
analyticsProductsSchema,
|
|
11
|
+
analyticsRangeQuerySchema,
|
|
12
|
+
analyticsSourcesQuerySchema,
|
|
13
|
+
analyticsSourcesSchema,
|
|
14
|
+
} from "./schemas/analytics";
|
|
4
15
|
import {
|
|
5
16
|
type ApiClientListParams,
|
|
6
17
|
apiClientSchema,
|
|
@@ -606,6 +617,29 @@ export function createStoreClient(options: StoreClientOptions) {
|
|
|
606
617
|
}),
|
|
607
618
|
},
|
|
608
619
|
|
|
620
|
+
/**
|
|
621
|
+
* 방문 분석 — 스코프 `analytics:r`. 스토어프런트가 `@sayren/storefront-sdk`로 수집한 이벤트를 Asia/Seoul 날짜별로
|
|
622
|
+
* 집계한 값이다. 집계는 주기적으로 갱신되고 응답 `lastComputedAt`이 마지막 집계 시각이다. 봇 세션은 빠진다.
|
|
623
|
+
* 기간은 양끝 포함 최대 92일이고, 테스트 결제 구매는 `includeTest: "true"`일 때만 포함한다.
|
|
624
|
+
*/
|
|
625
|
+
analytics: {
|
|
626
|
+
/** `GET /v1/analytics/overview` — 합계·세션 퍼널·날짜별 값 */
|
|
627
|
+
overview: (params: AnalyticsRangeParams) =>
|
|
628
|
+
storeHttp.request("GET", "/analytics/overview", analyticsOverviewSchema, {
|
|
629
|
+
query: analyticsRangeQuerySchema.parse(params),
|
|
630
|
+
}),
|
|
631
|
+
/** `GET /v1/analytics/products` — 상품별 노출·조회·장바구니·구매 */
|
|
632
|
+
products: (params: AnalyticsProductsParams) =>
|
|
633
|
+
storeHttp.request("GET", "/analytics/products", analyticsProductsSchema, {
|
|
634
|
+
query: analyticsProductsQuerySchema.parse(params) as unknown as Query,
|
|
635
|
+
}),
|
|
636
|
+
/** `GET /v1/analytics/sources` — 채널·소스·캠페인·기기별 세션과 구매 */
|
|
637
|
+
sources: (params: AnalyticsSourcesParams) =>
|
|
638
|
+
storeHttp.request("GET", "/analytics/sources", analyticsSourcesSchema, {
|
|
639
|
+
query: analyticsSourcesQuerySchema.parse(params),
|
|
640
|
+
}),
|
|
641
|
+
},
|
|
642
|
+
|
|
609
643
|
/**
|
|
610
644
|
* 결제 내역 — 스코프 `settlement:r`. 결제 건(세션) 단위이고 주문 목록과 다르다. 주문이 만들어지지 않은
|
|
611
645
|
* 결제(카드 거절·결제창 이탈·승인 결과 확인 중)도 그대로 나온다.
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 방문 분석 조회 (관리 API `/v1/analytics/*`, 스코프 `analytics:r`).
|
|
5
|
+
*
|
|
6
|
+
* 스토어프런트가 `@sayren/storefront-sdk`로 수집한 이벤트를 서버가 날짜(Asia/Seoul)별로 집계한 값이다. 집계는 주기적으로
|
|
7
|
+
* 갱신되므로 오늘 값은 `lastComputedAt` 시점까지 반영돼 있다. 봇·자동화 브라우저의 세션은 모든 집계에서 빠진다.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const reportDate = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "날짜 형식은 YYYY-MM-DD 입니다");
|
|
11
|
+
|
|
12
|
+
const includeTest = z
|
|
13
|
+
.enum(["true", "false"])
|
|
14
|
+
.optional()
|
|
15
|
+
.describe("테스트 결제(샌드박스 결제)로 만든 구매 포함 여부. 기본 `false`");
|
|
16
|
+
|
|
17
|
+
export const analyticsRangeQuerySchema = z.object({
|
|
18
|
+
from: reportDate.describe("시작일 (YYYY-MM-DD, Asia/Seoul 기준, 포함)"),
|
|
19
|
+
to: reportDate.describe("종료일 (YYYY-MM-DD, 포함). from부터 최대 92일"),
|
|
20
|
+
includeTest,
|
|
21
|
+
});
|
|
22
|
+
export type AnalyticsRangeParams = z.infer<typeof analyticsRangeQuerySchema>;
|
|
23
|
+
|
|
24
|
+
const rangeMeta = {
|
|
25
|
+
from: z.string(),
|
|
26
|
+
to: z.string(),
|
|
27
|
+
timezone: z.literal("Asia/Seoul"),
|
|
28
|
+
currency: z.literal("KRW"),
|
|
29
|
+
includeTest: z.boolean().describe("테스트 결제 구매를 포함했는가"),
|
|
30
|
+
lastComputedAt: z
|
|
31
|
+
.string()
|
|
32
|
+
.nullable()
|
|
33
|
+
.describe("기간 안에서 가장 최근에 집계한 시각(ISO 8601). 집계된 날이 없으면 null"),
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 비율(0 이상). 단계가 세션 안에서 꼭 이어지지는 않아 1을 넘을 수 있다 — 예: 조회 없이 장바구니에서 바로 산 구매,
|
|
38
|
+
* 자정을 넘겨 다음 날 확정된 구매.
|
|
39
|
+
*/
|
|
40
|
+
const rate = (description: string) => z.number().min(0).nullable().describe(description);
|
|
41
|
+
|
|
42
|
+
export const analyticsTotalsSchema = z.object({
|
|
43
|
+
visitors: z
|
|
44
|
+
.number()
|
|
45
|
+
.int()
|
|
46
|
+
.describe("방문자 수 — 날짜별 순방문자의 합. 여러 날 방문한 사람은 날마다 센다"),
|
|
47
|
+
sessions: z
|
|
48
|
+
.number()
|
|
49
|
+
.int()
|
|
50
|
+
.describe("세션 수. 30분 동안 활동이 없거나 다른 캠페인으로 들어오면 새 세션"),
|
|
51
|
+
engagedSessions: z
|
|
52
|
+
.number()
|
|
53
|
+
.int()
|
|
54
|
+
.describe(
|
|
55
|
+
"참여 세션 수 — 페이지뷰 2개 이상, 체류 10초 이상, 장바구니 담기·결제 시작·구매 중 하나",
|
|
56
|
+
),
|
|
57
|
+
pageViews: z.number().int(),
|
|
58
|
+
engagementSeconds: z
|
|
59
|
+
.number()
|
|
60
|
+
.int()
|
|
61
|
+
.describe(
|
|
62
|
+
"페이지가 화면에 보인 시간의 합(초). 페이지뷰 하나는 최대 30분, 세션은 세션 길이 + 30분까지 센다",
|
|
63
|
+
),
|
|
64
|
+
productViews: z.number().int().describe("상품 조회 수"),
|
|
65
|
+
productViewSessions: z.number().int().describe("상품을 조회한 세션 수"),
|
|
66
|
+
addToCartSessions: z.number().int().describe("장바구니에 담은 세션 수"),
|
|
67
|
+
beginCheckoutSessions: z.number().int().describe("주문서를 연 세션 수"),
|
|
68
|
+
purchaseSessions: z.number().int().describe("구매한 세션 수"),
|
|
69
|
+
purchases: z.number().int().describe("구매(주문) 수"),
|
|
70
|
+
revenue: z
|
|
71
|
+
.number()
|
|
72
|
+
.int()
|
|
73
|
+
.describe(
|
|
74
|
+
"구매 금액 합계 — 주문 결제 금액(배송비 포함). 이후 취소·환불은 빼지 않으므로 매출 리포트의 순매출과 다르다",
|
|
75
|
+
),
|
|
76
|
+
engagementRate: rate("참여율 = 참여 세션 / 세션. 세션이 없으면 null"),
|
|
77
|
+
conversionRate: rate("전환율 = 구매 세션 / 세션. 세션이 없으면 null"),
|
|
78
|
+
});
|
|
79
|
+
export type AnalyticsTotals = z.infer<typeof analyticsTotalsSchema>;
|
|
80
|
+
|
|
81
|
+
export const analyticsFunnelStepSchema = z.object({
|
|
82
|
+
step: z.enum(["SESSION", "PRODUCT_VIEW", "ADD_TO_CART", "BEGIN_CHECKOUT", "PURCHASE"]),
|
|
83
|
+
sessions: z.number().int(),
|
|
84
|
+
rateFromPrevious: rate("직전 단계 대비 비율. 첫 단계이거나 직전 단계가 0이면 null"),
|
|
85
|
+
});
|
|
86
|
+
export type AnalyticsFunnelStep = z.infer<typeof analyticsFunnelStepSchema>;
|
|
87
|
+
|
|
88
|
+
export const analyticsOverviewSchema = z.object({
|
|
89
|
+
...rangeMeta,
|
|
90
|
+
summary: analyticsTotalsSchema.describe("기간 합계"),
|
|
91
|
+
funnel: z
|
|
92
|
+
.array(analyticsFunnelStepSchema)
|
|
93
|
+
.describe(
|
|
94
|
+
"세션 기준 구매 퍼널. 각 단계는 그 행동을 한 세션 수이고, 앞 단계를 거쳤는지는 따지지 않는다",
|
|
95
|
+
),
|
|
96
|
+
rows: z
|
|
97
|
+
.array(analyticsTotalsSchema.extend({ date: z.string().describe("일자 (YYYY-MM-DD)") }))
|
|
98
|
+
.describe("날짜별 값. 세션이 없는 날은 생략된다"),
|
|
99
|
+
});
|
|
100
|
+
export type AnalyticsOverview = z.infer<typeof analyticsOverviewSchema>;
|
|
101
|
+
|
|
102
|
+
export const analyticsProductSortSchema = z
|
|
103
|
+
.enum(["VIEWS", "ADD_TO_CARTS", "PURCHASES", "REVENUE", "IMPRESSIONS"])
|
|
104
|
+
.describe("정렬 기준(내림차순). 기본 `VIEWS`");
|
|
105
|
+
export type AnalyticsProductSort = z.infer<typeof analyticsProductSortSchema>;
|
|
106
|
+
|
|
107
|
+
export const analyticsProductsQuerySchema = analyticsRangeQuerySchema.extend({
|
|
108
|
+
sort: analyticsProductSortSchema.optional(),
|
|
109
|
+
limit: z.coerce
|
|
110
|
+
.number()
|
|
111
|
+
.int()
|
|
112
|
+
.min(1)
|
|
113
|
+
.max(100)
|
|
114
|
+
.optional()
|
|
115
|
+
.describe("최대 행 수. 기본 20, 최대 100"),
|
|
116
|
+
});
|
|
117
|
+
export type AnalyticsProductsParams = z.infer<typeof analyticsProductsQuerySchema>;
|
|
118
|
+
|
|
119
|
+
export const analyticsProductRowSchema = z.object({
|
|
120
|
+
productId: z.string(),
|
|
121
|
+
productName: z.string().nullable().describe("현재 상품명. 삭제된 상품이면 null"),
|
|
122
|
+
impressions: z.number().int().describe("목록 노출 수"),
|
|
123
|
+
views: z.number().int().describe("상세 조회 수"),
|
|
124
|
+
viewSessions: z.number().int().describe("상세를 조회한 세션 수"),
|
|
125
|
+
addToCarts: z.number().int().describe("장바구니 담기 수"),
|
|
126
|
+
purchases: z.number().int().describe("이 상품이 포함된 구매(주문) 수"),
|
|
127
|
+
quantity: z.number().int().describe("구매 수량"),
|
|
128
|
+
revenue: z
|
|
129
|
+
.number()
|
|
130
|
+
.int()
|
|
131
|
+
.describe(
|
|
132
|
+
"이 상품의 구매 금액 — 주문 상품 금액(할인 반영, 배송비 제외) 합계. 이후 취소·환불은 빼지 않는다",
|
|
133
|
+
),
|
|
134
|
+
purchaseRate: rate("구매율 = 구매 / 조회 세션. 조회 세션이 없으면 null"),
|
|
135
|
+
});
|
|
136
|
+
export type AnalyticsProductRow = z.infer<typeof analyticsProductRowSchema>;
|
|
137
|
+
|
|
138
|
+
export const analyticsProductsSchema = z.object({
|
|
139
|
+
...rangeMeta,
|
|
140
|
+
sort: analyticsProductSortSchema,
|
|
141
|
+
rows: z.array(analyticsProductRowSchema),
|
|
142
|
+
});
|
|
143
|
+
export type AnalyticsProducts = z.infer<typeof analyticsProductsSchema>;
|
|
144
|
+
|
|
145
|
+
export const analyticsChannelSchema = z
|
|
146
|
+
.enum(["DIRECT", "ORGANIC_SEARCH", "SOCIAL", "PAID", "EMAIL", "CAMPAIGN", "REFERRAL", "UNKNOWN"])
|
|
147
|
+
.describe(
|
|
148
|
+
"유입 채널 — 세션 첫 페이지뷰의 utm·리퍼러로 정한다. " +
|
|
149
|
+
"`PAID`(utm_medium이 cpc·ppc·paid·display 등), `EMAIL`(utm_medium email), `SOCIAL`(SNS 리퍼러·utm_source), " +
|
|
150
|
+
"`ORGANIC_SEARCH`(검색 엔진 리퍼러), `CAMPAIGN`(그 밖의 utm), `REFERRAL`(그 밖의 리퍼러), `DIRECT`(없음), " +
|
|
151
|
+
"`UNKNOWN`(페이지뷰 없이 서버 이벤트만 있는 세션)",
|
|
152
|
+
);
|
|
153
|
+
export type AnalyticsChannel = z.infer<typeof analyticsChannelSchema>;
|
|
154
|
+
|
|
155
|
+
export const analyticsSourceGroupBySchema = z
|
|
156
|
+
.enum(["CHANNEL", "SOURCE", "CAMPAIGN", "DEVICE"])
|
|
157
|
+
.describe("행 집계 기준. 기본 `CHANNEL`");
|
|
158
|
+
export type AnalyticsSourceGroupBy = z.infer<typeof analyticsSourceGroupBySchema>;
|
|
159
|
+
|
|
160
|
+
export const analyticsSourcesQuerySchema = analyticsRangeQuerySchema.extend({
|
|
161
|
+
groupBy: analyticsSourceGroupBySchema.optional(),
|
|
162
|
+
});
|
|
163
|
+
export type AnalyticsSourcesParams = z.infer<typeof analyticsSourcesQuerySchema>;
|
|
164
|
+
|
|
165
|
+
export const analyticsSourceRowSchema = z.object({
|
|
166
|
+
channel: analyticsChannelSchema.nullable().describe("groupBy=CHANNEL일 때만 값"),
|
|
167
|
+
source: z
|
|
168
|
+
.string()
|
|
169
|
+
.nullable()
|
|
170
|
+
.describe(
|
|
171
|
+
"groupBy=SOURCE·CAMPAIGN일 때 값. utm_source, 없으면 리퍼러 호스트, 둘 다 없으면 `(direct)`",
|
|
172
|
+
),
|
|
173
|
+
medium: z
|
|
174
|
+
.string()
|
|
175
|
+
.nullable()
|
|
176
|
+
.describe("groupBy=SOURCE·CAMPAIGN일 때 값. utm_medium, 없으면 `referral`·`(none)`"),
|
|
177
|
+
campaign: z
|
|
178
|
+
.string()
|
|
179
|
+
.nullable()
|
|
180
|
+
.describe("groupBy=CAMPAIGN일 때 값. utm_campaign, 없으면 `(not set)`"),
|
|
181
|
+
device: z
|
|
182
|
+
.enum(["desktop", "mobile", "tablet", "unknown"])
|
|
183
|
+
.nullable()
|
|
184
|
+
.describe("groupBy=DEVICE일 때만 값"),
|
|
185
|
+
sessions: z.number().int(),
|
|
186
|
+
visitors: z.number().int().describe("날짜별 순방문자의 합"),
|
|
187
|
+
engagedSessions: z.number().int(),
|
|
188
|
+
purchaseSessions: z.number().int(),
|
|
189
|
+
purchases: z.number().int(),
|
|
190
|
+
revenue: z.number().int(),
|
|
191
|
+
conversionRate: rate("전환율 = 구매 세션 / 세션"),
|
|
192
|
+
});
|
|
193
|
+
export type AnalyticsSourceRow = z.infer<typeof analyticsSourceRowSchema>;
|
|
194
|
+
|
|
195
|
+
export const analyticsSourcesSchema = z.object({
|
|
196
|
+
...rangeMeta,
|
|
197
|
+
groupBy: analyticsSourceGroupBySchema,
|
|
198
|
+
rows: z.array(analyticsSourceRowSchema).describe("세션 수 내림차순"),
|
|
199
|
+
});
|
|
200
|
+
export type AnalyticsSources = z.infer<typeof analyticsSourcesSchema>;
|
package/src/schemas/scope.ts
CHANGED
|
@@ -14,7 +14,7 @@ export const scopeAccessSchema = z
|
|
|
14
14
|
.describe("접근 수준. `r`=읽기, `rw`=읽기+쓰기(r을 함의)");
|
|
15
15
|
export type ScopeAccess = z.infer<typeof scopeAccessSchema>;
|
|
16
16
|
|
|
17
|
-
/** 리소스별로 부여 가능한 접근 수준. settlement는 쓰기 API가 없어 `r`만 존재한다 */
|
|
17
|
+
/** 리소스별로 부여 가능한 접근 수준. settlement·analytics는 쓰기 API가 없어 `r`만 존재한다 */
|
|
18
18
|
export const STORE_SCOPE_RESOURCES = {
|
|
19
19
|
product: ["r", "rw"],
|
|
20
20
|
category: ["r", "rw"],
|
|
@@ -23,6 +23,7 @@ export const STORE_SCOPE_RESOURCES = {
|
|
|
23
23
|
inquiry: ["r", "rw"],
|
|
24
24
|
review: ["r", "rw"],
|
|
25
25
|
settlement: ["r"],
|
|
26
|
+
analytics: ["r"],
|
|
26
27
|
webhook: ["r", "rw"],
|
|
27
28
|
store: ["r", "rw"],
|
|
28
29
|
member: ["r", "rw"],
|
|
@@ -56,6 +57,7 @@ export const STORE_ROLE_SCOPES = {
|
|
|
56
57
|
"inquiry:rw",
|
|
57
58
|
"review:rw",
|
|
58
59
|
"settlement:r",
|
|
60
|
+
"analytics:r",
|
|
59
61
|
"webhook:rw",
|
|
60
62
|
"store:rw",
|
|
61
63
|
"member:rw",
|
|
@@ -67,6 +69,7 @@ export const STORE_ROLE_SCOPES = {
|
|
|
67
69
|
"claim:rw",
|
|
68
70
|
"inquiry:rw",
|
|
69
71
|
"review:rw",
|
|
72
|
+
"analytics:r",
|
|
70
73
|
"webhook:rw",
|
|
71
74
|
"store:rw",
|
|
72
75
|
"member:rw",
|