@fluyappgocore/commons-backend 1.0.205 → 1.0.210

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,34 @@
1
+ export declare class DialectHelper {
2
+ private dialect;
3
+ constructor(dialectOrSequelize: string | {
4
+ getDialect(): string;
5
+ });
6
+ get isPostgres(): boolean;
7
+ get isMssql(): boolean;
8
+ get isMysql(): boolean;
9
+ get dialectName(): string;
10
+ now(): string;
11
+ bool(val: boolean): string;
12
+ qi(name: string): string;
13
+ jsonType(): string;
14
+ autoIncrement(): string;
15
+ textArrayType(): string;
16
+ ilike(): string;
17
+ booleanType(): string;
18
+ textType(): string;
19
+ jsonValue(column: string, path: string): string;
20
+ jsonQuery(column: string, path: string): string;
21
+ jsonSet(column: string, path: string, value: string): string;
22
+ upsertIgnore(table: string, columns: string[], values: string[][], conflictColumn: string): string;
23
+ upsertUpdate(table: string, columns: string[], values: string[], conflictColumn: string, updateColumns: string[]): string;
24
+ returning(columns?: string[]): string;
25
+ limit(n: number): string;
26
+ limitClause(n: number): string;
27
+ timestampDefault(): string;
28
+ createIndexIfNotExists(table: string, indexName: string, columns: string[], unique?: boolean): string;
29
+ concat(...parts: string[]): string;
30
+ toTimestamp(value: string): string;
31
+ }
32
+ export declare function createDialectHelper(dialectOrSequelize: string | {
33
+ getDialect(): string;
34
+ }): DialectHelper;
@@ -0,0 +1,206 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createDialectHelper = exports.DialectHelper = void 0;
4
+ var DialectHelper = /** @class */ (function () {
5
+ function DialectHelper(dialectOrSequelize) {
6
+ this.dialect = typeof dialectOrSequelize === 'string'
7
+ ? dialectOrSequelize
8
+ : dialectOrSequelize.getDialect();
9
+ }
10
+ Object.defineProperty(DialectHelper.prototype, "isPostgres", {
11
+ get: function () { return this.dialect === 'postgres'; },
12
+ enumerable: false,
13
+ configurable: true
14
+ });
15
+ Object.defineProperty(DialectHelper.prototype, "isMssql", {
16
+ get: function () { return this.dialect === 'mssql'; },
17
+ enumerable: false,
18
+ configurable: true
19
+ });
20
+ Object.defineProperty(DialectHelper.prototype, "isMysql", {
21
+ get: function () { return this.dialect === 'mysql' || this.dialect === 'mariadb'; },
22
+ enumerable: false,
23
+ configurable: true
24
+ });
25
+ Object.defineProperty(DialectHelper.prototype, "dialectName", {
26
+ get: function () { return this.dialect; },
27
+ enumerable: false,
28
+ configurable: true
29
+ });
30
+ DialectHelper.prototype.now = function () {
31
+ if (this.isMssql)
32
+ return 'GETDATE()';
33
+ return 'NOW()'; // postgres + mysql
34
+ };
35
+ DialectHelper.prototype.bool = function (val) {
36
+ if (this.isMssql)
37
+ return val ? '1' : '0';
38
+ if (this.isMysql)
39
+ return val ? '1' : '0';
40
+ return val ? 'true' : 'false'; // postgres
41
+ };
42
+ DialectHelper.prototype.qi = function (name) {
43
+ if (this.isMssql)
44
+ return "[" + name + "]";
45
+ if (this.isMysql)
46
+ return "`" + name + "`";
47
+ return "\"" + name + "\""; // postgres
48
+ };
49
+ DialectHelper.prototype.jsonType = function () {
50
+ if (this.isMssql)
51
+ return 'NVARCHAR(MAX)';
52
+ if (this.isMysql)
53
+ return 'JSON';
54
+ return 'JSONB'; // postgres
55
+ };
56
+ DialectHelper.prototype.autoIncrement = function () {
57
+ if (this.isMssql)
58
+ return 'INT IDENTITY(1,1)';
59
+ if (this.isMysql)
60
+ return 'INT AUTO_INCREMENT';
61
+ return 'SERIAL'; // postgres
62
+ };
63
+ DialectHelper.prototype.textArrayType = function () {
64
+ if (this.isPostgres)
65
+ return 'TEXT[]';
66
+ return 'NVARCHAR(MAX)'; // mssql + mysql (store as JSON string)
67
+ };
68
+ DialectHelper.prototype.ilike = function () {
69
+ return this.isPostgres ? 'ILIKE' : 'LIKE'; // mssql + mysql use LIKE
70
+ };
71
+ DialectHelper.prototype.booleanType = function () {
72
+ if (this.isMssql)
73
+ return 'BIT';
74
+ if (this.isMysql)
75
+ return 'TINYINT(1)';
76
+ return 'BOOLEAN'; // postgres
77
+ };
78
+ DialectHelper.prototype.textType = function () {
79
+ if (this.isMssql)
80
+ return 'NVARCHAR(MAX)';
81
+ if (this.isMysql)
82
+ return 'LONGTEXT';
83
+ return 'TEXT'; // postgres
84
+ };
85
+ DialectHelper.prototype.jsonValue = function (column, path) {
86
+ if (this.isMssql)
87
+ return "JSON_VALUE(" + this.qi(column) + ", '$." + path + "')";
88
+ if (this.isMysql)
89
+ return "JSON_UNQUOTE(JSON_EXTRACT(" + this.qi(column) + ", '$." + path + "'))";
90
+ return this.qi(column) + "->>'" + path + "'"; // postgres
91
+ };
92
+ DialectHelper.prototype.jsonQuery = function (column, path) {
93
+ if (this.isMssql)
94
+ return "JSON_QUERY(" + this.qi(column) + ", '$." + path + "')";
95
+ if (this.isMysql)
96
+ return "JSON_EXTRACT(" + this.qi(column) + ", '$." + path + "')";
97
+ return this.qi(column) + "->'" + path + "'"; // postgres
98
+ };
99
+ DialectHelper.prototype.jsonSet = function (column, path, value) {
100
+ if (this.isMssql)
101
+ return "JSON_MODIFY(" + this.qi(column) + ", '$." + path + "', " + value + ")";
102
+ if (this.isMysql)
103
+ return "JSON_SET(" + this.qi(column) + ", '$." + path + "', " + value + ")";
104
+ return "jsonb_set(" + this.qi(column) + ", '{" + path.replace(/\./g, ',') + "}', " + value + ")"; // postgres
105
+ };
106
+ DialectHelper.prototype.upsertIgnore = function (table, columns, values, conflictColumn) {
107
+ var _this = this;
108
+ var colList = columns.map(function (c) { return _this.qi(c); }).join(', ');
109
+ if (this.isMssql) {
110
+ return values.map(function (row) {
111
+ var conflictIdx = columns.indexOf(conflictColumn);
112
+ var whereClause = _this.qi(conflictColumn) + " = " + row[conflictIdx];
113
+ var valList = row.join(', ');
114
+ return "IF NOT EXISTS (SELECT 1 FROM " + _this.qi(table) + " WHERE " + whereClause + ")\n INSERT INTO " + _this.qi(table) + " (" + colList + ") VALUES (" + valList + ");";
115
+ }).join('\n');
116
+ }
117
+ if (this.isMysql) {
118
+ var valRows_1 = values.map(function (row) { return "(" + row.join(', ') + ")"; }).join(',\n ');
119
+ return "INSERT IGNORE INTO " + this.qi(table) + " (" + colList + ") VALUES\n " + valRows_1 + ";";
120
+ }
121
+ // postgres
122
+ var valRows = values.map(function (row) { return "(" + row.join(', ') + ")"; }).join(',\n ');
123
+ return "INSERT INTO " + this.qi(table) + " (" + colList + ") VALUES\n " + valRows + "\n ON CONFLICT (" + this.qi(conflictColumn) + ") DO NOTHING;";
124
+ };
125
+ DialectHelper.prototype.upsertUpdate = function (table, columns, values, conflictColumn, updateColumns) {
126
+ var _this = this;
127
+ var colList = columns.map(function (c) { return _this.qi(c); }).join(', ');
128
+ var valList = values.join(', ');
129
+ if (this.isMssql) {
130
+ var updateSet_1 = updateColumns.map(function (c) {
131
+ var idx = columns.indexOf(c);
132
+ return _this.qi(c) + " = " + values[idx];
133
+ }).join(', ');
134
+ return "MERGE " + this.qi(table) + " AS target\nUSING (SELECT " + values.map(function (v, i) { return v + " AS " + _this.qi(columns[i]); }).join(', ') + ") AS source\nON target." + this.qi(conflictColumn) + " = source." + this.qi(conflictColumn) + "\nWHEN MATCHED THEN UPDATE SET " + updateSet_1 + "\nWHEN NOT MATCHED THEN INSERT (" + colList + ") VALUES (" + valList + ");";
135
+ }
136
+ if (this.isMysql) {
137
+ var updateSet_2 = updateColumns.map(function (c) { return _this.qi(c) + " = VALUES(" + _this.qi(c) + ")"; }).join(', ');
138
+ return "INSERT INTO " + this.qi(table) + " (" + colList + ") VALUES (" + valList + ")\nON DUPLICATE KEY UPDATE " + updateSet_2 + ";";
139
+ }
140
+ // postgres
141
+ var updateSet = updateColumns.map(function (c) { return _this.qi(c) + " = EXCLUDED." + _this.qi(c); }).join(', ');
142
+ return "INSERT INTO " + this.qi(table) + " (" + colList + ") VALUES (" + valList + ")\nON CONFLICT (" + this.qi(conflictColumn) + ") DO UPDATE SET " + updateSet + ";";
143
+ };
144
+ DialectHelper.prototype.returning = function (columns) {
145
+ var _this = this;
146
+ if (columns === void 0) { columns = ['*']; }
147
+ if (this.isMssql || this.isMysql)
148
+ return '';
149
+ return "RETURNING " + columns.map(function (c) { return _this.qi(c); }).join(', '); // postgres only
150
+ };
151
+ DialectHelper.prototype.limit = function (n) {
152
+ return this.isMssql ? "TOP " + n : ''; // postgres + mysql use LIMIT clause
153
+ };
154
+ DialectHelper.prototype.limitClause = function (n) {
155
+ if (this.isMssql)
156
+ return '';
157
+ return "LIMIT " + n; // postgres + mysql
158
+ };
159
+ DialectHelper.prototype.timestampDefault = function () {
160
+ if (this.isMssql)
161
+ return 'DEFAULT GETDATE()';
162
+ return 'DEFAULT NOW()'; // postgres + mysql
163
+ };
164
+ // Create index with IF NOT EXISTS support
165
+ DialectHelper.prototype.createIndexIfNotExists = function (table, indexName, columns, unique) {
166
+ var _this = this;
167
+ if (unique === void 0) { unique = false; }
168
+ var uniqueStr = unique ? 'UNIQUE ' : '';
169
+ var colList = columns.map(function (c) { return _this.qi(c); }).join(', ');
170
+ if (this.isMssql) {
171
+ return "IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = '" + indexName + "')\nCREATE " + uniqueStr + "INDEX " + this.qi(indexName) + " ON " + this.qi(table) + " (" + colList + ");";
172
+ }
173
+ if (this.isMysql) {
174
+ // MySQL doesn't support IF NOT EXISTS for CREATE INDEX, use procedure
175
+ return "CREATE " + uniqueStr + "INDEX " + this.qi(indexName) + " ON " + this.qi(table) + " (" + colList + ");";
176
+ }
177
+ // postgres
178
+ return "CREATE " + uniqueStr + "INDEX IF NOT EXISTS " + this.qi(indexName) + " ON " + this.qi(table) + " (" + colList + ");";
179
+ };
180
+ // Concatenation
181
+ DialectHelper.prototype.concat = function () {
182
+ var parts = [];
183
+ for (var _i = 0; _i < arguments.length; _i++) {
184
+ parts[_i] = arguments[_i];
185
+ }
186
+ if (this.isMssql)
187
+ return parts.join(' + ');
188
+ if (this.isMysql)
189
+ return "CONCAT(" + parts.join(', ') + ")";
190
+ return parts.join(' || '); // postgres
191
+ };
192
+ // String to timestamp
193
+ DialectHelper.prototype.toTimestamp = function (value) {
194
+ if (this.isMssql)
195
+ return "CAST(" + value + " AS DATETIME2)";
196
+ if (this.isMysql)
197
+ return "CAST(" + value + " AS DATETIME)";
198
+ return value + "::TIMESTAMP"; // postgres
199
+ };
200
+ return DialectHelper;
201
+ }());
202
+ exports.DialectHelper = DialectHelper;
203
+ function createDialectHelper(dialectOrSequelize) {
204
+ return new DialectHelper(dialectOrSequelize);
205
+ }
206
+ exports.createDialectHelper = createDialectHelper;
@@ -0,0 +1,2 @@
1
+ export { DialectHelper, createDialectHelper } from './dialectHelper';
2
+ export { getMultiDialectGlobs } from './multiDialectMigrator';
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getMultiDialectGlobs = exports.createDialectHelper = exports.DialectHelper = void 0;
4
+ var dialectHelper_1 = require("./dialectHelper");
5
+ Object.defineProperty(exports, "DialectHelper", { enumerable: true, get: function () { return dialectHelper_1.DialectHelper; } });
6
+ Object.defineProperty(exports, "createDialectHelper", { enumerable: true, get: function () { return dialectHelper_1.createDialectHelper; } });
7
+ var multiDialectMigrator_1 = require("./multiDialectMigrator");
8
+ Object.defineProperty(exports, "getMultiDialectGlobs", { enumerable: true, get: function () { return multiDialectMigrator_1.getMultiDialectGlobs; } });
@@ -0,0 +1,15 @@
1
+ interface MigratorConfig {
2
+ migrationsPath: string;
3
+ dialect: string;
4
+ serviceName: string;
5
+ }
6
+ /**
7
+ * Returns the glob patterns for multi-dialect migrations.
8
+ * If common/ or {dialect}/ folders exist, returns those paths.
9
+ * Otherwise falls back to flat migrations/*.{ts,js} (backward compatible).
10
+ */
11
+ export declare function getMultiDialectGlobs(config: MigratorConfig): {
12
+ globs: string[];
13
+ isMultiDialect: boolean;
14
+ };
15
+ export {};
@@ -0,0 +1,32 @@
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.getMultiDialectGlobs = void 0;
7
+ var path_1 = __importDefault(require("path"));
8
+ var fs_1 = __importDefault(require("fs"));
9
+ /**
10
+ * Returns the glob patterns for multi-dialect migrations.
11
+ * If common/ or {dialect}/ folders exist, returns those paths.
12
+ * Otherwise falls back to flat migrations/*.{ts,js} (backward compatible).
13
+ */
14
+ function getMultiDialectGlobs(config) {
15
+ var migrationsPath = config.migrationsPath, dialect = config.dialect, serviceName = config.serviceName;
16
+ var commonDir = path_1.default.join(migrationsPath, 'common');
17
+ var dialectDir = path_1.default.join(migrationsPath, dialect);
18
+ var hasCommon = fs_1.default.existsSync(commonDir);
19
+ var hasDialect = fs_1.default.existsSync(dialectDir);
20
+ if (hasCommon || hasDialect) {
21
+ var globs = [];
22
+ if (hasCommon)
23
+ globs.push(path_1.default.join(commonDir, '*.{ts,js}'));
24
+ if (hasDialect)
25
+ globs.push(path_1.default.join(dialectDir, '*.{ts,js}'));
26
+ console.log("[" + serviceName + "] Multi-dialect migrations: common/" + (hasCommon ? '✓' : '✗') + " " + dialect + "/" + (hasDialect ? '✓' : '✗'));
27
+ return { globs: globs, isMultiDialect: true };
28
+ }
29
+ console.log("[" + serviceName + "] Legacy flat migrations");
30
+ return { globs: [path_1.default.join(migrationsPath, '*.{ts,js}')], isMultiDialect: false };
31
+ }
32
+ exports.getMultiDialectGlobs = getMultiDialectGlobs;
package/build/index.d.ts CHANGED
@@ -5,6 +5,7 @@ export * from "./middlewares";
5
5
  export * from "./events";
