axe-api 1.0.0-rc24 → 1.0.0-rc25

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.
@@ -17,7 +17,10 @@ export declare const getRelatedData: (version: IVersion, data: any[], withArray:
17
17
  export declare const isBoolean: (value: any) => boolean;
18
18
  export declare const getModelCacheConfiguration: (model: IModelService, apiConfig: ICacheConfiguration, versionConfig: ICacheConfiguration | null, handler: string) => ICacheConfiguration;
19
19
  export declare const defaultCacheKeyFunction: (req: AxeRequest) => string;
20
+ export declare const toCacheTagKey: (model: IModelService, primaryKeyValue: string, config?: ICacheConfiguration | null) => string;
20
21
  export declare const toCacheKey: (context: IContext) => string;
21
22
  export declare const putCache: (context: IContext, data: any) => Promise<void>;
23
+ export declare const deleteCacheTagMembers: (key: string) => Promise<void>;
24
+ export declare const cleanRelatedCachedObjectByModel: (model: IModelService, config?: ICacheConfiguration | null) => Promise<void>;
22
25
  export declare const clearCacheTags: (tag: string) => Promise<void>;
23
26
  export declare const toCachePrefix: (value: string | undefined | null) => string;
@@ -12,7 +12,7 @@ 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.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;
15
+ exports.toCachePrefix = exports.clearCacheTags = exports.cleanRelatedCachedObjectByModel = exports.deleteCacheTagMembers = exports.putCache = exports.toCacheKey = exports.toCacheTagKey = 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
16
  const crypto_1 = __importDefault(require("crypto"));
17
17
  const change_case_1 = require("change-case");
18
18
  const Enums_1 = require("../Enums");
@@ -225,10 +225,7 @@ const getRelatedData = (version, data, withArray, model, modelList, database, ha
225
225
  // Adding related data source to the request tags to set cache tag values
226
226
  const { primaryKey } = foreignModel.instance;
227
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]}`));
228
+ request.original.tags.push(...relatedRecords.map((i) => (0, exports.toCacheTagKey)(foreignModel, i[primaryKey], cacheConfig)));
232
229
  // We should serialize related data if there is any serialization function
233
230
  relatedRecords = yield (0, exports.serializeData)(version, relatedRecords, foreignModel.serialize, handler, request);
234
231
  // We should hide hidden fields if there is any
@@ -301,6 +298,13 @@ const defaultCacheKeyFunction = (req) => {
301
298
  });
302
299
  };
303
300
  exports.defaultCacheKeyFunction = defaultCacheKeyFunction;
301
+ const toCacheTagKey = (model, primaryKeyValue, config) => {
302
+ const prefix = (0, exports.toCachePrefix)(config === null || config === void 0 ? void 0 : config.cachePrefix);
303
+ const tagPrefix = (config === null || config === void 0 ? void 0 : config.tagPrefix) ? config === null || config === void 0 ? void 0 : config.tagPrefix : "";
304
+ const modelName = model.name.toLowerCase();
305
+ return `${prefix}:${tagPrefix}:${modelName}:${primaryKeyValue}`;
306
+ };
307
+ exports.toCacheTagKey = toCacheTagKey;
304
308
  const toCacheKey = (context) => {
305
309
  const { model, handlerType } = context;
306
310
  const config = model.getCacheConfiguration(handlerType);
@@ -308,7 +312,9 @@ const toCacheKey = (context) => {
308
312
  ? config.cacheKey(context.req)
309
313
  : (0, exports.defaultCacheKeyFunction)(context.req);
310
314
  const key = crypto_1.default.createHash("sha256").update(keyData).digest("hex");
311
- return (0, exports.toCachePrefix)(config === null || config === void 0 ? void 0 : config.cachePrefix) + key;
315
+ const prefix = (0, exports.toCachePrefix)(config === null || config === void 0 ? void 0 : config.cachePrefix);
316
+ const modelName = model.name.toLowerCase();
317
+ return `${prefix}:${modelName}:${key}`;
312
318
  };
313
319
  exports.toCacheKey = toCacheKey;
314
320
  const putCache = (context, data) => __awaiter(void 0, void 0, void 0, function* () {
@@ -316,27 +322,45 @@ const putCache = (context, data) => __awaiter(void 0, void 0, void 0, function*
316
322
  const { model, handlerType } = context;
317
323
  const config = model.getCacheConfiguration(handlerType);
318
324
  // Check if the cache enable for this handler
319
- if (config === null || config === void 0 ? void 0 : config.enable) {
320
- // Getting the redis service
321
- const redis = yield Services_1.IoCService.use("Redis");
322
- // Generating the cache key
323
- const key = (0, exports.toCacheKey)(context);
324
- // Setting the tags if the cache configuration of the model has been set as
325
- // tag-based cache invalidation strategy. Which means, the key cached value
326
- // can be deleted if the tagged items updated/delete
327
- if (config.invalidation === Enums_1.CacheStrategies.TagBased) {
328
- redis.tags(context.req.original.tags, key);
329
- }
330
- // Putting the cache data
331
- redis.set(key, JSON.stringify(data), config.ttl || 1000);
332
- if (config.responseHeader) {
333
- context.res.header(config.responseHeader, "Missed");
334
- }
335
- // Logging
336
- Services_1.LogService.debug(`\tšŸ”„ redis.cache(${key},${config.ttl})`);
325
+ if (!(config === null || config === void 0 ? void 0 : config.enable)) {
326
+ return;
327
+ }
328
+ // Getting the redis service
329
+ const redis = yield Services_1.IoCService.use("Redis");
330
+ // Generating the cache key
331
+ const key = (0, exports.toCacheKey)(context);
332
+ // Setting the tags if the cache configuration of the model has been set as
333
+ // tag-based cache invalidation strategy. Which means, the key cached value
334
+ // can be deleted if the tagged items updated/delete
335
+ if (config.invalidation === Enums_1.CacheStrategies.TagBased) {
336
+ redis.tags(context.req.original.tags, key);
337
337
  }
338
+ // Putting the cache data
339
+ redis.set(key, JSON.stringify(data), config.ttl || 1000);
340
+ if (config.responseHeader) {
341
+ context.res.header(config.responseHeader, "Missed");
342
+ }
343
+ // Logging
344
+ Services_1.LogService.debug(`\tšŸ”„ redis.cache(${key},${config.ttl})`);
338
345
  });
339
346
  exports.putCache = putCache;
347
+ const deleteCacheTagMembers = (key) => __awaiter(void 0, void 0, void 0, function* () {
348
+ const redis = yield Services_1.IoCService.use("Redis");
349
+ const members = yield redis.getTagMemebers(key);
350
+ yield redis.delete(members);
351
+ });
352
+ exports.deleteCacheTagMembers = deleteCacheTagMembers;
353
+ const cleanRelatedCachedObjectByModel = (model, config) => __awaiter(void 0, void 0, void 0, function* () {
354
+ const redis = yield Services_1.IoCService.use("Redis");
355
+ const prefix = (0, exports.toCachePrefix)(config === null || config === void 0 ? void 0 : config.cachePrefix);
356
+ const tagPrefix = (config === null || config === void 0 ? void 0 : config.tagPrefix) ? config === null || config === void 0 ? void 0 : config.tagPrefix : "";
357
+ const modelName = model.name.toLowerCase();
358
+ const searchKey = `${prefix}:${tagPrefix}:${modelName}:*`;
359
+ const { keys } = yield redis.searchTags(searchKey);
360
+ const tasks = keys.map((key) => (0, exports.deleteCacheTagMembers)(key));
361
+ Promise.all(tasks);
362
+ });
363
+ exports.cleanRelatedCachedObjectByModel = cleanRelatedCachedObjectByModel;
340
364
  const clearCacheTags = (tag) => __awaiter(void 0, void 0, void 0, function* () {
341
365
  const redis = yield Services_1.IoCService.use("Redis");
342
366
  const members = yield redis.getTagMemebers(tag);
@@ -346,6 +370,6 @@ const clearCacheTags = (tag) => __awaiter(void 0, void 0, void 0, function* () {
346
370
  });
347
371
  exports.clearCacheTags = clearCacheTags;
348
372
  const toCachePrefix = (value) => {
349
- return value ? `${value}:` : "";
373
+ return value ? value : "";
350
374
  };
351
375
  exports.toCachePrefix = toCachePrefix;
@@ -11,5 +11,9 @@ declare class RedisAdaptor implements ICacheAdaptor {
11
11
  getTagMemebers(tag: string): Promise<string[]>;
12
12
  delete(keys: string[]): Promise<number>;
13
13
  decr(key: string): Promise<void>;
14
+ searchTags(pattern: string): Promise<{
15
+ cursor: number;
16
+ keys: string[];
17
+ }>;
14
18
  }
15
19
  export default RedisAdaptor;
@@ -48,5 +48,12 @@ class RedisAdaptor {
48
48
  yield this.client.decr(`${this.prefix}${key}`);
49
49
  });
50
50
  }
51
+ searchTags(pattern) {
52
+ return __awaiter(this, void 0, void 0, function* () {
53
+ return yield this.client.scan(0, {
54
+ MATCH: pattern,
55
+ });
56
+ });
57
+ }
51
58
  }
52
59
  exports.default = RedisAdaptor;
@@ -14,6 +14,5 @@ exports.default = (context) => __awaiter(void 0, void 0, void 0, function* () {
14
14
  const { item, model, handlerType } = context;
15
15
  const { primaryKey } = model.instance;
16
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]}`);
17
+ (0, Helpers_1.clearCacheTags)((0, Helpers_1.toCacheTagKey)(model, item[primaryKey], config));
19
18
  });
