🚀. Socket Launch Week Day 2:Introducing Manifest Alerts.Learn more
Sign In

@athenna/cache

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@athenna/cache - npm Package Compare versions

Comparing version
5.1.0
to
5.2.0
configurer/cache

Sorry, the diff of this file is not supported yet

+8
version: '3'
services:
redis:
container_name: athenna_redis
image: redis
ports:
- '6379:6379'
/**
* @athenna/cache
*
* (c) João Lenon <lenon@athenna.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare const _default: {
container_name: string;
image: string;
ports: string[];
};
export default _default;
/**
* @athenna/cache
*
* (c) João Lenon <lenon@athenna.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
export default {
container_name: 'athenna_redis',
image: 'redis',
ports: ['6379:6379']
};
/**
* @athenna/cache
*
* (c) João Lenon <lenon@athenna.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
export default {
container_name: 'athenna_redis',
image: 'redis',
ports: ['6379:6379']
}
/**
* @athenna/cache
*
* (c) João Lenon <lenon@athenna.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
import type { RedisClientType } from 'redis';
import type { StoreOptions } from '#src/types';
import { Driver } from '#src/cache/drivers/Driver';
export declare class RedisDriver extends Driver<RedisClientType> {
/**
* Redis database URL.
*/
url: string;
/**
* Redis database socket.
*/
socket: any;
/**
* Redis database host.
*/
host: string;
/**
* Redis database port.
*/
port: number;
/**
* Redis connection protocol.
*/
protocol: string;
/**
* Redis database username.
*/
username: string;
/**
* Redis database password.
*/
password: string;
/**
* Redis database number.
*/
database: number;
constructor(store: string, client?: any, options?: StoreOptions['options']);
/**
* Connect to client.
*/
connect(options: StoreOptions): void;
/**
* Close the connection with the client in this instance.
*/
close(): Promise<void>;
/**
* Reset all data defined inside cache.
*/
truncate(): Promise<void>;
/**
* Get a value from the cache.
*/
get<T = any>(key: string, defaultValue?: T): Promise<T>;
/**
* Validate if a value exists in the cache.
*/
has(key: string): Promise<boolean>;
/**
* Set a value in the cache.
*/
set(key: string, value: any, options?: {
ttl?: number;
}): Promise<void>;
/**
* Get a value from the cache and delete it at
* the same time.
*/
pull<T = any>(key: string): Promise<T>;
/**
* Delete a value from the cache.
*/
delete(key: string): Promise<void>;
}
/**
* @athenna/cache
*
* (c) João Lenon <lenon@athenna.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
import { Log } from '@athenna/logger';
import { Config } from '@athenna/config';
import { Driver } from '#src/cache/drivers/Driver';
import { Is, Parser, Options } from '@athenna/common';
import { StoreFactory } from '#src/factories/StoreFactory';
export class RedisDriver extends Driver {
constructor(store, client = null, options) {
super(store, client, options);
const config = Config.get(`cache.stores.${store}`);
this.url = options?.url || config?.url;
this.host = options?.host || config?.host;
this.port = options?.port || config?.port || 6379;
this.socket = options?.socket || config?.socket;
this.username = options?.username || config?.username;
this.password = options?.password || config?.password;
this.database = options?.database || config?.database || 0;
this.protocol = options?.protocol || config?.protocol || 'redis';
if (!this.url) {
this.url = Parser.connectionObjToDbUrl({
host: this.host,
port: this.port,
user: this.username,
password: this.password,
protocol: this.protocol,
database: ''
});
this.url = `${this.url.slice(0, -1)}?database=${this.database}`;
}
}
/**
* Connect to client.
*/
connect(options) {
options = Options.create(options, {
force: false,
connect: true,
saveOnFactory: true
});
if (!options.connect) {
return;
}
if (this.isConnected && !options.force) {
return;
}
const { createClient } = this.getRedis();
this.client = createClient({ url: this.url, socket: this.socket });
this.client
.connect()
.then(() => {
if (Config.is('rc.bootLogs', true)) {
Log.channelOrVanilla('application').success(`Successfully connected to ({yellow} ${this.store}) cache store`);
}
})
.catch(err => {
console.error(err);
});
this.isConnected = true;
this.isSavedOnFactory = options.saveOnFactory;
if (options.saveOnFactory) {
StoreFactory.setClient(this.store, this.client);
}
}
/**
* Close the connection with the client in this instance.
*/
async close() {
if (!this.client || !this.isConnected) {
return;
}
try {
await this.client.quit();
}
finally {
this.client = null;
this.isConnected = false;
StoreFactory.setClient(this.store, null);
}
}
/**
* Reset all data defined inside cache.
*/
async truncate() {
let cursor = '0';
do {
const response = await this.client.scan(cursor, {
COUNT: 500,
MATCH: `${this.prefix}*`
});
cursor = response.cursor;
if (response.keys.length) {
await this.client.del(response.keys);
}
} while (cursor !== '0');
}
/**
* Get a value from the cache.
*/
async get(key, defaultValue) {
const value = await this.client.get(this.getCacheKey(key));
if (Is.Null(value) || Is.Undefined(value)) {
return defaultValue;
}
return value;
}
/**
* Validate if a value exists in the cache.
*/
async has(key) {
const value = await this.get(key);
return !!value;
}
/**
* Set a value in the cache.
*/
async set(key, value, options) {
await this.client.set(this.getCacheKey(key), value, {
expiration: {
type: 'EX',
value: Math.ceil((options?.ttl || this.ttl) / 1000)
}
});
}
/**
* Get a value from the cache and delete it at
* the same time.
*/
async pull(key) {
const value = await this.get(key);
await this.delete(key);
return value;
}
/**
* Delete a value from the cache.
*/
async delete(key) {
await this.client.del(this.getCacheKey(key));
}
}
+33
-1

