@almatar/branding 1.0.0-beta.3.5 → 1.0.0-beta.3.7

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.
@@ -1,5 +1,8 @@
1
1
  export default class AlmatarBranding {
2
- static employeeAuthService: string;
3
2
  static dictionaryService: string;
3
+ /** Set to true to enable package debug logs. Default is false; set debug: true in setup() when needed. */
4
+ static debug: boolean;
4
5
  static setup(configs: any): void;
6
+ /** Logs only when AlmatarBranding.debug is true. Enable via setup({ debug: true }). */
7
+ static log(...args: any[]): void;
5
8
  }
@@ -2,10 +2,21 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  class AlmatarBranding {
4
4
  static setup(configs) {
5
- this.employeeAuthService = configs.employeeAuthService;
6
- this.dictionaryService = configs.dictionaryService;
5
+ var _a;
6
+ this.dictionaryService = (_a = configs.dictionaryService) !== null && _a !== void 0 ? _a : this.dictionaryService;
7
+ if (typeof configs.debug === 'boolean') {
8
+ this.debug = configs.debug;
9
+ }
10
+ }
11
+ /** Logs only when AlmatarBranding.debug is true. Enable via setup({ debug: true }). */
12
+ static log(...args) {
13
+ if (this.debug) {
14
+ // tslint:disable-next-line no-console
15
+ console.log(...args);
16
+ }
7
17
  }
8
18
  }
9
19
  exports.default = AlmatarBranding;
10
- AlmatarBranding.employeeAuthService = '';
11
20
  AlmatarBranding.dictionaryService = '';
21
+ /** Set to true to enable package debug logs. Default is false; set debug: true in setup() when needed. */
22
+ AlmatarBranding.debug = false;
@@ -18,9 +18,13 @@ var __importStar = (this && this.__importStar) || function (mod) {
18
18
  __setModuleDefault(result, mod);
19
19
  return result;
20
20
  };
21
+ var __importDefault = (this && this.__importDefault) || function (mod) {
22
+ return (mod && mod.__esModule) ? mod : { "default": mod };
23
+ };
21
24
  Object.defineProperty(exports, "__esModule", { value: true });
22
25
  exports.BrandIdentifier = void 0;
23
26
  const Boom = __importStar(require("@hapi/boom"));
27
+ const AlmatarBranding_1 = __importDefault(require("./AlmatarBranding"));
24
28
  const BrandManager_1 = require("./BrandManager");
25
29
  const url = __importStar(require("url"));
