@paakd/api 0.0.1 → 0.0.2
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/buf/validate/validate_pb.ts +5001 -0
- package/dist/gen/buf/validate/validate_pb.d.ts +4634 -0
- package/dist/gen/buf/validate/validate_pb.d.ts.map +1 -0
- package/dist/gen/buf/validate/validate_pb.js +414 -0
- package/dist/gen/src/proto/auth/v1/entities/auth_pb.d.ts +268 -0
- package/dist/gen/src/proto/auth/v1/entities/auth_pb.d.ts.map +1 -0
- package/dist/gen/src/proto/auth/v1/entities/auth_pb.js +120 -0
- package/dist/gen/src/proto/auth/v1/entities/policy_pb.d.ts +235 -0
- package/dist/gen/src/proto/auth/v1/entities/policy_pb.d.ts.map +1 -0
- package/dist/gen/src/proto/auth/v1/entities/policy_pb.js +98 -0
- package/dist/gen/src/proto/auth/v1/service_pb.d.ts +117 -0
- package/dist/gen/src/proto/auth/v1/service_pb.d.ts.map +1 -0
- package/dist/gen/src/proto/auth/v1/service_pb.js +22 -0
- package/dist/gen/src/proto/customers/v1/entities/address_pb.d.ts +371 -0
- package/dist/gen/src/proto/customers/v1/entities/address_pb.d.ts.map +1 -0
- package/dist/gen/src/proto/customers/v1/entities/address_pb.js +84 -0
- package/dist/gen/src/proto/customers/v1/entities/profile_pb.d.ts +189 -0
- package/dist/gen/src/proto/customers/v1/entities/profile_pb.d.ts.map +1 -0
- package/dist/gen/src/proto/customers/v1/entities/profile_pb.js +70 -0
- package/dist/gen/src/proto/customers/v1/service_pb.d.ts +85 -0
- package/dist/gen/src/proto/customers/v1/service_pb.d.ts.map +1 -0
- package/dist/gen/src/proto/customers/v1/service_pb.js +22 -0
- package/dist/gen/src/proto/products/v1/entities/category_pb.d.ts +234 -0
- package/dist/gen/src/proto/products/v1/entities/category_pb.d.ts.map +1 -0
- package/dist/gen/src/proto/products/v1/entities/category_pb.js +84 -0
- package/dist/gen/src/proto/products/v1/entities/collection_pb.d.ts +159 -0
- package/dist/gen/src/proto/products/v1/entities/collection_pb.d.ts.map +1 -0
- package/dist/gen/src/proto/products/v1/entities/collection_pb.js +70 -0
- package/dist/gen/src/proto/products/v1/entities/product/create_pb.d.ts +146 -0
- package/dist/gen/src/proto/products/v1/entities/product/create_pb.d.ts.map +1 -0
- package/dist/gen/src/proto/products/v1/entities/product/create_pb.js +32 -0
- package/dist/gen/src/proto/products/v1/entities/product/option_pb.d.ts +50 -0
- package/dist/gen/src/proto/products/v1/entities/product/option_pb.d.ts.map +1 -0
- package/dist/gen/src/proto/products/v1/entities/product/option_pb.js +32 -0
- package/dist/gen/src/proto/products/v1/entities/product/shared_pb.d.ts +1042 -0
- package/dist/gen/src/proto/products/v1/entities/product/shared_pb.d.ts.map +1 -0
- package/dist/gen/src/proto/products/v1/entities/product/shared_pb.js +258 -0
- package/dist/gen/src/proto/products/v1/entities/product/update_pb.d.ts +236 -0
- package/dist/gen/src/proto/products/v1/entities/product/update_pb.d.ts.map +1 -0
- package/dist/gen/src/proto/products/v1/entities/product/update_pb.js +88 -0
- package/dist/gen/src/proto/products/v1/entities/tag_pb.d.ts +175 -0
- package/dist/gen/src/proto/products/v1/entities/tag_pb.d.ts.map +1 -0
- package/dist/gen/src/proto/products/v1/entities/tag_pb.js +84 -0
- package/dist/gen/src/proto/products/v1/entities/taxonomy_pb.d.ts +477 -0
- package/dist/gen/src/proto/products/v1/entities/taxonomy_pb.d.ts.map +1 -0
- package/dist/gen/src/proto/products/v1/entities/taxonomy_pb.js +235 -0
- package/dist/gen/src/proto/products/v1/entities/type_pb.d.ts +158 -0
- package/dist/gen/src/proto/products/v1/entities/type_pb.d.ts.map +1 -0
- package/dist/gen/src/proto/products/v1/entities/type_pb.js +70 -0
- package/dist/gen/src/proto/products/v1/entities/variant_pb.d.ts +489 -0
- package/dist/gen/src/proto/products/v1/entities/variant_pb.d.ts.map +1 -0
- package/dist/gen/src/proto/products/v1/entities/variant_pb.js +147 -0
- package/dist/gen/src/proto/products/v1/service_pb.d.ts +316 -0
- package/dist/gen/src/proto/products/v1/service_pb.d.ts.map +1 -0
- package/dist/gen/src/proto/products/v1/service_pb.js +36 -0
- package/dist/src/address.d.ts +53 -0
- package/dist/src/address.d.ts.map +1 -0
- package/dist/src/address.js +233 -0
- package/dist/src/address.spec.d.ts +2 -0
- package/dist/src/address.spec.d.ts.map +1 -0
- package/dist/src/address.spec.js +488 -0
- package/dist/src/auth.d.ts +27 -0
- package/dist/src/auth.d.ts.map +1 -0
- package/dist/src/auth.js +155 -0
- package/dist/src/auth.spec.d.ts +2 -0
- package/dist/src/auth.spec.d.ts.map +1 -0
- package/dist/src/auth.spec.js +582 -0
- package/dist/src/compressor/brotli.d.ts +3 -0
- package/dist/src/compressor/brotli.d.ts.map +1 -0
- package/dist/src/compressor/brotli.js +30 -0
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/interceptors.d.ts +16 -0
- package/dist/src/interceptors.d.ts.map +1 -0
- package/dist/src/interceptors.js +156 -0
- package/dist/src/interceptors.spec.d.ts +2 -0
- package/dist/src/interceptors.spec.d.ts.map +1 -0
- package/dist/src/interceptors.spec.js +1063 -0
- package/dist/src/policies.d.ts +217 -0
- package/dist/src/policies.d.ts.map +1 -0
- package/dist/src/policies.js +322 -0
- package/dist/src/policies.spec.d.ts +2 -0
- package/dist/src/policies.spec.d.ts.map +1 -0
- package/dist/src/policies.spec.js +463 -0
- package/dist/src/products.d.ts +39 -0
- package/dist/src/products.d.ts.map +1 -0
- package/dist/src/products.js +95 -0
- package/dist/src/products.spec.d.ts +2 -0
- package/dist/src/products.spec.d.ts.map +1 -0
- package/dist/src/products.spec.js +519 -0
- package/dist/src/profile.d.ts +62 -0
- package/dist/src/profile.d.ts.map +1 -0
- package/dist/src/profile.js +151 -0
- package/dist/src/profile.spec.d.ts +2 -0
- package/dist/src/profile.spec.d.ts.map +1 -0
- package/dist/src/profile.spec.js +475 -0
- package/dist/src/registration.d.ts +60 -0
- package/dist/src/registration.d.ts.map +1 -0
- package/dist/src/registration.js +147 -0
- package/dist/src/test-utils.d.ts +87 -0
- package/dist/src/test-utils.d.ts.map +1 -0
- package/dist/src/test-utils.js +132 -0
- package/gen/buf/validate/validate_pb.ts +4799 -0
- package/gen/src/proto/auth/v1/authv1connect/service.connect.go +454 -0
- package/gen/src/proto/auth/v1/entities/auth.pb.go +818 -0
- package/gen/src/proto/auth/v1/entities/auth_pb.ts +348 -0
- package/gen/src/proto/auth/v1/entities/policy.pb.go +727 -0
- package/gen/src/proto/auth/v1/entities/policy_pb.ts +306 -0
- package/gen/src/proto/auth/v1/service-AuthService_connectquery.ts +70 -0
- package/gen/src/proto/auth/v1/service.pb.go +119 -0
- package/gen/src/proto/auth/v1/service_pb.ts +152 -0
- package/gen/src/proto/customers/v1/customersv1connect/service.connect.go +358 -0
- package/gen/src/proto/customers/v1/entities/address.pb.go +1073 -0
- package/gen/src/proto/customers/v1/entities/address_pb.ts +478 -0
- package/gen/src/proto/customers/v1/entities/profile.pb.go +633 -0
- package/gen/src/proto/customers/v1/entities/profile_pb.ts +252 -0
- package/gen/src/proto/customers/v1/service-CustomerService_connectquery.ts +50 -0
- package/gen/src/proto/customers/v1/service.pb.go +110 -0
- package/gen/src/proto/customers/v1/service_pb.ts +121 -0
- package/gen/src/proto/files/v1/entities/file.pb.go +669 -0
- package/gen/src/proto/files/v1/entities/file_pb.ts +265 -0
- package/gen/src/proto/files/v1/filesv1connect/service.connect.go +200 -0
- package/gen/src/proto/files/v1/service-FileService_connectquery.ts +25 -0
- package/gen/src/proto/files/v1/service.pb.go +85 -0
- package/gen/src/proto/files/v1/service_pb.ts +65 -0
- package/gen/src/proto/products/v1/entities/category.pb.go +744 -0
- package/gen/src/proto/products/v1/entities/category_pb.ts +318 -0
- package/gen/src/proto/products/v1/entities/collection.pb.go +528 -0
- package/gen/src/proto/products/v1/entities/collection_pb.ts +214 -0
- package/gen/src/proto/products/v1/entities/product/create.pb.go +453 -0
- package/gen/src/proto/products/v1/entities/product/create_pb.ts +199 -0
- package/gen/src/proto/products/v1/entities/product/option.pb.go +206 -0
- package/gen/src/proto/products/v1/entities/product/option_pb.ts +74 -0
- package/gen/src/proto/products/v1/entities/product/shared.pb.go +2890 -0
- package/gen/src/proto/products/v1/entities/product/shared_pb.ts +1317 -0
- package/gen/src/proto/products/v1/entities/product/update.pb.go +794 -0
- package/gen/src/proto/products/v1/entities/product/update_pb.ts +325 -0
- package/gen/src/proto/products/v1/entities/tag.pb.go +610 -0
- package/gen/src/proto/products/v1/entities/tag_pb.ts +233 -0
- package/gen/src/proto/products/v1/entities/taxonomy.pb.go +1352 -0
- package/gen/src/proto/products/v1/entities/taxonomy_pb.ts +606 -0
- package/gen/src/proto/products/v1/entities/type.pb.go +553 -0
- package/gen/src/proto/products/v1/entities/type_pb.ts +215 -0
- package/gen/src/proto/products/v1/entities/variant.pb.go +1474 -0
- package/gen/src/proto/products/v1/entities/variant_pb.ts +629 -0
- package/gen/src/proto/products/v1/productsv1connect/service.connect.go +1195 -0
- package/gen/src/proto/products/v1/service-ProductsService_connectquery.ts +199 -0
- package/gen/src/proto/products/v1/service.pb.go +250 -0
- package/gen/src/proto/products/v1/service_pb.ts +429 -0
- package/gen/src/proto/promotions/v1/entities/campaign.pb.go +1229 -0
- package/gen/src/proto/promotions/v1/entities/campaign_pb.ts +511 -0
- package/gen/src/proto/promotions/v1/promotionsv1connect/service.connect.go +289 -0
- package/gen/src/proto/promotions/v1/service-CampaignService_connectquery.ts +42 -0
- package/gen/src/proto/promotions/v1/service.pb.go +98 -0
- package/gen/src/proto/promotions/v1/service_pb.ts +95 -0
- package/gen/src/proto/stocknodes/v1/entities/stocknode.pb.go +1499 -0
- package/gen/src/proto/stocknodes/v1/entities/stocknode_pb.ts +655 -0
- package/gen/src/proto/stocknodes/v1/service-StockNodesService_connectquery.ts +41 -0
- package/gen/src/proto/stocknodes/v1/service.pb.go +98 -0
- package/gen/src/proto/stocknodes/v1/service_pb.ts +95 -0
- package/gen/src/proto/stocknodes/v1/stocknodesv1connect/service.connect.go +297 -0
- package/package.json +5 -2
- package/src/address.spec.ts +0 -662
- package/src/address.ts +0 -300
- package/src/auth.spec.ts +0 -771
- package/src/auth.ts +0 -168
- package/src/compressor/brotli.ts +0 -26
- package/src/index.ts +0 -5
- package/src/interceptors.spec.ts +0 -1343
- package/src/interceptors.ts +0 -224
- package/src/policies.spec.ts +0 -595
- package/src/policies.ts +0 -431
- package/src/products.spec.ts +0 -710
- package/src/products.ts +0 -112
- package/src/profile.spec.ts +0 -626
- package/src/profile.ts +0 -169
- package/src/proto/auth/v1/entities/auth.proto +0 -140
- package/src/proto/auth/v1/entities/policy.proto +0 -57
- package/src/proto/auth/v1/service.proto +0 -26
- package/src/proto/customers/v1/entities/address.proto +0 -101
- package/src/proto/customers/v1/entities/profile.proto +0 -118
- package/src/proto/customers/v1/service.proto +0 -36
- package/src/proto/files/v1/entities/file.proto +0 -62
- package/src/proto/files/v1/service.proto +0 -19
- package/src/proto/products/v1/entities/category.proto +0 -98
- package/src/proto/products/v1/entities/collection.proto +0 -72
- package/src/proto/products/v1/entities/product/create.proto +0 -41
- package/src/proto/products/v1/entities/product/option.proto +0 -17
- package/src/proto/products/v1/entities/product/shared.proto +0 -255
- package/src/proto/products/v1/entities/product/update.proto +0 -66
- package/src/proto/products/v1/entities/tag.proto +0 -73
- package/src/proto/products/v1/entities/taxonomy.proto +0 -146
- package/src/proto/products/v1/entities/type.proto +0 -98
- package/src/proto/products/v1/entities/variant.proto +0 -127
- package/src/proto/products/v1/service.proto +0 -78
- package/src/proto/promotions/v1/entities/campaign.proto +0 -145
- package/src/proto/promotions/v1/service.proto +0 -17
- package/src/proto/stocknodes/v1/entities/stocknode.proto +0 -167
- package/src/proto/stocknodes/v1/service.proto +0 -21
- package/src/registration.ts +0 -170
- package/src/test-utils.ts +0 -176
|
@@ -0,0 +1,1063 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
|
|
12
|
+
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
|
|
13
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
14
|
+
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
|
15
|
+
return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
|
|
16
|
+
function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
|
|
17
|
+
function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
|
|
18
|
+
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
|
|
19
|
+
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
|
|
20
|
+
function fulfill(value) { resume("next", value); }
|
|
21
|
+
function reject(value) { resume("throw", value); }
|
|
22
|
+
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
|
|
23
|
+
};
|
|
24
|
+
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
25
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
26
|
+
var m = o[Symbol.asyncIterator], i;
|
|
27
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
28
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
29
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
30
|
+
};
|
|
31
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
|
+
const connect_1 = require("@connectrpc/connect");
|
|
33
|
+
const interceptors_1 = require("./interceptors");
|
|
34
|
+
// Mock the checkout config
|
|
35
|
+
vi.mock('@paakd/config', () => ({
|
|
36
|
+
Checkout: {},
|
|
37
|
+
}));
|
|
38
|
+
vi.mock('./compressor/brotli', () => ({
|
|
39
|
+
brotliCompression: {
|
|
40
|
+
name: 'brotli',
|
|
41
|
+
compress: vi.fn(),
|
|
42
|
+
decompress: vi.fn(),
|
|
43
|
+
},
|
|
44
|
+
}));
|
|
45
|
+
describe('interceptors', () => {
|
|
46
|
+
describe('createLoggingInterceptor', () => {
|
|
47
|
+
let mockLogger;
|
|
48
|
+
let mockNext;
|
|
49
|
+
let mockRequest;
|
|
50
|
+
let mockResponse;
|
|
51
|
+
beforeEach(() => {
|
|
52
|
+
mockLogger = {
|
|
53
|
+
onRequestHeader: vi.fn(),
|
|
54
|
+
onRequestMessage: vi.fn(),
|
|
55
|
+
onResponseHeader: vi.fn(),
|
|
56
|
+
onResponseMessage: vi.fn(),
|
|
57
|
+
onResponseTrailer: vi.fn(),
|
|
58
|
+
onError: vi.fn(),
|
|
59
|
+
};
|
|
60
|
+
mockNext = vi.fn();
|
|
61
|
+
mockRequest = {
|
|
62
|
+
stream: false,
|
|
63
|
+
method: {
|
|
64
|
+
methodKind: 'unary',
|
|
65
|
+
toString: () => 'TestService/TestMethod',
|
|
66
|
+
},
|
|
67
|
+
header: new Headers(),
|
|
68
|
+
message: { $typeName: 'test.Message' },
|
|
69
|
+
};
|
|
70
|
+
mockResponse = {
|
|
71
|
+
stream: false,
|
|
72
|
+
header: new Headers(),
|
|
73
|
+
message: { $typeName: 'test.Message' },
|
|
74
|
+
trailer: new Headers(),
|
|
75
|
+
};
|
|
76
|
+
});
|
|
77
|
+
it('should create a logging interceptor with default logger', () => {
|
|
78
|
+
const interceptor = (0, interceptors_1.createLoggingInterceptor)();
|
|
79
|
+
expect(typeof interceptor).toBe('function');
|
|
80
|
+
});
|
|
81
|
+
it('should create a logging interceptor with custom logger', () => {
|
|
82
|
+
const customLogger = vi.fn().mockReturnValue(mockLogger);
|
|
83
|
+
const interceptor = (0, interceptors_1.createLoggingInterceptor)(customLogger);
|
|
84
|
+
expect(typeof interceptor).toBe('function');
|
|
85
|
+
});
|
|
86
|
+
it('should log unary request and response', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
87
|
+
const customLogger = vi.fn().mockReturnValue(mockLogger);
|
|
88
|
+
const interceptor = (0, interceptors_1.createLoggingInterceptor)(customLogger);
|
|
89
|
+
const interceptorFn = interceptor(mockNext);
|
|
90
|
+
mockNext.mockResolvedValue(mockResponse);
|
|
91
|
+
const result = yield interceptorFn(mockRequest);
|
|
92
|
+
expect(customLogger).toHaveBeenCalledWith(mockRequest);
|
|
93
|
+
expect(mockLogger.onRequestHeader).toHaveBeenCalledWith(mockRequest.header);
|
|
94
|
+
expect(mockLogger.onRequestMessage).toHaveBeenCalledWith(mockRequest.message);
|
|
95
|
+
expect(mockLogger.onResponseHeader).toHaveBeenCalledWith(mockResponse.header);
|
|
96
|
+
expect(mockLogger.onResponseMessage).toHaveBeenCalledWith(mockResponse.message);
|
|
97
|
+
expect(mockLogger.onResponseTrailer).toHaveBeenCalledWith(mockResponse.trailer);
|
|
98
|
+
expect(result).toBe(mockResponse);
|
|
99
|
+
}));
|
|
100
|
+
it('should handle stream requests with multiple messages', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
101
|
+
var _a, e_1, _b, _c;
|
|
102
|
+
const customLogger = vi.fn().mockReturnValue(mockLogger);
|
|
103
|
+
const interceptor = (0, interceptors_1.createLoggingInterceptor)(customLogger);
|
|
104
|
+
const interceptorFn = interceptor(mockNext);
|
|
105
|
+
const messages = [
|
|
106
|
+
{ $typeName: 'test.Message', id: 1 },
|
|
107
|
+
{ $typeName: 'test.Message', id: 2 },
|
|
108
|
+
{ $typeName: 'test.Message', id: 3 },
|
|
109
|
+
];
|
|
110
|
+
const streamRequest = Object.assign(Object.assign({}, mockRequest), { stream: true, message: (function () {
|
|
111
|
+
return __asyncGenerator(this, arguments, function* () {
|
|
112
|
+
for (const msg of messages) {
|
|
113
|
+
yield yield __await(msg);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
})() });
|
|
117
|
+
const streamResponse = Object.assign(Object.assign({}, mockResponse), { stream: true, message: (function () {
|
|
118
|
+
return __asyncGenerator(this, arguments, function* () {
|
|
119
|
+
for (const msg of messages) {
|
|
120
|
+
yield yield __await(msg);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
})() });
|
|
124
|
+
mockNext.mockResolvedValue(streamResponse);
|
|
125
|
+
const result = yield interceptorFn(streamRequest);
|
|
126
|
+
expect(customLogger).toHaveBeenCalledWith(streamRequest);
|
|
127
|
+
expect(mockLogger.onRequestHeader).toHaveBeenCalledWith(streamRequest.header);
|
|
128
|
+
expect(result).toBeDefined();
|
|
129
|
+
expect(result.stream).toBe(true);
|
|
130
|
+
// Consume the stream to trigger message logging
|
|
131
|
+
const responseMessages = [];
|
|
132
|
+
try {
|
|
133
|
+
for (var _d = true, _e = __asyncValues(result.message), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
|
|
134
|
+
_c = _f.value;
|
|
135
|
+
_d = false;
|
|
136
|
+
const msg = _c;
|
|
137
|
+
responseMessages.push(msg);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
141
|
+
finally {
|
|
142
|
+
try {
|
|
143
|
+
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
144
|
+
}
|
|
145
|
+
finally { if (e_1) throw e_1.error; }
|
|
146
|
+
}
|
|
147
|
+
expect(responseMessages).toHaveLength(3);
|
|
148
|
+
expect(mockLogger.onResponseMessage).toHaveBeenCalledTimes(3);
|
|
149
|
+
expect(mockLogger.onResponseTrailer).toHaveBeenCalledWith(mockResponse.trailer);
|
|
150
|
+
}));
|
|
151
|
+
it('should log errors in stream and rethrow', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
152
|
+
const customLogger = vi.fn().mockReturnValue(mockLogger);
|
|
153
|
+
const interceptor = (0, interceptors_1.createLoggingInterceptor)(customLogger);
|
|
154
|
+
const interceptorFn = interceptor(mockNext);
|
|
155
|
+
const streamError = new Error('Stream processing error');
|
|
156
|
+
const streamRequest = Object.assign(Object.assign({}, mockRequest), { stream: true, message: (function () {
|
|
157
|
+
return __asyncGenerator(this, arguments, function* () {
|
|
158
|
+
yield yield __await({ $typeName: 'test.Message' });
|
|
159
|
+
throw streamError;
|
|
160
|
+
});
|
|
161
|
+
})() });
|
|
162
|
+
const streamResponse = Object.assign(Object.assign({}, mockResponse), { stream: true, message: (function () {
|
|
163
|
+
return __asyncGenerator(this, arguments, function* () {
|
|
164
|
+
throw streamError;
|
|
165
|
+
});
|
|
166
|
+
})() });
|
|
167
|
+
mockNext.mockResolvedValue(streamResponse);
|
|
168
|
+
const result = yield interceptorFn(streamRequest);
|
|
169
|
+
// Consume the response stream to trigger error
|
|
170
|
+
yield expect(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
171
|
+
var _a, e_2, _b, _c;
|
|
172
|
+
try {
|
|
173
|
+
for (var _d = true, _e = __asyncValues(result.message), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
|
|
174
|
+
_c = _f.value;
|
|
175
|
+
_d = false;
|
|
176
|
+
const msg = _c;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
180
|
+
finally {
|
|
181
|
+
try {
|
|
182
|
+
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
183
|
+
}
|
|
184
|
+
finally { if (e_2) throw e_2.error; }
|
|
185
|
+
}
|
|
186
|
+
})).rejects.toThrow('Stream processing error');
|
|
187
|
+
expect(mockLogger.onError).toHaveBeenCalledWith(streamError);
|
|
188
|
+
}));
|
|
189
|
+
it('should log errors and rethrow them in unary calls', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
190
|
+
const customLogger = vi.fn().mockReturnValue(mockLogger);
|
|
191
|
+
const interceptor = (0, interceptors_1.createLoggingInterceptor)(customLogger);
|
|
192
|
+
const interceptorFn = interceptor(mockNext);
|
|
193
|
+
const error = new Error('Test error');
|
|
194
|
+
mockNext.mockRejectedValue(error);
|
|
195
|
+
yield expect(interceptorFn(mockRequest)).rejects.toThrow('Test error');
|
|
196
|
+
expect(mockLogger.onError).toHaveBeenCalledWith(error);
|
|
197
|
+
}));
|
|
198
|
+
it('should log ConnectError during request processing', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
199
|
+
const customLogger = vi.fn().mockReturnValue(mockLogger);
|
|
200
|
+
const interceptor = (0, interceptors_1.createLoggingInterceptor)(customLogger);
|
|
201
|
+
const interceptorFn = interceptor(mockNext);
|
|
202
|
+
const connectError = new connect_1.ConnectError('Service unavailable', connect_1.Code.Unavailable);
|
|
203
|
+
mockNext.mockRejectedValue(connectError);
|
|
204
|
+
yield expect(interceptorFn(mockRequest)).rejects.toThrow();
|
|
205
|
+
expect(mockLogger.onError).toHaveBeenCalledWith(connectError);
|
|
206
|
+
}));
|
|
207
|
+
it('should use default logger when none provided', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
208
|
+
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
|
|
209
|
+
const interceptor = (0, interceptors_1.createLoggingInterceptor)();
|
|
210
|
+
const interceptorFn = interceptor(mockNext);
|
|
211
|
+
mockNext.mockResolvedValue(mockResponse);
|
|
212
|
+
yield interceptorFn(mockRequest);
|
|
213
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
214
|
+
const calls = consoleSpy.mock.calls.filter(call => { var _a; return (_a = call[0]) === null || _a === void 0 ? void 0 : _a.includes('TestService'); });
|
|
215
|
+
expect(calls.length).toBeGreaterThan(0);
|
|
216
|
+
consoleSpy.mockRestore();
|
|
217
|
+
}));
|
|
218
|
+
it('should handle partial logger implementation', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
219
|
+
const partialLogger = {
|
|
220
|
+
onRequestHeader: vi.fn(),
|
|
221
|
+
// Missing other callbacks
|
|
222
|
+
};
|
|
223
|
+
const customLogger = vi.fn().mockReturnValue(partialLogger);
|
|
224
|
+
const interceptor = (0, interceptors_1.createLoggingInterceptor)(customLogger);
|
|
225
|
+
const interceptorFn = interceptor(mockNext);
|
|
226
|
+
mockNext.mockResolvedValue(mockResponse);
|
|
227
|
+
// Should not throw even with missing callbacks
|
|
228
|
+
yield expect(interceptorFn(mockRequest)).resolves.toBeDefined();
|
|
229
|
+
expect(partialLogger.onRequestHeader).toHaveBeenCalled();
|
|
230
|
+
}));
|
|
231
|
+
it('should pass correct method info to logger function', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
232
|
+
const customLogger = vi.fn().mockReturnValue(mockLogger);
|
|
233
|
+
const interceptor = (0, interceptors_1.createLoggingInterceptor)(customLogger);
|
|
234
|
+
const interceptorFn = interceptor(mockNext);
|
|
235
|
+
mockNext.mockResolvedValue(mockResponse);
|
|
236
|
+
const testRequest = Object.assign(Object.assign({}, mockRequest), { method: {
|
|
237
|
+
methodKind: 'unary',
|
|
238
|
+
toString: () => 'CustomService/CustomMethod',
|
|
239
|
+
} });
|
|
240
|
+
yield interceptorFn(testRequest);
|
|
241
|
+
expect(customLogger).toHaveBeenCalledWith(testRequest);
|
|
242
|
+
const loggerResult = customLogger.mock.results[0].value;
|
|
243
|
+
expect(loggerResult).toBeDefined();
|
|
244
|
+
}));
|
|
245
|
+
it('should handle stream response completion without error', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
246
|
+
var _a, e_3, _b, _c;
|
|
247
|
+
const customLogger = vi.fn().mockReturnValue(mockLogger);
|
|
248
|
+
const interceptor = (0, interceptors_1.createLoggingInterceptor)(customLogger);
|
|
249
|
+
const interceptorFn = interceptor(mockNext);
|
|
250
|
+
const streamResponse = Object.assign(Object.assign({}, mockResponse), { stream: true, message: (function () {
|
|
251
|
+
return __asyncGenerator(this, arguments, function* () {
|
|
252
|
+
yield yield __await({ $typeName: 'test.Message', id: 1 }
|
|
253
|
+
// Stream ends normally
|
|
254
|
+
);
|
|
255
|
+
// Stream ends normally
|
|
256
|
+
});
|
|
257
|
+
})() });
|
|
258
|
+
mockNext.mockResolvedValue(streamResponse);
|
|
259
|
+
const result = yield interceptorFn(mockRequest);
|
|
260
|
+
// Consume the stream
|
|
261
|
+
const messages = [];
|
|
262
|
+
try {
|
|
263
|
+
for (var _d = true, _e = __asyncValues(result.message), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
|
|
264
|
+
_c = _f.value;
|
|
265
|
+
_d = false;
|
|
266
|
+
const msg = _c;
|
|
267
|
+
messages.push(msg);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
271
|
+
finally {
|
|
272
|
+
try {
|
|
273
|
+
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
274
|
+
}
|
|
275
|
+
finally { if (e_3) throw e_3.error; }
|
|
276
|
+
}
|
|
277
|
+
expect(messages).toHaveLength(1);
|
|
278
|
+
expect(mockLogger.onResponseTrailer).toHaveBeenCalled();
|
|
279
|
+
}));
|
|
280
|
+
it('should handle stream iterator with throw method', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
281
|
+
const customLogger = vi.fn().mockReturnValue(mockLogger);
|
|
282
|
+
const interceptor = (0, interceptors_1.createLoggingInterceptor)(customLogger);
|
|
283
|
+
const interceptorFn = interceptor(mockNext);
|
|
284
|
+
const mockIterator = {
|
|
285
|
+
next: vi.fn().mockResolvedValue({
|
|
286
|
+
done: false,
|
|
287
|
+
value: { $typeName: 'test.Message' },
|
|
288
|
+
}),
|
|
289
|
+
throw: vi.fn().mockRejectedValue(new Error('Thrown error')),
|
|
290
|
+
return: vi.fn().mockResolvedValue({ done: true }),
|
|
291
|
+
};
|
|
292
|
+
const streamResponse = Object.assign(Object.assign({}, mockResponse), { stream: true, message: {
|
|
293
|
+
[Symbol.asyncIterator]: () => mockIterator,
|
|
294
|
+
} });
|
|
295
|
+
mockNext.mockResolvedValue(streamResponse);
|
|
296
|
+
const result = yield interceptorFn(mockRequest);
|
|
297
|
+
// Get the intercepted iterator
|
|
298
|
+
const interceptedIterator = result.message[Symbol.asyncIterator]();
|
|
299
|
+
// The intercepted iterator should have throw and return methods
|
|
300
|
+
expect(typeof interceptedIterator.throw).toBe('function');
|
|
301
|
+
expect(typeof interceptedIterator.return).toBe('function');
|
|
302
|
+
}));
|
|
303
|
+
it('should handle stream iterator without throw method', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
304
|
+
const customLogger = vi.fn().mockReturnValue(mockLogger);
|
|
305
|
+
const interceptor = (0, interceptors_1.createLoggingInterceptor)(customLogger);
|
|
306
|
+
const interceptorFn = interceptor(mockNext);
|
|
307
|
+
const mockIterator = {
|
|
308
|
+
next: vi.fn().mockResolvedValue({
|
|
309
|
+
done: false,
|
|
310
|
+
value: { $typeName: 'test.Message' },
|
|
311
|
+
}),
|
|
312
|
+
// No throw or return methods
|
|
313
|
+
};
|
|
314
|
+
const streamResponse = Object.assign(Object.assign({}, mockResponse), { stream: true, message: {
|
|
315
|
+
[Symbol.asyncIterator]: () => mockIterator,
|
|
316
|
+
} });
|
|
317
|
+
mockNext.mockResolvedValue(streamResponse);
|
|
318
|
+
const result = yield interceptorFn(mockRequest);
|
|
319
|
+
const interceptedIterator = result.message[Symbol.asyncIterator]();
|
|
320
|
+
// Should work without throw/return methods
|
|
321
|
+
const msg = yield interceptedIterator.next();
|
|
322
|
+
expect(msg.value).toBeDefined();
|
|
323
|
+
}));
|
|
324
|
+
});
|
|
325
|
+
describe('createAuthenticationInterceptor', () => {
|
|
326
|
+
let mockNext;
|
|
327
|
+
let mockRequest;
|
|
328
|
+
let mockResponse;
|
|
329
|
+
let mockCheckoutConfig;
|
|
330
|
+
beforeEach(() => {
|
|
331
|
+
mockNext = vi.fn();
|
|
332
|
+
mockRequest = {
|
|
333
|
+
header: new Headers(),
|
|
334
|
+
};
|
|
335
|
+
mockResponse = {
|
|
336
|
+
header: new Headers(),
|
|
337
|
+
message: { $typeName: 'test.Message' },
|
|
338
|
+
trailer: new Headers(),
|
|
339
|
+
};
|
|
340
|
+
mockCheckoutConfig = {
|
|
341
|
+
hostname: 'example.com',
|
|
342
|
+
cmsRemoteURL: 'https://cms.example.com',
|
|
343
|
+
enterpriseRemoteURL: 'https://enterprise.example.com',
|
|
344
|
+
cmsURL: 'https://cms-local.example.com',
|
|
345
|
+
enterpriseURL: 'https://enterprise.example.com',
|
|
346
|
+
secureCookiePassword: 'secure-cookie-password',
|
|
347
|
+
forestAPIKey: 'forest-api-key',
|
|
348
|
+
saleChannelAccessKey: 'test-sales-channel-access',
|
|
349
|
+
salesChannelAPISecret: 'test-sales-channel-secret',
|
|
350
|
+
storeAccessKey: 'test-store-access',
|
|
351
|
+
storeAPISecret: 'test-store-secret',
|
|
352
|
+
isProduction: false,
|
|
353
|
+
posthogKey: 'posthog-key',
|
|
354
|
+
posthogDomain: 'posthog.example.com',
|
|
355
|
+
posthogHost: 'posthog.example.com',
|
|
356
|
+
assetsPath: '/assets',
|
|
357
|
+
assetsDomain: 'assets.example.com',
|
|
358
|
+
turnstileKey: 'turnstile-key',
|
|
359
|
+
turnstileSecret: 'turnstile-secret',
|
|
360
|
+
redis: {
|
|
361
|
+
user: 'redis-user',
|
|
362
|
+
host: 'localhost',
|
|
363
|
+
password: 'redis-password',
|
|
364
|
+
port: 6379,
|
|
365
|
+
},
|
|
366
|
+
};
|
|
367
|
+
});
|
|
368
|
+
it('should create an authentication interceptor', () => {
|
|
369
|
+
const interceptor = (0, interceptors_1.createAuthenticationInterceptor)(mockCheckoutConfig);
|
|
370
|
+
expect(typeof interceptor).toBe('function');
|
|
371
|
+
});
|
|
372
|
+
it('should set all authentication headers', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
373
|
+
const interceptor = (0, interceptors_1.createAuthenticationInterceptor)(mockCheckoutConfig);
|
|
374
|
+
const interceptorFn = interceptor(mockNext);
|
|
375
|
+
mockNext.mockResolvedValue(mockResponse);
|
|
376
|
+
const result = yield interceptorFn(mockRequest);
|
|
377
|
+
expect(mockRequest.header.get('X-Store-Key')).toBe('test-store-secret');
|
|
378
|
+
expect(mockRequest.header.get('X-SA-Key')).toBe('test-store-access');
|
|
379
|
+
expect(mockRequest.header.get('X-CH-Key')).toBe('test-sales-channel-secret');
|
|
380
|
+
expect(mockRequest.header.get('X-CHA-Key')).toBe('test-sales-channel-access');
|
|
381
|
+
expect(mockNext).toHaveBeenCalledWith(mockRequest);
|
|
382
|
+
expect(result).toBe(mockResponse);
|
|
383
|
+
}));
|
|
384
|
+
it('should set headers exactly once per call', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
385
|
+
var _a;
|
|
386
|
+
const interceptor = (0, interceptors_1.createAuthenticationInterceptor)(mockCheckoutConfig);
|
|
387
|
+
const interceptorFn = interceptor(mockNext);
|
|
388
|
+
mockNext.mockResolvedValue(mockResponse);
|
|
389
|
+
yield interceptorFn(mockRequest);
|
|
390
|
+
// Verify headers are set exactly once
|
|
391
|
+
const headerSetCalls = ((_a = mockRequest.header.set.mock) === null || _a === void 0 ? void 0 : _a.calls) || [];
|
|
392
|
+
// Headers.set might not be mockable, so we verify via get
|
|
393
|
+
expect(mockRequest.header.get('X-Store-Key')).toBe('test-store-secret');
|
|
394
|
+
expect(mockRequest.header.get('X-SA-Key')).toBe('test-store-access');
|
|
395
|
+
expect(mockRequest.header.get('X-CH-Key')).toBe('test-sales-channel-secret');
|
|
396
|
+
expect(mockRequest.header.get('X-CHA-Key')).toBe('test-sales-channel-access');
|
|
397
|
+
}));
|
|
398
|
+
it('should work with stream requests', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
399
|
+
const interceptor = (0, interceptors_1.createAuthenticationInterceptor)(mockCheckoutConfig);
|
|
400
|
+
const interceptorFn = interceptor(mockNext);
|
|
401
|
+
const streamRequest = Object.assign(Object.assign({}, mockRequest), { stream: true });
|
|
402
|
+
mockNext.mockResolvedValue(mockResponse);
|
|
403
|
+
const result = yield interceptorFn(streamRequest);
|
|
404
|
+
expect(streamRequest.header.get('X-Store-Key')).toBe('test-store-secret');
|
|
405
|
+
expect(streamRequest.header.get('X-SA-Key')).toBe('test-store-access');
|
|
406
|
+
expect(streamRequest.header.get('X-CH-Key')).toBe('test-sales-channel-secret');
|
|
407
|
+
expect(streamRequest.header.get('X-CHA-Key')).toBe('test-sales-channel-access');
|
|
408
|
+
expect(result).toBe(mockResponse);
|
|
409
|
+
}));
|
|
410
|
+
it('should pass request unchanged to next interceptor', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
411
|
+
const interceptor = (0, interceptors_1.createAuthenticationInterceptor)(mockCheckoutConfig);
|
|
412
|
+
const interceptorFn = interceptor(mockNext);
|
|
413
|
+
mockNext.mockResolvedValue(mockResponse);
|
|
414
|
+
const originalRequest = mockRequest;
|
|
415
|
+
yield interceptorFn(originalRequest);
|
|
416
|
+
expect(mockNext).toHaveBeenCalledWith(originalRequest);
|
|
417
|
+
}));
|
|
418
|
+
it('should handle empty config values', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
419
|
+
const emptyConfig = {
|
|
420
|
+
hostname: 'example.com',
|
|
421
|
+
cmsRemoteURL: 'https://cms.example.com',
|
|
422
|
+
enterpriseRemoteURL: 'https://enterprise.example.com',
|
|
423
|
+
cmsURL: 'https://cms-local.example.com',
|
|
424
|
+
enterpriseURL: 'https://enterprise.example.com',
|
|
425
|
+
secureCookiePassword: 'secure-cookie-password',
|
|
426
|
+
forestAPIKey: 'forest-api-key',
|
|
427
|
+
saleChannelAccessKey: '',
|
|
428
|
+
salesChannelAPISecret: '',
|
|
429
|
+
storeAccessKey: '',
|
|
430
|
+
storeAPISecret: '',
|
|
431
|
+
isProduction: false,
|
|
432
|
+
posthogKey: 'posthog-key',
|
|
433
|
+
posthogDomain: 'posthog.example.com',
|
|
434
|
+
posthogHost: 'posthog.example.com',
|
|
435
|
+
assetsPath: '/assets',
|
|
436
|
+
assetsDomain: 'assets.example.com',
|
|
437
|
+
turnstileKey: 'turnstile-key',
|
|
438
|
+
turnstileSecret: 'turnstile-secret',
|
|
439
|
+
redis: {
|
|
440
|
+
user: 'redis-user',
|
|
441
|
+
host: 'localhost',
|
|
442
|
+
password: 'redis-password',
|
|
443
|
+
port: 6379,
|
|
444
|
+
},
|
|
445
|
+
};
|
|
446
|
+
const interceptor = (0, interceptors_1.createAuthenticationInterceptor)(emptyConfig);
|
|
447
|
+
const interceptorFn = interceptor(mockNext);
|
|
448
|
+
mockNext.mockResolvedValue(mockResponse);
|
|
449
|
+
const result = yield interceptorFn(mockRequest);
|
|
450
|
+
expect(mockRequest.header.get('X-Store-Key')).toBe('');
|
|
451
|
+
expect(mockRequest.header.get('X-SA-Key')).toBe('');
|
|
452
|
+
expect(result).toBe(mockResponse);
|
|
453
|
+
}));
|
|
454
|
+
it('should propagate response from next interceptor', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
455
|
+
const interceptor = (0, interceptors_1.createAuthenticationInterceptor)(mockCheckoutConfig);
|
|
456
|
+
const interceptorFn = interceptor(mockNext);
|
|
457
|
+
const customResponse = Object.assign(Object.assign({}, mockResponse), { message: { $typeName: 'custom.Message', data: 'custom' } });
|
|
458
|
+
mockNext.mockResolvedValue(customResponse);
|
|
459
|
+
const result = yield interceptor(mockNext)(mockRequest);
|
|
460
|
+
expect(result).toBe(customResponse);
|
|
461
|
+
expect(result.message.data).toBe('custom');
|
|
462
|
+
}));
|
|
463
|
+
});
|
|
464
|
+
describe('createCustomerAuthenticationInterceptor', () => {
|
|
465
|
+
let mockNext;
|
|
466
|
+
let mockRequest;
|
|
467
|
+
let mockResponse;
|
|
468
|
+
beforeEach(() => {
|
|
469
|
+
mockNext = vi.fn();
|
|
470
|
+
mockRequest = {
|
|
471
|
+
header: new Headers(),
|
|
472
|
+
};
|
|
473
|
+
mockResponse = {
|
|
474
|
+
header: new Headers(),
|
|
475
|
+
message: { $typeName: 'test.Message' },
|
|
476
|
+
trailer: new Headers(),
|
|
477
|
+
};
|
|
478
|
+
});
|
|
479
|
+
it('should create a customer authentication interceptor', () => {
|
|
480
|
+
const interceptor = (0, interceptors_1.createCustomerAuthenticationInterceptor)('test-jwt-token');
|
|
481
|
+
expect(typeof interceptor).toBe('function');
|
|
482
|
+
});
|
|
483
|
+
it('should set Authorization header with Bearer token', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
484
|
+
const jwtToken = 'test-jwt-token';
|
|
485
|
+
const interceptor = (0, interceptors_1.createCustomerAuthenticationInterceptor)(jwtToken);
|
|
486
|
+
const interceptorFn = interceptor(mockNext);
|
|
487
|
+
mockNext.mockResolvedValue(mockResponse);
|
|
488
|
+
const result = yield interceptorFn(mockRequest);
|
|
489
|
+
expect(mockRequest.header.get('Authorization')).toBe(`Bearer ${jwtToken}`);
|
|
490
|
+
expect(mockNext).toHaveBeenCalledWith(mockRequest);
|
|
491
|
+
expect(result).toBe(mockResponse);
|
|
492
|
+
}));
|
|
493
|
+
it('should work with various JWT token formats', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
494
|
+
const tokens = [
|
|
495
|
+
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c',
|
|
496
|
+
'simple-token',
|
|
497
|
+
'token-with-many-dashes-123-456-789',
|
|
498
|
+
];
|
|
499
|
+
for (const token of tokens) {
|
|
500
|
+
const interceptor = (0, interceptors_1.createCustomerAuthenticationInterceptor)(token);
|
|
501
|
+
const interceptorFn = interceptor(mockNext);
|
|
502
|
+
mockNext.mockResolvedValue(mockResponse);
|
|
503
|
+
const request = { header: new Headers() };
|
|
504
|
+
yield interceptorFn(request);
|
|
505
|
+
expect(request.header.get('Authorization')).toBe(`Bearer ${token}`);
|
|
506
|
+
}
|
|
507
|
+
}));
|
|
508
|
+
it('should work with stream requests', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
509
|
+
const jwtToken = 'test-jwt-token';
|
|
510
|
+
const interceptor = (0, interceptors_1.createCustomerAuthenticationInterceptor)(jwtToken);
|
|
511
|
+
const interceptorFn = interceptor(mockNext);
|
|
512
|
+
const streamRequest = Object.assign(Object.assign({}, mockRequest), { stream: true });
|
|
513
|
+
mockNext.mockResolvedValue(mockResponse);
|
|
514
|
+
const result = yield interceptorFn(streamRequest);
|
|
515
|
+
expect(streamRequest.header.get('Authorization')).toBe(`Bearer ${jwtToken}`);
|
|
516
|
+
expect(result).toBe(mockResponse);
|
|
517
|
+
}));
|
|
518
|
+
it('should throw error for empty JWT token', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
519
|
+
const interceptor = (0, interceptors_1.createCustomerAuthenticationInterceptor)('');
|
|
520
|
+
const interceptorFn = interceptor(mockNext);
|
|
521
|
+
try {
|
|
522
|
+
yield interceptorFn(mockRequest);
|
|
523
|
+
expect.fail('Should have thrown error');
|
|
524
|
+
}
|
|
525
|
+
catch (error) {
|
|
526
|
+
expect(error).toBeInstanceOf(connect_1.ConnectError);
|
|
527
|
+
}
|
|
528
|
+
}));
|
|
529
|
+
it('should throw Unauthenticated error code for empty JWT', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
530
|
+
const interceptor = (0, interceptors_1.createCustomerAuthenticationInterceptor)('');
|
|
531
|
+
const interceptorFn = interceptor(mockNext);
|
|
532
|
+
try {
|
|
533
|
+
yield interceptorFn(mockRequest);
|
|
534
|
+
expect.fail('Should have thrown error');
|
|
535
|
+
}
|
|
536
|
+
catch (error) {
|
|
537
|
+
expect(error).toBeInstanceOf(connect_1.ConnectError);
|
|
538
|
+
expect(error.code).toBe(connect_1.Code.Unauthenticated);
|
|
539
|
+
}
|
|
540
|
+
}));
|
|
541
|
+
it('should throw error for null JWT token', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
542
|
+
const interceptor = (0, interceptors_1.createCustomerAuthenticationInterceptor)(null);
|
|
543
|
+
const interceptorFn = interceptor(mockNext);
|
|
544
|
+
yield expect(interceptorFn(mockRequest)).rejects.toThrow();
|
|
545
|
+
}));
|
|
546
|
+
it('should throw error for undefined JWT token', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
547
|
+
const interceptor = (0, interceptors_1.createCustomerAuthenticationInterceptor)(undefined);
|
|
548
|
+
const interceptorFn = interceptor(mockNext);
|
|
549
|
+
yield expect(interceptorFn(mockRequest)).rejects.toThrow();
|
|
550
|
+
}));
|
|
551
|
+
it('should not call next when JWT validation fails', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
552
|
+
const interceptor = (0, interceptors_1.createCustomerAuthenticationInterceptor)('');
|
|
553
|
+
const interceptorFn = interceptor(mockNext);
|
|
554
|
+
yield expect(interceptorFn(mockRequest)).rejects.toThrow();
|
|
555
|
+
// next should never be called if validation fails
|
|
556
|
+
expect(mockNext).not.toHaveBeenCalled();
|
|
557
|
+
}));
|
|
558
|
+
it('should propagate response from next interceptor', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
559
|
+
const jwtToken = 'test-jwt-token';
|
|
560
|
+
const interceptor = (0, interceptors_1.createCustomerAuthenticationInterceptor)(jwtToken);
|
|
561
|
+
const interceptorFn = interceptor(mockNext);
|
|
562
|
+
const customResponse = Object.assign(Object.assign({}, mockResponse), { message: { $typeName: 'custom.Message', userId: 'user123' } });
|
|
563
|
+
mockNext.mockResolvedValue(customResponse);
|
|
564
|
+
const result = yield interceptorFn(mockRequest);
|
|
565
|
+
expect(result).toBe(customResponse);
|
|
566
|
+
expect(result.message.userId).toBe('user123');
|
|
567
|
+
}));
|
|
568
|
+
});
|
|
569
|
+
describe('createHeadersInterceptor', () => {
|
|
570
|
+
let mockNext;
|
|
571
|
+
let mockRequest;
|
|
572
|
+
let mockResponse;
|
|
573
|
+
beforeEach(() => {
|
|
574
|
+
mockNext = vi.fn();
|
|
575
|
+
mockRequest = {
|
|
576
|
+
header: new Headers(),
|
|
577
|
+
};
|
|
578
|
+
mockResponse = {
|
|
579
|
+
header: new Headers(),
|
|
580
|
+
message: { $typeName: 'test.Message' },
|
|
581
|
+
trailer: new Headers(),
|
|
582
|
+
};
|
|
583
|
+
});
|
|
584
|
+
it('should set expected headers from header mapping', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
585
|
+
const customHeaders = {
|
|
586
|
+
'x-original-host': 'example.com',
|
|
587
|
+
'x-shop-id': 'shop123',
|
|
588
|
+
'x-sitepath': '/path',
|
|
589
|
+
'x-locale': 'en',
|
|
590
|
+
'x-region': 'US',
|
|
591
|
+
};
|
|
592
|
+
const interceptor = (0, interceptors_1.createHeadersInterceptor)(customHeaders);
|
|
593
|
+
const interceptorFn = interceptor(mockNext);
|
|
594
|
+
mockNext.mockResolvedValue(mockResponse);
|
|
595
|
+
const result = yield interceptorFn(mockRequest);
|
|
596
|
+
expect(mockRequest.header.get('X-Original-Host')).toBe('example.com');
|
|
597
|
+
expect(mockRequest.header.get('X-shop-id')).toBe('shop123');
|
|
598
|
+
expect(mockRequest.header.get('X-Sitepath')).toBe('/path');
|
|
599
|
+
expect(mockRequest.header.get('X-locale')).toBe('en');
|
|
600
|
+
expect(mockRequest.header.get('X-region')).toBe('US');
|
|
601
|
+
expect(mockNext).toHaveBeenCalledWith(mockRequest);
|
|
602
|
+
expect(result).toBe(mockResponse);
|
|
603
|
+
}));
|
|
604
|
+
it('should throw error when x-original-host is missing', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
605
|
+
const customHeaders = {
|
|
606
|
+
'x-shop-id': 'shop123',
|
|
607
|
+
'x-sitepath': '/path',
|
|
608
|
+
'x-locale': 'en',
|
|
609
|
+
'x-region': 'US',
|
|
610
|
+
};
|
|
611
|
+
const interceptor = (0, interceptors_1.createHeadersInterceptor)(customHeaders);
|
|
612
|
+
const interceptorFn = interceptor(mockNext);
|
|
613
|
+
try {
|
|
614
|
+
yield interceptorFn(mockRequest);
|
|
615
|
+
expect.fail('Should have thrown error');
|
|
616
|
+
}
|
|
617
|
+
catch (error) {
|
|
618
|
+
expect(error).toBeInstanceOf(connect_1.ConnectError);
|
|
619
|
+
expect(error.code).toBe(connect_1.Code.InvalidArgument);
|
|
620
|
+
expect(error.message).toContain('Original host');
|
|
621
|
+
}
|
|
622
|
+
}));
|
|
623
|
+
it('should throw error when x-shop-id is missing', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
624
|
+
const customHeaders = {
|
|
625
|
+
'x-original-host': 'example.com',
|
|
626
|
+
'x-sitepath': '/path',
|
|
627
|
+
'x-locale': 'en',
|
|
628
|
+
'x-region': 'US',
|
|
629
|
+
};
|
|
630
|
+
const interceptor = (0, interceptors_1.createHeadersInterceptor)(customHeaders);
|
|
631
|
+
const interceptorFn = interceptor(mockNext);
|
|
632
|
+
try {
|
|
633
|
+
yield interceptorFn(mockRequest);
|
|
634
|
+
expect.fail('Should have thrown error');
|
|
635
|
+
}
|
|
636
|
+
catch (error) {
|
|
637
|
+
expect(error).toBeInstanceOf(connect_1.ConnectError);
|
|
638
|
+
expect(error.message).toContain('Shop id');
|
|
639
|
+
}
|
|
640
|
+
}));
|
|
641
|
+
it('should throw error when x-sitepath is missing', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
642
|
+
const customHeaders = {
|
|
643
|
+
'x-original-host': 'example.com',
|
|
644
|
+
'x-shop-id': 'shop123',
|
|
645
|
+
'x-locale': 'en',
|
|
646
|
+
'x-region': 'US',
|
|
647
|
+
};
|
|
648
|
+
const interceptor = (0, interceptors_1.createHeadersInterceptor)(customHeaders);
|
|
649
|
+
const interceptorFn = interceptor(mockNext);
|
|
650
|
+
try {
|
|
651
|
+
yield interceptorFn(mockRequest);
|
|
652
|
+
expect.fail('Should have thrown error');
|
|
653
|
+
}
|
|
654
|
+
catch (error) {
|
|
655
|
+
expect(error).toBeInstanceOf(connect_1.ConnectError);
|
|
656
|
+
expect(error.message).toContain('Sitepath');
|
|
657
|
+
}
|
|
658
|
+
}));
|
|
659
|
+
it('should throw error when x-locale is missing', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
660
|
+
const customHeaders = {
|
|
661
|
+
'x-original-host': 'example.com',
|
|
662
|
+
'x-shop-id': 'shop123',
|
|
663
|
+
'x-sitepath': '/path',
|
|
664
|
+
'x-region': 'US',
|
|
665
|
+
};
|
|
666
|
+
const interceptor = (0, interceptors_1.createHeadersInterceptor)(customHeaders);
|
|
667
|
+
const interceptorFn = interceptor(mockNext);
|
|
668
|
+
try {
|
|
669
|
+
yield interceptorFn(mockRequest);
|
|
670
|
+
expect.fail('Should have thrown error');
|
|
671
|
+
}
|
|
672
|
+
catch (error) {
|
|
673
|
+
expect(error).toBeInstanceOf(connect_1.ConnectError);
|
|
674
|
+
expect(error.message).toContain('Locale');
|
|
675
|
+
}
|
|
676
|
+
}));
|
|
677
|
+
it('should throw error when x-region is missing', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
678
|
+
const customHeaders = {
|
|
679
|
+
'x-original-host': 'example.com',
|
|
680
|
+
'x-shop-id': 'shop123',
|
|
681
|
+
'x-sitepath': '/path',
|
|
682
|
+
'x-locale': 'en',
|
|
683
|
+
};
|
|
684
|
+
const interceptor = (0, interceptors_1.createHeadersInterceptor)(customHeaders);
|
|
685
|
+
const interceptorFn = interceptor(mockNext);
|
|
686
|
+
try {
|
|
687
|
+
yield interceptorFn(mockRequest);
|
|
688
|
+
expect.fail('Should have thrown error');
|
|
689
|
+
}
|
|
690
|
+
catch (error) {
|
|
691
|
+
expect(error).toBeInstanceOf(connect_1.ConnectError);
|
|
692
|
+
expect(error.message).toContain('Region');
|
|
693
|
+
}
|
|
694
|
+
}));
|
|
695
|
+
it('should throw error when x-original-host is null', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
696
|
+
const customHeaders = {
|
|
697
|
+
'x-original-host': null,
|
|
698
|
+
'x-shop-id': 'shop123',
|
|
699
|
+
'x-sitepath': '/path',
|
|
700
|
+
'x-locale': 'en',
|
|
701
|
+
'x-region': 'US',
|
|
702
|
+
};
|
|
703
|
+
const interceptor = (0, interceptors_1.createHeadersInterceptor)(customHeaders);
|
|
704
|
+
const interceptorFn = interceptor(mockNext);
|
|
705
|
+
yield expect(interceptorFn(mockRequest)).rejects.toThrow();
|
|
706
|
+
}));
|
|
707
|
+
it('should throw error when x-shop-id is null', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
708
|
+
const customHeaders = {
|
|
709
|
+
'x-original-host': 'example.com',
|
|
710
|
+
'x-shop-id': null,
|
|
711
|
+
'x-sitepath': '/path',
|
|
712
|
+
'x-locale': 'en',
|
|
713
|
+
'x-region': 'US',
|
|
714
|
+
};
|
|
715
|
+
const interceptor = (0, interceptors_1.createHeadersInterceptor)(customHeaders);
|
|
716
|
+
const interceptorFn = interceptor(mockNext);
|
|
717
|
+
yield expect(interceptorFn(mockRequest)).rejects.toThrow();
|
|
718
|
+
}));
|
|
719
|
+
it('should throw error when x-sitepath is null', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
720
|
+
const customHeaders = {
|
|
721
|
+
'x-original-host': 'example.com',
|
|
722
|
+
'x-shop-id': 'shop123',
|
|
723
|
+
'x-sitepath': null,
|
|
724
|
+
'x-locale': 'en',
|
|
725
|
+
'x-region': 'US',
|
|
726
|
+
};
|
|
727
|
+
const interceptor = (0, interceptors_1.createHeadersInterceptor)(customHeaders);
|
|
728
|
+
const interceptorFn = interceptor(mockNext);
|
|
729
|
+
yield expect(interceptorFn(mockRequest)).rejects.toThrow();
|
|
730
|
+
}));
|
|
731
|
+
it('should throw error when x-locale is null', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
732
|
+
const customHeaders = {
|
|
733
|
+
'x-original-host': 'example.com',
|
|
734
|
+
'x-shop-id': 'shop123',
|
|
735
|
+
'x-sitepath': '/path',
|
|
736
|
+
'x-locale': null,
|
|
737
|
+
'x-region': 'US',
|
|
738
|
+
};
|
|
739
|
+
const interceptor = (0, interceptors_1.createHeadersInterceptor)(customHeaders);
|
|
740
|
+
const interceptorFn = interceptor(mockNext);
|
|
741
|
+
yield expect(interceptorFn(mockRequest)).rejects.toThrow();
|
|
742
|
+
}));
|
|
743
|
+
it('should throw error when x-region is null', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
744
|
+
const customHeaders = {
|
|
745
|
+
'x-original-host': 'example.com',
|
|
746
|
+
'x-shop-id': 'shop123',
|
|
747
|
+
'x-sitepath': '/path',
|
|
748
|
+
'x-locale': 'en',
|
|
749
|
+
'x-region': null,
|
|
750
|
+
};
|
|
751
|
+
const interceptor = (0, interceptors_1.createHeadersInterceptor)(customHeaders);
|
|
752
|
+
const interceptorFn = interceptor(mockNext);
|
|
753
|
+
yield expect(interceptorFn(mockRequest)).rejects.toThrow();
|
|
754
|
+
}));
|
|
755
|
+
it('should work with stream requests', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
756
|
+
const customHeaders = {
|
|
757
|
+
'x-original-host': 'example.com',
|
|
758
|
+
'x-shop-id': 'shop123',
|
|
759
|
+
'x-sitepath': '/path',
|
|
760
|
+
'x-locale': 'en',
|
|
761
|
+
'x-region': 'US',
|
|
762
|
+
};
|
|
763
|
+
const interceptor = (0, interceptors_1.createHeadersInterceptor)(customHeaders);
|
|
764
|
+
const interceptorFn = interceptor(mockNext);
|
|
765
|
+
const streamRequest = {
|
|
766
|
+
header: new Headers(),
|
|
767
|
+
stream: true,
|
|
768
|
+
};
|
|
769
|
+
mockNext.mockResolvedValue(mockResponse);
|
|
770
|
+
const result = yield interceptorFn(streamRequest);
|
|
771
|
+
expect(streamRequest.header.get('X-Original-Host')).toBe('example.com');
|
|
772
|
+
expect(streamRequest.header.get('X-shop-id')).toBe('shop123');
|
|
773
|
+
expect(result).toBe(mockResponse);
|
|
774
|
+
}));
|
|
775
|
+
it('should not call next when header validation fails', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
776
|
+
const customHeaders = {
|
|
777
|
+
'x-original-host': 'example.com',
|
|
778
|
+
// Missing x-shop-id
|
|
779
|
+
'x-sitepath': '/path',
|
|
780
|
+
'x-locale': 'en',
|
|
781
|
+
'x-region': 'US',
|
|
782
|
+
};
|
|
783
|
+
const interceptor = (0, interceptors_1.createHeadersInterceptor)(customHeaders);
|
|
784
|
+
const interceptorFn = interceptor(mockNext);
|
|
785
|
+
yield expect(interceptorFn(mockRequest)).rejects.toThrow();
|
|
786
|
+
// next should never be called if validation fails
|
|
787
|
+
expect(mockNext).not.toHaveBeenCalled();
|
|
788
|
+
}));
|
|
789
|
+
it('should propagate response from next interceptor', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
790
|
+
const customHeaders = {
|
|
791
|
+
'x-original-host': 'example.com',
|
|
792
|
+
'x-shop-id': 'shop123',
|
|
793
|
+
'x-sitepath': '/path',
|
|
794
|
+
'x-locale': 'en',
|
|
795
|
+
'x-region': 'US',
|
|
796
|
+
};
|
|
797
|
+
const interceptor = (0, interceptors_1.createHeadersInterceptor)(customHeaders);
|
|
798
|
+
const interceptorFn = interceptor(mockNext);
|
|
799
|
+
const customResponse = Object.assign(Object.assign({}, mockResponse), { message: { $typeName: 'custom.Message', requestId: 'req123' } });
|
|
800
|
+
mockNext.mockResolvedValue(customResponse);
|
|
801
|
+
const result = yield interceptor(mockNext)(mockRequest);
|
|
802
|
+
expect(result).toBe(customResponse);
|
|
803
|
+
expect(result.message.requestId).toBe('req123');
|
|
804
|
+
}));
|
|
805
|
+
it('should handle headers with special characters', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
806
|
+
const customHeaders = {
|
|
807
|
+
'x-original-host': 'example.com:8080',
|
|
808
|
+
'x-shop-id': 'shop-123-456',
|
|
809
|
+
'x-sitepath': '/en-GB/products',
|
|
810
|
+
'x-locale': 'en_GB',
|
|
811
|
+
'x-region': 'EU-West-1',
|
|
812
|
+
};
|
|
813
|
+
const interceptor = (0, interceptors_1.createHeadersInterceptor)(customHeaders);
|
|
814
|
+
const interceptorFn = interceptor(mockNext);
|
|
815
|
+
mockNext.mockResolvedValue(mockResponse);
|
|
816
|
+
const result = yield interceptorFn(mockRequest);
|
|
817
|
+
expect(mockRequest.header.get('X-Original-Host')).toBe('example.com:8080');
|
|
818
|
+
expect(mockRequest.header.get('X-shop-id')).toBe('shop-123-456');
|
|
819
|
+
expect(mockRequest.header.get('X-Sitepath')).toBe('/en-GB/products');
|
|
820
|
+
expect(result).toBe(mockResponse);
|
|
821
|
+
}));
|
|
822
|
+
it('should handle empty string headers (should fail validation)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
823
|
+
const customHeaders = {
|
|
824
|
+
'x-original-host': '',
|
|
825
|
+
'x-shop-id': 'shop123',
|
|
826
|
+
'x-sitepath': '/path',
|
|
827
|
+
'x-locale': 'en',
|
|
828
|
+
'x-region': 'US',
|
|
829
|
+
};
|
|
830
|
+
const interceptor = (0, interceptors_1.createHeadersInterceptor)(customHeaders);
|
|
831
|
+
const interceptorFn = interceptor(mockNext);
|
|
832
|
+
// Empty string is falsy, so validation should fail
|
|
833
|
+
yield expect(interceptorFn(mockRequest)).rejects.toThrow();
|
|
834
|
+
}));
|
|
835
|
+
});
|
|
836
|
+
describe('interceptor integration', () => {
|
|
837
|
+
it('should chain multiple interceptors in order', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
838
|
+
const jwtToken = 'test-jwt';
|
|
839
|
+
const mockNext = vi.fn();
|
|
840
|
+
mockNext.mockResolvedValue({
|
|
841
|
+
header: new Headers(),
|
|
842
|
+
message: { $typeName: 'test.Message' },
|
|
843
|
+
trailer: new Headers(),
|
|
844
|
+
});
|
|
845
|
+
const mockCheckoutConfig = {
|
|
846
|
+
hostname: 'example.com',
|
|
847
|
+
cmsRemoteURL: 'https://cms.example.com',
|
|
848
|
+
enterpriseRemoteURL: 'https://enterprise.example.com',
|
|
849
|
+
cmsURL: 'https://cms-local.example.com',
|
|
850
|
+
enterpriseURL: 'https://enterprise.example.com',
|
|
851
|
+
secureCookiePassword: 'secure-cookie-password',
|
|
852
|
+
forestAPIKey: 'forest-api-key',
|
|
853
|
+
saleChannelAccessKey: 'test-sales-channel-access',
|
|
854
|
+
salesChannelAPISecret: 'test-sales-channel-secret',
|
|
855
|
+
storeAccessKey: 'test-store-access',
|
|
856
|
+
storeAPISecret: 'test-store-secret',
|
|
857
|
+
isProduction: false,
|
|
858
|
+
posthogKey: 'posthog-key',
|
|
859
|
+
posthogDomain: 'posthog.example.com',
|
|
860
|
+
posthogHost: 'posthog.example.com',
|
|
861
|
+
assetsPath: '/assets',
|
|
862
|
+
assetsDomain: 'assets.example.com',
|
|
863
|
+
turnstileKey: 'turnstile-key',
|
|
864
|
+
turnstileSecret: 'turnstile-secret',
|
|
865
|
+
redis: {
|
|
866
|
+
user: 'redis-user',
|
|
867
|
+
host: 'localhost',
|
|
868
|
+
password: 'redis-password',
|
|
869
|
+
port: 6379,
|
|
870
|
+
},
|
|
871
|
+
};
|
|
872
|
+
// Create interceptors
|
|
873
|
+
const authInterceptor = (0, interceptors_1.createAuthenticationInterceptor)(mockCheckoutConfig);
|
|
874
|
+
const customerAuthInterceptor = (0, interceptors_1.createCustomerAuthenticationInterceptor)(jwtToken);
|
|
875
|
+
const loggingInterceptor = (0, interceptors_1.createLoggingInterceptor)();
|
|
876
|
+
// Chain them together
|
|
877
|
+
const chainedInterceptor = authInterceptor(customerAuthInterceptor(loggingInterceptor(mockNext)));
|
|
878
|
+
const mockRequest = {
|
|
879
|
+
header: new Headers(),
|
|
880
|
+
method: {
|
|
881
|
+
toString: () => 'TestService/TestMethod',
|
|
882
|
+
},
|
|
883
|
+
message: { $typeName: 'test.Message' },
|
|
884
|
+
};
|
|
885
|
+
yield chainedInterceptor(mockRequest);
|
|
886
|
+
// Verify all headers are set
|
|
887
|
+
expect(mockRequest.header.get('X-Store-Key')).toBe('test-store-secret');
|
|
888
|
+
expect(mockRequest.header.get('X-SA-Key')).toBe('test-store-access');
|
|
889
|
+
expect(mockRequest.header.get('Authorization')).toBe(`Bearer ${jwtToken}`);
|
|
890
|
+
expect(mockNext).toHaveBeenCalled();
|
|
891
|
+
}));
|
|
892
|
+
it('should handle errors in chained interceptors', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
893
|
+
const jwtToken = '';
|
|
894
|
+
const mockNext = vi.fn();
|
|
895
|
+
mockNext.mockResolvedValue({
|
|
896
|
+
header: new Headers(),
|
|
897
|
+
message: { $typeName: 'test.Message' },
|
|
898
|
+
trailer: new Headers(),
|
|
899
|
+
});
|
|
900
|
+
const mockCheckoutConfig = {
|
|
901
|
+
hostname: 'example.com',
|
|
902
|
+
cmsRemoteURL: 'https://cms.example.com',
|
|
903
|
+
enterpriseRemoteURL: 'https://enterprise.example.com',
|
|
904
|
+
cmsURL: 'https://cms-local.example.com',
|
|
905
|
+
enterpriseURL: 'https://enterprise.example.com',
|
|
906
|
+
secureCookiePassword: 'secure-cookie-password',
|
|
907
|
+
forestAPIKey: 'forest-api-key',
|
|
908
|
+
saleChannelAccessKey: 'test-sales-channel-access',
|
|
909
|
+
salesChannelAPISecret: 'test-sales-channel-secret',
|
|
910
|
+
storeAccessKey: 'test-store-access',
|
|
911
|
+
storeAPISecret: 'test-store-secret',
|
|
912
|
+
isProduction: false,
|
|
913
|
+
posthogKey: 'posthog-key',
|
|
914
|
+
posthogDomain: 'posthog.example.com',
|
|
915
|
+
posthogHost: 'posthog.example.com',
|
|
916
|
+
assetsPath: '/assets',
|
|
917
|
+
assetsDomain: 'assets.example.com',
|
|
918
|
+
turnstileKey: 'turnstile-key',
|
|
919
|
+
turnstileSecret: 'turnstile-secret',
|
|
920
|
+
redis: {
|
|
921
|
+
user: 'redis-user',
|
|
922
|
+
host: 'localhost',
|
|
923
|
+
password: 'redis-password',
|
|
924
|
+
port: 6379,
|
|
925
|
+
},
|
|
926
|
+
};
|
|
927
|
+
// Chain: auth -> customer auth (will fail) -> logging
|
|
928
|
+
const authInterceptor = (0, interceptors_1.createAuthenticationInterceptor)(mockCheckoutConfig);
|
|
929
|
+
const customerAuthInterceptor = (0, interceptors_1.createCustomerAuthenticationInterceptor)(jwtToken);
|
|
930
|
+
const loggingInterceptor = (0, interceptors_1.createLoggingInterceptor)();
|
|
931
|
+
const chainedInterceptor = authInterceptor(customerAuthInterceptor(loggingInterceptor(mockNext)));
|
|
932
|
+
const mockRequest = {
|
|
933
|
+
header: new Headers(),
|
|
934
|
+
method: {
|
|
935
|
+
toString: () => 'TestService/TestMethod',
|
|
936
|
+
},
|
|
937
|
+
message: { $typeName: 'test.Message' },
|
|
938
|
+
};
|
|
939
|
+
// Should fail at customer auth interceptor
|
|
940
|
+
yield expect(chainedInterceptor(mockRequest)).rejects.toThrow();
|
|
941
|
+
// Auth headers should still be set before error
|
|
942
|
+
expect(mockRequest.header.get('X-Store-Key')).toBe('test-store-secret');
|
|
943
|
+
// But next should not be called
|
|
944
|
+
expect(mockNext).not.toHaveBeenCalled();
|
|
945
|
+
}));
|
|
946
|
+
it('should work with all interceptors including headers', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
947
|
+
const jwtToken = 'test-jwt';
|
|
948
|
+
const mockNext = vi.fn();
|
|
949
|
+
mockNext.mockResolvedValue({
|
|
950
|
+
header: new Headers(),
|
|
951
|
+
message: { $typeName: 'test.Message' },
|
|
952
|
+
trailer: new Headers(),
|
|
953
|
+
});
|
|
954
|
+
const mockCheckoutConfig = {
|
|
955
|
+
hostname: 'example.com',
|
|
956
|
+
cmsRemoteURL: 'https://cms.example.com',
|
|
957
|
+
enterpriseRemoteURL: 'https://enterprise.example.com',
|
|
958
|
+
cmsURL: 'https://cms-local.example.com',
|
|
959
|
+
enterpriseURL: 'https://enterprise.example.com',
|
|
960
|
+
secureCookiePassword: 'secure-cookie-password',
|
|
961
|
+
forestAPIKey: 'forest-api-key',
|
|
962
|
+
saleChannelAccessKey: 'test-sales-channel-access',
|
|
963
|
+
salesChannelAPISecret: 'test-sales-channel-secret',
|
|
964
|
+
storeAccessKey: 'test-store-access',
|
|
965
|
+
storeAPISecret: 'test-store-secret',
|
|
966
|
+
isProduction: false,
|
|
967
|
+
posthogKey: 'posthog-key',
|
|
968
|
+
posthogDomain: 'posthog.example.com',
|
|
969
|
+
posthogHost: 'posthog.example.com',
|
|
970
|
+
assetsPath: '/assets',
|
|
971
|
+
assetsDomain: 'assets.example.com',
|
|
972
|
+
turnstileKey: 'turnstile-key',
|
|
973
|
+
turnstileSecret: 'turnstile-secret',
|
|
974
|
+
redis: {
|
|
975
|
+
user: 'redis-user',
|
|
976
|
+
host: 'localhost',
|
|
977
|
+
password: 'redis-password',
|
|
978
|
+
port: 6379,
|
|
979
|
+
},
|
|
980
|
+
};
|
|
981
|
+
const customHeaders = {
|
|
982
|
+
'x-original-host': 'example.com',
|
|
983
|
+
'x-shop-id': 'shop123',
|
|
984
|
+
'x-sitepath': '/path',
|
|
985
|
+
'x-locale': 'en',
|
|
986
|
+
'x-region': 'US',
|
|
987
|
+
};
|
|
988
|
+
// Chain all interceptors
|
|
989
|
+
const headersInterceptor = (0, interceptors_1.createHeadersInterceptor)(customHeaders);
|
|
990
|
+
const authInterceptor = (0, interceptors_1.createAuthenticationInterceptor)(mockCheckoutConfig);
|
|
991
|
+
const customerAuthInterceptor = (0, interceptors_1.createCustomerAuthenticationInterceptor)(jwtToken);
|
|
992
|
+
const loggingInterceptor = (0, interceptors_1.createLoggingInterceptor)();
|
|
993
|
+
const chainedInterceptor = headersInterceptor(authInterceptor(customerAuthInterceptor(loggingInterceptor(mockNext))));
|
|
994
|
+
const mockRequest = {
|
|
995
|
+
header: new Headers(),
|
|
996
|
+
method: {
|
|
997
|
+
toString: () => 'TestService/TestMethod',
|
|
998
|
+
},
|
|
999
|
+
message: { $typeName: 'test.Message' },
|
|
1000
|
+
};
|
|
1001
|
+
yield chainedInterceptor(mockRequest);
|
|
1002
|
+
// Verify all headers from all interceptors are set
|
|
1003
|
+
expect(mockRequest.header.get('X-Original-Host')).toBe('example.com');
|
|
1004
|
+
expect(mockRequest.header.get('X-shop-id')).toBe('shop123');
|
|
1005
|
+
expect(mockRequest.header.get('X-Store-Key')).toBe('test-store-secret');
|
|
1006
|
+
expect(mockRequest.header.get('Authorization')).toBe(`Bearer ${jwtToken}`);
|
|
1007
|
+
expect(mockNext).toHaveBeenCalled();
|
|
1008
|
+
}));
|
|
1009
|
+
it('should validate headers before auth in chain', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
1010
|
+
const mockNext = vi.fn();
|
|
1011
|
+
mockNext.mockResolvedValue({
|
|
1012
|
+
header: new Headers(),
|
|
1013
|
+
message: { $typeName: 'test.Message' },
|
|
1014
|
+
trailer: new Headers(),
|
|
1015
|
+
});
|
|
1016
|
+
const mockCheckoutConfig = {
|
|
1017
|
+
hostname: 'example.com',
|
|
1018
|
+
cmsRemoteURL: 'https://cms.example.com',
|
|
1019
|
+
enterpriseRemoteURL: 'https://enterprise.example.com',
|
|
1020
|
+
cmsURL: 'https://cms-local.example.com',
|
|
1021
|
+
enterpriseURL: 'https://enterprise.example.com',
|
|
1022
|
+
secureCookiePassword: 'secure-cookie-password',
|
|
1023
|
+
forestAPIKey: 'forest-api-key',
|
|
1024
|
+
saleChannelAccessKey: 'test-sales-channel-access',
|
|
1025
|
+
salesChannelAPISecret: 'test-sales-channel-secret',
|
|
1026
|
+
storeAccessKey: 'test-store-access',
|
|
1027
|
+
storeAPISecret: 'test-store-secret',
|
|
1028
|
+
isProduction: false,
|
|
1029
|
+
posthogKey: 'posthog-key',
|
|
1030
|
+
posthogDomain: 'posthog.example.com',
|
|
1031
|
+
posthogHost: 'posthog.example.com',
|
|
1032
|
+
assetsPath: '/assets',
|
|
1033
|
+
assetsDomain: 'assets.example.com',
|
|
1034
|
+
turnstileKey: 'turnstile-key',
|
|
1035
|
+
turnstileSecret: 'turnstile-secret',
|
|
1036
|
+
redis: {
|
|
1037
|
+
user: 'redis-user',
|
|
1038
|
+
host: 'localhost',
|
|
1039
|
+
password: 'redis-password',
|
|
1040
|
+
port: 6379,
|
|
1041
|
+
},
|
|
1042
|
+
};
|
|
1043
|
+
const invalidHeaders = {
|
|
1044
|
+
// Missing x-shop-id
|
|
1045
|
+
'x-original-host': 'example.com',
|
|
1046
|
+
'x-sitepath': '/path',
|
|
1047
|
+
'x-locale': 'en',
|
|
1048
|
+
'x-region': 'US',
|
|
1049
|
+
};
|
|
1050
|
+
const headersInterceptor = (0, interceptors_1.createHeadersInterceptor)(invalidHeaders);
|
|
1051
|
+
const authInterceptor = (0, interceptors_1.createAuthenticationInterceptor)(mockCheckoutConfig);
|
|
1052
|
+
const chainedInterceptor = headersInterceptor(authInterceptor(mockNext));
|
|
1053
|
+
const mockRequest = {
|
|
1054
|
+
header: new Headers(),
|
|
1055
|
+
message: { $typeName: 'test.Message' },
|
|
1056
|
+
};
|
|
1057
|
+
// Should fail at headers validation
|
|
1058
|
+
yield expect(chainedInterceptor(mockRequest)).rejects.toThrow();
|
|
1059
|
+
// Auth headers should not be set because headers validation failed
|
|
1060
|
+
expect(mockRequest.header.get('X-Store-Key')).toBeNull();
|
|
1061
|
+
}));
|
|
1062
|
+
});
|
|
1063
|
+
});
|