@@ -9,7 +9,9 @@ /**

*/
import { File, Path } from '@athenna/common';
import { BaseConfigurer } from '@athenna/artisan';
import { File, Path, Parser, Module } from '@athenna/common';
export default class CacheConfigurer extends BaseConfigurer {
async configure() {
const stores = await this.prompt.checkbox('Which cache stores do you plan to use?', ['redis', 'memory']);
const task = this.logger.task();
const hasSelectedRedis = stores.find(store => store === 'redis');
task.addPromise(`Create cache.${Path.ext()} config file`, () => {

@@ -23,2 +25,32 @@ return new File('./cache').copy(Path.config(`cache.${Path.ext()}`));

});
task.addPromise('Update .env, .env.test and .env.example', () => {
let envs = '\nCACHE_STORE=memory\n';
if (hasSelectedRedis) {
envs += 'REDIS_URL=redis://localhost:6379?database=0\n';
}
return new File(Path.pwd('.env'), '')
.append(envs)
.then(() => new File(Path.pwd('.env.test'), '').append(envs))
.then(() => new File(Path.pwd('.env.example'), '').append(envs));
});
if (hasSelectedRedis) {
task.addPromise('Add service to docker-compose.yml file', async () => {
const hasDockerCompose = await File.exists(Path.pwd('docker-compose.yml'));
if (hasDockerCompose) {
const docker = await new File(Path.pwd('docker-compose.yml')).getContentAsYaml();
docker.services.redis = await Module.get(import('./docker/redis/service.js'));
return new File(Path.pwd('docker-compose.yml')).setContent(Parser.objectToYamlString(docker));
}
return new File(`./docker/redis/file.yml`).copy(Path.pwd('docker-compose.yml'));
});
}
const libraries = {
redis: ['redis'],
memory: ['lru-cache']
};
task.addPromise(`Install ${stores.join(', ')} libraries`, () => {
return stores.athenna.concurrently(store => {
return this.npm.install(libraries[store]);
});
});
await task.run();

@@ -25,0 +57,0 @@ console.log();

@@ -10,8 +10,14 @@ /**

import { File, Path } from '@athenna/common'
import { BaseConfigurer } from '@athenna/artisan'
import { File, Path, Parser, Module } from '@athenna/common'
export default class CacheConfigurer extends BaseConfigurer {
public async configure() {
const stores = await this.prompt.checkbox(
'Which cache stores do you plan to use?',
['redis', 'memory']
)
const task = this.logger.task()
const hasSelectedRedis = stores.find(store => store === 'redis')

@@ -28,2 +34,52 @@ task.addPromise(`Create cache.${Path.ext()} config file`, () => {

task.addPromise('Update .env, .env.test and .env.example', () => {
let envs = '\nCACHE_STORE=memory\n'
if (hasSelectedRedis) {
envs += 'REDIS_URL=redis://localhost:6379?database=0\n'
}
return new File(Path.pwd('.env'), '')
.append(envs)
.then(() => new File(Path.pwd('.env.test'), '').append(envs))
.then(() => new File(Path.pwd('.env.example'), '').append(envs))
})
if (hasSelectedRedis) {
task.addPromise('Add service to docker-compose.yml file', async () => {
const hasDockerCompose = await File.exists(
Path.pwd('docker-compose.yml')
)
if (hasDockerCompose) {
const docker = await new File(
Path.pwd('docker-compose.yml')
).getContentAsYaml()
docker.services.redis = await Module.get(
import('./docker/redis/service.js')
)
return new File(Path.pwd('docker-compose.yml')).setContent(
Parser.objectToYamlString(docker)
)
}
return new File(`./docker/redis/file.yml`).copy(
Path.pwd('docker-compose.yml')
)
})
}
const libraries = {
redis: ['redis'],
memory: ['lru-cache']
}
task.addPromise(`Install ${stores.join(', ')} libraries`, () => {
return stores.athenna.concurrently(store => {
return this.npm.install(libraries[store])
})
})
await task.run()

@@ -30,0 +86,0 @@

+4
-5
{
"name": "@athenna/cache",
"version": "5.1.0",
"version": "5.2.0",
"description": "The cache handler for Athenna Framework.",

@@ -73,3 +73,5 @@ "license": "MIT",

"lint-staged": "^12.5.0",
"prettier": "^2.8.8"
"lru-cache": "^11.1.0",
"prettier": "^2.8.8",
"redis": "^5.8.1"
},

@@ -168,6 +170,3 @@ "c8": {

}
},
"dependencies": {
"lru-cache": "^11.1.0"
}
}

@@ -11,3 +11,4 @@ /**

import type { StoreOptions } from '#src/types/StoreOptions';
import { MemoryDriver } from '#src/cache/drivers/MemoryDriver';
import type { RedisDriver } from '#src/cache/drivers/RedisDriver';
import type { MemoryDriver } from '#src/cache/drivers/MemoryDriver';
import type { Driver as DriverImpl } from '#src/cache/drivers/Driver';

@@ -22,3 +23,3 @@ export declare class CacheImpl<Driver extends DriverImpl = any> extends Macroable {

*/
driver: Driver;
driver: RedisDriver | MemoryDriver;
/**

@@ -28,4 +29,5 @@ * Creates a new instance of CacheImpl.

constructor(athennaCacheOpts?: StoreOptions);
store(store: 'redis', options?: StoreOptions): CacheImpl<RedisDriver>;
store(store: 'memory', options?: StoreOptions): CacheImpl<MemoryDriver>;
store(store: 'memory' | string): CacheImpl<MemoryDriver>;
store(store: 'redis' | 'memory' | string, options?: StoreOptions): CacheImpl<RedisDriver> | CacheImpl<MemoryDriver>;
/**

@@ -104,3 +106,3 @@ * Verify if client is already connected.

*/
pull(key: string): Promise<string>;
pull(key: string): Promise<any>;
/**

@@ -107,0 +109,0 @@ * Delete a value from the cache my its key.

@@ -11,3 +11,2 @@ /**

import { StoreFactory } from '#src/factories/StoreFactory';
import { MemoryDriver } from '#src/cache/drivers/MemoryDriver';
export class CacheImpl extends Macroable {

@@ -14,0 +13,0 @@ /**

@@ -32,2 +32,6 @@ /**

/**
* Set the cache prefix of the driver.
*/
prefix: string;
/**
* Define the max number of items that could be inserted in the cache.

@@ -45,2 +49,10 @@ */

/**
* Import the redis module if it exists.
*/
getRedis(): any;
/**
* Import the lru-cache module if it exists.
*/
getLruCache(): any;
/**
* Clone the driver instance.

@@ -58,2 +70,11 @@ */

/**
* Sanitize the cache prefix by removing any trailing colons.
*/
sanitizePrefix(prefix: string): string;
/**
* Automatically set the cache prefix if it exists.
* Otherwise just return the key defined.
*/
getCacheKey(key: string): string;
/**
* Connect to client.

@@ -60,0 +81,0 @@ */

@@ -10,2 +10,3 @@ /**

import { Config } from '@athenna/config';
import { Module } from '@athenna/common';
export class Driver {

@@ -32,2 +33,3 @@ /**

this.maxEntrySize = options?.maxEntrySize || config.maxEntrySize;
this.prefix = this.sanitizePrefix(options?.prefix || config?.prefix);
this.store = store;

@@ -41,2 +43,16 @@ if (client) {

/**
* Import the redis module if it exists.
*/
getRedis() {
const require = Module.createRequire(import.meta.url);
return require('redis');
}
/**
* Import the lru-cache module if it exists.
*/
getLruCache() {
const require = Module.createRequire(import.meta.url);
return require('lru-cache');
}
/**
* Clone the driver instance.

@@ -62,2 +78,21 @@ */

}
/**
* Sanitize the cache prefix by removing any trailing colons.
*/
sanitizePrefix(prefix) {
if (!prefix) {
return '';
}
return prefix.replace(/:+$/, '');
}
/**
* Automatically set the cache prefix if it exists.
* Otherwise just return the key defined.
*/
getCacheKey(key) {
if (this.prefix) {
return `${this.prefix}:${key}`;
}
return key;
}
}

