@paakd/api 0.0.1
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/src/index.js +21 -0
- package/package.json +59 -0
- package/src/address.spec.ts +662 -0
- package/src/address.ts +300 -0
- package/src/auth.spec.ts +771 -0
- package/src/auth.ts +168 -0
- package/src/compressor/brotli.ts +26 -0
- package/src/index.ts +5 -0
- package/src/interceptors.spec.ts +1343 -0
- package/src/interceptors.ts +224 -0
- package/src/policies.spec.ts +595 -0
- package/src/policies.ts +431 -0
- package/src/products.spec.ts +710 -0
- package/src/products.ts +112 -0
- package/src/profile.spec.ts +626 -0
- package/src/profile.ts +169 -0
- package/src/proto/auth/v1/entities/auth.proto +140 -0
- package/src/proto/auth/v1/entities/policy.proto +57 -0
- package/src/proto/auth/v1/service.proto +26 -0
- package/src/proto/customers/v1/entities/address.proto +101 -0
- package/src/proto/customers/v1/entities/profile.proto +118 -0
- package/src/proto/customers/v1/service.proto +36 -0
- package/src/proto/files/v1/entities/file.proto +62 -0
- package/src/proto/files/v1/service.proto +19 -0
- package/src/proto/products/v1/entities/category.proto +98 -0
- package/src/proto/products/v1/entities/collection.proto +72 -0
- package/src/proto/products/v1/entities/product/create.proto +41 -0
- package/src/proto/products/v1/entities/product/option.proto +17 -0
- package/src/proto/products/v1/entities/product/shared.proto +255 -0
- package/src/proto/products/v1/entities/product/update.proto +66 -0
- package/src/proto/products/v1/entities/tag.proto +73 -0
- package/src/proto/products/v1/entities/taxonomy.proto +146 -0
- package/src/proto/products/v1/entities/type.proto +98 -0
- package/src/proto/products/v1/entities/variant.proto +127 -0
- package/src/proto/products/v1/service.proto +78 -0
- package/src/proto/promotions/v1/entities/campaign.proto +145 -0
- package/src/proto/promotions/v1/service.proto +17 -0
- package/src/proto/stocknodes/v1/entities/stocknode.proto +167 -0
- package/src/proto/stocknodes/v1/service.proto +21 -0
- package/src/registration.ts +170 -0
- package/src/test-utils.ts +176 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import type { Message } from '@bufbuild/protobuf'
|
|
2
|
+
import {
|
|
3
|
+
Code,
|
|
4
|
+
ConnectError,
|
|
5
|
+
type Interceptor,
|
|
6
|
+
type StreamRequest,
|
|
7
|
+
type StreamResponse,
|
|
8
|
+
type UnaryRequest,
|
|
9
|
+
type UnaryResponse,
|
|
10
|
+
} from '@connectrpc/connect'
|
|
11
|
+
import type { Checkout } from '@paakd/config'
|
|
12
|
+
|
|
13
|
+
export interface RequestLogger {
|
|
14
|
+
onRequestHeader?: (header: Headers) => void
|
|
15
|
+
onRequestMessage?: (message: Message) => void
|
|
16
|
+
onResponseHeader?: (header: Headers) => void
|
|
17
|
+
onResponseMessage?: (message: Message) => void
|
|
18
|
+
onResponseTrailer?: (trailer: Headers) => void
|
|
19
|
+
onError?: (error: unknown) => void
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function defaultRequestLogger(
|
|
23
|
+
req: UnaryRequest | StreamRequest
|
|
24
|
+
): RequestLogger {
|
|
25
|
+
const name = `${req.method.methodKind} ${req.method.toString()}`
|
|
26
|
+
return {
|
|
27
|
+
onRequestHeader(header: Headers) {
|
|
28
|
+
console.log(name, 'request header', header)
|
|
29
|
+
},
|
|
30
|
+
onRequestMessage(message: Message) {
|
|
31
|
+
console.log(name, 'request message', message)
|
|
32
|
+
},
|
|
33
|
+
onResponseHeader(header: Headers) {
|
|
34
|
+
console.log(name, 'response header', header)
|
|
35
|
+
},
|
|
36
|
+
onResponseMessage(message: Message) {
|
|
37
|
+
console.log(name, 'response message', message)
|
|
38
|
+
},
|
|
39
|
+
onResponseTrailer(trailer: Headers) {
|
|
40
|
+
console.log(name, 'response trailer', trailer)
|
|
41
|
+
},
|
|
42
|
+
onError(error: unknown) {
|
|
43
|
+
console.log(name, 'error', error)
|
|
44
|
+
},
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function createLoggingInterceptor(
|
|
49
|
+
reqLogger: (
|
|
50
|
+
request: UnaryRequest | StreamRequest
|
|
51
|
+
) => RequestLogger = defaultRequestLogger
|
|
52
|
+
): Interceptor {
|
|
53
|
+
return next => async req => {
|
|
54
|
+
const logger = reqLogger(req)
|
|
55
|
+
const reqIntercepted = interceptRequest(req, logger)
|
|
56
|
+
let res: UnaryResponse | StreamResponse
|
|
57
|
+
try {
|
|
58
|
+
res = await next(reqIntercepted)
|
|
59
|
+
} catch (e) {
|
|
60
|
+
logger.onError?.(e)
|
|
61
|
+
throw e
|
|
62
|
+
}
|
|
63
|
+
return interceptResponse(res, logger)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function createAuthenticationInterceptor(
|
|
68
|
+
checkoutConfig: Checkout
|
|
69
|
+
): Interceptor {
|
|
70
|
+
return next => async req => {
|
|
71
|
+
req.header.set('X-Store-Key', checkoutConfig.storeAPISecret)
|
|
72
|
+
req.header.set('X-SA-Key', checkoutConfig.storeAccessKey)
|
|
73
|
+
req.header.set('X-CH-Key', checkoutConfig.salesChannelAPISecret)
|
|
74
|
+
req.header.set('X-CHA-Key', checkoutConfig.saleChannelAccessKey)
|
|
75
|
+
|
|
76
|
+
return await next(req)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function createCustomerAuthenticationInterceptor(
|
|
81
|
+
jwtKey: string
|
|
82
|
+
): Interceptor {
|
|
83
|
+
return next => async req => {
|
|
84
|
+
if (!jwtKey) {
|
|
85
|
+
throw new ConnectError(
|
|
86
|
+
'JWT key is required for customer authentication',
|
|
87
|
+
Code.Unauthenticated
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
req.header.set('Authorization', `Bearer ${jwtKey}`)
|
|
91
|
+
|
|
92
|
+
return await next(req)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function interceptRequest<R extends UnaryRequest | StreamRequest>(
|
|
97
|
+
req: R,
|
|
98
|
+
logger: RequestLogger
|
|
99
|
+
): R {
|
|
100
|
+
logger.onRequestHeader?.(req.header)
|
|
101
|
+
if (req.stream) {
|
|
102
|
+
return {
|
|
103
|
+
...req,
|
|
104
|
+
message: interceptIterable(
|
|
105
|
+
req.message,
|
|
106
|
+
message => logger.onRequestMessage?.(message),
|
|
107
|
+
() => {},
|
|
108
|
+
() => {}
|
|
109
|
+
),
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
logger.onRequestMessage?.(req.message)
|
|
113
|
+
|
|
114
|
+
return req
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function interceptResponse<R extends UnaryResponse | StreamResponse>(
|
|
118
|
+
res: R,
|
|
119
|
+
logger: RequestLogger
|
|
120
|
+
): R {
|
|
121
|
+
logger.onResponseHeader?.(res.header)
|
|
122
|
+
if (res.stream) {
|
|
123
|
+
return {
|
|
124
|
+
...res,
|
|
125
|
+
message: interceptIterable(
|
|
126
|
+
res.message,
|
|
127
|
+
message => logger.onResponseMessage?.(message),
|
|
128
|
+
e => logger.onError?.(e),
|
|
129
|
+
() => logger.onResponseTrailer?.(res.trailer)
|
|
130
|
+
),
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
logger.onResponseMessage?.(res.message)
|
|
134
|
+
logger.onResponseTrailer?.(res.trailer)
|
|
135
|
+
|
|
136
|
+
return res
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function interceptIterable(
|
|
140
|
+
original: AsyncIterable<Message>,
|
|
141
|
+
onNext: (value: Message) => void,
|
|
142
|
+
onNextReject: (e: unknown) => void,
|
|
143
|
+
onDone: () => void
|
|
144
|
+
): AsyncIterable<Message> {
|
|
145
|
+
return {
|
|
146
|
+
[Symbol.asyncIterator]() {
|
|
147
|
+
const o = original[Symbol.asyncIterator]()
|
|
148
|
+
const n: AsyncIterator<Message> = {
|
|
149
|
+
async next(value: Message): Promise<IteratorResult<Message>> {
|
|
150
|
+
let result: IteratorResult<Message>
|
|
151
|
+
try {
|
|
152
|
+
result = await o.next(value)
|
|
153
|
+
} catch (e) {
|
|
154
|
+
onNextReject(e)
|
|
155
|
+
throw e
|
|
156
|
+
}
|
|
157
|
+
if (result.done !== true) {
|
|
158
|
+
onNext(result.value)
|
|
159
|
+
} else {
|
|
160
|
+
onDone()
|
|
161
|
+
}
|
|
162
|
+
return result
|
|
163
|
+
},
|
|
164
|
+
}
|
|
165
|
+
if (o.throw) {
|
|
166
|
+
n.throw = (e: unknown): Promise<IteratorResult<Message>> => {
|
|
167
|
+
return o.throw!(e)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (o.return) {
|
|
171
|
+
n.return = (value: unknown): Promise<IteratorResult<Message>> => {
|
|
172
|
+
return o.return!(value)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return n
|
|
176
|
+
},
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export function createHeadersInterceptor(
|
|
181
|
+
headers: Record<string, string | null>
|
|
182
|
+
): Interceptor {
|
|
183
|
+
return next => async req => {
|
|
184
|
+
if (!headers['x-original-host']) {
|
|
185
|
+
throw new ConnectError(
|
|
186
|
+
'Original host missing from request',
|
|
187
|
+
Code.InvalidArgument
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
if (!headers['x-shop-id']) {
|
|
191
|
+
throw new ConnectError(
|
|
192
|
+
'Shop id missing from request',
|
|
193
|
+
Code.InvalidArgument
|
|
194
|
+
)
|
|
195
|
+
}
|
|
196
|
+
if (!headers['x-sitepath']) {
|
|
197
|
+
throw new ConnectError(
|
|
198
|
+
'Sitepath missing from request',
|
|
199
|
+
Code.InvalidArgument
|
|
200
|
+
)
|
|
201
|
+
}
|
|
202
|
+
if (!headers['x-locale']) {
|
|
203
|
+
throw new ConnectError(
|
|
204
|
+
'Locale missing from request',
|
|
205
|
+
Code.InvalidArgument
|
|
206
|
+
)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (!headers['x-region']) {
|
|
210
|
+
throw new ConnectError(
|
|
211
|
+
'Region missing from request',
|
|
212
|
+
Code.InvalidArgument
|
|
213
|
+
)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
req.header.set('X-Original-Host', headers['x-original-host'])
|
|
217
|
+
req.header.set('X-shop-id', headers['x-shop-id'])
|
|
218
|
+
req.header.set('X-Sitepath', headers['x-sitepath'])
|
|
219
|
+
req.header.set('X-locale', headers['x-locale'])
|
|
220
|
+
req.header.set('X-Region', headers['x-region'])
|
|
221
|
+
|
|
222
|
+
return await next(req)
|
|
223
|
+
}
|
|
224
|
+
}
|