26
30
  class BrandIdentifier {
@@ -32,9 +36,7 @@ class BrandIdentifier {
32
36
  const brandManager = new BrandManager_1.BrandManager(this.type);
33
37
  // Priority 1: Query parameter brand (super admin override)
34
38
  const queryBrand = this.getQueryBrand(req);
35
- // Troubleshoot logs (keep while integrating across microservices)
36
- // tslint:disable-next-line no-console
37
- console.log('[BrandIdentifier] Query brand detection:', {
39
+ AlmatarBranding_1.default.log('[BrandIdentifier] Query brand detection:', {
38
40
  'req.query': req === null || req === void 0 ? void 0 : req.query,
39
41
  'req.query.brand': (_a = req === null || req === void 0 ? void 0 : req.query) === null || _a === void 0 ? void 0 : _a.brand,
40
42
  'req.url': req === null || req === void 0 ? void 0 : req.url,
@@ -42,8 +44,7 @@ class BrandIdentifier {
42
44
  'queryBrand (final)': queryBrand,
43
45
  });
44
46
  if (queryBrand) {
45
- // tslint:disable-next-line no-console
46
- console.log('[BrandIdentifier] Using query parameter brand (overriding token brands):', queryBrand);
47
+ AlmatarBranding_1.default.log('[BrandIdentifier] Using query parameter brand (overriding token brands):', queryBrand);
47
48
  // Return as array so ContextNamespace stores it as employeeBrands (used by filters)
48
49
  return [queryBrand];
49
50
  }
@@ -55,28 +56,24 @@ class BrandIdentifier {
55
56
  // Employee/Console scenario - extract from token or x-employee-brands header
56
57
  const brand = await brandManager.getConsoleBrands(req);
57
58
  if (brand && brand.length > 0) {
58
- // tslint:disable-next-line no-console
59
- console.log('[BrandIdentifier] Using console/token brands:', brand);
59
+ AlmatarBranding_1.default.log('[BrandIdentifier] Using console/token brands:', brand);
60
60
  return brand;
61
61
  }
62
62
  // If no brand found but we have authorization, try extracting from token directly
63
63
  if (req.headers.authorization) {
64
64
  const tokenBrands = brandManager.extractBrandFromToken(req.headers.authorization);
65
65
  if (tokenBrands && tokenBrands.length > 0) {
66
- // tslint:disable-next-line no-console
67
- console.log('[BrandIdentifier] Using brands extracted directly from token:', tokenBrands);
66
+ AlmatarBranding_1.default.log('[BrandIdentifier] Using brands extracted directly from token:', tokenBrands);
68
67
  return tokenBrands;
69
68
  }
70
69
  }
71
70
  // No brand found in token/headers - return null (don't use default brand)
72
- // tslint:disable-next-line no-console
73
- console.log('[BrandIdentifier] No brand found in token or headers, returning null');
71
+ AlmatarBranding_1.default.log('[BrandIdentifier] No brand found in token or headers, returning null');
74
72
  return null;
75
73
  }
76
74
  else {
77
75
  // No auth token and no x-brand header - return null (don't use default brand)
78
- // tslint:disable-next-line no-console
79
- console.log('[BrandIdentifier] No auth token or x-brand header, returning null');
76
+ AlmatarBranding_1.default.log('[BrandIdentifier] No auth token or x-brand header, returning null');
80
77
  return null;
81
78
  }
82
79
  }
@@ -85,15 +82,13 @@ class BrandIdentifier {
85
82
  try {
86
83
  const brands = await brandManager.getBrands();
87
84
  if (!brands) {
88
- // tslint:disable-next-line no-console
89
- console.log('[BrandIdentifier] Could not fetch brands list from dictionary service, continuing without it');
85
+ AlmatarBranding_1.default.log('[BrandIdentifier] Could not fetch brands list from dictionary service, continuing without it');
90
86
  return null;
91
87
  }
92
88
  return brands;
93
89
  }
94
90
  catch (err) {
95
- // tslint:disable-next-line no-console
96
- console.log('[BrandIdentifier] Error fetching brands list, continuing without it:', err);
91
+ AlmatarBranding_1.default.log('[BrandIdentifier] Error fetching brands list, continuing without it:', err);
97
92
  return null;
98
93
  }
99
94
  }
@@ -9,10 +9,8 @@ export declare class BrandManager {
9
9
  */
10
10
  extractBrandFromToken(token: string): string[] | null;
11
11
  getConsoleBrands(req: any): Promise<string[] | null>;
12
- loadBrands(req: any): Promise<string[] | null>;
13
12
  /**
14
13
  * get all brands list
15
- * @param req
16
14
  */
17
15
  getBrands(): Promise<string[] | null>;
18
16
  /**
@@ -26,8 +26,7 @@ class BrandManager {
26
26
  // JWT format: header.payload.signature
27
27
  const parts = cleanToken.split('.');
28
28
  if (parts.length !== 3) {
29
- // tslint:disable-next-line no-console
30
- console.log('[BrandManager] Invalid JWT token format - expected 3 parts');
29
+ AlmatarBranding_1.default.log('[BrandManager] Invalid JWT token format - expected 3 parts');
31
30
  return null;
32
31
  }
33
32
  // Decode payload (base64url)
@@ -49,21 +48,17 @@ class BrandManager {
49
48
  brands = [tokenPayload.brand];
50
49
  }
51
50
  else {
52
- // tslint:disable-next-line no-console
53
- console.log('[BrandManager] Brand in token is neither array nor string:', typeof tokenPayload.brand);
51
+ AlmatarBranding_1.default.log('[BrandManager] Brand in token is neither array nor string:', typeof tokenPayload.brand);
54
52
  return null;
55
53
  }
56
- // tslint:disable-next-line no-console
57
- console.log('[BrandManager] Successfully extracted brands from token:', brands);
54
+ AlmatarBranding_1.default.log('[BrandManager] Successfully extracted brands from token:', brands);
58
55
  return brands;
59
56
  }
60
- // tslint:disable-next-line no-console
61
- console.log('[BrandManager] No brand field found in token payload');
57
+ AlmatarBranding_1.default.log('[BrandManager] No brand field found in token payload');
62
58
  return null;
63
59
  }
64
60
  catch (err) {
65
- // tslint:disable-next-line no-console
66
- console.log('[BrandManager] Error extracting brand from token:', err);
61
+ AlmatarBranding_1.default.log('[BrandManager] Error extracting brand from token:', err);
67
62
  return null;
68
63
  }
69
64
  }
@@ -71,8 +66,7 @@ class BrandManager {
71
66
  // Priority 1: Check x-employee-brands header first
72
67
  if (req.headers['x-employee-brands']) {
73
68
  const brands = req.headers['x-employee-brands'].split(',').map((b) => b.trim()).filter((b) => b);
74
- // tslint:disable-next-line no-console
75
- console.log('[BrandManager] Extracted brands from x-employee-brands header:', brands);
69
+ AlmatarBranding_1.default.log('[BrandManager] Extracted brands from x-employee-brands header:', brands);
76
70
  if (brands.length > 0) {
77
71
  return brands;
78
72
  }
@@ -81,78 +75,22 @@ class BrandManager {
81
75
  if (req.headers.authorization) {
82
76
  const tokenBrands = this.extractBrandFromToken(req.headers.authorization);
83
77
  if (tokenBrands && tokenBrands.length > 0) {
84
- // tslint:disable-next-line no-console
85
- console.log('[BrandManager] Using brands extracted from token:', tokenBrands);
78
+ AlmatarBranding_1.default.log('[BrandManager] Using brands extracted from token:', tokenBrands);
86
79
  return tokenBrands;
87
80
  }
88
81
  }
89
- // DO NOT call loadBrands() here - it makes HTTP requests that can cause infinite loops
90
- // If we don't have brand from token/header, return null instead
91
- // tslint:disable-next-line no-console
92
- console.log('[BrandManager] No brand found in token or headers, returning null (skipping loadBrands to prevent loops)');
82
+ AlmatarBranding_1.default.log('[BrandManager] No brand found in token or headers, returning null');
93
83
  return null;
94
84
  }
95
- async loadBrands(req) {
96
- try {
97
- const reqBody = req.payload ? req.payload : req.body;
98
- const options = {
99
- url: AlmatarBranding_1.default.employeeAuthService + '/v1/user/brands',
100
- method: 'GET',
101
- headers: {
102
- authorization: req.headers.authorization,
103
- },
104
- };
105
- const employeeBrands = await PromiseRequest_1.PromiseRequest.request(options);
106
- // Check if response is valid and has the expected structure
107
- if (employeeBrands && employeeBrands.status === 200 && employeeBrands.data) {
108
- // Handle different possible response structures
109
- const brandsData = Array.isArray(employeeBrands.data)
110
- ? employeeBrands.data
111
- : (employeeBrands.data.data || employeeBrands.data.list || []);
112
- if (Array.isArray(brandsData) && brandsData.length > 0) {
113
- const brands = brandsData
114
- .map((brand) => {
115
- if (typeof brand === 'string') {
116
- return brand;
117
- }
118
- return (brand === null || brand === void 0 ? void 0 : brand.slug) || '';
119
- })
120
- .filter((b) => !!b);
121
- if (reqBody && reqBody.brand) {
122
- return brands.indexOf(reqBody.brand) > -1 ? brands : null;
123
- }
124
- // tslint:disable-next-line no-console
125
- console.log('[BrandManager] Successfully loaded brands from employee auth service:', brands);
126
- return brands;
127
- }
128
- else {
129
- // tslint:disable-next-line no-console
130
- console.log('[BrandManager] Invalid response structure from employee auth service, expected array but got:', typeof brandsData);
131
- }
132
- }
133
- else {
134
- // tslint:disable-next-line no-console
135
- console.log('[BrandManager] Failed to load brands from employee auth service, status:', employeeBrands === null || employeeBrands === void 0 ? void 0 : employeeBrands.status, 'data:', employeeBrands === null || employeeBrands === void 0 ? void 0 : employeeBrands.data);
136
- }
137
- return null;
138
- }
139
- catch (err) {
140
- // tslint:disable-next-line no-console
141
- console.log('[BrandManager] Error loading brands:', err);
142
- return null;
143
- }
144
- }
145
85
  /**
146
86
  * get all brands list
147
- * @param req
148
87
  */
149
88
  async getBrands() {
150
89
  var _a;
151
90
  try {
152
91
  // Check if dictionary service URL is configured
153
92
  if (!AlmatarBranding_1.default.dictionaryService || AlmatarBranding_1.default.dictionaryService.trim() === '') {
154
- // tslint:disable-next-line no-console
155
- console.log('[BrandManager] Dictionary service URL not configured, skipping brands fetch');
93
+ AlmatarBranding_1.default.log('[BrandManager] Dictionary service URL not configured, skipping brands fetch');
156
94
  return null;
157
95
  }
158
96
  const option = {
@@ -175,24 +113,20 @@ class BrandManager {
175
113
  })
176
114
  .filter((b) => !!b);
177
115
  Storage_1.default.setBrands(brands);
178
- // tslint:disable-next-line:no-console
179
- console.log('[BrandManager] Successfully loaded brands from dictionary service:', brands);
116
+ AlmatarBranding_1.default.log('[BrandManager] Successfully loaded brands from dictionary service:', brands);
180
117
  return brands;
181
118
  }
182
119
  else {
183
- // tslint:disable-next-line:no-console
184
- console.log('[BrandManager] Invalid response structure from dictionary service, expected array but got:', typeof brandsList);
120
+ AlmatarBranding_1.default.log('[BrandManager] Invalid response structure from dictionary service, expected array but got:', typeof brandsList);
185
121
  }
186
122
  }
187
123
  else {
188
- // tslint:disable-next-line:no-console
189
- console.log('[BrandManager] Failed to get brands from dictionary service, status:', brandsResponse === null || brandsResponse === void 0 ? void 0 : brandsResponse.status, 'data:', brandsResponse === null || brandsResponse === void 0 ? void 0 : brandsResponse.data);
124
+ AlmatarBranding_1.default.log('[BrandManager] Failed to get brands from dictionary service, status:', brandsResponse === null || brandsResponse === void 0 ? void 0 : brandsResponse.status, 'data:', brandsResponse === null || brandsResponse === void 0 ? void 0 : brandsResponse.data);
190
125
  }
191
126
  return null;
192
127
  }
193
128
  catch (err) {
194
- // tslint:disable-next-line:no-console
195
- console.log('[BrandManager] Error getting brands from dictionary service:', err);
129
+ AlmatarBranding_1.default.log('[BrandManager] Error getting brands from dictionary service:', err);
196
130
  return null;
197
131
  }
198
132
  }
@@ -18,7 +18,11 @@ var __importStar = (this && this.__importStar) || function (mod) {
18
18
  __setModuleDefault(result, mod);
19
19
  return result;
20
20
  };
21
+ var __importDefault = (this && this.__importDefault) || function (mod) {
22
+ return (mod && mod.__esModule) ? mod : { "default": mod };
23
+ };
21
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
+ const AlmatarBranding_1 = __importDefault(require("./AlmatarBranding"));
22
26
  const BrandIdentifier_1 = require("./BrandIdentifier");
23
27
  const url = __importStar(require("url"));
24
28
  const createNamespace = require('cls-hooked').createNamespace;
@@ -42,9 +46,7 @@ class ContextNamespace {
42
46
  // Check if query parameter brand was used (allows super admin to query specific brand)
43
47
  const queryBrand = ContextNamespace.getQueryBrand(req);
44
48
  const isQueryParameterBrand = !!queryBrand;
45
- // Troubleshoot logs (keep while integrating across microservices)
46
- // tslint:disable-next-line no-console
47
- console.log('[ContextNamespace] setEBrand request snapshot:', {
49
+ AlmatarBranding_1.default.log('[ContextNamespace] setEBrand request snapshot:', {
48
50
  'req.url': req === null || req === void 0 ? void 0 : req.url,
49
51
  'req.originalUrl': req === null || req === void 0 ? void 0 : req.originalUrl,
50
52
  'req.query': req === null || req === void 0 ? void 0 : req.query,
@@ -59,75 +61,63 @@ class ContextNamespace {
59
61
  const isEmployeeRequest = !!req.headers.authorization || !!req.headers['x-employee-brands'] || isQueryParameterBrand;
60
62
  if (Array.isArray(brand)) {
61
63
  // Employee/Console scenario with multiple brands (or query parameter brand)
62
- // tslint:disable-next-line no-console
63
- console.log('[ContextNamespace] Setting employeeBrands in context:', brand, isQueryParameterBrand ? '(from query parameter)' : '');
64
+ AlmatarBranding_1.default.log('[ContextNamespace] Setting employeeBrands in context:', brand, isQueryParameterBrand ? '(from query parameter)' : '');
64
65
  // IMPORTANT: If query parameter brand is used, clear any existing brand context first
65
66
  // This ensures query parameter brand takes absolute priority
66
67
  if (isQueryParameterBrand) {
67
68
  // Clear any existing brand context to ensure query parameter brand is used
68
69
  ns.set('brand', null);
69
- // tslint:disable-next-line no-console
70
- console.log('[ContextNamespace] Cleared existing brand context to prioritize query parameter brand');
70
+ AlmatarBranding_1.default.log('[ContextNamespace] Cleared existing brand context to prioritize query parameter brand');
71
71
  }
72
72
  // IMPORTANT: Set employeeBrands in context - this is what MongooseModel pre-hooks will read
73
73
  ns.set('employeeBrands', brand);
74
- // Troubleshoot: verify it was set
75
- // tslint:disable-next-line no-console
76
- console.log('[ContextNamespace] employeeBrands in context now:', ns.get('employeeBrands'));
74
+ AlmatarBranding_1.default.log('[ContextNamespace] employeeBrands in context now:', ns.get('employeeBrands'));
77
75
  // If query parameter brand is used with authorization token, always set x-employee-brands header
78
76
  if (isQueryParameterBrand && req.headers.authorization && brand.length > 0) {
79
77
  req.headers['x-employee-brands'] = brand.join(',');
80
- // tslint:disable-next-line no-console
81
- console.log('[ContextNamespace] Set x-employee-brands from query brand (with token):', req.headers['x-employee-brands']);
78
+ AlmatarBranding_1.default.log('[ContextNamespace] Set x-employee-brands from query brand (with token):', req.headers['x-employee-brands']);
82
79
  }
83
80
  else if (isEmployeeRequest && brand.length > 0) {
84
81
  // Set x-employee-brands header for employee requests (normal flow)
85
82
  req.headers['x-employee-brands'] = brand.join(',');
86
- // tslint:disable-next-line no-console
87
- console.log('[ContextNamespace] Setting x-employee-brands header on request:', req.headers['x-employee-brands']);
83
+ AlmatarBranding_1.default.log('[ContextNamespace] Setting x-employee-brands header on request:', req.headers['x-employee-brands']);
88
84
  }
89
85
  next();
90
86
  }
91
87
  else if (typeof brand === 'string') {
92
88
  if (isB2CRequest) {
93
89
  // B2C scenario - set brand in context but NOT x-employee-brands header
94
- // tslint:disable-next-line no-console
95
- console.log('[ContextNamespace] Setting brand in context (B2C):', brand);
90
+ AlmatarBranding_1.default.log('[ContextNamespace] Setting brand in context (B2C):', brand);
96
91
  ns.set('brand', brand);
97
92
  // Don't set x-employee-brands for B2C requests
98
93
  next();
99
94
  }
100
95
  else if (isEmployeeRequest) {
101
96
  // Employee/Console scenario with single brand
102
- // tslint:disable-next-line no-console
103
- console.log('[ContextNamespace] Setting brand in context (Employee):', brand);
97
+ AlmatarBranding_1.default.log('[ContextNamespace] Setting brand in context (Employee):', brand);
104
98
  ns.set('brand', brand);
105
99
  // If query parameter brand is used with authorization token, always set x-employee-brands header
106
100
  if (isQueryParameterBrand && req.headers.authorization) {
107
101
  req.headers['x-employee-brands'] = brand;
108
- // tslint:disable-next-line no-console
109
- console.log('[ContextNamespace] Set x-employee-brands from query brand (with token):', req.headers['x-employee-brands']);
102
+ AlmatarBranding_1.default.log('[ContextNamespace] Set x-employee-brands from query brand (with token):', req.headers['x-employee-brands']);
110
103
  }
111
104
  else {
112
105
  // Set x-employee-brands header for employee requests (normal flow)
113
106
  req.headers['x-employee-brands'] = brand;
114
- // tslint:disable-next-line no-console
115
- console.log('[ContextNamespace] Setting x-employee-brands header on request:', req.headers['x-employee-brands']);
107
+ AlmatarBranding_1.default.log('[ContextNamespace] Setting x-employee-brands header on request:', req.headers['x-employee-brands']);
116
108
  }
117
109
  next();
118
110
  }
119
111
  else {
120
112
  // Should not happen, but handle gracefully
121
- // tslint:disable-next-line no-console
122
- console.log('[ContextNamespace] Brand is string but no auth/x-brand detected, not setting headers');
113
+ AlmatarBranding_1.default.log('[ContextNamespace] Brand is string but no auth/x-brand detected, not setting headers');
123
114
  ns.set('brand', brand);
124
115
  next();
125
116
  }
126
117
  }
127
118
  else {
128
119
  // Brand is null or undefined - don't set anything
129
- // tslint:disable-next-line no-console
130
- console.log('[ContextNamespace] No brand found (no token/x-brand), not setting brand context or headers');
120
+ AlmatarBranding_1.default.log('[ContextNamespace] No brand found (no token/x-brand), not setting brand context or headers');
131
121
  // Don't set employeeBrands or x-employee-brands when no brand is found
132
122
  next();
133
123
  }
@@ -152,8 +142,7 @@ class ContextNamespace {
152
142
  const isQueryParameterBrand = !!queryBrand;
153
143
  if (Array.isArray(brand)) {
154
144
  // Employee/Console scenario with multiple brands (or query parameter brand)
155
- // tslint:disable-next-line no-console
156
- console.log('[ContextNamespace] Setting employeeBrands in context (Hapi):', brand, isQueryParameterBrand ? '(from query parameter)' : '');
145
+ AlmatarBranding_1.default.log('[ContextNamespace] Setting employeeBrands in context (Hapi):', brand, isQueryParameterBrand ? '(from query parameter)' : '');
157
146
  ns.set('employeeBrands', brand);
158
147
  reply();
159
148
  }
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.MongooseModel = void 0;
7
+ const AlmatarBranding_1 = __importDefault(require("../AlmatarBranding"));
7
8
  const Storage_1 = __importDefault(require("../Storage"));
8
9
  class MongooseModel {
9
10
  constructor(mongoose) {
@@ -38,9 +39,7 @@ class MongooseModel {
38
39
  const employeeBrands = Storage_1.default.getEmployeeBrands();
39
40
  const brand = Storage_1.default.getBrand();
40
41
  const contextBrands = employeeBrands || (brand ? [brand] : null);
41
- // Troubleshoot logs (keep while integrating across microservices)
42
- // tslint:disable-next-line no-console
43
- console.log('[MongooseModel] addPreCondition - Context:', {
42
+ AlmatarBranding_1.default.log('[MongooseModel] addPreCondition - Context:', {
44
43
  employeeBrands,
45
44
  brand,
46
45
  contextBrands,
@@ -49,18 +48,15 @@ class MongooseModel {
49
48
  if (contextBrands && contextBrands.length > 0) {
50
49
  // Use $in to check if entity's brand is in the user's brands array
51
50
  this.where({ brand: { $in: contextBrands } });
52
- // tslint:disable-next-line no-console
53
- console.log('[MongooseModel] addPreCondition - Applied brand filter:', { brand: { $in: contextBrands } });
51
+ AlmatarBranding_1.default.log('[MongooseModel] addPreCondition - Applied brand filter:', { brand: { $in: contextBrands } });
54
52
  }
55
53
  else {
56
- // tslint:disable-next-line no-console
57
- console.log('[MongooseModel] addPreCondition - No brands in context, skipping filter');
54
+ AlmatarBranding_1.default.log('[MongooseModel] addPreCondition - No brands in context, skipping filter');
58
55
  }
59
56
  next();
60
57
  }
61
58
  catch (err) {
62
- // tslint:disable-next-line no-console
63
- console.log('[MongooseModel] addPreCondition - Error in hook, continuing without filter:', err);
59
+ AlmatarBranding_1.default.log('[MongooseModel] addPreCondition - Error in hook, continuing without filter:', err);
64
60
  next();
65
61
  }
66
62
  }
@@ -88,8 +84,7 @@ class MongooseModel {
88
84
  // Only apply filter if brands are explicitly set (not null/undefined)
89
85
  if (contextBrands && contextBrands.length > 0) {
90
86
  const pipeline = this.pipeline();
91
- // tslint:disable-next-line no-console
92
- console.log('[MongooseModel] addPreAggregate - Current pipeline before brand filter:', JSON.stringify(pipeline, null, 2));
87
+ AlmatarBranding_1.default.log('[MongooseModel] addPreAggregate - Current pipeline before brand filter:', JSON.stringify(pipeline, null, 2));
93
88
  // Try to merge with existing $match stage if it exists
94
89
  let mergedMatch = false;
95
90
  for (const stage of pipeline) {
@@ -97,29 +92,24 @@ class MongooseModel {
97
92
  // Merge brand filter with existing $match
98
93
  stage.$match.brand = { $in: contextBrands };
99
94
  mergedMatch = true;
100
- // tslint:disable-next-line no-console
101
- console.log('[MongooseModel] addPreAggregate - Merged brand filter with existing $match:', JSON.stringify(stage.$match, null, 2));
95
+ AlmatarBranding_1.default.log('[MongooseModel] addPreAggregate - Merged brand filter with existing $match:', JSON.stringify(stage.$match, null, 2));
102
96
  break;
103
97
  }
104
98
  }
105
99
  // If no $match stage exists, add brand filter at the beginning
106
100
  if (!mergedMatch) {
107
101
  pipeline.unshift({ $match: { brand: { $in: contextBrands } } });
108
- // tslint:disable-next-line no-console
109
- console.log('[MongooseModel] addPreAggregate - Added brand filter to pipeline:', { brand: { $in: contextBrands } });
102
+ AlmatarBranding_1.default.log('[MongooseModel] addPreAggregate - Added brand filter to pipeline:', { brand: { $in: contextBrands } });
110
103
  }
111
- // tslint:disable-next-line no-console
112
- console.log('[MongooseModel] addPreAggregate - Final pipeline after brand filter:', JSON.stringify(pipeline, null, 2));
104
+ AlmatarBranding_1.default.log('[MongooseModel] addPreAggregate - Final pipeline after brand filter:', JSON.stringify(pipeline, null, 2));
113
105
  }
114
106
  else {
115
- // tslint:disable-next-line no-console
116
- console.log('[MongooseModel] addPreAggregate - No brands in context, skipping filter');
107
+ AlmatarBranding_1.default.log('[MongooseModel] addPreAggregate - No brands in context, skipping filter');
117
108
  }
118
109
  next();
119
110
  }
120
111
  catch (err) {
121
- // tslint:disable-next-line no-console
122
- console.log('[MongooseModel] addPreAggregate - Error in hook, continuing without filter:', err);
112
+ AlmatarBranding_1.default.log('[MongooseModel] addPreAggregate - Error in hook, continuing without filter:', err);
123
113
  next();
124
114
  }
125
115
  }
@@ -138,14 +128,12 @@ class MongooseModel {
138
128
  if (!this.brand && contextBrands && contextBrands.length > 0) {
139
129
  // Use first brand from employeeBrands array if available, otherwise use single brand
140
130
  this.brand = contextBrands[0];
141
- // tslint:disable-next-line no-console
142
- console.log('[MongooseModel] addPreSave - Set brand on document:', this.brand);
131
+ AlmatarBranding_1.default.log('[MongooseModel] addPreSave - Set brand on document:', this.brand);
143
132
  }
144
133
  next();
145
134
  }
146
135
  catch (err) {
147
- // tslint:disable-next-line no-console
148
- console.log('[MongooseModel] addPreSave - Error in hook, continuing:', err);
136
+ AlmatarBranding_1.default.log('[MongooseModel] addPreSave - Error in hook, continuing:', err);
149
137
  next();
150
138
  }
151
139
  }
@@ -167,14 +155,12 @@ class MongooseModel {
167
155
  data.brand = brandToSet;
168
156
  }
169
157
  });
170
- // tslint:disable-next-line no-console
171
- console.log('[MongooseModel] addPreInsertMany - Set brand on documents:', brandToSet);
158
+ AlmatarBranding_1.default.log('[MongooseModel] addPreInsertMany - Set brand on documents:', brandToSet);
172
159
  }
173
160
  next();
174
161
  }
175
162
  catch (err) {
176
- // tslint:disable-next-line no-console
177
- console.log('[MongooseModel] addPreInsertMany - Error in hook, continuing:', err);
163
+ AlmatarBranding_1.default.log('[MongooseModel] addPreInsertMany - Error in hook, continuing:', err);
178
164
  next();
179
165
  }
180
166
  }
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.MongooseTenantHelper = void 0;
7
+ const AlmatarBranding_1 = __importDefault(require("../AlmatarBranding"));
7
8
  const Storage_1 = __importDefault(require("../Storage"));
8
9
  /**
9
10
  * Utility class for manually applying tenant scoping in Mongoose repositories
@@ -49,12 +50,10 @@ class MongooseTenantHelper {
49
50
  // If query is empty, just add brand filter
50
51
  query.brand = { $in: contextBrands };
51
52
  }
52
- // tslint:disable-next-line no-console
53
- console.log('[MongooseTenantHelper] Added brand filter to query:', { brand: { $in: contextBrands } });
53
+ AlmatarBranding_1.default.log('[MongooseTenantHelper] Added brand filter to query:', { brand: { $in: contextBrands } });
54
54
  }
55
55
  else {
56
- // tslint:disable-next-line no-console
57
- console.log('[MongooseTenantHelper] No brand context, skipping brand filter');
56
+ AlmatarBranding_1.default.log('[MongooseTenantHelper] No brand context, skipping brand filter');
58
57
  }
59
58
  return query;
60
59
  }
@@ -75,21 +74,18 @@ class MongooseTenantHelper {
75
74
  // Merge brand filter with existing $match
76
75
  stage.$match = Object.assign(Object.assign({}, stage.$match), brandFilter);
77
76
  mergedMatch = true;
78
- // tslint:disable-next-line no-console
79
- console.log('[MongooseTenantHelper] Merged brand filter with existing $match:', stage.$match);
77
+ AlmatarBranding_1.default.log('[MongooseTenantHelper] Merged brand filter with existing $match:', stage.$match);
80
78
  break;
81
79
  }
82
80
  }
83
81
  // If no $match stage exists, add brand filter at the beginning
84
82
  if (!mergedMatch) {
85
83
  pipeline.unshift({ $match: brandFilter });
86
- // tslint:disable-next-line no-console
87
- console.log('[MongooseTenantHelper] Added brand filter to pipeline:', brandFilter);
84
+ AlmatarBranding_1.default.log('[MongooseTenantHelper] Added brand filter to pipeline:', brandFilter);
88
85
  }
89
86
  }
90
87
  else {
91
- // tslint:disable-next-line no-console
92
- console.log('[MongooseTenantHelper] No brand context, skipping brand filter in pipeline');
88
+ AlmatarBranding_1.default.log('[MongooseTenantHelper] No brand context, skipping brand filter in pipeline');
93
89
  }
94
90
  return pipeline;
95
91
  }
@@ -103,12 +99,10 @@ class MongooseTenantHelper {
103
99
  const brand = this.getBrandForDocument();
104
100
  if (brand && !document.brand) {
105
101
  document.brand = brand;
106
- // tslint:disable-next-line no-console
107
- console.log('[MongooseTenantHelper] Set brand on document:', brand);
102
+ AlmatarBranding_1.default.log('[MongooseTenantHelper] Set brand on document:', brand);
108
103
  }
109
104
  else if (!brand) {
110
- // tslint:disable-next-line no-console
111
- console.log('[MongooseTenantHelper] No brand context, skipping brand on document');
105
+ AlmatarBranding_1.default.log('[MongooseTenantHelper] No brand context, skipping brand on document');
112
106
  }
113
107
  return document;
114
108
  }
@@ -126,12 +120,10 @@ class MongooseTenantHelper {
126
120
  doc.brand = brand;
127
121
  }
128
122
  });
129
- // tslint:disable-next-line no-console
130
- console.log('[MongooseTenantHelper] Set brand on documents:', brand);
123
+ AlmatarBranding_1.default.log('[MongooseTenantHelper] Set brand on documents:', brand);
131
124
  }
132
125
  else {
133
- // tslint:disable-next-line no-console
134
- console.log('[MongooseTenantHelper] No brand context, skipping brand on documents');
126
+ AlmatarBranding_1.default.log('[MongooseTenantHelper] No brand context, skipping brand on documents');
135
127
  }
136
128
  return documents;
137
129
  }
@@ -11,6 +11,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.TenantEntitySubscriber = void 0;
13
13
  const typeorm_1 = require("typeorm");
14
+ const AlmatarBranding_1 = __importDefault(require("../../AlmatarBranding"));
14
15
  const Storage_1 = __importDefault(require("../../Storage"));
15
16
  /**
16
17
  * TypeORM EntitySubscriber that automatically handles brand in all entities
@@ -55,9 +56,7 @@ let TenantEntitySubscriber = class TenantEntitySubscriber {
55
56
  const hasMatchingBrand = contextBrands.some((b) => entityBrands.includes(b));
56
57
  if (!hasMatchingBrand) {
57
58
  // Entity doesn't match brand - this shouldn't happen if TenantRepository is used
58
- // Log for debugging (optional - can be removed)
59
- // tslint:disable-next-line no-console
60
- console.warn(`[TenantEntitySubscriber] Entity ${event.metadata.name} (id: ${entity.id}) doesn't match brand context`);
59
+ AlmatarBranding_1.default.log(`[TenantEntitySubscriber] Entity ${event.metadata.name} (id: ${entity.id}) doesn't match brand context`);
61
60
  }
62
61
  }
63
62
  }
@@ -11,6 +11,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.TenantHttpInterceptor = void 0;
13
13
  const common_1 = require("@nestjs/common");
14
+ const AlmatarBranding_1 = __importDefault(require("../../AlmatarBranding"));
14
15
  const Storage_1 = __importDefault(require("../../Storage"));
15
16
  /**
16
17
  * HTTP Interceptor that automatically adds x-brand and x-employee-brands headers
@@ -53,14 +54,12 @@ let TenantHttpInterceptor = class TenantHttpInterceptor {
53
54
  }
54
55
  catch (e) {
55
56
  // HttpService not available - skip interceptor setup
56
- // tslint:disable-next-line no-console
57
- console.warn('[TenantHttpInterceptor] HttpService not available, skipping axios interceptor setup');
57
+ AlmatarBranding_1.default.log('[TenantHttpInterceptor] HttpService not available, skipping axios interceptor setup');
58
58
  return;
59
59
  }
60
60
  }
61
61
  if (!httpService.axiosRef) {
62
- // tslint:disable-next-line no-console
63
- console.warn('[TenantHttpInterceptor] HttpService.axiosRef not available, skipping axios interceptor setup');
62
+ AlmatarBranding_1.default.log('[TenantHttpInterceptor] HttpService.axiosRef not available, skipping axios interceptor setup');
64
63
  return;
65
64
  }
66
65
  httpService.axiosRef.interceptors.request.use((config) => {
@@ -53,6 +53,7 @@ export declare class TenantRepository<T extends ObjectLiteral> extends Repositor
53
53
  * Apply brand filter to query builder
54
54
  * Handles both cases: brand as JSON array and brand as string
55
55
  * Uses $in equivalent for multiple brands from x-employee-brands
56
+ * When column is varchar/string, only IN clause is used (JSON_CONTAINS would fail on non-JSON).
56
57
  */
57
58
  private applyBrandFilter;
58
59
  }
@@ -251,29 +251,33 @@ class TenantRepository extends typeorm_1.Repository {
251
251
  * Apply brand filter to query builder
252
252
  * Handles both cases: brand as JSON array and brand as string
253
253
  * Uses $in equivalent for multiple brands from x-employee-brands
254
+ * When column is varchar/string, only IN clause is used (JSON_CONTAINS would fail on non-JSON).
254
255
  */
255
256
  applyBrandFilter(query, tableAlias) {
256
257
  const brands = this.getBrandsFromContext();
257
258
  if (brands && brands.length > 0) {
258
- // Handle both cases for multiple brands (x-employee-brands can have many):
259
- // 1. Brand column is JSON array: Check if ANY of the user's brands exist in the entity's brand array
260
- // Using JSON_CONTAINS for each brand (equivalent to $in for arrays)
261
- // 2. Brand column is string: Check if entity's brand is IN the user's brands array
262
- // Using IN clause (equivalent to $in for strings)
263
- // For JSON array: Check if any user brand is contained in entity's brand array
264
- const jsonArrayConditions = brands.map((brandItem, index) => {
265
- return `JSON_CONTAINS(${tableAlias}.${this.brandColumn}, :brand${index})`;
266
- }).join(' OR ');
267
- // For string: Check if entity's brand is in user's brands (IN clause)
268
- const stringInPlaceholders = brands.map((brandItem, index) => `:brandStr${index}`).join(', ');
269
- // Combine both conditions: (JSON array match) OR (string IN match)
270
- const brandConditions = `(${jsonArrayConditions}) OR (${tableAlias}.${this.brandColumn} IN (${stringInPlaceholders}))`;
259
+ const stringInPlaceholders = brands.map((_, index) => `:brandStr${index}`).join(', ');
271
260
  const brandParams = {};
272
261
  brands.forEach((brand, index) => {
273
- brandParams[`brand${index}`] = JSON.stringify(brand);
274
262
  brandParams[`brandStr${index}`] = brand;
275
263
  });
276
- query.andWhere(`(${brandConditions})`, brandParams);
264
+ const brandColumnMeta = this.metadata.columns.find((c) => c.propertyName === this.brandColumn);
265
+ const isJsonColumn = brandColumnMeta && String(brandColumnMeta.type).toLowerCase() === 'json';
266
+ if (isJsonColumn) {
267
+ // JSON column: JSON_CONTAINS OR string IN (both for flexibility)
268
+ const jsonArrayConditions = brands.map((_, index) => {
269
+ return `JSON_CONTAINS(${tableAlias}.${this.brandColumn}, :brand${index})`;
270
+ }).join(' OR ');
271
+ brands.forEach((brand, index) => {
272
+ brandParams[`brand${index}`] = JSON.stringify(brand);
273
+ });
274
+ const brandConditions = `(${jsonArrayConditions}) OR (${tableAlias}.${this.brandColumn} IN (${stringInPlaceholders}))`;
275
+ query.andWhere(`(${brandConditions})`, brandParams);
276
+ }
277
+ else {
278
+ // String/varchar column: only IN clause (JSON_CONTAINS would fail)
279
+ query.andWhere(`${tableAlias}.${this.brandColumn} IN (${stringInPlaceholders})`, brandParams);
280
+ }
277
281
  }
278
282
  return query;
279
283
  }
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.PromiseRequest = void 0;
7
+ const AlmatarBranding_1 = __importDefault(require("../AlmatarBranding"));
7
8
  const Storage_1 = __importDefault(require("../Storage"));
8
9
  class PromiseRequest {
9
10
  static async request(options) {
@@ -24,8 +25,7 @@ class PromiseRequest {
24
25
  if (brand) {
25
26
  headers['x-brand'] = brand;
26
27
  }
27
- // tslint:disable-next-line no-console
28
- console.log('[PromiseRequest] Making request:', { url, method, headers: Object.assign(Object.assign({}, headers), { authorization: headers.authorization ? 'Bearer ***' : undefined }) });
28
+ AlmatarBranding_1.default.log('[PromiseRequest] Making request:', { url, method, headers: Object.assign(Object.assign({}, headers), { authorization: headers.authorization ? 'Bearer ***' : undefined }) });
29
29
  const response = await fetch(url, {
30
30
  method,
31
31
  headers: Object.assign({ 'Content-Type': 'application/json' }, headers),
@@ -37,8 +37,7 @@ class PromiseRequest {
37
37
  parsedBody = responseData ? JSON.parse(responseData) : null;
38
38
  }
39
39
  catch (parseError) {
40
- // tslint:disable-next-line no-console
41
- console.log('[PromiseRequest] Failed to parse response as JSON:', parseError);
40
+ AlmatarBranding_1.default.log('[PromiseRequest] Failed to parse response as JSON:', parseError);
42
41
  parsedBody = responseData;
43
42
  }
44
43
  // Return in the same format as the old request library
@@ -49,8 +48,7 @@ class PromiseRequest {
49
48
  };
50
49
  }
51
50
  catch (err) {
52
- // tslint:disable-next-line no-console
53
- console.log('[PromiseRequest] Request error:', err);
51
+ AlmatarBranding_1.default.log('[PromiseRequest] Request error:', err);
54
52
  throw err;
55
53
  }
56
54
  }
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ const AlmatarBranding_1 = __importDefault(require("../AlmatarBranding"));
6
7
  const Storage_1 = __importDefault(require("../Storage"));
7
8
  class TenantRequest {
8
9
  static async request(options) {
@@ -34,8 +35,7 @@ class TenantRequest {
34
35
  };
35
36
  }
36
37
  catch (e) {
37
- // tslint:disable-next-line no-console
38
- console.log('[TenantRequest] Request error:', e);
38
+ AlmatarBranding_1.default.log('[TenantRequest] Request error:', e);
39
39
  return null;
40
40
  }
41
41
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almatar/branding",
3
- "version": "1.0.0-beta.3.5",
3
+ "version": "1.0.0-beta.3.7",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",