@@ -9,3 +9,3 @@ /**

*/
import { LRUCache } from 'lru-cache';
import type { LRUCache } from 'lru-cache';
import type { StoreOptions } from '#src/types';

@@ -12,0 +12,0 @@ import { Driver } from '#src/cache/drivers/Driver';

@@ -9,3 +9,2 @@ /**

*/
import { LRUCache } from 'lru-cache';
import { Driver } from '#src/cache/drivers/Driver';

@@ -30,2 +29,3 @@ import { Parser, Options, Is } from '@athenna/common';

}
const { LRUCache } = this.getLruCache();
this.client = new LRUCache({

@@ -32,0 +32,0 @@ max: this.maxItems,

@@ -11,2 +11,3 @@ /**

import type { Driver } from '#src/cache/drivers/Driver';
import { RedisDriver } from '#src/cache/drivers/RedisDriver';
import { MemoryDriver } from '#src/cache/drivers/MemoryDriver';

@@ -22,4 +23,7 @@ export declare class StoreFactory {

static drivers: Map<string, any>;
static fabricate(store: 'redis', options?: StoreOptions['options']): RedisDriver;
static fabricate(store: 'redis' | string, options?: StoreOptions['options']): RedisDriver;
static fabricate(con: 'memory', options?: StoreOptions['options']): MemoryDriver;
static fabricate(con: 'memory' | string, options?: StoreOptions['options']): MemoryDriver;
static fabricate(con: 'redis' | 'memory' | string, options?: StoreOptions['options']): RedisDriver | MemoryDriver;
/**

@@ -26,0 +30,0 @@ * Verify if client is present on a driver connection.

@@ -10,2 +10,3 @@ /**

import { debug } from '#src/debug';
import { RedisDriver } from '#src/cache/drivers/RedisDriver';
import { MemoryDriver } from '#src/cache/drivers/MemoryDriver';

@@ -22,3 +23,5 @@ import { NotFoundDriverException } from '#src/exceptions/NotFoundDriverException';

*/
static { this.drivers = new Map().set('memory', MemoryDriver); }
static { this.drivers = new Map()
.set('redis', RedisDriver)
.set('memory', MemoryDriver); }
/**

@@ -25,0 +28,0 @@ * Fabricate a new connection for a specific driver.

@@ -51,2 +51,9 @@ /**

/**
* Define a prefix for the store. By default, prefix
* will always be used in front of your keys if it exists.
*
* @default Config.get(`cache.stores.${store}.prefix`)
*/
prefix?: string;
/**
* Define the max number of items that could be inserted in the cache.

@@ -53,0 +60,0 @@ *