axe-api 1.0.0-rc21 → 1.0.0-rc23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/src/Builders/ModelTreeBuilder.js +2 -1
- package/build/src/Enums.d.ts +4 -0
- package/build/src/Enums.js +6 -1
- package/build/src/Handlers/Helpers.d.ts +8 -2
- package/build/src/Handlers/Helpers.js +91 -1
- package/build/src/Handlers/RequestHandler.js +9 -4
- package/build/src/Interfaces.d.ts +22 -12
- package/build/src/Middlewares/RateLimit/AdaptorFactory.d.ts +2 -2
- package/build/src/Middlewares/RateLimit/RedisAdaptor.d.ts +7 -2
- package/build/src/Middlewares/RateLimit/RedisAdaptor.js +17 -0
- package/build/src/Middlewares/RateLimit/index.js +2 -2
- package/build/src/Model.d.ts +2 -1
- package/build/src/Model.js +3 -0
- package/build/src/Phases/CacheTagCleanPhase.d.ts +3 -0
- package/build/src/Phases/CacheTagCleanPhase.js +19 -0
- package/build/src/Phases/Delete/ResponsePhase.js +1 -7
- package/build/src/Phases/GetCachePhase.d.ts +3 -0
- package/build/src/Phases/GetCachePhase.js +39 -0
- package/build/src/Phases/List/ResultPhase.js +9 -7
- package/build/src/Phases/Single/ResultPhase.js +9 -7
- package/build/src/Resolvers/ModelResolver.d.ts +1 -0
- package/build/src/Resolvers/ModelResolver.js +19 -0
- package/build/src/Server.js +7 -1
- package/build/src/Services/APIService.js +1 -0
- package/build/src/Services/AxeRequest.js +1 -0
- package/build/src/Services/ModelService.d.ts +6 -2
- package/build/src/Services/ModelService.js +11 -0
- package/build/src/constants.d.ts +3 -1
- package/build/src/constants.js +35 -4
- package/package.json +4 -3
|
@@ -59,7 +59,8 @@ class ModelTreeBuilder {
|
|
|
59
59
|
this.version.modelList.get().forEach((model) => {
|
|
60
60
|
const recursiveRelations = model.relations.filter((relation) => relation.model === model.name);
|
|
61
61
|
if (recursiveRelations.length === 2) {
|
|
62
|
-
|
|
62
|
+
model.setAsRecursive();
|
|
63
|
+
tree.push(model);
|
|
63
64
|
}
|
|
64
65
|
});
|
|
65
66
|
}
|
package/build/src/Enums.d.ts
CHANGED
package/build/src/Enums.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.StatusCodes = exports.QueryFeature = exports.QueryFeatureType = exports.AxeErrorCode = exports.TimestampColumns = exports.SortTypes = exports.Relationships = exports.HttpMethods = exports.Extensions = exports.HookFunctionTypes = exports.HandlerTypes = exports.DependencyTypes = exports.ConditionTypes = void 0;
|
|
3
|
+
exports.CacheStrategies = exports.StatusCodes = exports.QueryFeature = exports.QueryFeatureType = exports.AxeErrorCode = exports.TimestampColumns = exports.SortTypes = exports.Relationships = exports.HttpMethods = exports.Extensions = exports.HookFunctionTypes = exports.HandlerTypes = exports.DependencyTypes = exports.ConditionTypes = void 0;
|
|
4
4
|
var ConditionTypes;
|
|
5
5
|
(function (ConditionTypes) {
|
|
6
6
|
ConditionTypes["NotNull"] = "NotNull";
|
|
@@ -187,3 +187,8 @@ var StatusCodes;
|
|
|
187
187
|
StatusCodes[StatusCodes["USE_PROXY"] = 305] = "USE_PROXY";
|
|
188
188
|
StatusCodes[StatusCodes["MISDIRECTED_REQUEST"] = 421] = "MISDIRECTED_REQUEST";
|
|
189
189
|
})(StatusCodes || (exports.StatusCodes = StatusCodes = {}));
|
|
190
|
+
var CacheStrategies;
|
|
191
|
+
(function (CacheStrategies) {
|
|
192
|
+
CacheStrategies["TimeBased"] = "time-based";
|
|
193
|
+
CacheStrategies["TagBased"] = "tag-based";
|
|
194
|
+
})(CacheStrategies || (exports.CacheStrategies = CacheStrategies = {}));
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { IModelService, IRelation, IQuery, IVersion, IWith, IContext } from "../Interfaces";
|
|
1
|
+
import { IModelService, IRelation, IQuery, IVersion, IWith, IContext, ICacheConfiguration } from "../Interfaces";
|
|
2
2
|
import { Knex } from "knex";
|
|
3
3
|
import { HandlerTypes, HookFunctionTypes, TimestampColumns } from "../Enums";
|
|
4
4
|
import { ModelListService } from "../Services";
|
|
5
5
|
import { SerializationFunction } from "../Types";
|
|
6
|
-
import AxeRequest from "
|
|
6
|
+
import AxeRequest from "../Services/AxeRequest";
|
|
7
7
|
export declare const bindTimestampValues: (formData: Record<string, any>, model: IModelService, columnTypes?: TimestampColumns[]) => void;
|
|
8
8
|
export declare const getMergedFormData: (req: AxeRequest, fillables: string[]) => Record<string, any>;
|
|
9
9
|
export declare const callHooks: (model: IModelService, type: HookFunctionTypes, params: IContext) => Promise<void>;
|
|
@@ -15,3 +15,9 @@ export declare const filterHiddenFields: (itemArray: any[], hiddens: string[] |
|
|
|
15
15
|
export declare const addSoftDeleteQuery: (model: IModelService, conditions: IQuery | null, query: Knex.QueryBuilder) => void;
|
|
16
16
|
export declare const getRelatedData: (version: IVersion, data: any[], withArray: IWith[], model: IModelService, modelList: ModelListService, database: Knex | Knex.Transaction, handler: HandlerTypes, request: AxeRequest) => Promise<void>;
|
|
17
17
|
export declare const isBoolean: (value: any) => boolean;
|
|
18
|
+
export declare const getModelCacheConfiguration: (model: IModelService, apiConfig: ICacheConfiguration, versionConfig: ICacheConfiguration | null, handler: string) => ICacheConfiguration;
|
|
19
|
+
export declare const defaultCacheKeyFunction: (req: AxeRequest) => string;
|
|
20
|
+
export declare const toCacheKey: (context: IContext) => string;
|
|
21
|
+
export declare const putCache: (context: IContext, data: any) => Promise<void>;
|
|
22
|
+
export declare const clearCacheTags: (tag: string) => Promise<void>;
|
|
23
|
+
export declare const toCachePrefix: (value: string | undefined | null) => string;
|
|
@@ -12,7 +12,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.isBoolean = exports.getRelatedData = exports.addSoftDeleteQuery = exports.filterHiddenFields = exports.serializeData = exports.addForeignKeyQuery = exports.checkPrimaryKeyValueType = exports.getParentColumn = exports.callHooks = exports.getMergedFormData = exports.bindTimestampValues = void 0;
|
|
15
|
+
exports.toCachePrefix = exports.clearCacheTags = exports.putCache = exports.toCacheKey = exports.defaultCacheKeyFunction = exports.getModelCacheConfiguration = exports.isBoolean = exports.getRelatedData = exports.addSoftDeleteQuery = exports.filterHiddenFields = exports.serializeData = exports.addForeignKeyQuery = exports.checkPrimaryKeyValueType = exports.getParentColumn = exports.callHooks = exports.getMergedFormData = exports.bindTimestampValues = void 0;
|
|
16
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
16
17
|
const change_case_1 = require("change-case");
|
|
17
18
|
const Enums_1 = require("../Enums");
|
|
18
19
|
const ApiError_1 = __importDefault(require("../Exceptions/ApiError"));
|
|
@@ -221,6 +222,13 @@ const getRelatedData = (version, data, withArray, model, modelList, database, ha
|
|
|
221
222
|
}
|
|
222
223
|
// Fetching related records by foreignKey and primary key values.
|
|
223
224
|
let relatedRecords = yield foreignModelQuery.whereIn(searchFieldKey, parentPrimaryKeyValues);
|
|
225
|
+
// Adding related data source to the request tags to set cache tag values
|
|
226
|
+
const { primaryKey } = foreignModel.instance;
|
|
227
|
+
const cacheConfig = foreignModel.getCacheConfiguration(handler);
|
|
228
|
+
const tagPrefix = (cacheConfig === null || cacheConfig === void 0 ? void 0 : cacheConfig.tagPrefix)
|
|
229
|
+
? `${cacheConfig === null || cacheConfig === void 0 ? void 0 : cacheConfig.tagPrefix}:`
|
|
230
|
+
: "";
|
|
231
|
+
request.original.tags.push(...relatedRecords.map((i) => `${tagPrefix}${foreignModel.name}:${i[primaryKey]}`));
|
|
224
232
|
// We should serialize related data if there is any serialization function
|
|
225
233
|
relatedRecords = yield (0, exports.serializeData)(version, relatedRecords, foreignModel.serialize, handler, request);
|
|
226
234
|
// We should hide hidden fields if there is any
|
|
@@ -251,3 +259,85 @@ const isBoolean = (value) => {
|
|
|
251
259
|
return false;
|
|
252
260
|
};
|
|
253
261
|
exports.isBoolean = isBoolean;
|
|
262
|
+
const getModelCacheConfiguration = (model, apiConfig, versionConfig, handler) => {
|
|
263
|
+
let base = Object.assign(Object.assign({}, constants_1.DEFAULT_CACHE_CONFIGURATION), apiConfig);
|
|
264
|
+
if (model.instance.cache) {
|
|
265
|
+
const data = model.instance.cache;
|
|
266
|
+
if (Array.isArray(data)) {
|
|
267
|
+
const handlerBasedConfigs = data;
|
|
268
|
+
for (const item of handlerBasedConfigs) {
|
|
269
|
+
const isFound = item.handlers.map((i) => i).includes(handler);
|
|
270
|
+
if (isFound) {
|
|
271
|
+
base = Object.assign(Object.assign({}, base), item.cache);
|
|
272
|
+
return base;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
base = Object.assign(Object.assign({}, base), data);
|
|
278
|
+
return base;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if (versionConfig) {
|
|
282
|
+
base = Object.assign(Object.assign({}, base), versionConfig);
|
|
283
|
+
}
|
|
284
|
+
return base;
|
|
285
|
+
};
|
|
286
|
+
exports.getModelCacheConfiguration = getModelCacheConfiguration;
|
|
287
|
+
const defaultCacheKeyFunction = (req) => {
|
|
288
|
+
return JSON.stringify({
|
|
289
|
+
url: req.url,
|
|
290
|
+
method: req.method,
|
|
291
|
+
headers: req.original.headers,
|
|
292
|
+
});
|
|
293
|
+
};
|
|
294
|
+
exports.defaultCacheKeyFunction = defaultCacheKeyFunction;
|
|
295
|
+
const toCacheKey = (context) => {
|
|
296
|
+
const { model, handlerType } = context;
|
|
297
|
+
const config = model.getCacheConfiguration(handlerType);
|
|
298
|
+
const keyData = (config === null || config === void 0 ? void 0 : config.cacheKey)
|
|
299
|
+
? config.cacheKey(context.req)
|
|
300
|
+
: (0, exports.defaultCacheKeyFunction)(context.req);
|
|
301
|
+
const key = crypto_1.default.createHash("sha256").update(keyData).digest("hex");
|
|
302
|
+
return (0, exports.toCachePrefix)(config === null || config === void 0 ? void 0 : config.cachePrefix) + key;
|
|
303
|
+
};
|
|
304
|
+
exports.toCacheKey = toCacheKey;
|
|
305
|
+
const putCache = (context, data) => __awaiter(void 0, void 0, void 0, function* () {
|
|
306
|
+
// Getting the correct configuration
|
|
307
|
+
const { model, handlerType } = context;
|
|
308
|
+
const config = model.getCacheConfiguration(handlerType);
|
|
309
|
+
// Check if the cache enable for this handler
|
|
310
|
+
if (config === null || config === void 0 ? void 0 : config.enable) {
|
|
311
|
+
// Getting the redis service
|
|
312
|
+
const redis = yield Services_1.IoCService.use("Redis");
|
|
313
|
+
// Generating the cache key
|
|
314
|
+
const key = (0, exports.toCacheKey)(context);
|
|
315
|
+
console.log("HERE", key);
|
|
316
|
+
// Setting the tags if the cache configuration of the model has been set as
|
|
317
|
+
// tag-based cache invalidation strategy. Which means, the key cached value
|
|
318
|
+
// can be deleted if the tagged items updated/delete
|
|
319
|
+
if (config.invalidation === Enums_1.CacheStrategies.TagBased) {
|
|
320
|
+
redis.tags(context.req.original.tags, key);
|
|
321
|
+
}
|
|
322
|
+
// Putting the cache data
|
|
323
|
+
redis.set(key, JSON.stringify(data), config.ttl || 1000);
|
|
324
|
+
if (config.responseHeader) {
|
|
325
|
+
context.res.header(config.responseHeader, "Missed");
|
|
326
|
+
}
|
|
327
|
+
// Logging
|
|
328
|
+
Services_1.LogService.debug(`\t🔄 redis.cache(${key},${config.ttl})`);
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
exports.putCache = putCache;
|
|
332
|
+
const clearCacheTags = (tag) => __awaiter(void 0, void 0, void 0, function* () {
|
|
333
|
+
const redis = yield Services_1.IoCService.use("Redis");
|
|
334
|
+
const members = yield redis.getTagMemebers(tag);
|
|
335
|
+
if (members.length > 0) {
|
|
336
|
+
yield redis.delete(members);
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
exports.clearCacheTags = clearCacheTags;
|
|
340
|
+
const toCachePrefix = (value) => {
|
|
341
|
+
return value ? `${value}:` : "";
|
|
342
|
+
};
|
|
343
|
+
exports.toCachePrefix = toCachePrefix;
|
|
@@ -15,13 +15,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
15
15
|
const Services_1 = require("../Services");
|
|
16
16
|
const URLService_1 = __importDefault(require("../Services/URLService"));
|
|
17
17
|
const ConverterService_1 = require("../Services/ConverterService");
|
|
18
|
-
const api = Services_1.APIService.getInstance();
|
|
19
18
|
const return404 = (response) => {
|
|
20
19
|
response.statusCode = 404;
|
|
21
20
|
response.write(JSON.stringify({ error: "Resource not found" }));
|
|
22
21
|
response.end();
|
|
23
22
|
};
|
|
24
23
|
exports.default = (request, response, next) => __awaiter(void 0, void 0, void 0, function* () {
|
|
24
|
+
const api = Services_1.APIService.getInstance();
|
|
25
25
|
Services_1.LogService.debug(`📥 ${request.method} ${request.url}`);
|
|
26
26
|
const { axeRequest, axeResponse } = (0, ConverterService_1.toAxeRequestResponsePair)(request, response);
|
|
27
27
|
const match = URLService_1.default.match(axeRequest);
|
|
@@ -35,7 +35,7 @@ exports.default = (request, response, next) => __awaiter(void 0, void 0, void 0,
|
|
|
35
35
|
// Prepare the database by the transaction option
|
|
36
36
|
let trx = null;
|
|
37
37
|
if (match.hasTransaction) {
|
|
38
|
-
Services_1.LogService.warn("\
|
|
38
|
+
Services_1.LogService.warn("\t🛢 DBTransaction:created()");
|
|
39
39
|
trx = yield database.transaction();
|
|
40
40
|
}
|
|
41
41
|
const context = Object.assign(Object.assign({}, match.data), { params: match.params, api, req: axeRequest, res: axeResponse, isTransactionOpen: match.hasTransaction, database: match.hasTransaction && trx ? trx : database });
|
|
@@ -57,7 +57,7 @@ exports.default = (request, response, next) => __awaiter(void 0, void 0, void 0,
|
|
|
57
57
|
Services_1.LogService.error(error);
|
|
58
58
|
// Rollback transaction
|
|
59
59
|
if (match.hasTransaction && trx) {
|
|
60
|
-
Services_1.LogService.warn("\
|
|
60
|
+
Services_1.LogService.warn("\t🛢 DBTransaction:rollback()");
|
|
61
61
|
trx.rollback();
|
|
62
62
|
}
|
|
63
63
|
if (error.type === "ApiError") {
|
|
@@ -77,12 +77,17 @@ exports.default = (request, response, next) => __awaiter(void 0, void 0, void 0,
|
|
|
77
77
|
// we should rollback it before the HTTP request end.
|
|
78
78
|
if (context.res.statusCode() >= 400 && context.res.statusCode() < 599) {
|
|
79
79
|
if (match.hasTransaction && trx) {
|
|
80
|
-
Services_1.LogService.warn("\
|
|
80
|
+
Services_1.LogService.warn("\t🛢 DBTransaction:rollback()");
|
|
81
81
|
trx.rollback();
|
|
82
82
|
}
|
|
83
83
|
Services_1.LogService.debug(`\tResponse ${context.res.statusCode()}`);
|
|
84
84
|
break;
|
|
85
85
|
}
|
|
86
|
+
// We should commit the transaction if there is any
|
|
87
|
+
if (match.hasTransaction && trx) {
|
|
88
|
+
Services_1.LogService.warn("\t🛢 DBTransaction:commit()");
|
|
89
|
+
trx.commit();
|
|
90
|
+
}
|
|
86
91
|
Services_1.LogService.debug(`\t🟢 Response ${context.res.statusCode()}`);
|
|
87
92
|
// We should brake the for-loop
|
|
88
93
|
break;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { Knex } from "knex";
|
|
4
4
|
import { Options as FormOptions } from "formidable";
|
|
5
5
|
import { Column } from "knex-schema-inspector/lib/types/column";
|
|
6
|
-
import { HandlerTypes, HttpMethods, HookFunctionTypes, Extensions, Relationships, SortTypes, ConditionTypes, DependencyTypes, QueryFeature, QueryFeatureType } from "./Enums";
|
|
6
|
+
import { HandlerTypes, HttpMethods, HookFunctionTypes, Extensions, Relationships, SortTypes, ConditionTypes, DependencyTypes, QueryFeature, QueryFeatureType, CacheStrategies } from "./Enums";
|
|
7
7
|
import Model from "./Model";
|
|
8
8
|
import { AdaptorType, AxeFunction, GeneralFunction, HandlerFunction, ModelHooks, PhaseFunction, SerializationFunction } from "./Types";
|
|
9
9
|
import { ModelListService, QueryService } from "./Services";
|
|
@@ -13,6 +13,7 @@ import App from "./Services/App";
|
|
|
13
13
|
import { LoggerOptions } from "pino";
|
|
14
14
|
import { IncomingMessage } from "http";
|
|
15
15
|
import { ErrorHandleFunction } from "connect";
|
|
16
|
+
import { RedisClientOptions } from "redis";
|
|
16
17
|
export interface IColumn extends Column {
|
|
17
18
|
table_name: string;
|
|
18
19
|
}
|
|
@@ -22,6 +23,10 @@ export interface IHandlerBasedTransactionConfig {
|
|
|
22
23
|
handlers: HandlerTypes[];
|
|
23
24
|
transaction: boolean;
|
|
24
25
|
}
|
|
26
|
+
export interface IHandlerBasedCacheConfig {
|
|
27
|
+
handlers: HandlerTypes[];
|
|
28
|
+
cache: ICacheConfiguration;
|
|
29
|
+
}
|
|
25
30
|
interface IHandlerBasedSerializer {
|
|
26
31
|
handler: HandlerTypes[];
|
|
27
32
|
serializer: ((data: any, request: AxeRequest) => void)[];
|
|
@@ -40,23 +45,13 @@ export interface IQueryConfig {
|
|
|
40
45
|
limits: Array<IQueryLimitConfig[]>;
|
|
41
46
|
defaults?: IQueryDefaultConfig;
|
|
42
47
|
}
|
|
43
|
-
export interface IRedisOptions {
|
|
44
|
-
host?: string;
|
|
45
|
-
port?: number;
|
|
46
|
-
password?: string;
|
|
47
|
-
db?: number;
|
|
48
|
-
}
|
|
49
|
-
export interface IRateLimitAdaptorConfig {
|
|
50
|
-
type: AdaptorType;
|
|
51
|
-
redis?: IRedisOptions;
|
|
52
|
-
}
|
|
53
48
|
export interface IRateLimitOptions {
|
|
54
49
|
maxRequests: number;
|
|
55
50
|
windowInSeconds: number;
|
|
56
51
|
}
|
|
57
52
|
export interface IRateLimitConfig extends IRateLimitOptions {
|
|
58
53
|
enabled: boolean;
|
|
59
|
-
adaptor:
|
|
54
|
+
adaptor: AdaptorType;
|
|
60
55
|
trustProxyIP: boolean;
|
|
61
56
|
keyGenerator?: (req: IncomingMessage) => string;
|
|
62
57
|
}
|
|
@@ -67,8 +62,18 @@ export interface AxeVersionConfig {
|
|
|
67
62
|
defaultLanguage: string;
|
|
68
63
|
query: IQueryConfig;
|
|
69
64
|
formidable: FormOptions;
|
|
65
|
+
cache: ICacheConfiguration | null;
|
|
70
66
|
}
|
|
71
67
|
export type IVersionConfig = Partial<AxeVersionConfig>;
|
|
68
|
+
export interface ICacheConfiguration {
|
|
69
|
+
enable?: boolean;
|
|
70
|
+
ttl?: number;
|
|
71
|
+
invalidation?: CacheStrategies;
|
|
72
|
+
cachePrefix?: string;
|
|
73
|
+
tagPrefix?: string;
|
|
74
|
+
responseHeader?: string | null;
|
|
75
|
+
cacheKey?: (req: AxeRequest) => string;
|
|
76
|
+
}
|
|
72
77
|
export interface AxeConfig extends IConfig {
|
|
73
78
|
env: string;
|
|
74
79
|
port: number;
|
|
@@ -78,6 +83,8 @@ export interface AxeConfig extends IConfig {
|
|
|
78
83
|
rateLimit: IRateLimitConfig;
|
|
79
84
|
errorHandler: ErrorHandleFunction;
|
|
80
85
|
docs: boolean;
|
|
86
|
+
redis: RedisClientOptions | undefined;
|
|
87
|
+
cache: ICacheConfiguration;
|
|
81
88
|
}
|
|
82
89
|
export type IApplicationConfig = Partial<AxeConfig>;
|
|
83
90
|
export interface ILanguage {
|
|
@@ -140,6 +147,9 @@ export interface IModelService {
|
|
|
140
147
|
setExtensions(type: Extensions, hookFunctionType: HookFunctionTypes, data: PhaseFunction): void;
|
|
141
148
|
setQueryLimits(limits: IQueryLimitConfig[]): void;
|
|
142
149
|
setSerialization(callback: SerializationFunction): void;
|
|
150
|
+
setCacheConfiguration(handler: string, cache: ICacheConfiguration): void;
|
|
151
|
+
getCacheConfiguration(handler: HandlerTypes): ICacheConfiguration | null;
|
|
152
|
+
setAsRecursive(): void;
|
|
143
153
|
}
|
|
144
154
|
export interface IRelation {
|
|
145
155
|
type: Relationships;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AdaptorType } from "../../Types";
|
|
2
2
|
import RedisAdaptor from "./RedisAdaptor";
|
|
3
3
|
import MemoryAdaptor from "./MemoryAdaptor";
|
|
4
|
-
import {
|
|
5
|
-
declare const _default: (adaptor: AdaptorType, redisOptions:
|
|
4
|
+
import { RedisClientOptions } from "redis";
|
|
5
|
+
declare const _default: (adaptor: AdaptorType, redisOptions: RedisClientOptions | undefined, prefix: string) => RedisAdaptor | MemoryAdaptor;
|
|
6
6
|
export default _default;
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createClient } from "redis";
|
|
2
|
+
import { ICacheAdaptor } from "../../Interfaces";
|
|
3
|
+
type RedisClientOptions = Parameters<typeof createClient>[0];
|
|
2
4
|
declare class RedisAdaptor implements ICacheAdaptor {
|
|
3
5
|
private client;
|
|
4
6
|
private prefix;
|
|
5
|
-
constructor(options:
|
|
7
|
+
constructor(options: RedisClientOptions | undefined, prefix: string);
|
|
6
8
|
get(key: string): Promise<string | null>;
|
|
7
9
|
set(key: string, value: string, ttl: number): Promise<void>;
|
|
10
|
+
tags(keys: string[], value: string): Promise<void>;
|
|
11
|
+
getTagMemebers(tag: string): Promise<string[]>;
|
|
12
|
+
delete(keys: string[]): Promise<number>;
|
|
8
13
|
decr(key: string): Promise<void>;
|
|
9
14
|
}
|
|
10
15
|
export default RedisAdaptor;
|
|
@@ -26,6 +26,23 @@ class RedisAdaptor {
|
|
|
26
26
|
yield this.client.setEx(`${this.prefix}${key}`, ttl, value);
|
|
27
27
|
});
|
|
28
28
|
}
|
|
29
|
+
tags(keys, value) {
|
|
30
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
31
|
+
keys.forEach((key) => {
|
|
32
|
+
this.client.sAdd(key, [value]);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
getTagMemebers(tag) {
|
|
37
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
38
|
+
return yield this.client.sMembers(tag);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
delete(keys) {
|
|
42
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
43
|
+
return yield this.client.del(keys);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
29
46
|
decr(key) {
|
|
30
47
|
return __awaiter(this, void 0, void 0, function* () {
|
|
31
48
|
yield this.client.decr(`${this.prefix}${key}`);
|
|
@@ -65,9 +65,9 @@ const getClientKeyByConfigurations = (req, config) => {
|
|
|
65
65
|
return `axe-api-rate-limit:${req.socket.remoteAddress || ""}`;
|
|
66
66
|
};
|
|
67
67
|
const setupRateLimitAdaptors = (config) => {
|
|
68
|
-
var _a
|
|
68
|
+
var _a;
|
|
69
69
|
// Creating the correct adaptor by the configuration
|
|
70
|
-
adaptor = (0, AdaptorFactory_1.default)(((_a = config.rateLimit) === null || _a === void 0 ? void 0 : _a.adaptor
|
|
70
|
+
adaptor = (0, AdaptorFactory_1.default)(((_a = config.rateLimit) === null || _a === void 0 ? void 0 : _a.adaptor) || "memory", config.redis, "");
|
|
71
71
|
};
|
|
72
72
|
exports.setupRateLimitAdaptors = setupRateLimitAdaptors;
|
|
73
73
|
/**
|
package/build/src/Model.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IRelation, IMethodBaseConfig, IQueryLimitConfig, IHandlerBasedTransactionConfig } from "./Interfaces";
|
|
1
|
+
import { IRelation, IMethodBaseConfig, IQueryLimitConfig, IHandlerBasedTransactionConfig, ICacheConfiguration, IHandlerBasedCacheConfig } from "./Interfaces";
|
|
2
2
|
import { HandlerTypes, HttpMethods } from "./Enums";
|
|
3
3
|
import { ModelMiddleware, AxeFunction, ModelValidation } from "./Types";
|
|
4
4
|
declare class Model {
|
|
@@ -187,6 +187,7 @@ declare class Model {
|
|
|
187
187
|
* @tutorial https://axe-api.com/reference/model-limits.html
|
|
188
188
|
*/
|
|
189
189
|
get limits(): Array<IQueryLimitConfig[]>;
|
|
190
|
+
get cache(): ICacheConfiguration | IHandlerBasedCacheConfig[] | null;
|
|
190
191
|
/**
|
|
191
192
|
* Model relationship definition. Axe API creates `hasMany` routes automatically.
|
|
192
193
|
*
|
package/build/src/Model.js
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const Helpers_1 = require("../Handlers/Helpers");
|
|
13
|
+
exports.default = (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
14
|
+
const { item, model, handlerType } = context;
|
|
15
|
+
const { primaryKey } = model.instance;
|
|
16
|
+
const config = model.getCacheConfiguration(handlerType);
|
|
17
|
+
const prefix = (0, Helpers_1.toCachePrefix)(config === null || config === void 0 ? void 0 : config.tagPrefix);
|
|
18
|
+
(0, Helpers_1.clearCacheTags)(`${prefix}${model.name}:${item[primaryKey]}`);
|
|
19
|
+
});
|
|
@@ -9,13 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
const Services_1 = require("../../Services");
|
|
13
12
|
exports.default = (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
14
|
-
const {
|
|
15
|
-
// If there is a valid transaction, we should commit it
|
|
16
|
-
if (isTransactionOpen) {
|
|
17
|
-
Services_1.LogService.warn("\tDB transaction commit");
|
|
18
|
-
database.commit();
|
|
19
|
-
}
|
|
13
|
+
const { res } = context;
|
|
20
14
|
res.noContent();
|
|
21
15
|
});
|
|
@@ -0,0 +1,39 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const Services_1 = require("../Services");
|
|
13
|
+
const Helpers_1 = require("../Handlers/Helpers");
|
|
14
|
+
exports.default = (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
15
|
+
// Getting the correct configuration
|
|
16
|
+
const { model, handlerType } = context;
|
|
17
|
+
const config = model.getCacheConfiguration(handlerType);
|
|
18
|
+
// Check if the cache enable for this handler
|
|
19
|
+
if (config === null || config === void 0 ? void 0 : config.enable) {
|
|
20
|
+
// Getting the redis service
|
|
21
|
+
const redis = yield Services_1.IoCService.use("Redis");
|
|
22
|
+
// Generating the cache key
|
|
23
|
+
const key = (0, Helpers_1.toCacheKey)(context);
|
|
24
|
+
// Try to fetch the value via Redis
|
|
25
|
+
const value = yield redis.get(key);
|
|
26
|
+
// Check if there is a value
|
|
27
|
+
if (value) {
|
|
28
|
+
// Parse and respond the value
|
|
29
|
+
const result = JSON.parse(value);
|
|
30
|
+
const { res } = context;
|
|
31
|
+
if (config.responseHeader) {
|
|
32
|
+
res.header(config.responseHeader, "Hit");
|
|
33
|
+
}
|
|
34
|
+
res.json(result);
|
|
35
|
+
// Logging
|
|
36
|
+
Services_1.LogService.debug(`\t🔄 redis.get(${key})`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
});
|
|
@@ -9,13 +9,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
const
|
|
12
|
+
const Helpers_1 = require("../../Handlers/Helpers");
|
|
13
13
|
exports.default = (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
14
|
-
const {
|
|
15
|
-
//
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
14
|
+
const { result, res, model, handlerType } = context;
|
|
15
|
+
// Adding cache tags
|
|
16
|
+
const { primaryKey } = model.instance;
|
|
17
|
+
const config = model.getCacheConfiguration(handlerType);
|
|
18
|
+
const tagPrefix = (0, Helpers_1.toCachePrefix)(config === null || config === void 0 ? void 0 : config.tagPrefix);
|
|
19
|
+
context.req.original.tags.push(...result.data.map((i) => `${tagPrefix}${model.name}:${i[primaryKey]}`));
|
|
20
|
+
// Caching the results
|
|
21
|
+
yield (0, Helpers_1.putCache)(context, result);
|
|
20
22
|
res.json(result);
|
|
21
23
|
});
|
|
@@ -9,13 +9,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
const
|
|
12
|
+
const Helpers_1 = require("../../Handlers/Helpers");
|
|
13
13
|
exports.default = (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
14
|
-
const {
|
|
15
|
-
//
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
14
|
+
const { item, res, model, handlerType } = context;
|
|
15
|
+
// Adding cache tags
|
|
16
|
+
const { primaryKey } = model.instance;
|
|
17
|
+
const config = model.getCacheConfiguration(handlerType);
|
|
18
|
+
const tagPrefix = (0, Helpers_1.toCachePrefix)(config === null || config === void 0 ? void 0 : config.tagPrefix);
|
|
19
|
+
context.req.original.tags.push(`${tagPrefix}${model.name}:${item[primaryKey]}`);
|
|
20
|
+
// Caching the results
|
|
21
|
+
yield (0, Helpers_1.putCache)(context, item);
|
|
20
22
|
res.json(item);
|
|
21
23
|
});
|
|
@@ -20,6 +20,7 @@ const Enums_1 = require("../Enums");
|
|
|
20
20
|
const Services_1 = require("../Services");
|
|
21
21
|
const constants_1 = require("../constants");
|
|
22
22
|
const AxeError_1 = __importDefault(require("../Exceptions/AxeError"));
|
|
23
|
+
const Helpers_1 = require("../Handlers/Helpers");
|
|
23
24
|
class ModelResolver {
|
|
24
25
|
constructor(version) {
|
|
25
26
|
this.version = version;
|
|
@@ -41,9 +42,27 @@ class ModelResolver {
|
|
|
41
42
|
yield this.setModelQueryLimits(modelList);
|
|
42
43
|
Services_1.LogService.debug(`[${this.version.name}] Model query limits have been loaded`);
|
|
43
44
|
this.version.modelList = modelList;
|
|
45
|
+
yield this.setCacheOptions(modelList);
|
|
44
46
|
Services_1.LogService.debug(`[${this.version.name}] All models have been resolved.`);
|
|
45
47
|
});
|
|
46
48
|
}
|
|
49
|
+
setCacheOptions(modelList) {
|
|
50
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
51
|
+
const api = Services_1.APIService.getInstance();
|
|
52
|
+
// For each model should be analyzed
|
|
53
|
+
for (const model of modelList.get()) {
|
|
54
|
+
// For each cachable handler, developers are able to set a different
|
|
55
|
+
// configuration. That's why we should check for each of them.
|
|
56
|
+
for (const handler of constants_1.ALL_HANDLERS) {
|
|
57
|
+
// API configuration, version configuration and the handler type are in
|
|
58
|
+
// order. The following function gets the correct configuration
|
|
59
|
+
const configuration = (0, Helpers_1.getModelCacheConfiguration)(model, api.config.cache, this.version.config.cache, handler);
|
|
60
|
+
// We need to set this to use late in action
|
|
61
|
+
model.setCacheConfiguration(handler, configuration);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
47
66
|
setModelRelations(modelList) {
|
|
48
67
|
return __awaiter(this, void 0, void 0, function* () {
|
|
49
68
|
for (const model of modelList.get()) {
|
package/build/src/Server.js
CHANGED
|
@@ -50,6 +50,7 @@ const http_1 = __importDefault(require("http"));
|
|
|
50
50
|
const RequestHandler_1 = __importDefault(require("./Handlers/RequestHandler"));
|
|
51
51
|
const App_1 = __importDefault(require("./Services/App"));
|
|
52
52
|
const constants_1 = require("./constants");
|
|
53
|
+
const RedisAdaptor_1 = __importDefault(require("./Middlewares/RateLimit/RedisAdaptor"));
|
|
53
54
|
class Server {
|
|
54
55
|
/**
|
|
55
56
|
* Start the application with the rootFolder.
|
|
@@ -83,11 +84,16 @@ class Server {
|
|
|
83
84
|
Services_1.IoCService.singleton("App", () => new App_1.default());
|
|
84
85
|
Services_1.IoCService.singleton("Database", () => __awaiter(this, void 0, void 0, function* () {
|
|
85
86
|
const database = (0, knex_1.default)(api.config.database);
|
|
86
|
-
|
|
87
|
+
const { client } = api.config.database;
|
|
88
|
+
const { database: db, filename } = api.config.database.connection;
|
|
89
|
+
Services_1.LogService.debug(`Created a knex connection instance: [${client}:${db || filename}]`);
|
|
87
90
|
(0, knex_paginate_1.attachPaginate)();
|
|
88
91
|
Services_1.LogService.debug("Added pagination support to the knex");
|
|
89
92
|
return database;
|
|
90
93
|
}));
|
|
94
|
+
Services_1.IoCService.singleton("Redis", () => {
|
|
95
|
+
return new RedisAdaptor_1.default(api.config.redis, "");
|
|
96
|
+
});
|
|
91
97
|
});
|
|
92
98
|
}
|
|
93
99
|
analyzeVersions() {
|
|
@@ -20,6 +20,7 @@ class AxeRequest {
|
|
|
20
20
|
constructor(request) {
|
|
21
21
|
this.privateParams = {};
|
|
22
22
|
this.request = request;
|
|
23
|
+
this.request.tags = [];
|
|
23
24
|
this.urlObject = new URL(request.url || "", "http://127.0.0.1");
|
|
24
25
|
// Application configuration is need for the default setting.
|
|
25
26
|
this.version = (0, Helpers_1.getVersionByRequest)(this.urlObject);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { HookFunctionTypes, Extensions } from "../Enums";
|
|
2
|
-
import { IColumn, IModelService, IQueryLimitConfig, IRelation } from "../Interfaces";
|
|
1
|
+
import { HookFunctionTypes, Extensions, HandlerTypes } from "../Enums";
|
|
2
|
+
import { ICacheConfiguration, IColumn, IModelService, IQueryLimitConfig, IRelation } from "../Interfaces";
|
|
3
3
|
import Model from "./../Model";
|
|
4
4
|
import { ModelHooks, PhaseFunction, SerializationFunction } from "../Types";
|
|
5
5
|
declare class ModelService implements IModelService {
|
|
@@ -14,11 +14,15 @@ declare class ModelService implements IModelService {
|
|
|
14
14
|
isRecursive: boolean;
|
|
15
15
|
queryLimits: IQueryLimitConfig[];
|
|
16
16
|
serialize: SerializationFunction | null;
|
|
17
|
+
cacheConfiguration: Record<string, ICacheConfiguration>;
|
|
17
18
|
constructor(name: string, instance: Model);
|
|
18
19
|
setColumns(columns: IColumn[]): void;
|
|
20
|
+
setCacheConfiguration(handler: string, cache: ICacheConfiguration): void;
|
|
21
|
+
getCacheConfiguration(handler: HandlerTypes): ICacheConfiguration;
|
|
19
22
|
setExtensions(type: Extensions, hookFunctionType: HookFunctionTypes, data: PhaseFunction): void;
|
|
20
23
|
setQueryLimits(limits: IQueryLimitConfig[]): void;
|
|
21
24
|
setSerialization(callback: SerializationFunction): void;
|
|
25
|
+
setAsRecursive(): void;
|
|
22
26
|
private setHooks;
|
|
23
27
|
private setEvents;
|
|
24
28
|
}
|
|
@@ -14,11 +14,18 @@ class ModelService {
|
|
|
14
14
|
this.isRecursive = false;
|
|
15
15
|
this.queryLimits = [];
|
|
16
16
|
this.serialize = null;
|
|
17
|
+
this.cacheConfiguration = {};
|
|
17
18
|
}
|
|
18
19
|
setColumns(columns) {
|
|
19
20
|
this.columns = columns;
|
|
20
21
|
this.columnNames = this.columns.map((i) => i.name);
|
|
21
22
|
}
|
|
23
|
+
setCacheConfiguration(handler, cache) {
|
|
24
|
+
this.cacheConfiguration[handler] = cache;
|
|
25
|
+
}
|
|
26
|
+
getCacheConfiguration(handler) {
|
|
27
|
+
return this.cacheConfiguration[handler];
|
|
28
|
+
}
|
|
22
29
|
setExtensions(type, hookFunctionType, data) {
|
|
23
30
|
if (type == Enums_1.Extensions.Hooks) {
|
|
24
31
|
this.setHooks(hookFunctionType, data);
|
|
@@ -36,6 +43,10 @@ class ModelService {
|
|
|
36
43
|
setSerialization(callback) {
|
|
37
44
|
this.serialize = callback;
|
|
38
45
|
}
|
|
46
|
+
setAsRecursive() {
|
|
47
|
+
this.isRecursive = true;
|
|
48
|
+
this.children = [];
|
|
49
|
+
}
|
|
39
50
|
setHooks(hookFunctionType, data) {
|
|
40
51
|
this.hooks[hookFunctionType] = data;
|
|
41
52
|
}
|
package/build/src/constants.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ConditionTypes, HandlerTypes, HttpMethods, QueryFeature, Relationships } from "./Enums";
|
|
2
|
-
import { AxeConfig, AxeVersionConfig, IStepDefinition } from "./Interfaces";
|
|
2
|
+
import { AxeConfig, AxeVersionConfig, ICacheConfiguration, IStepDefinition } from "./Interfaces";
|
|
3
3
|
export declare const RESERVED_KEYWORDS: string[];
|
|
4
4
|
export declare const DEFAULT_HANDLERS: HandlerTypes[];
|
|
5
5
|
export declare const DEFAULT_METHODS_OF_MODELS: string[];
|
|
@@ -19,5 +19,7 @@ export declare const NUMERIC_PRIMARY_KEY_TYPES: string[];
|
|
|
19
19
|
export declare const STRING_COLUMN_TYPES: string[];
|
|
20
20
|
export declare const HANDLER_METHOD_MAP: Record<HandlerTypes, HttpMethods>;
|
|
21
21
|
export declare const HANDLER_CYLES: Record<HandlerTypes, IStepDefinition[]>;
|
|
22
|
+
export declare const DEFAULT_CACHE_CONFIGURATION: ICacheConfiguration;
|
|
22
23
|
export declare const DEFAULT_APP_CONFIG: AxeConfig;
|
|
23
24
|
export declare const DEFAULT_VERSION_CONFIG: AxeVersionConfig;
|
|
25
|
+
export declare const ALL_HANDLERS: HandlerTypes[];
|
package/build/src/constants.js
CHANGED
|
@@ -3,7 +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
|
-
exports.DEFAULT_VERSION_CONFIG = exports.DEFAULT_APP_CONFIG = exports.HANDLER_CYLES = exports.HANDLER_METHOD_MAP = exports.STRING_COLUMN_TYPES = exports.NUMERIC_PRIMARY_KEY_TYPES = exports.RelationQueryFeatureMap = exports.ConditionQueryFeatureMap = exports.API_ROUTE_TEMPLATES = exports.DEFAULT_METHODS_OF_MODELS = exports.DEFAULT_HANDLERS = exports.RESERVED_KEYWORDS = void 0;
|
|
6
|
+
exports.ALL_HANDLERS = exports.DEFAULT_VERSION_CONFIG = exports.DEFAULT_APP_CONFIG = exports.DEFAULT_CACHE_CONFIGURATION = exports.HANDLER_CYLES = exports.HANDLER_METHOD_MAP = exports.STRING_COLUMN_TYPES = exports.NUMERIC_PRIMARY_KEY_TYPES = exports.RelationQueryFeatureMap = exports.ConditionQueryFeatureMap = exports.API_ROUTE_TEMPLATES = exports.DEFAULT_METHODS_OF_MODELS = exports.DEFAULT_HANDLERS = exports.RESERVED_KEYWORDS = void 0;
|
|
7
7
|
const Enums_1 = require("./Enums");
|
|
8
8
|
const LimitService_1 = require("./Services/LimitService");
|
|
9
9
|
const Single_1 = __importDefault(require("./Phases/Single"));
|
|
@@ -20,6 +20,9 @@ const Phase_1 = __importDefault(require("./Steps/Phase"));
|
|
|
20
20
|
const Hook_1 = __importDefault(require("./Steps/Hook"));
|
|
21
21
|
const Event_1 = __importDefault(require("./Steps/Event"));
|
|
22
22
|
const ErrorHandler_1 = __importDefault(require("./Handlers/ErrorHandler"));
|
|
23
|
+
const GetCachePhase_1 = __importDefault(require("./Phases/GetCachePhase"));
|
|
24
|
+
const CacheTagCleanPhase_1 = __importDefault(require("./Phases/CacheTagCleanPhase"));
|
|
25
|
+
const Helpers_1 = require("./Handlers/Helpers");
|
|
23
26
|
exports.RESERVED_KEYWORDS = [
|
|
24
27
|
"force",
|
|
25
28
|
"model",
|
|
@@ -71,6 +74,7 @@ exports.DEFAULT_METHODS_OF_MODELS = [
|
|
|
71
74
|
"limits",
|
|
72
75
|
"getFillableFields",
|
|
73
76
|
"getValidationRules",
|
|
77
|
+
"cache",
|
|
74
78
|
];
|
|
75
79
|
exports.API_ROUTE_TEMPLATES = {
|
|
76
80
|
[Enums_1.HandlerTypes.INSERT]: (prefix, parentUrl, resource) => `/${prefix}/${parentUrl}${resource}`,
|
|
@@ -135,6 +139,7 @@ exports.HANDLER_CYLES = {
|
|
|
135
139
|
new Phase_1.default("insert.response", Single_1.default.ResultPhase),
|
|
136
140
|
],
|
|
137
141
|
[Enums_1.HandlerTypes.PAGINATE]: [
|
|
142
|
+
new Phase_1.default("paginate.cache", GetCachePhase_1.default),
|
|
138
143
|
new Phase_1.default("paginate.prepareQuery", Paginate_1.default.PreparePhase),
|
|
139
144
|
new Hook_1.default(Enums_1.HookFunctionTypes.onBeforePaginate),
|
|
140
145
|
new Event_1.default(Enums_1.HookFunctionTypes.onBeforePaginate),
|
|
@@ -146,6 +151,7 @@ exports.HANDLER_CYLES = {
|
|
|
146
151
|
new Phase_1.default("paginate.response", List_1.default.ResultPhase),
|
|
147
152
|
],
|
|
148
153
|
[Enums_1.HandlerTypes.SHOW]: [
|
|
154
|
+
new Phase_1.default("paginate.cache", GetCachePhase_1.default),
|
|
149
155
|
new Phase_1.default("show.prepareQuery", Show_1.default.PreparePhase),
|
|
150
156
|
new Hook_1.default(Enums_1.HookFunctionTypes.onBeforeShow),
|
|
151
157
|
new Event_1.default(Enums_1.HookFunctionTypes.onBeforeShow),
|
|
@@ -169,6 +175,7 @@ exports.HANDLER_CYLES = {
|
|
|
169
175
|
new Phase_1.default("update.action", Update_1.default.ActionPhase),
|
|
170
176
|
new Hook_1.default(Enums_1.HookFunctionTypes.onAfterUpdate),
|
|
171
177
|
new Event_1.default(Enums_1.HookFunctionTypes.onAfterUpdate),
|
|
178
|
+
new Phase_1.default("cache.cleanTags", CacheTagCleanPhase_1.default),
|
|
172
179
|
new Phase_1.default("update.serialize", Single_1.default.SerializePhase),
|
|
173
180
|
new Phase_1.default("update.response", Single_1.default.ResultPhase),
|
|
174
181
|
],
|
|
@@ -184,6 +191,7 @@ exports.HANDLER_CYLES = {
|
|
|
184
191
|
new Phase_1.default("delete.action", Delete_1.default.ActionPhase),
|
|
185
192
|
new Hook_1.default(Enums_1.HookFunctionTypes.onAfterDelete),
|
|
186
193
|
new Event_1.default(Enums_1.HookFunctionTypes.onAfterDelete),
|
|
194
|
+
new Phase_1.default("cache.cleanTags", CacheTagCleanPhase_1.default),
|
|
187
195
|
new Phase_1.default("delete.response", Delete_1.default.ResponsePhase),
|
|
188
196
|
],
|
|
189
197
|
[Enums_1.HandlerTypes.FORCE_DELETE]: [
|
|
@@ -198,6 +206,7 @@ exports.HANDLER_CYLES = {
|
|
|
198
206
|
new Phase_1.default("force-delete.action", ForceDelete_1.default.ActionPhase),
|
|
199
207
|
new Hook_1.default(Enums_1.HookFunctionTypes.onAfterForceDelete),
|
|
200
208
|
new Event_1.default(Enums_1.HookFunctionTypes.onAfterForceDelete),
|
|
209
|
+
new Phase_1.default("cache.cleanTags", CacheTagCleanPhase_1.default),
|
|
201
210
|
new Phase_1.default("force-delete.response", Delete_1.default.ResponsePhase),
|
|
202
211
|
],
|
|
203
212
|
[Enums_1.HandlerTypes.PATCH]: [
|
|
@@ -213,10 +222,12 @@ exports.HANDLER_CYLES = {
|
|
|
213
222
|
new Phase_1.default("patch.action", Update_1.default.ActionPhase),
|
|
214
223
|
new Hook_1.default(Enums_1.HookFunctionTypes.onAfterUpdate),
|
|
215
224
|
new Event_1.default(Enums_1.HookFunctionTypes.onAfterUpdate),
|
|
225
|
+
new Phase_1.default("cache.cleanTags", CacheTagCleanPhase_1.default),
|
|
216
226
|
new Phase_1.default("patch.serialize", Single_1.default.SerializePhase),
|
|
217
227
|
new Phase_1.default("patch.response", Single_1.default.ResultPhase),
|
|
218
228
|
],
|
|
219
229
|
[Enums_1.HandlerTypes.ALL]: [
|
|
230
|
+
new Phase_1.default("paginate.cache", GetCachePhase_1.default),
|
|
220
231
|
new Phase_1.default("all.prepareQuery", Paginate_1.default.PreparePhase),
|
|
221
232
|
new Hook_1.default(Enums_1.HookFunctionTypes.onBeforePaginate),
|
|
222
233
|
new Event_1.default(Enums_1.HookFunctionTypes.onBeforePaginate),
|
|
@@ -228,6 +239,15 @@ exports.HANDLER_CYLES = {
|
|
|
228
239
|
new Phase_1.default("all.response", List_1.default.ResultPhase),
|
|
229
240
|
],
|
|
230
241
|
};
|
|
242
|
+
exports.DEFAULT_CACHE_CONFIGURATION = {
|
|
243
|
+
enable: false,
|
|
244
|
+
ttl: 100,
|
|
245
|
+
invalidation: Enums_1.CacheStrategies.TimeBased,
|
|
246
|
+
tagPrefix: "tag",
|
|
247
|
+
cachePrefix: "axe-cache",
|
|
248
|
+
responseHeader: "X-Axe-API-Cache",
|
|
249
|
+
cacheKey: Helpers_1.defaultCacheKeyFunction,
|
|
250
|
+
};
|
|
231
251
|
exports.DEFAULT_APP_CONFIG = {
|
|
232
252
|
prefix: "api",
|
|
233
253
|
env: "production",
|
|
@@ -241,9 +261,7 @@ exports.DEFAULT_APP_CONFIG = {
|
|
|
241
261
|
},
|
|
242
262
|
rateLimit: {
|
|
243
263
|
enabled: false,
|
|
244
|
-
adaptor:
|
|
245
|
-
type: "memory",
|
|
246
|
-
},
|
|
264
|
+
adaptor: "memory",
|
|
247
265
|
maxRequests: 200,
|
|
248
266
|
windowInSeconds: 5,
|
|
249
267
|
trustProxyIP: false,
|
|
@@ -255,6 +273,8 @@ exports.DEFAULT_APP_CONFIG = {
|
|
|
255
273
|
},
|
|
256
274
|
},
|
|
257
275
|
errorHandler: ErrorHandler_1.default,
|
|
276
|
+
redis: {},
|
|
277
|
+
cache: Object.assign({}, exports.DEFAULT_CACHE_CONFIGURATION),
|
|
258
278
|
};
|
|
259
279
|
exports.DEFAULT_VERSION_CONFIG = {
|
|
260
280
|
transaction: false,
|
|
@@ -276,4 +296,15 @@ exports.DEFAULT_VERSION_CONFIG = {
|
|
|
276
296
|
},
|
|
277
297
|
},
|
|
278
298
|
formidable: {},
|
|
299
|
+
cache: null,
|
|
279
300
|
};
|
|
301
|
+
exports.ALL_HANDLERS = [
|
|
302
|
+
Enums_1.HandlerTypes.ALL,
|
|
303
|
+
Enums_1.HandlerTypes.DELETE,
|
|
304
|
+
Enums_1.HandlerTypes.FORCE_DELETE,
|
|
305
|
+
Enums_1.HandlerTypes.INSERT,
|
|
306
|
+
Enums_1.HandlerTypes.PAGINATE,
|
|
307
|
+
Enums_1.HandlerTypes.PATCH,
|
|
308
|
+
Enums_1.HandlerTypes.SHOW,
|
|
309
|
+
Enums_1.HandlerTypes.UPDATE,
|
|
310
|
+
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "axe-api",
|
|
3
|
-
"version": "1.0.0-
|
|
3
|
+
"version": "1.0.0-rc23",
|
|
4
4
|
"description": "AXE API is a simple tool to create Rest APIs quickly.",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -64,8 +64,8 @@
|
|
|
64
64
|
"knex-paginate": "^3.1.1",
|
|
65
65
|
"knex-schema-inspector": "^3.0.1",
|
|
66
66
|
"nanoid": "^3.3.6",
|
|
67
|
-
"pino": "^8.
|
|
68
|
-
"pino-pretty": "^10.2.
|
|
67
|
+
"pino": "^8.16.1",
|
|
68
|
+
"pino-pretty": "^10.2.3",
|
|
69
69
|
"pluralize": "^8.0.0",
|
|
70
70
|
"validatorjs": "^3.22.1"
|
|
71
71
|
},
|
|
@@ -107,6 +107,7 @@
|
|
|
107
107
|
"set-value": ">=4.1.0",
|
|
108
108
|
"sqlite3": "^5.1.6",
|
|
109
109
|
"ts-node": "^10.9.1",
|
|
110
|
+
"ts-node-dev": "^2.0.0",
|
|
110
111
|
"typescript": "^5.2.2"
|
|
111
112
|
},
|
|
112
113
|
"lint-staged": {
|