@@ -15,8 +15,7 @@ exports.default = (context) => __awaiter(void 0, void 0, void 0, function* () {
15
15
  // Adding cache tags
16
16
  const { primaryKey } = model.instance;
17
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]}`));
18
+ context.req.original.tags.push(...result.data.map((i) => (0, Helpers_1.toCacheTagKey)(model, i[primaryKey], config)));
20
19
  // Caching the results
21
20
  yield (0, Helpers_1.putCache)(context, result);
22
21
  res.json(result);
@@ -15,8 +15,7 @@ exports.default = (context) => __awaiter(void 0, void 0, void 0, function* () {
15
15
  // Adding cache tags
16
16
  const { primaryKey } = model.instance;
17
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]}`);
18
+ context.req.original.tags.push((0, Helpers_1.toCacheTagKey)(model, item[primaryKey], config));
20
19
  // Caching the results
21
20
  yield (0, Helpers_1.putCache)(context, item);
22
21
  res.json(item);
@@ -0,0 +1,3 @@
1
+ import { IContext } from "../../Interfaces";
2
+ declare const _default: (context: IContext) => Promise<void>;
3
+ export default _default;
@@ -0,0 +1,20 @@
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, res, model, handlerType } = context;
15
+ // Deleting all cached result for the model
16
+ const config = model.getCacheConfiguration(handlerType);
17
+ (0, Helpers_1.cleanRelatedCachedObjectByModel)(model, config);
18
+ // Preparing the json response
19
+ res.json(item);
20
+ });
@@ -1,5 +1,6 @@
1
1
  declare const _default: {
2
2
  PreparePhase: (context: import("../../Interfaces").IContext) => Promise<void>;
3
3
  ActionPhase: (context: import("../../Interfaces").IContext) => Promise<void>;
4
+ ResultPhase: (context: import("../../Interfaces").IContext) => Promise<void>;
4
5
  };
