@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,167 @@
|
|
|
1
|
+
syntax = "proto3";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import "buf/validate/validate.proto";
|
|
5
|
+
|
|
6
|
+
message StockNodeAddress {
|
|
7
|
+
optional string id = 1;
|
|
8
|
+
string address_1 = 2;
|
|
9
|
+
string address_2 = 3;
|
|
10
|
+
string address_3 = 4;
|
|
11
|
+
string phone_number = 5;
|
|
12
|
+
string zip_code = 6;
|
|
13
|
+
string country = 7;
|
|
14
|
+
string country_code = 8;
|
|
15
|
+
string company = 9;
|
|
16
|
+
string city = 10;
|
|
17
|
+
string province = 11;
|
|
18
|
+
string state_code = 12;
|
|
19
|
+
string email_address = 13;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
message StockNodeFulfillmentSet {
|
|
23
|
+
string id = 1;
|
|
24
|
+
string name = 2;
|
|
25
|
+
string type = 3;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
message CreateStockNodeRequest {
|
|
29
|
+
string name = 1 [
|
|
30
|
+
(buf.validate.field).required = true
|
|
31
|
+
];
|
|
32
|
+
optional string description = 2;
|
|
33
|
+
optional string contact_name = 3;
|
|
34
|
+
string contact_email = 4 [
|
|
35
|
+
(buf.validate.field).string.email = true
|
|
36
|
+
];
|
|
37
|
+
repeated string tags = 5;
|
|
38
|
+
repeated string sales_channels = 6;
|
|
39
|
+
repeated string fulfillment_providers = 7;
|
|
40
|
+
StockNodeAddress address = 8;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
message CreateStockNodeResponse {
|
|
44
|
+
string id = 1;
|
|
45
|
+
string name = 2;
|
|
46
|
+
string description = 3;
|
|
47
|
+
string contact_name = 4;
|
|
48
|
+
string contact_email = 5;
|
|
49
|
+
repeated string tags = 6;
|
|
50
|
+
repeated string sales_channels = 7;
|
|
51
|
+
repeated string fulfillment_providers = 8;
|
|
52
|
+
StockNodeAddress address = 9;
|
|
53
|
+
repeated StockNodeFulfillmentSet fulfillment_sets = 10;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
message UpdateStockNodeRequest {
|
|
57
|
+
string id = 1 [
|
|
58
|
+
(buf.validate.field).required = true,
|
|
59
|
+
(buf.validate.field).string.pattern = "^[a-z]{3}[_][0-9a-hjkmnp-tv-z]{26}$"
|
|
60
|
+
];
|
|
61
|
+
optional string name = 2 ;
|
|
62
|
+
optional string description = 3;
|
|
63
|
+
optional string contact_name = 4;
|
|
64
|
+
optional string contact_email = 5 [
|
|
65
|
+
(buf.validate.field).string.email = true
|
|
66
|
+
];
|
|
67
|
+
repeated string tags = 6;
|
|
68
|
+
repeated string sales_channels = 7;
|
|
69
|
+
repeated string fulfillment_providers = 8;
|
|
70
|
+
optional StockNodeAddress address = 9;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
message UpdateStockNodeResponse {
|
|
74
|
+
string id = 1;
|
|
75
|
+
string name = 2;
|
|
76
|
+
string description = 3;
|
|
77
|
+
string contact_name = 4;
|
|
78
|
+
string contact_email = 5;
|
|
79
|
+
repeated string tags = 6;
|
|
80
|
+
repeated string sales_channels = 7;
|
|
81
|
+
repeated string fulfillment_providers = 8;
|
|
82
|
+
StockNodeAddress address = 9;
|
|
83
|
+
repeated StockNodeFulfillmentSet fulfillment_sets = 10;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
message DeleteStockNodeRequest {
|
|
87
|
+
string id = 1 [
|
|
88
|
+
(buf.validate.field).required = true,
|
|
89
|
+
(buf.validate.field).string.pattern = "^[a-z]{3}[_][0-9a-hjkmnp-tv-z]{26}$"
|
|
90
|
+
];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
message DeleteStockNodeResponse {
|
|
94
|
+
string id = 1;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
message GetStockNodeRequest {
|
|
98
|
+
string id = 1 [
|
|
99
|
+
(buf.validate.field).required = true,
|
|
100
|
+
(buf.validate.field).string.pattern = "^[a-z]{3}[_][0-9a-hjkmnp-tv-z]{26}$"
|
|
101
|
+
];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
message GetStockNodeResponse {
|
|
105
|
+
string id = 1;
|
|
106
|
+
string name = 2;
|
|
107
|
+
string description = 3;
|
|
108
|
+
string contact_name = 4;
|
|
109
|
+
string contact_email = 5;
|
|
110
|
+
repeated string tags = 6;
|
|
111
|
+
repeated string sales_channels = 7;
|
|
112
|
+
repeated string fulfillment_providers = 8;
|
|
113
|
+
StockNodeAddress address = 9;
|
|
114
|
+
repeated StockNodeFulfillmentSet fulfillment_sets = 10;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
message ListStockNodesRequest {
|
|
118
|
+
int32 offset = 1 [
|
|
119
|
+
(buf.validate.field).int32.gte = 0
|
|
120
|
+
];
|
|
121
|
+
uint32 limit = 2 [
|
|
122
|
+
(buf.validate.field).uint32.gte = 1,
|
|
123
|
+
(buf.validate.field).uint32.lte = 100
|
|
124
|
+
];
|
|
125
|
+
optional string order_by = 3;
|
|
126
|
+
optional string filter = 4;
|
|
127
|
+
optional bool ascending = 5;
|
|
128
|
+
optional string request_path = 6;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
message ListStockNodesResponse {
|
|
132
|
+
repeated CreateStockNodeResponse stock_nodes = 1;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
enum FulfillmentSetType {
|
|
136
|
+
SHIPPING = 0;
|
|
137
|
+
PICKUP = 1;
|
|
138
|
+
DROPOFF = 2;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
message AddFulfillmentSetRequest {
|
|
142
|
+
string name = 1;
|
|
143
|
+
FulfillmentSetType type = 2;
|
|
144
|
+
string stock_node_id = 3 [
|
|
145
|
+
(buf.validate.field).required = true,
|
|
146
|
+
(buf.validate.field).string.pattern = "^[a-z]{3}[_][0-9a-hjkmnp-tv-z]{26}$"
|
|
147
|
+
];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
message AddFulfillmentSetResponse {
|
|
151
|
+
CreateStockNodeResponse stock_node = 1;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
message RemoveFulfillmentSetRequest {
|
|
155
|
+
string stock_node_id = 1 [
|
|
156
|
+
(buf.validate.field).required = true,
|
|
157
|
+
(buf.validate.field).string.pattern = "^[a-z]{3}[_][0-9a-hjkmnp-tv-z]{26}$"
|
|
158
|
+
];
|
|
159
|
+
string fulfillment_set_id = 2 [
|
|
160
|
+
(buf.validate.field).required = true,
|
|
161
|
+
(buf.validate.field).string.pattern = "^[a-z]{3}[_][0-9a-hjkmnp-tv-z]{26}$"
|
|
162
|
+
];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
message RemoveFulfillmentSetResponse {
|
|
166
|
+
CreateStockNodeResponse stock_node = 1;
|
|
167
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
syntax = "proto3";
|
|
2
|
+
|
|
3
|
+
package apps.enterprise.interfaces.rpc.stocknodes.v1;
|
|
4
|
+
|
|
5
|
+
option go_package = "paakd.com/packages/api/gen/stocknodes/v1;stocknodesv1";
|
|
6
|
+
|
|
7
|
+
import "src/proto/stocknodes/v1/entities/stocknode.proto";
|
|
8
|
+
|
|
9
|
+
service StockNodesService {
|
|
10
|
+
rpc RemoveFulfillmentSet(RemoveFulfillmentSetRequest) returns (RemoveFulfillmentSetResponse) {}
|
|
11
|
+
rpc AddFulfillmentSet(AddFulfillmentSetRequest) returns (AddFulfillmentSetResponse) {}
|
|
12
|
+
rpc CreateStockNode(CreateStockNodeRequest) returns (CreateStockNodeResponse) {}
|
|
13
|
+
rpc DeleteStockNode(DeleteStockNodeRequest) returns (DeleteStockNodeResponse) {}
|
|
14
|
+
rpc GetStockNode(GetStockNodeRequest) returns (GetStockNodeResponse) {}
|
|
15
|
+
rpc UpdateStockNode(UpdateStockNodeRequest) returns (UpdateStockNodeResponse) {
|
|
16
|
+
option idempotency_level = NO_SIDE_EFFECTS;
|
|
17
|
+
}
|
|
18
|
+
rpc ListStockNodes(ListStockNodesRequest) returns (ListStockNodesResponse) {
|
|
19
|
+
option idempotency_level = NO_SIDE_EFFECTS;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { Code, ConnectError, createClient } from '@connectrpc/connect'
|
|
2
|
+
import { createGrpcTransport } from '@connectrpc/connect-node'
|
|
3
|
+
import { getCheckoutConfig } from '@paakd/config'
|
|
4
|
+
import { AuthService } from '../gen/src/proto/auth/v1/service_pb'
|
|
5
|
+
import type { RegisterRequest } from '../gen/src/proto/auth/v1/entities/auth_pb'
|
|
6
|
+
import { brotliCompression } from './compressor/brotli'
|
|
7
|
+
import {
|
|
8
|
+
createAuthenticationInterceptor,
|
|
9
|
+
createHeadersInterceptor,
|
|
10
|
+
} from './interceptors'
|
|
11
|
+
|
|
12
|
+
const localeMap: Record<string, number> = {
|
|
13
|
+
'en-GB': 0,
|
|
14
|
+
'en-US': 1,
|
|
15
|
+
'nl-NL': 2,
|
|
16
|
+
'de-DE': 3,
|
|
17
|
+
en: 0,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface RegisterCustomerRequest {
|
|
21
|
+
body: Omit<RegisterRequest, '$typeName'>
|
|
22
|
+
headers: Record<string, string | null>
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface VerifyEmailRequest {
|
|
26
|
+
body: {
|
|
27
|
+
email: string
|
|
28
|
+
locale: string
|
|
29
|
+
idempotencyKey?: string
|
|
30
|
+
}
|
|
31
|
+
headers: Record<string, string | null>
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface ValidateOTPRequest {
|
|
35
|
+
body: {
|
|
36
|
+
email: string
|
|
37
|
+
otp: string
|
|
38
|
+
}
|
|
39
|
+
headers: Record<string, string | null>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function verifyEmail({
|
|
43
|
+
body: { email, idempotencyKey, locale },
|
|
44
|
+
headers,
|
|
45
|
+
}: VerifyEmailRequest) {
|
|
46
|
+
const checkoutConfig = await getCheckoutConfig()
|
|
47
|
+
const transport = createGrpcTransport({
|
|
48
|
+
baseUrl: checkoutConfig.enterpriseURL,
|
|
49
|
+
interceptors: [
|
|
50
|
+
createHeadersInterceptor(headers),
|
|
51
|
+
createAuthenticationInterceptor(checkoutConfig),
|
|
52
|
+
],
|
|
53
|
+
acceptCompression: [brotliCompression],
|
|
54
|
+
sendCompression: brotliCompression,
|
|
55
|
+
})
|
|
56
|
+
const auth = createClient(AuthService, transport)
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const value = await auth.verifyEmail({
|
|
60
|
+
email,
|
|
61
|
+
locale: localeMap[locale] ?? 0,
|
|
62
|
+
idempotencyKey,
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
value,
|
|
67
|
+
status: 'success',
|
|
68
|
+
}
|
|
69
|
+
} catch (err: unknown) {
|
|
70
|
+
if (err instanceof ConnectError) {
|
|
71
|
+
return {
|
|
72
|
+
code: err.code,
|
|
73
|
+
rawMessage: err.rawMessage,
|
|
74
|
+
message: err.rawMessage,
|
|
75
|
+
status: 'failed',
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
code: Code.Internal,
|
|
81
|
+
rawMessage: 'An unexpected error occurred while verifying the email.',
|
|
82
|
+
message: 'An unexpected error occurred while verifying the email.',
|
|
83
|
+
status: 'failed',
|
|
84
|
+
} as unknown as ConnectError
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export async function validateOTP({
|
|
89
|
+
body: { email, otp },
|
|
90
|
+
headers,
|
|
91
|
+
}: ValidateOTPRequest) {
|
|
92
|
+
const checkoutConfig = await getCheckoutConfig()
|
|
93
|
+
const transport = createGrpcTransport({
|
|
94
|
+
baseUrl: checkoutConfig.enterpriseURL,
|
|
95
|
+
interceptors: [
|
|
96
|
+
createHeadersInterceptor(headers),
|
|
97
|
+
createAuthenticationInterceptor(checkoutConfig),
|
|
98
|
+
],
|
|
99
|
+
acceptCompression: [brotliCompression],
|
|
100
|
+
sendCompression: brotliCompression,
|
|
101
|
+
})
|
|
102
|
+
const auth = createClient(AuthService, transport)
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
const value = await auth.validateOTP({
|
|
106
|
+
email,
|
|
107
|
+
otp,
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
value,
|
|
112
|
+
status: 'success',
|
|
113
|
+
}
|
|
114
|
+
} catch (err: unknown) {
|
|
115
|
+
if (err instanceof ConnectError) {
|
|
116
|
+
return {
|
|
117
|
+
code: err.code,
|
|
118
|
+
rawMessage: err.rawMessage,
|
|
119
|
+
message: err.rawMessage,
|
|
120
|
+
status: 'failed',
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
code: Code.Internal,
|
|
126
|
+
rawMessage: 'An unexpected error occurred while validating the OTP.',
|
|
127
|
+
message: 'An unexpected error occurred while validating the OTP.',
|
|
128
|
+
status: 'failed',
|
|
129
|
+
} as unknown as ConnectError
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export async function registerCustomer({
|
|
134
|
+
body: val,
|
|
135
|
+
headers,
|
|
136
|
+
}: RegisterCustomerRequest) {
|
|
137
|
+
const checkoutConfig = await getCheckoutConfig()
|
|
138
|
+
const transport = createGrpcTransport({
|
|
139
|
+
baseUrl: checkoutConfig.enterpriseURL,
|
|
140
|
+
interceptors: [
|
|
141
|
+
createHeadersInterceptor(headers),
|
|
142
|
+
createAuthenticationInterceptor(checkoutConfig),
|
|
143
|
+
],
|
|
144
|
+
acceptCompression: [brotliCompression],
|
|
145
|
+
sendCompression: brotliCompression,
|
|
146
|
+
})
|
|
147
|
+
const auth = createClient(AuthService, transport)
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
await auth.register(val)
|
|
151
|
+
return {
|
|
152
|
+
status: 'success',
|
|
153
|
+
}
|
|
154
|
+
} catch (err: unknown) {
|
|
155
|
+
if (err instanceof ConnectError) {
|
|
156
|
+
return {
|
|
157
|
+
code: err.code,
|
|
158
|
+
rawMessage: err.rawMessage,
|
|
159
|
+
message: err.rawMessage,
|
|
160
|
+
status: 'failed',
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
code: Code.Internal,
|
|
166
|
+
message: 'An unexpected error occurred during registration.',
|
|
167
|
+
status: 'failed',
|
|
168
|
+
} as unknown as ConnectError
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { ConnectError } from '@connectrpc/connect'
|
|
2
|
+
import type { Checkout } from '@paakd/config'
|
|
3
|
+
import { vi, type MockedFunction } from 'vitest'
|
|
4
|
+
|
|
5
|
+
// Re-export for test files
|
|
6
|
+
export type { Checkout, MockedFunction }
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Common mock client interface for service tests
|
|
10
|
+
*/
|
|
11
|
+
export type MockServiceClient = Record<
|
|
12
|
+
string,
|
|
13
|
+
MockedFunction<(...args: unknown[]) => unknown>
|
|
14
|
+
>
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Mock Transport type
|
|
18
|
+
*/
|
|
19
|
+
export type Transport = any
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Base test context for API service tests
|
|
23
|
+
*/
|
|
24
|
+
export interface BaseTestContext {
|
|
25
|
+
client: MockServiceClient
|
|
26
|
+
config: Checkout
|
|
27
|
+
interceptors: Record<string, MockedFunction<(...args: unknown[]) => unknown>>
|
|
28
|
+
transport: Transport
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Creates a mock ConnectError with proper prototype chain
|
|
33
|
+
* This ensures that instanceof ConnectError checks work correctly
|
|
34
|
+
*/
|
|
35
|
+
export function createMockConnectError(
|
|
36
|
+
code: number,
|
|
37
|
+
rawMessage: string,
|
|
38
|
+
message: string
|
|
39
|
+
): ConnectError {
|
|
40
|
+
const error = {
|
|
41
|
+
code,
|
|
42
|
+
rawMessage,
|
|
43
|
+
message,
|
|
44
|
+
name: 'ConnectError',
|
|
45
|
+
} as ConnectError
|
|
46
|
+
|
|
47
|
+
Object.setPrototypeOf(error, ConnectError.prototype)
|
|
48
|
+
return error
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Creates a default mock configuration used across API services
|
|
53
|
+
*/
|
|
54
|
+
export function createMockConfig(): Checkout {
|
|
55
|
+
return {
|
|
56
|
+
hostname: 'example.com',
|
|
57
|
+
cmsRemoteURL: 'https://cms.example.com',
|
|
58
|
+
enterpriseRemoteURL: 'https://enterprise.example.com',
|
|
59
|
+
cmsURL: 'https://cms-local.example.com',
|
|
60
|
+
enterpriseURL: 'https://enterprise.example.com',
|
|
61
|
+
secureCookiePassword: 'secure-cookie-password',
|
|
62
|
+
forestAPIKey: 'forest-api-key',
|
|
63
|
+
saleChannelAccessKey: 'channel-access',
|
|
64
|
+
salesChannelAPISecret: 'channel-secret',
|
|
65
|
+
storeAccessKey: 'store-access',
|
|
66
|
+
storeAPISecret: 'store-secret',
|
|
67
|
+
isProduction: false,
|
|
68
|
+
posthogKey: 'posthog-key',
|
|
69
|
+
posthogDomain: 'posthog.example.com',
|
|
70
|
+
posthogHost: 'posthog.example.com',
|
|
71
|
+
assetsPath: '/assets',
|
|
72
|
+
assetsDomain: 'assets.example.com',
|
|
73
|
+
turnstileKey: 'turnstile-key',
|
|
74
|
+
turnstileSecret: 'turnstile-secret',
|
|
75
|
+
redis: {
|
|
76
|
+
user: 'redis-user',
|
|
77
|
+
host: 'localhost',
|
|
78
|
+
password: 'redis-password',
|
|
79
|
+
port: 6379,
|
|
80
|
+
},
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Creates a default mock interceptors object
|
|
86
|
+
*/
|
|
87
|
+
export function createMockInterceptors(): Record<
|
|
88
|
+
string,
|
|
89
|
+
MockedFunction<(...args: unknown[]) => unknown>
|
|
90
|
+
> {
|
|
91
|
+
return {
|
|
92
|
+
headers: vi
|
|
93
|
+
.fn()
|
|
94
|
+
.mockReturnValue(Symbol('headers-interceptor')) as MockedFunction<
|
|
95
|
+
(...args: unknown[]) => unknown
|
|
96
|
+
>,
|
|
97
|
+
auth: vi.fn().mockReturnValue(Symbol('auth-interceptor')) as MockedFunction<
|
|
98
|
+
(...args: unknown[]) => unknown
|
|
99
|
+
>,
|
|
100
|
+
customer: vi
|
|
101
|
+
.fn()
|
|
102
|
+
.mockReturnValue(Symbol('customer-interceptor')) as MockedFunction<
|
|
103
|
+
(...args: unknown[]) => unknown
|
|
104
|
+
>,
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Creates a mock gRPC transport
|
|
110
|
+
*/
|
|
111
|
+
export function createMockTransport(): Transport {
|
|
112
|
+
return {} as Transport
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Helper to setup common mocks for API service tests
|
|
117
|
+
* Returns objects ready to be used with setupService functions
|
|
118
|
+
*/
|
|
119
|
+
export function setupCommonMocks(): {
|
|
120
|
+
config: Checkout
|
|
121
|
+
interceptors: Record<string, MockedFunction<(...args: unknown[]) => unknown>>
|
|
122
|
+
transport: Transport
|
|
123
|
+
} {
|
|
124
|
+
const config = createMockConfig()
|
|
125
|
+
const interceptors = createMockInterceptors()
|
|
126
|
+
const transport = createMockTransport()
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
config,
|
|
130
|
+
interceptors,
|
|
131
|
+
transport,
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Clears all Vitest mocks - useful for test isolation
|
|
137
|
+
*/
|
|
138
|
+
export function clearAllMocks(): void {
|
|
139
|
+
vi.clearAllMocks()
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Common error scenarios for testing
|
|
144
|
+
*/
|
|
145
|
+
export const COMMON_ERROR_SCENARIOS = {
|
|
146
|
+
INVALID_CREDENTIALS: {
|
|
147
|
+
code: 16,
|
|
148
|
+
message: 'UNAUTHENTICATED',
|
|
149
|
+
rawMessage: 'Invalid credentials provided',
|
|
150
|
+
},
|
|
151
|
+
NOT_FOUND: {
|
|
152
|
+
code: 5,
|
|
153
|
+
message: 'NOT_FOUND',
|
|
154
|
+
rawMessage: 'Resource not found',
|
|
155
|
+
},
|
|
156
|
+
PERMISSION_DENIED: {
|
|
157
|
+
code: 7,
|
|
158
|
+
message: 'PERMISSION_DENIED',
|
|
159
|
+
rawMessage: 'Permission denied',
|
|
160
|
+
},
|
|
161
|
+
INTERNAL_ERROR: {
|
|
162
|
+
code: 13,
|
|
163
|
+
message: 'INTERNAL',
|
|
164
|
+
rawMessage: 'Internal server error',
|
|
165
|
+
},
|
|
166
|
+
SERVICE_UNAVAILABLE: {
|
|
167
|
+
code: 14,
|
|
168
|
+
message: 'UNAVAILABLE',
|
|
169
|
+
rawMessage: 'Service temporarily unavailable',
|
|
170
|
+
},
|
|
171
|
+
INVALID_ARGUMENT: {
|
|
172
|
+
code: 3,
|
|
173
|
+
message: 'INVALID_ARGUMENT',
|
|
174
|
+
rawMessage: 'Invalid argument provided',
|
|
175
|
+
},
|
|
176
|
+
} as const
|