@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.
Files changed (41) hide show
  1. package/dist/src/index.js +21 -0
  2. package/package.json +59 -0
  3. package/src/address.spec.ts +662 -0
  4. package/src/address.ts +300 -0
  5. package/src/auth.spec.ts +771 -0
  6. package/src/auth.ts +168 -0
  7. package/src/compressor/brotli.ts +26 -0
  8. package/src/index.ts +5 -0
  9. package/src/interceptors.spec.ts +1343 -0
  10. package/src/interceptors.ts +224 -0
  11. package/src/policies.spec.ts +595 -0
  12. package/src/policies.ts +431 -0
  13. package/src/products.spec.ts +710 -0
  14. package/src/products.ts +112 -0
  15. package/src/profile.spec.ts +626 -0
  16. package/src/profile.ts +169 -0
  17. package/src/proto/auth/v1/entities/auth.proto +140 -0
  18. package/src/proto/auth/v1/entities/policy.proto +57 -0
  19. package/src/proto/auth/v1/service.proto +26 -0
  20. package/src/proto/customers/v1/entities/address.proto +101 -0
  21. package/src/proto/customers/v1/entities/profile.proto +118 -0
  22. package/src/proto/customers/v1/service.proto +36 -0
  23. package/src/proto/files/v1/entities/file.proto +62 -0
  24. package/src/proto/files/v1/service.proto +19 -0
  25. package/src/proto/products/v1/entities/category.proto +98 -0
  26. package/src/proto/products/v1/entities/collection.proto +72 -0
  27. package/src/proto/products/v1/entities/product/create.proto +41 -0
  28. package/src/proto/products/v1/entities/product/option.proto +17 -0
  29. package/src/proto/products/v1/entities/product/shared.proto +255 -0
  30. package/src/proto/products/v1/entities/product/update.proto +66 -0
  31. package/src/proto/products/v1/entities/tag.proto +73 -0
  32. package/src/proto/products/v1/entities/taxonomy.proto +146 -0
  33. package/src/proto/products/v1/entities/type.proto +98 -0
  34. package/src/proto/products/v1/entities/variant.proto +127 -0
  35. package/src/proto/products/v1/service.proto +78 -0
  36. package/src/proto/promotions/v1/entities/campaign.proto +145 -0
  37. package/src/proto/promotions/v1/service.proto +17 -0
  38. package/src/proto/stocknodes/v1/entities/stocknode.proto +167 -0
  39. package/src/proto/stocknodes/v1/service.proto +21 -0
  40. package/src/registration.ts +170 -0
  41. 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
+ }