@almatar/branding 0.2.0 → 1.0.0-beta.3

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.
@@ -0,0 +1,26 @@
1
+ import { OnModuleInit } from '@nestjs/common';
2
+ /**
3
+ * HTTP Interceptor that automatically adds x-brand and x-employee-brands headers
4
+ * to ALL outgoing HTTP requests, similar to holiday-consumer-service
5
+ *
6
+ * Usage in app.module.ts:
7
+ * ```typescript
8
+ * import { TenantHttpInterceptor } from '@almatar/branding';
9
+ * import { HttpModule } from '@nestjs/axios';
10
+ *
11
+ * @Module({
12
+ * imports: [HttpModule],
13
+ * providers: [
14
+ * {
15
+ * provide: APP_INTERCEPTOR,
16
+ * useClass: TenantHttpInterceptor,
17
+ * },
18
+ * ],
19
+ * })
20
+ * ```
21
+ */
22
+ export declare class TenantHttpInterceptor implements OnModuleInit {
23
+ private readonly httpService?;
24
+ constructor(httpService?: any);
25
+ onModuleInit(): void;
26
+ }
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.TenantHttpInterceptor = void 0;
13
+ const common_1 = require("@nestjs/common");
14
+ const Storage_1 = __importDefault(require("../../Storage"));
15
+ /**
16
+ * HTTP Interceptor that automatically adds x-brand and x-employee-brands headers
17
+ * to ALL outgoing HTTP requests, similar to holiday-consumer-service
18
+ *
19
+ * Usage in app.module.ts:
20
+ * ```typescript
21
+ * import { TenantHttpInterceptor } from '@almatar/branding';
22
+ * import { HttpModule } from '@nestjs/axios';
23
+ *
24
+ * @Module({
25
+ * imports: [HttpModule],
26
+ * providers: [
27
+ * {
28
+ * provide: APP_INTERCEPTOR,
29
+ * useClass: TenantHttpInterceptor,
30
+ * },
31
+ * ],
32
+ * })
33
+ * ```
34
+ */
35
+ let TenantHttpInterceptor = class TenantHttpInterceptor {
36
+ // Use any type to avoid requiring @nestjs/axios at compile time (it's a peer dependency)
37
+ // HttpService will be injected by NestJS when HttpModule is imported
38
+ // We use a factory function in app.module.ts to inject HttpService
39
+ constructor(httpService) {
40
+ this.httpService = httpService;
41
+ }
42
+ onModuleInit() {
43
+ // Intercept ALL axios requests and add brand headers automatically
44
+ // Checks both x-brand and x-employee-brands from context
45
+ // Try to get HttpService if not injected
46
+ let httpService = this.httpService;
47
+ if (!httpService) {
48
+ try {
49
+ // Dynamic require to avoid compile-time dependency
50
+ const axios = require('axios');
51
+ // Use axios directly if HttpService not available
52
+ httpService = { axiosRef: axios };
53
+ }
54
+ catch (e) {
55
+ // HttpService not available - skip interceptor setup
56
+ // tslint:disable-next-line no-console
57
+ console.warn('[TenantHttpInterceptor] HttpService not available, skipping axios interceptor setup');
58
+ return;
59
+ }
60
+ }
61
+ if (!httpService.axiosRef) {
62
+ // tslint:disable-next-line no-console
63
+ console.warn('[TenantHttpInterceptor] HttpService.axiosRef not available, skipping axios interceptor setup');
64
+ return;
65
+ }
66
+ httpService.axiosRef.interceptors.request.use((config) => {
67
+ const employeeBrands = Storage_1.default.getEmployeeBrands();
68
+ const brand = Storage_1.default.getBrand();
69
+ // Add x-employee-brands header (priority: employeeBrands > brand)
70
+ if (employeeBrands && employeeBrands.length > 0) {
71
+ config.headers = config.headers || {};
72
+ config.headers['x-employee-brands'] = employeeBrands.join(',');
73
+ }
74
+ else if (brand) {
75
+ config.headers = config.headers || {};
76
+ config.headers['x-employee-brands'] = brand;
77
+ }
78
+ // Add x-brand header (for backward compatibility)
79
+ if (brand) {
80
+ config.headers = config.headers || {};
81
+ config.headers['x-brand'] = brand;
82
+ }
83
+ return config;
84
+ }, (error) => {
85
+ return Promise.reject(error);
86
+ });
87
+ }
88
+ };
89
+ TenantHttpInterceptor = __decorate([
90
+ common_1.Injectable()
91
+ ], TenantHttpInterceptor);
92
+ exports.TenantHttpInterceptor = TenantHttpInterceptor;
@@ -0,0 +1,58 @@
1
+ import { Repository, SelectQueryBuilder, FindOptionsWhere, FindManyOptions, FindOneOptions, ObjectLiteral } from 'typeorm';
2
+ /**
3
+ * Base Repository class for TypeORM that AUTOMATICALLY applies brand filtering to ALL queries
4
+ * Similar to TenantModel in PHP/MongoDB - just extend this class and everything works!
5
+ *
6
+ * Usage:
7
+ * ```typescript
8
+ * import { TenantRepository } from '@almatar/branding';
9
+ *
10
+ * export class EmployeeRepository extends TenantRepository<EmployeeEntity> {
11
+ * constructor(@InjectRepository(EmployeeEntity) repository: Repository<EmployeeEntity>) {
12
+ * super(repository.target, repository.manager, repository.queryRunner);
13
+ * }
14
+ * }
15
+ * ```
16
+ *
17
+ * Brand filtering is automatically applied to:
18
+ * - createQueryBuilder() - automatically adds brand filter
19
+ * - find() - automatically filters by brand
20
+ * - findOne() - automatically filters by brand
21
+ * - findOneBy() - automatically filters by brand
22
+ * - findAndCount() - automatically filters by brand
23
+ */
24
+ export declare class TenantRepository<T extends ObjectLiteral> extends Repository<T> {
25
+ protected readonly brandColumn: string;
26
+ protected readonly tableName: string;
27
+ constructor(target: any, manager: any, queryRunner?: any);
28
+ /**
29
+ * Override createQueryBuilder to automatically apply brand filtering
30
+ */
31
+ createQueryBuilder(alias?: string): SelectQueryBuilder<T>;
32
+ /**
33
+ * Override find to automatically apply brand filtering
34
+ */
35
+ find(options?: FindManyOptions<T>): Promise<T[]>;
36
+ /**
37
+ * Override findOne to automatically apply brand filtering
38
+ */
39
+ findOne(options?: FindOneOptions<T>): Promise<T | null>;
40
+ /**
41
+ * Override findOneBy to automatically apply brand filtering
42
+ */
43
+ findOneBy(where: FindOptionsWhere<T> | FindOptionsWhere<T>[]): Promise<T | null>;
44
+ /**
45
+ * Override findAndCount to automatically apply brand filtering
46
+ */
47
+ findAndCount(options?: FindManyOptions<T>): Promise<[T[], number]>;
48
+ /**
49
+ * Get brands from context (from token/headers)
50
+ */
51
+ private getBrandsFromContext;
52
+ /**
53
+ * Apply brand filter to query builder
54
+ * Handles both cases: brand as JSON array and brand as string
55
+ * Uses $in equivalent for multiple brands from x-employee-brands
56
+ */
57
+ private applyBrandFilter;
58
+ }
@@ -0,0 +1,281 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.TenantRepository = void 0;
7
+ const typeorm_1 = require("typeorm");
8
+ const Storage_1 = __importDefault(require("../../Storage"));
9
+ /**
10
+ * Base Repository class for TypeORM that AUTOMATICALLY applies brand filtering to ALL queries
11
+ * Similar to TenantModel in PHP/MongoDB - just extend this class and everything works!
12
+ *
13
+ * Usage:
14
+ * ```typescript
15
+ * import { TenantRepository } from '@almatar/branding';
16
+ *
17
+ * export class EmployeeRepository extends TenantRepository<EmployeeEntity> {
18
+ * constructor(@InjectRepository(EmployeeEntity) repository: Repository<EmployeeEntity>) {
19
+ * super(repository.target, repository.manager, repository.queryRunner);
20
+ * }
21
+ * }
22
+ * ```
23
+ *
24
+ * Brand filtering is automatically applied to:
25
+ * - createQueryBuilder() - automatically adds brand filter
26
+ * - find() - automatically filters by brand
27
+ * - findOne() - automatically filters by brand
28
+ * - findOneBy() - automatically filters by brand
29
+ * - findAndCount() - automatically filters by brand
30
+ */
31
+ class TenantRepository extends typeorm_1.Repository {
32
+ constructor(target, manager, queryRunner) {
33
+ super(target, manager, queryRunner);
34
+ this.brandColumn = 'brand';
35
+ // Get table name from metadata
36
+ this.tableName = this.metadata.tableName;
37
+ }
38
+ /**
39
+ * Override createQueryBuilder to automatically apply brand filtering
40
+ */
41
+ createQueryBuilder(alias) {
42
+ const query = super.createQueryBuilder(alias);
43
+ const tableAlias = alias || this.tableName;
44
+ // Automatically apply brand filter
45
+ return this.applyBrandFilter(query, tableAlias);
46
+ }
47
+ /**
48
+ * Override find to automatically apply brand filtering
49
+ */
50
+ async find(options) {
51
+ const brands = this.getBrandsFromContext();
52
+ if (brands && brands.length > 0) {
53
+ // Use query builder to support JSON_CONTAINS
54
+ const alias = this.tableName;
55
+ let query = this.createQueryBuilder(alias);
56
+ // Apply existing where conditions
57
+ if (options === null || options === void 0 ? void 0 : options.where) {
58
+ if (Array.isArray(options.where)) {
59
+ options.where.forEach((where, index) => {
60
+ Object.keys(where).forEach(key => {
61
+ query = query.andWhere(`${alias}.${key} = :${key}_${index}`, { [`${key}_${index}`]: where[key] });
62
+ });
63
+ });
64
+ }
65
+ else {
66
+ Object.keys(options.where).forEach(key => {
67
+ query = query.andWhere(`${alias}.${key} = :${key}`, { [key]: options.where[key] });
68
+ });
69
+ }
70
+ }
71
+ // Apply relations
72
+ if (options === null || options === void 0 ? void 0 : options.relations) {
73
+ const relations = Array.isArray(options.relations)
74
+ ? options.relations
75
+ : Object.keys(options.relations).filter(key => options.relations[key]);
76
+ relations.forEach((relation) => {
77
+ query = query.leftJoinAndSelect(`${alias}.${relation}`, relation);
78
+ });
79
+ }
80
+ // Apply select
81
+ if (options === null || options === void 0 ? void 0 : options.select) {
82
+ const selectCols = Array.isArray(options.select)
83
+ ? options.select
84
+ : Object.keys(options.select).filter(key => options.select[key]);
85
+ const selectPaths = selectCols.map((col) => `${alias}.${String(col)}`);
86
+ query = query.select(selectPaths);
87
+ }
88
+ // Apply order
89
+ if (options === null || options === void 0 ? void 0 : options.order) {
90
+ if (typeof options.order === 'object' && !Array.isArray(options.order)) {
91
+ Object.keys(options.order).forEach(key => {
92
+ const orderValue = options.order[key];
93
+ if (orderValue) {
94
+ query = query.orderBy(`${alias}.${key}`, orderValue);
95
+ }
96
+ });
97
+ }
98
+ }
99
+ // Apply skip/take
100
+ if (options === null || options === void 0 ? void 0 : options.skip) {
101
+ query = query.skip(options.skip);
102
+ }
103
+ if (options === null || options === void 0 ? void 0 : options.take) {
104
+ query = query.take(options.take);
105
+ }
106
+ return query.getMany();
107
+ }
108
+ return super.find(options);
109
+ }
110
+ /**
111
+ * Override findOne to automatically apply brand filtering
112
+ */
113
+ async findOne(options) {
114
+ const brands = this.getBrandsFromContext();
115
+ if (brands && brands.length > 0) {
116
+ const alias = this.tableName;
117
+ let query = this.createQueryBuilder(alias);
118
+ if (options === null || options === void 0 ? void 0 : options.where) {
119
+ if (Array.isArray(options.where)) {
120
+ options.where.forEach((where, index) => {
121
+ Object.keys(where).forEach(key => {
122
+ query = query.andWhere(`${alias}.${key} = :${key}_${index}`, { [`${key}_${index}`]: where[key] });
123
+ });
124
+ });
125
+ }
126
+ else {
127
+ Object.keys(options.where).forEach(key => {
128
+ query = query.andWhere(`${alias}.${key} = :${key}`, { [key]: options.where[key] });
129
+ });
130
+ }
131
+ }
132
+ if (options === null || options === void 0 ? void 0 : options.relations) {
133
+ const relations = Array.isArray(options.relations)
134
+ ? options.relations
135
+ : Object.keys(options.relations).filter(key => options.relations[key]);
136
+ relations.forEach((relation) => {
137
+ query = query.leftJoinAndSelect(`${alias}.${relation}`, relation);
138
+ });
139
+ }
140
+ if (options === null || options === void 0 ? void 0 : options.select) {
141
+ const selectCols = Array.isArray(options.select)
142
+ ? options.select
143
+ : Object.keys(options.select).filter(key => options.select[key]);
144
+ const selectPaths = selectCols.map((col) => `${alias}.${String(col)}`);
145
+ query = query.select(selectPaths);
146
+ }
147
+ if (options === null || options === void 0 ? void 0 : options.order) {
148
+ if (typeof options.order === 'object' && !Array.isArray(options.order)) {
149
+ Object.keys(options.order).forEach(key => {
150
+ const orderValue = options.order[key];
151
+ if (orderValue) {
152
+ query = query.orderBy(`${alias}.${key}`, orderValue);
153
+ }
154
+ });
155
+ }
156
+ }
157
+ return query.getOne();
158
+ }
159
+ return super.findOne(options || {});
160
+ }
161
+ /**
162
+ * Override findOneBy to automatically apply brand filtering
163
+ */
164
+ async findOneBy(where) {
165
+ const brands = this.getBrandsFromContext();
166
+ if (brands && brands.length > 0) {
167
+ const alias = this.tableName;
168
+ let query = this.createQueryBuilder(alias);
169
+ if (Array.isArray(where)) {
170
+ where.forEach((w, index) => {
171
+ Object.keys(w).forEach(key => {
172
+ query = query.andWhere(`${alias}.${key} = :${key}_${index}`, { [`${key}_${index}`]: w[key] });
173
+ });
174
+ });
175
+ }
176
+ else {
177
+ Object.keys(where).forEach(key => {
178
+ query = query.andWhere(`${alias}.${key} = :${key}`, { [key]: where[key] });
179
+ });
180
+ }
181
+ return query.getOne();
182
+ }
183
+ return super.findOneBy(where);
184
+ }
185
+ /**
186
+ * Override findAndCount to automatically apply brand filtering
187
+ */
188
+ async findAndCount(options) {
189
+ const brands = this.getBrandsFromContext();
190
+ if (brands && brands.length > 0) {
191
+ const alias = this.tableName;
192
+ let query = this.createQueryBuilder(alias);
193
+ if (options === null || options === void 0 ? void 0 : options.where) {
194
+ if (Array.isArray(options.where)) {
195
+ options.where.forEach((where, index) => {
196
+ Object.keys(where).forEach(key => {
197
+ query = query.andWhere(`${alias}.${key} = :${key}_${index}`, { [`${key}_${index}`]: where[key] });
198
+ });
199
+ });
200
+ }
201
+ else {
202
+ Object.keys(options.where).forEach(key => {
203
+ query = query.andWhere(`${alias}.${key} = :${key}`, { [key]: options.where[key] });
204
+ });
205
+ }
206
+ }
207
+ if (options === null || options === void 0 ? void 0 : options.relations) {
208
+ const relations = Array.isArray(options.relations)
209
+ ? options.relations
210
+ : Object.keys(options.relations).filter(key => options.relations[key]);
211
+ relations.forEach((relation) => {
212
+ query = query.leftJoinAndSelect(`${alias}.${relation}`, relation);
213
+ });
214
+ }
215
+ if (options === null || options === void 0 ? void 0 : options.select) {
216
+ const selectCols = Array.isArray(options.select)
217
+ ? options.select
218
+ : Object.keys(options.select).filter(key => options.select[key]);
219
+ const selectPaths = selectCols.map((col) => `${alias}.${String(col)}`);
220
+ query = query.select(selectPaths);
221
+ }
222
+ if (options === null || options === void 0 ? void 0 : options.order) {
223
+ if (typeof options.order === 'object' && !Array.isArray(options.order)) {
224
+ Object.keys(options.order).forEach(key => {
225
+ const orderValue = options.order[key];
226
+ if (orderValue) {
227
+ query = query.orderBy(`${alias}.${key}`, orderValue);
228
+ }
229
+ });
230
+ }
231
+ }
232
+ if (options === null || options === void 0 ? void 0 : options.skip) {
233
+ query = query.skip(options.skip);
234
+ }
235
+ if (options === null || options === void 0 ? void 0 : options.take) {
236
+ query = query.take(options.take);
237
+ }
238
+ return query.getManyAndCount();
239
+ }
240
+ return super.findAndCount(options);
241
+ }
242
+ /**
243
+ * Get brands from context (from token/headers)
244
+ */
245
+ getBrandsFromContext() {
246
+ const contextEmployeeBrands = Storage_1.default.getEmployeeBrands();
247
+ const contextBrand = Storage_1.default.getBrand();
248
+ return contextEmployeeBrands || (contextBrand ? [contextBrand] : null);
249
+ }
250
+ /**
251
+ * Apply brand filter to query builder
252
+ * Handles both cases: brand as JSON array and brand as string
253
+ * Uses $in equivalent for multiple brands from x-employee-brands
254
+ */
255
+ applyBrandFilter(query, tableAlias) {
256
+ const brands = this.getBrandsFromContext();
257
+ 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}))`;
271
+ const brandParams = {};
272
+ brands.forEach((brand, index) => {
273
+ brandParams[`brand${index}`] = JSON.stringify(brand);
274
+ brandParams[`brandStr${index}`] = brand;
275
+ });
276
+ query.andWhere(`(${brandConditions})`, brandParams);
277
+ }
278
+ return query;
279
+ }
280
+ }
281
+ exports.TenantRepository = TenantRepository;
@@ -1,61 +1,42 @@
1
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 __generator = (this && this.__generator) || function (thisArg, body) {
12
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
- function verb(n) { return function (v) { return step([n, v]); }; }
15
- function step(op) {
16
- if (f) throw new TypeError("Generator is already executing.");
17
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
- if (y = 0, t) op = [op[0] & 2, t.value];
20
- switch (op[0]) {
21
- case 0: case 1: t = op; break;
22
- case 4: _.label++; return { value: op[1], done: false };
23
- case 5: _.label++; y = op[1]; op = [0]; continue;
24
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
- default:
26
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
- if (t[2]) _.ops.pop();
31
- _.trys.pop(); continue;
32
- }
33
- op = body.call(thisArg, _);
34
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
- }
37
- };
38
2
  Object.defineProperty(exports, "__esModule", { value: true });
39
3
  exports.PromiseRequest = void 0;
40
- var request = require("request");
41
- var PromiseRequest = /** @class */ (function () {
42
- function PromiseRequest() {
43
- }
44
- PromiseRequest.request = function (options) {
45
- return __awaiter(this, void 0, void 0, function () {
46
- return __generator(this, function (_a) {
47
- return [2 /*return*/, new Promise(function (resolve, reject) {
48
- request(options, function (err, response, body) {
49
- if (err) {
50
- reject(err);
51
- }
52
- body = body ? JSON.parse(body) : null;
53
- resolve(body);
54
- });
55
- })];
4
+ class PromiseRequest {
5
+ static async request(options) {
6
+ try {
7
+ const url = options.url || options.uri;
8
+ const method = options.method || 'GET';
9
+ const headers = options.headers || {};
10
+ const body = options.body ? JSON.stringify(options.body) : undefined;
11
+ // tslint:disable-next-line no-console
12
+ console.log('[PromiseRequest] Making request:', { url, method, headers: Object.assign(Object.assign({}, headers), { authorization: headers.authorization ? 'Bearer ***' : undefined }) });
13
+ const response = await fetch(url, {
14
+ method,
15
+ headers: Object.assign({ 'Content-Type': 'application/json' }, headers),
16
+ body,
56
17
  });
57
- });
58
- };
59
- return PromiseRequest;
60
- }());
18
+ const responseData = await response.text();
19
+ let parsedBody;
20
+ try {
21
+ parsedBody = responseData ? JSON.parse(responseData) : null;
22
+ }
23
+ catch (parseError) {
24
+ // tslint:disable-next-line no-console
25
+ console.log('[PromiseRequest] Failed to parse response as JSON:', parseError);
26
+ parsedBody = responseData;
27
+ }
28
+ // Return in the same format as the old request library
29
+ return {
30
+ status: response.status,
31
+ data: parsedBody,
32
+ body: parsedBody,
33
+ };
34
+ }
35
+ catch (err) {
36
+ // tslint:disable-next-line no-console
37
+ console.log('[PromiseRequest] Request error:', err);
38
+ throw err;
39
+ }
40
+ }
41
+ }
61
42
  exports.PromiseRequest = PromiseRequest;
@@ -1,4 +1,7 @@
1
1
  declare class TenantRequest {
2
- static request(options: any): Promise<any>;
2
+ static request(options: any): Promise<{
3
+ status: number;
4
+ data: any;
5
+ } | null>;
3
6
  }
4
7
  export default TenantRequest;