6
6
  export * from "./dtos";
7
7
  export * from "./lib";
8
+ export * from "./helpers";
8
9
  export { BacklogManager } from './classes/BacklogManager';
9
10
  export { BacklogMonitor } from './classes/BacklogMonitor';
10
11
  export { Listener } from './events/baseListener';
package/build/index.js CHANGED
@@ -18,6 +18,7 @@ __exportStar(require("./middlewares"), exports);
18
18
  __exportStar(require("./events"), exports);
19
19
  __exportStar(require("./dtos"), exports);
20
20
  __exportStar(require("./lib"), exports);
21
+ __exportStar(require("./helpers"), exports);
21
22
  // Classes
22
23
  var BacklogManager_1 = require("./classes/BacklogManager");
23
24
  Object.defineProperty(exports, "BacklogManager", { enumerable: true, get: function () { return BacklogManager_1.BacklogManager; } });
@@ -1,3 +1 @@
1
- import { NextFunction, Request, Response } from 'express';
2
- import { HttpException } from '../exceptions';
3
- export declare const errorMiddleware: (error: HttpException, request: Request, response: Response, next: NextFunction) => void;
1
+ export declare const errorMiddleware: any;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.errorMiddleware = void 0;
4
+ // Typed as 'any' to avoid Express version conflicts across microservices
4
5
  var errorMiddleware = function (error, request, response, next) {
5
6
  var status = error.status || 500;
6
7
  var message = error.message || 'Something went wrong';
@@ -1,3 +1,4 @@
1
1
  export * from './auth.middleware';
2
2
  export * from './error.middleware';
3
3
  export * from './validation.middleware';
4
+ export * from './licenseGuard.middleware';
@@ -13,3 +13,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
13
13
  __exportStar(require("./auth.middleware"), exports);
14
14
  __exportStar(require("./error.middleware"), exports);
15
15
  __exportStar(require("./validation.middleware"), exports);
16
+ __exportStar(require("./licenseGuard.middleware"), exports);
@@ -0,0 +1,56 @@
1
+ import { Request, Response, NextFunction } from "express";
2
+ /**
3
+ * License feature guard middleware for microservices.
4
+ * Caches license data from the licensing server and checks feature flags.
5
+ *
6
+ * Usage in any MS route:
7
+ * router.get("/analytics", authFBMiddleware, licenseGuard("analytics-summary"), controller)
8
+ *
9
+ * Requires LICENSE_URL and INSTALLATION_UUID env vars.
10
+ * Falls back to allowing access if license server is unreachable.
11
+ */
12
+ interface LicenseCache {
13
+ valid: boolean;
14
+ readOnly: boolean;
15
+ blocked: boolean;
16
+ features: Record<string, boolean>;
17
+ limits: {
18
+ maxBranches: number;
19
+ maxAgents: number;
20
+ maxServices: number;
21
+ };
22
+ tier: string;
23
+ fetchedAt: number;
24
+ }
25
+ /**
26
+ * Check if a license feature is enabled.
27
+ * Can be used programmatically without middleware.
28
+ */
29
+ export declare function isLicenseFeatureEnabled(featureKey: string): Promise<boolean>;
30
+ /**
31
+ * Get cached license limits.
32
+ */
33
+ export declare function getLicenseLimits(): Promise<LicenseCache["limits"] | null>;
34
+ /**
35
+ * Express middleware that blocks access if a license feature is not enabled.
36
+ */
37
+ export declare function licenseGuard(...requiredFeatures: string[]): (_req: Request, res: Response, next: NextFunction) => Promise<void | Response<any, Record<string, any>>>;
38
+ /**
39
+ * Blocks write operations (POST/PUT/DELETE) when license is in READONLY mode.
40
+ * Use on all mutation routes. GET requests are always allowed in readonly.
41
+ */
42
+ export declare function licenseWriteGuard(): (req: Request, res: Response, next: NextFunction) => Promise<void | Response<any, Record<string, any>>>;
43
+ /**
44
+ * Blocks ALL access (including login) when license is BLOCKED.
45
+ * Use on auth/login routes.
46
+ */
47
+ export declare function licenseLoginGuard(): (_req: Request, res: Response, next: NextFunction) => Promise<void | Response<any, Record<string, any>>>;
48
+ /**
49
+ * Get current license status (for use in controllers).
50
+ */
51
+ export declare function getLicenseStatus(): Promise<{
52
+ valid: boolean;
53
+ readOnly: boolean;
54
+ blocked: boolean;
55
+ } | null>;
56
+ export {};
@@ -0,0 +1,263 @@
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 (_) 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
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.getLicenseStatus = exports.licenseLoginGuard = exports.licenseWriteGuard = exports.licenseGuard = exports.getLicenseLimits = exports.isLicenseFeatureEnabled = void 0;
40
+ var cache = null;
41
+ var CACHE_TTL = 1000 * 60 * 60; // 1 hour
42
+ function fetchLicense() {
43
+ return __awaiter(this, void 0, void 0, function () {
44
+ var licenseUrl, installationUuid, controller_1, timeout_1, res, data, _a;
45
+ return __generator(this, function (_b) {
46
+ switch (_b.label) {
47
+ case 0:
48
+ licenseUrl = process.env.LICENSE_URL || "";
49
+ installationUuid = process.env.INSTALLATION_UUID || process.env.ENTITY_UUID || "";
50
+ if (!licenseUrl || !installationUuid)
51
+ return [2 /*return*/, null];
52
+ _b.label = 1;
53
+ case 1:
54
+ _b.trys.push([1, 4, , 5]);
55
+ controller_1 = new AbortController();
56
+ timeout_1 = setTimeout(function () { return controller_1.abort(); }, 5000);
57
+ return [4 /*yield*/, fetch(licenseUrl + "/api/license/validate/" + installationUuid, { signal: controller_1.signal }).finally(function () { return clearTimeout(timeout_1); })];
58
+ case 2:
59
+ res = _b.sent();
60
+ if (!res.ok)
61
+ return [2 /*return*/, null];
62
+ return [4 /*yield*/, res.json()];
63
+ case 3:
64
+ data = _b.sent();
65
+ return [2 /*return*/, {
66
+ valid: data.valid,
67
+ readOnly: data.readOnly || false,
68
+ blocked: data.blocked || false,
69
+ features: data.features || {},
70
+ limits: data.limits || {},
71
+ tier: data.tier || "BASIC",
72
+ fetchedAt: Date.now(),
73
+ }];
74
+ case 4:
75
+ _a = _b.sent();
76
+ return [2 /*return*/, null];
77
+ case 5: return [2 /*return*/];
78
+ }
79
+ });
80
+ });
81
+ }
82
+ function getCachedLicense() {
83
+ return __awaiter(this, void 0, void 0, function () {
84
+ var fresh;
85
+ return __generator(this, function (_a) {
86
+ switch (_a.label) {
87
+ case 0:
88
+ if (cache && (Date.now() - cache.fetchedAt) < CACHE_TTL)
89
+ return [2 /*return*/, cache];
90
+ return [4 /*yield*/, fetchLicense()];
91
+ case 1:
92
+ fresh = _a.sent();
93
+ if (fresh)
94
+ cache = fresh;
95
+ return [2 /*return*/, cache];
96
+ }
97
+ });
98
+ });
99
+ }
100
+ /**
101
+ * Check if a license feature is enabled.
102
+ * Can be used programmatically without middleware.
103
+ */
104
+ function isLicenseFeatureEnabled(featureKey) {
105
+ return __awaiter(this, void 0, void 0, function () {
106
+ var license;
107
+ return __generator(this, function (_a) {
108
+ switch (_a.label) {
109
+ case 0: return [4 /*yield*/, getCachedLicense()];
110
+ case 1:
111
+ license = _a.sent();
112
+ if (!license)
113
+ return [2 /*return*/, true]; // Allow if can't check
114
+ if (Object.keys(license.features).length === 0)
115
+ return [2 /*return*/, true]; // No restrictions
116
+ return [2 /*return*/, license.features[featureKey] === true];
117
+ }
118
+ });
119
+ });
120
+ }
121
+ exports.isLicenseFeatureEnabled = isLicenseFeatureEnabled;
122
+ /**
123
+ * Get cached license limits.
124
+ */
125
+ function getLicenseLimits() {
126
+ return __awaiter(this, void 0, void 0, function () {
127
+ var license;
128
+ return __generator(this, function (_a) {
129
+ switch (_a.label) {
130
+ case 0: return [4 /*yield*/, getCachedLicense()];
131
+ case 1:
132
+ license = _a.sent();
133
+ return [2 /*return*/, (license === null || license === void 0 ? void 0 : license.limits) || null];
134
+ }
135
+ });
136
+ });
137
+ }
138
+ exports.getLicenseLimits = getLicenseLimits;
139
+ /**
140
+ * Express middleware that blocks access if a license feature is not enabled.
141
+ */
142
+ function licenseGuard() {
143
+ var _this = this;
144
+ var requiredFeatures = [];
145
+ for (var _i = 0; _i < arguments.length; _i++) {
146
+ requiredFeatures[_i] = arguments[_i];
147
+ }
148
+ return function (_req, res, next) { return __awaiter(_this, void 0, void 0, function () {
149
+ var license, _i, requiredFeatures_1, feature;
150
+ return __generator(this, function (_a) {
151
+ switch (_a.label) {
152
+ case 0: return [4 /*yield*/, getCachedLicense()];
153
+ case 1:
154
+ license = _a.sent();
155
+ // If can't check license, allow (don't block users)
156
+ if (!license)
157
+ return [2 /*return*/, next()];
158
+ // If license is not valid (expired/revoked), block
159
+ if (!license.valid) {
160
+ return [2 /*return*/, res.status(403).json({
161
+ error: "Licencia no valida",
162
+ code: "LICENSE_INVALID",
163
+ })];
164
+ }
165
+ // If no features defined in license, allow everything
166
+ if (Object.keys(license.features).length === 0)
167
+ return [2 /*return*/, next()];
168
+ // Check all required features
169
+ for (_i = 0, requiredFeatures_1 = requiredFeatures; _i < requiredFeatures_1.length; _i++) {
170
+ feature = requiredFeatures_1[_i];
171
+ if (license.features[feature] !== true) {
172
+ return [2 /*return*/, res.status(403).json({
173
+ error: "Modulo \"" + feature + "\" no habilitado en su licencia",
174
+ code: "FEATURE_DISABLED",
175
+ feature: feature,
176
+ tier: license.tier,
177
+ })];
178
+ }
179
+ }
180
+ next();
181
+ return [2 /*return*/];
182
+ }
183
+ });
184
+ }); };
185
+ }
186
+ exports.licenseGuard = licenseGuard;
187
+ /**
188
+ * Blocks write operations (POST/PUT/DELETE) when license is in READONLY mode.
189
+ * Use on all mutation routes. GET requests are always allowed in readonly.
190
+ */
191
+ function licenseWriteGuard() {
192
+ var _this = this;
193
+ return function (req, res, next) { return __awaiter(_this, void 0, void 0, function () {
194
+ var license;
195
+ return __generator(this, function (_a) {
196
+ switch (_a.label) {
197
+ case 0:
198
+ // Only block write methods
199
+ if (req.method === "GET" || req.method === "HEAD" || req.method === "OPTIONS")
200
+ return [2 /*return*/, next()];
201
+ return [4 /*yield*/, getCachedLicense()];
202
+ case 1:
203
+ license = _a.sent();
204
+ if (!license)
205
+ return [2 /*return*/, next()]; // Can't check → allow
206
+ if (license.blocked) {
207
+ return [2 /*return*/, res.status(403).json({
208
+ error: "Licencia expirada. Acceso bloqueado.",
209
+ code: "LICENSE_BLOCKED",
210
+ })];
211
+ }
212
+ if (license.readOnly) {
213
+ return [2 /*return*/, res.status(403).json({
214
+ error: "Licencia en modo solo lectura. No se permiten cambios.",
215
+ code: "LICENSE_READONLY",
216
+ })];
217
+ }
218
+ next();
219
+ return [2 /*return*/];
220
+ }
221
+ });
222
+ }); };
223
+ }
224
+ exports.licenseWriteGuard = licenseWriteGuard;
225
+ /**
226
+ * Blocks ALL access (including login) when license is BLOCKED.
227
+ * Use on auth/login routes.
228
+ */
229
+ function licenseLoginGuard() {
230
+ var _this = this;
231
+ return function (_req, res, next) { return __awaiter(_this, void 0, void 0, function () {
232
+ var license;
233
+ return __generator(this, function (_a) {
234
+ switch (_a.label) {
235
+ case 0: return [4 /*yield*/, getCachedLicense()];
236
+ case 1:
237
+ license = _a.sent();
238
+ if (!license)
239
+ return [2 /*return*/, next()]; // Can't check → allow
240
+ if (license.blocked) {
241
+ return [2 /*return*/, res.status(403).json({
242
+ error: "Licencia expirada. El acceso ha sido suspendido. Contacte al administrador.",
243
+ code: "LICENSE_BLOCKED",
244
+ })];
245
+ }
246
+ next();
247
+ return [2 /*return*/];
248
+ }
249
+ });
250
+ }); };
251
+ }
252
+ exports.licenseLoginGuard = licenseLoginGuard;
253
+ /**
254
+ * Get current license status (for use in controllers).
255
+ */
256
+ function getLicenseStatus() {
257
+ return __awaiter(this, void 0, void 0, function () {
258
+ return __generator(this, function (_a) {
259
+ return [2 /*return*/, getCachedLicense()];
260
+ });
261
+ });
262
+ }
263
+ exports.getLicenseStatus = getLicenseStatus;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluyappgocore/commons-backend",
3
- "version": "1.0.205",
3
+ "version": "1.0.210",
4
4
  "description": "",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",