5
6
  export default _default;
@@ -5,7 +5,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const PreparePhase_1 = __importDefault(require("./PreparePhase"));
7
7
  const ActionPhase_1 = __importDefault(require("./ActionPhase"));
8
+ const ResultPhase_1 = __importDefault(require("./ResultPhase"));
8
9
  exports.default = {
9
10
  PreparePhase: PreparePhase_1.default,
10
11
  ActionPhase: ActionPhase_1.default,
12
+ ResultPhase: ResultPhase_1.default,
11
13
  };
@@ -51,6 +51,7 @@ const RequestHandler_1 = __importDefault(require("./Handlers/RequestHandler"));
51
51
  const App_1 = __importDefault(require("./Services/App"));
52
52
  const constants_1 = require("./constants");
53
53
  const RedisAdaptor_1 = __importDefault(require("./Middlewares/RateLimit/RedisAdaptor"));
54
+ const RateLimit_1 = __importDefault(require("./Middlewares/RateLimit"));
54
55
  class Server {
55
56
  /**
56
57
  * Start the application with the rootFolder.
@@ -126,6 +127,7 @@ class Server {
126
127
  });
127
128
  }
128
129
  listen() {
130
+ var _a;
129
131
  return __awaiter(this, void 0, void 0, function* () {
130
132
  const app = yield Services_1.IoCService.use("App");
131
133
  const api = Services_1.APIService.getInstance();
@@ -142,6 +144,11 @@ class Server {
142
144
  app.get("/docs", DocsHandler_1.default);
143
145
  app.get("/routes", RoutesHandler_1.default);
144
146
  }
147
+ // Rate limitting should be added after init() functions.
148
+ if ((_a = api.config.rateLimit) === null || _a === void 0 ? void 0 : _a.enabled) {
149
+ Services_1.LogService.debug("New middleware: rateLimit()");
150
+ app.use(RateLimit_1.default);
151
+ }
145
152
  server.listen(api.config.port);
146
153
  Services_1.LogService.info(`Axe API listens requests on http://localhost:${api.config.port}`);
147
154
  });
@@ -1,27 +1,4 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
4
  };
@@ -30,14 +7,13 @@ const connect_1 = __importDefault(require("connect"));
30
7
  const body_parser_1 = __importDefault(require("body-parser"));
31
8
  const URLService_1 = __importDefault(require("./URLService"));
32
9
  const LogService_1 = __importDefault(require("./LogService"));
33
- const RateLimit_1 = __importStar(require("../Middlewares/RateLimit"));
10
+ const RateLimit_1 = require("../Middlewares/RateLimit");
34
11
  const APIService_1 = __importDefault(require("./APIService"));
35
12
  const ConverterService_1 = require("./ConverterService");
36
13
  const DocumentationService_1 = __importDefault(require("./DocumentationService"));
37
14
  const Enums_1 = require("../Enums");
38
15
  class App {
39
16
  constructor() {
40
- var _a;
41
17
  this.docs = DocumentationService_1.default.getInstance();
42
18
  this.connect = (0, connect_1.default)();
43
19
  LogService_1.default.debug("Created a new connect() instance");
@@ -47,10 +23,6 @@ class App {
47
23
  // Activate the Rate Limit middleware
48
24
  const api = APIService_1.default.getInstance();
49
25
  (0, RateLimit_1.setupRateLimitAdaptors)(api.config);
50
- if ((_a = api.config.rateLimit) === null || _a === void 0 ? void 0 : _a.enabled) {
51
- LogService_1.default.debug("New middleware: rateLimit()");
52
- this.connect.use(RateLimit_1.default);
53
- }
54
26
  }
55
27
  /**
56
28
  * Get the `connect` instance
@@ -136,7 +136,7 @@ exports.HANDLER_CYLES = {
136
136
  new Hook_1.default(Enums_1.HookFunctionTypes.onAfterInsert),
137
137
  new Event_1.default(Enums_1.HookFunctionTypes.onAfterInsert),
138
138
  new Phase_1.default("insert.serialize", Single_1.default.SerializePhase),
139
- new Phase_1.default("insert.response", Single_1.default.ResultPhase),
139
+ new Phase_1.default("insert.response", Store_1.default.ResultPhase),
140
140
  ],
141
141
  [Enums_1.HandlerTypes.PAGINATE]: [
142
142
  new Phase_1.default("paginate.cache", GetCachePhase_1.default),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "axe-api",
3
- "version": "1.0.0-rc24",
3
+ "version": "1.0.0-rc25",
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",