@akanjs/nest 0.0.54 → 0.0.56

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,109 @@
1
+ import { baseEnv } from "@akanjs/base";
2
+ import { createHash } from "crypto";
3
+ import { createTunnel } from "tunnel-ssh";
4
+ const generateHexStringFromSeed = (seed, length = 256) => {
5
+ let hexString = "";
6
+ let currentSeed = seed;
7
+ while (hexString.length < length * 2) {
8
+ const hash = createHash("sha256").update(currentSeed).digest("hex");
9
+ hexString += hash;
10
+ currentSeed = hash;
11
+ }
12
+ return hexString.substring(0, length * 2);
13
+ };
14
+ const generateJwtSecret = (appName, environment) => {
15
+ const seed = `${appName}-${environment}-jwt-secret`;
16
+ return generateHexStringFromSeed(seed);
17
+ };
18
+ const generateAeskey = (appName, environment) => {
19
+ const seed = `${appName}-${environment}-aes-key`;
20
+ return createHash("sha256").update(seed).digest("hex");
21
+ };
22
+ const DEFAULT_CLOUD_PORT = 3e4;
23
+ const getEnvironmentPort = (environment) => environment === "main" ? 2e3 : environment === "develop" ? 1e3 : environment === "debug" ? 0 : 0;
24
+ const getServicePort = (appCode, service) => (service === "redis" ? 300 : service === "mongo" ? 400 : 500) + appCode % 10 * 10 + (appCode >= 10 ? 5 : 0);
25
+ const createDatabaseTunnel = async ({
26
+ appName,
27
+ environment,
28
+ type,
29
+ port,
30
+ sshOptions = {
31
+ host: `${appName}-${environment}.${baseEnv.serveDomain}`,
32
+ port: 32767,
33
+ username: baseEnv.tunnelUsername,
34
+ password: baseEnv.tunnelPassword
35
+ }
36
+ }) => {
37
+ const tunnelOptions = { autoClose: true, reconnectOnError: false };
38
+ const serverOptions = { port };
39
+ const forwardOptions = {
40
+ srcAddr: "0.0.0.0",
41
+ srcPort: port,
42
+ dstAddr: `${type}-0.${type}-svc.${appName}-${environment}`,
43
+ dstPort: type === "mongo" ? 27017 : type === "redis" ? 6379 : 7700
44
+ };
45
+ const [server, client] = await createTunnel(tunnelOptions, serverOptions, sshOptions, forwardOptions);
46
+ return `localhost:${port}`;
47
+ };
48
+ const generateRedisUri = async ({ appName, appCode, environment, operationMode, sshOptions }) => {
49
+ if (process.env.REDIS_URI)
50
+ return process.env.REDIS_URI;
51
+ const port = operationMode === "local" ? DEFAULT_CLOUD_PORT + getEnvironmentPort(environment) + getServicePort(appCode, "redis") : 6379;
52
+ const url = operationMode === "cloud" ? `redis-svc.${appName}-${environment}.svc.cluster.local` : operationMode === "local" ? await createDatabaseTunnel({ appName, environment, type: "redis", port, sshOptions }) : "localhost:6379";
53
+ const uri = `redis://${url}`;
54
+ return uri;
55
+ };
56
+ const generateMongoUri = async ({
57
+ appName,
58
+ appCode,
59
+ environment,
60
+ operationMode,
61
+ username = `${appName}-${environment}-mongo-user`,
62
+ password,
63
+ sshOptions
64
+ }) => {
65
+ if (process.env.MONGO_URI)
66
+ return process.env.MONGO_URI;
67
+ const record = operationMode === "cloud" ? "mongodb+srv" : "mongodb";
68
+ const port = operationMode === "local" ? DEFAULT_CLOUD_PORT + getEnvironmentPort(environment) + getServicePort(appCode, "mongo") : 27017;
69
+ const url = operationMode === "cloud" ? `mongo-svc.${appName}-${environment}.svc.cluster.local` : operationMode === "local" ? await createDatabaseTunnel({ appName, environment, type: "mongo", port, sshOptions }) : "localhost:27017";
70
+ const usernameEncoded = password ? encodeURIComponent(username) : null;
71
+ const passwordEncoded = password ? encodeURIComponent(password) : null;
72
+ const dbName = `${appName}-${environment}`;
73
+ const directConnection = operationMode === "cloud" ? false : true;
74
+ const authInfo = usernameEncoded ? `${usernameEncoded}:${passwordEncoded}@` : "";
75
+ const uri = `${record}://${authInfo}${url}/${dbName}?authSource=${dbName}&readPreference=primary&ssl=false&retryWrites=true&directConnection=${directConnection}`;
76
+ return uri;
77
+ };
78
+ const generateMeiliUri = ({ appName, appCode, environment, operationMode }) => {
79
+ if (process.env.MEILI_URI)
80
+ return process.env.MEILI_URI;
81
+ const protocol = operationMode === "local" ? "https" : "http";
82
+ const url = operationMode === "cloud" ? `meili-0.meili-svc.${appName}-${environment}.svc.cluster.local:7700` : operationMode === "local" ? `${appName}-${environment}.${baseEnv.serveDomain}/search` : "localhost:7700";
83
+ const uri = `${protocol}://${url}`;
84
+ return uri;
85
+ };
86
+ const SALT_ROUNDS = 11;
87
+ const generateHost = (env) => {
88
+ if (process.env.HOST_NAME)
89
+ return process.env.HOST_NAME;
90
+ else if (env.hostname)
91
+ return env.hostname;
92
+ else if (env.operationMode === "local")
93
+ return "localhost";
94
+ else
95
+ return `${env.appName}-${env.environment}.${baseEnv.serveDomain}`;
96
+ };
97
+ const generateMeiliKey = ({ appName, environment }) => {
98
+ return `meilisearch-key-${appName}-${environment}`;
99
+ };
100
+ export {
101
+ SALT_ROUNDS,
102
+ generateAeskey,
103
+ generateHost,
104
+ generateJwtSecret,
105
+ generateMeiliKey,
106
+ generateMeiliUri,
107
+ generateMongoUri,
108
+ generateRedisUri
109
+ };
package/src/index.mjs ADDED
@@ -0,0 +1,22 @@
1
+ export * from "./authorization";
2
+ export * from "./authGuards";
3
+ import * as guards from "./authGuards";
4
+ export * from "./authentication";
5
+ export * from "./interceptors";
6
+ export * from "./redis-io.adapter";
7
+ export * from "./pipes";
8
+ import * as Exporter from "./exporter";
9
+ export * from "./exporter";
10
+ export * from "./verifyPayment";
11
+ export * from "./sso";
12
+ export * from "./exceptions";
13
+ export * from "./generateSecrets";
14
+ export * from "./mongoose";
15
+ export * from "./searchClient";
16
+ export * from "./cacheClient";
17
+ export * from "./databaseClient";
18
+ export * from "./decorators";
19
+ export {
20
+ Exporter,
21
+ guards
22
+ };
@@ -0,0 +1,169 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result)
9
+ __defProp(target, key, result);
10
+ return result;
11
+ };
12
+ var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
13
+ var __accessCheck = (obj, member, msg) => {
14
+ if (!member.has(obj))
15
+ throw TypeError("Cannot " + msg);
16
+ };
17
+ var __privateGet = (obj, member, getter) => {
18
+ __accessCheck(obj, member, "read from private field");
19
+ return getter ? getter.call(obj) : member.get(obj);
20
+ };
21
+ var __privateAdd = (obj, member, value) => {
22
+ if (member.has(obj))
23
+ throw TypeError("Cannot add the same private member more than once");
24
+ member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
25
+ };
26
+ var __privateMethod = (obj, member, method) => {
27
+ __accessCheck(obj, member, "access private method");
28
+ return method;
29
+ };
30
+ var _logger, _CACHE_PREFIX, _generateCacheKey, generateCacheKey_fn, _getCache, getCache_fn, _setCache, setCache_fn;
31
+ import { Logger } from "@akanjs/common";
32
+ import { getGqlMeta } from "@akanjs/signal";
33
+ import {
34
+ Inject,
35
+ Injectable,
36
+ RequestTimeoutException
37
+ } from "@nestjs/common";
38
+ import { GqlExecutionContext } from "@nestjs/graphql";
39
+ import { throwError, TimeoutError } from "rxjs";
40
+ import { catchError, map, tap, timeout } from "rxjs/operators";
41
+ import { getArgs, getRequest } from "./authGuards";
42
+ let CacheInterceptor = class {
43
+ constructor(redis) {
44
+ this.redis = redis;
45
+ __privateAdd(this, _generateCacheKey);
46
+ __privateAdd(this, _getCache);
47
+ __privateAdd(this, _setCache);
48
+ __privateAdd(this, _logger, new Logger("CacheInterceptor"));
49
+ __privateAdd(this, _CACHE_PREFIX, "signal:");
50
+ }
51
+ async intercept(context, next) {
52
+ const handler = context.getHandler();
53
+ const signalKey = handler.name;
54
+ const gqlMeta = getGqlMeta(context.getClass(), signalKey);
55
+ if (gqlMeta.type !== "Query" || !gqlMeta.signalOption.cache) {
56
+ if (gqlMeta.signalOption.cache)
57
+ __privateGet(this, _logger).warn(`CacheInterceptor: ${signalKey} is not Query endpoint or cache is not set`);
58
+ return next.handle();
59
+ }
60
+ const args = getArgs(context);
61
+ const cacheKey = __privateMethod(this, _generateCacheKey, generateCacheKey_fn).call(this, signalKey, args);
62
+ const cachedData = await __privateMethod(this, _getCache, getCache_fn).call(this, cacheKey);
63
+ if (cachedData) {
64
+ __privateGet(this, _logger).debug(`Cache hit for key: ${cacheKey}`);
65
+ return next.handle().pipe(
66
+ map(() => cachedData),
67
+ catchError((error) => {
68
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
69
+ __privateGet(this, _logger).error(`Error in cache interceptor for ${cacheKey}: ${errorMessage}`);
70
+ return throwError(() => error);
71
+ })
72
+ );
73
+ }
74
+ return next.handle().pipe(
75
+ map((data) => {
76
+ const cacheDuration = gqlMeta.signalOption.cache;
77
+ if (typeof cacheDuration === "number") {
78
+ void __privateMethod(this, _setCache, setCache_fn).call(this, cacheKey, data, cacheDuration);
79
+ __privateGet(this, _logger).debug(`Cache set for key: ${cacheKey}`);
80
+ }
81
+ return data;
82
+ }),
83
+ catchError((error) => {
84
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
85
+ __privateGet(this, _logger).error(`Error in cache interceptor for ${cacheKey}: ${errorMessage}`);
86
+ return throwError(() => error);
87
+ })
88
+ );
89
+ }
90
+ };
91
+ _logger = new WeakMap();
92
+ _CACHE_PREFIX = new WeakMap();
93
+ _generateCacheKey = new WeakSet();
94
+ generateCacheKey_fn = function(signalKey, args) {
95
+ return `${__privateGet(this, _CACHE_PREFIX)}${signalKey}:${JSON.stringify(args)}`;
96
+ };
97
+ _getCache = new WeakSet();
98
+ getCache_fn = async function(key) {
99
+ try {
100
+ const cached = await this.redis.get(key);
101
+ if (!cached)
102
+ return null;
103
+ const { data } = JSON.parse(cached);
104
+ return data;
105
+ } catch (error) {
106
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
107
+ __privateGet(this, _logger).error(`Error retrieving cache for key ${key}: ${errorMessage}`);
108
+ return null;
109
+ }
110
+ };
111
+ _setCache = new WeakSet();
112
+ setCache_fn = async function(key, data, ttlMs) {
113
+ try {
114
+ const cacheData = { data, timestamp: Date.now() };
115
+ await this.redis.set(key, JSON.stringify(cacheData), { PX: ttlMs });
116
+ } catch (error) {
117
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
118
+ __privateGet(this, _logger).error(`Error setting cache for key ${key}: ${errorMessage}`);
119
+ }
120
+ };
121
+ CacheInterceptor = __decorateClass([
122
+ Injectable(),
123
+ __decorateParam(0, Inject("REDIS_CLIENT"))
124
+ ], CacheInterceptor);
125
+ let TimeoutInterceptor = class {
126
+ intercept(context, next) {
127
+ const gqlMeta = getGqlMeta(context.getClass(), context.getHandler().name);
128
+ const timeoutMs = gqlMeta.signalOption.timeout ?? 3e4;
129
+ if (timeoutMs === 0)
130
+ return next.handle();
131
+ return next.handle().pipe(
132
+ timeout(timeoutMs),
133
+ catchError((err) => {
134
+ if (err instanceof TimeoutError)
135
+ return throwError(() => new RequestTimeoutException());
136
+ return throwError(() => err);
137
+ })
138
+ );
139
+ }
140
+ };
141
+ TimeoutInterceptor = __decorateClass([
142
+ Injectable()
143
+ ], TimeoutInterceptor);
144
+ let LoggingInterceptor = class {
145
+ logger = new Logger("IO");
146
+ intercept(context, next) {
147
+ const gqlReq = context.getArgByIndex(3);
148
+ const req = getRequest(context);
149
+ const reqType = gqlReq?.parentType?.name ?? req.method;
150
+ const reqName = gqlReq?.fieldName ?? req.url;
151
+ const before = Date.now();
152
+ const ip = GqlExecutionContext.create(context).getContext().req.ip;
153
+ this.logger.debug(`Before ${reqType}-${reqName} / ${ip} / ${before}`);
154
+ return next.handle().pipe(
155
+ tap(() => {
156
+ const after = Date.now();
157
+ this.logger.debug(`After ${reqType}-${reqName} / ${ip} / ${after} (${after - before}ms)`);
158
+ })
159
+ );
160
+ }
161
+ };
162
+ LoggingInterceptor = __decorateClass([
163
+ Injectable()
164
+ ], LoggingInterceptor);
165
+ export {
166
+ CacheInterceptor,
167
+ LoggingInterceptor,
168
+ TimeoutInterceptor
169
+ };
@@ -0,0 +1,60 @@
1
+ import { Logger } from "@akanjs/common";
2
+ import mongoose from "mongoose";
3
+ const initMongoDB = ({
4
+ logging,
5
+ threshold = 5e3,
6
+ sendReport = false
7
+ }) => {
8
+ const mongoDBLogger = new Logger("MongoDB");
9
+ if (logging)
10
+ mongoose.set("debug", function(collection, method, ...methodArgs) {
11
+ mongoDBLogger.verbose(
12
+ `${collection}.${method}(${methodArgs.slice(0, -1).map((arg) => JSON.stringify(arg)).join(", ")})`
13
+ );
14
+ });
15
+ const originalExec = mongoose.Query.prototype.exec;
16
+ const getQueryInfo = (queryAgent) => {
17
+ const model = queryAgent.model;
18
+ const collectionName = model.collection.collectionName;
19
+ const dbName = model.db.name;
20
+ const query = queryAgent.getQuery();
21
+ const queryOptions = queryAgent.getOptions();
22
+ return { dbName, collectionName, query, queryOptions };
23
+ };
24
+ mongoose.Query.prototype.exec = function(...args) {
25
+ const start = Date.now();
26
+ return originalExec.apply(this, args).then((result) => {
27
+ const duration = Date.now() - start;
28
+ const { dbName, collectionName, query, queryOptions } = getQueryInfo(this);
29
+ if (logging)
30
+ mongoDBLogger.verbose(
31
+ `Queried ${dbName}.${collectionName}.query(${JSON.stringify(query)}, ${JSON.stringify(
32
+ queryOptions
33
+ )}) - ${duration}ms`
34
+ );
35
+ return result;
36
+ });
37
+ };
38
+ const originalAggregate = mongoose.Model.aggregate;
39
+ const getAggregateInfo = (aggregateModel) => {
40
+ const dbName = aggregateModel.db.db?.databaseName ?? "unknown";
41
+ const collectionName = aggregateModel.collection.collectionName;
42
+ return { dbName, collectionName };
43
+ };
44
+ mongoose.Model.aggregate = function(...args) {
45
+ const startTime = Date.now();
46
+ return originalAggregate.apply(this, args).then((result) => {
47
+ const duration = Date.now() - startTime;
48
+ const { dbName, collectionName } = getAggregateInfo(this);
49
+ if (logging)
50
+ mongoDBLogger.verbose(
51
+ `Aggregated ${dbName}.${collectionName}.aggregate(${args.map((arg) => JSON.stringify(arg)).join(", ")}) - ${duration}ms`
52
+ );
53
+ return result;
54
+ });
55
+ };
56
+ mongoose.set("transactionAsyncLocalStorage", true);
57
+ };
58
+ export {
59
+ initMongoDB
60
+ };
package/src/pipes.mjs ADDED
@@ -0,0 +1,118 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result)
9
+ __defProp(target, key, result);
10
+ return result;
11
+ };
12
+ import { dayjs, Float, getNonArrayModel, Int, isGqlScalar, JSON as GqlJSON } from "@akanjs/base";
13
+ import { deserializeArg } from "@akanjs/signal";
14
+ import { Injectable } from "@nestjs/common";
15
+ import { Readable } from "stream";
16
+ let ArrayifyPipe = class {
17
+ transform(value, metadata) {
18
+ return Array.isArray(value) ? value : value.split(",");
19
+ }
20
+ };
21
+ ArrayifyPipe = __decorateClass([
22
+ Injectable()
23
+ ], ArrayifyPipe);
24
+ let IntPipe = class {
25
+ transform(value, metadata) {
26
+ return Array.isArray(value) ? value.map(parseInt) : [parseInt(value)];
27
+ }
28
+ };
29
+ IntPipe = __decorateClass([
30
+ Injectable()
31
+ ], IntPipe);
32
+ let FloatPipe = class {
33
+ transform(value, metadata) {
34
+ return Array.isArray(value) ? value.map(parseFloat) : [parseFloat(value)];
35
+ }
36
+ };
37
+ FloatPipe = __decorateClass([
38
+ Injectable()
39
+ ], FloatPipe);
40
+ let BooleanPipe = class {
41
+ transform(value, metadata) {
42
+ return Array.isArray(value) ? value.map((v) => Boolean(v)) : [Boolean(value)];
43
+ }
44
+ };
45
+ BooleanPipe = __decorateClass([
46
+ Injectable()
47
+ ], BooleanPipe);
48
+ let DayjsPipe = class {
49
+ transform(value, metadata) {
50
+ return Array.isArray(value) ? value.map(dayjs) : [dayjs(value)];
51
+ }
52
+ };
53
+ DayjsPipe = __decorateClass([
54
+ Injectable()
55
+ ], DayjsPipe);
56
+ let JSONPipe = class {
57
+ transform(value, metadata) {
58
+ const transformable = typeof value === "string" && value.length;
59
+ const obj = transformable ? JSON.parse(atob(value)) : value;
60
+ return obj;
61
+ }
62
+ };
63
+ JSONPipe = __decorateClass([
64
+ Injectable()
65
+ ], JSONPipe);
66
+ const convertToFileStream = (value) => ({
67
+ filename: value.originalname,
68
+ mimetype: value.mimetype,
69
+ encoding: value.encoding,
70
+ createReadStream: () => Readable.from(value.buffer)
71
+ });
72
+ let MulterToUploadPipe = class {
73
+ transform(value, metadata) {
74
+ return Array.isArray(value) ? value.map(convertToFileStream) : convertToFileStream(value);
75
+ }
76
+ };
77
+ MulterToUploadPipe = __decorateClass([
78
+ Injectable()
79
+ ], MulterToUploadPipe);
80
+ const gqlScalarPipeMap = /* @__PURE__ */ new Map([
81
+ [Int, IntPipe],
82
+ [Float, FloatPipe],
83
+ [Boolean, BooleanPipe],
84
+ [Date, DayjsPipe],
85
+ [GqlJSON, JSONPipe]
86
+ ]);
87
+ const getQueryPipes = (modelRef, arrDepth) => {
88
+ const pipes = arrDepth ? [ArrayifyPipe] : [];
89
+ const scalarPipe = gqlScalarPipeMap.get(modelRef);
90
+ if (scalarPipe)
91
+ pipes.push(scalarPipe);
92
+ return pipes;
93
+ };
94
+ const getBodyPipes = (argMeta) => {
95
+ const [returnRef] = getNonArrayModel(argMeta.returns());
96
+ if (returnRef.prototype !== Date.prototype && !isGqlScalar(returnRef))
97
+ return [];
98
+ let BodyPipe = class {
99
+ transform(value, metadata) {
100
+ return deserializeArg(argMeta, value);
101
+ }
102
+ };
103
+ BodyPipe = __decorateClass([
104
+ Injectable()
105
+ ], BodyPipe);
106
+ return [BodyPipe];
107
+ };
108
+ export {
109
+ ArrayifyPipe,
110
+ BooleanPipe,
111
+ DayjsPipe,
112
+ FloatPipe,
113
+ IntPipe,
114
+ JSONPipe,
115
+ MulterToUploadPipe,
116
+ getBodyPipes,
117
+ getQueryPipes
118
+ };
@@ -0,0 +1,61 @@
1
+ import { Logger, sleep } from "@akanjs/common";
2
+ import { IoAdapter } from "@nestjs/platform-socket.io";
3
+ import { createAdapter } from "@socket.io/redis-adapter";
4
+ import { createClient } from "redis";
5
+ class RedisIoAdapter extends IoAdapter {
6
+ adapterConstructor;
7
+ logger = new Logger("RedisIoAdapter");
8
+ server;
9
+ pubClient;
10
+ subClient;
11
+ option;
12
+ constructor(appOrHttpServer, option) {
13
+ super(appOrHttpServer);
14
+ this.option = option;
15
+ }
16
+ async connectToRedis(url) {
17
+ this.pubClient = createClient({ url });
18
+ this.subClient = this.pubClient.duplicate();
19
+ this.pubClient.on("disconnect", (err) => {
20
+ this.logger.error(`Redis pub database is disconnected. Error: ${err}`);
21
+ void this.pubClient.connect();
22
+ });
23
+ this.subClient.on("disconnect", (err) => {
24
+ this.logger.error(`Redis sub database is disconnected. Error: ${err}`);
25
+ void this.subClient.connect();
26
+ });
27
+ this.pubClient.on("error", (err) => {
28
+ this.logger.error(`Redis pub database is errored. Error: ${err}`);
29
+ const reconnect = async () => {
30
+ await this.pubClient.quit();
31
+ await sleep(1e3);
32
+ await this.pubClient.connect();
33
+ };
34
+ void reconnect();
35
+ });
36
+ this.subClient.on("error", (err) => {
37
+ this.logger.error(`Redis sub database is errored. Error: ${err}`);
38
+ const reconnect = async () => {
39
+ await this.subClient.quit();
40
+ await sleep(1e3);
41
+ await this.subClient.connect();
42
+ };
43
+ void reconnect();
44
+ });
45
+ await Promise.all([this.pubClient.connect(), this.subClient.connect()]);
46
+ this.adapterConstructor = createAdapter(this.pubClient, this.subClient);
47
+ }
48
+ createIOServer(port, options) {
49
+ this.server = super.createIOServer(port, options);
50
+ this.server.adapter(this.adapterConstructor);
51
+ return this.server;
52
+ }
53
+ async destroy() {
54
+ await Promise.all([this.pubClient.quit(), this.subClient.quit()]);
55
+ await this.close(this.server);
56
+ this.logger.log("RedisIoAdapter is closed");
57
+ }
58
+ }
59
+ export {
60
+ RedisIoAdapter
61
+ };
@@ -0,0 +1,46 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result)
9
+ __defProp(target, key, result);
10
+ return result;
11
+ };
12
+ import { DEFAULT_PAGE_SIZE } from "@akanjs/constant";
13
+ import { Inject, Injectable } from "@nestjs/common";
14
+ let SearchClient = class {
15
+ meili;
16
+ async getIndexNames() {
17
+ const { results } = await this.meili.getIndexes({ limit: 1e3 });
18
+ return results.map((index) => index.uid);
19
+ }
20
+ async getSearchResult(indexName, option) {
21
+ const { skip = 0, limit = DEFAULT_PAGE_SIZE, sort = "", searchString } = option;
22
+ if (!searchString) {
23
+ const { results, total } = await this.meili.index(indexName).getDocuments({ offset: skip, limit });
24
+ return { docs: results, skip, limit, sort, total };
25
+ }
26
+ const { hits, estimatedTotalHits } = await this.meili.index(indexName).search(searchString, { offset: skip, limit });
27
+ return { docs: hits, skip, limit, sort, total: estimatedTotalHits, query: searchString };
28
+ }
29
+ async upsertDocuments(indexName, documents) {
30
+ const task = await this.meili.index(indexName).addDocuments(documents);
31
+ return task;
32
+ }
33
+ async dropIndex(indexName) {
34
+ const task = await this.meili.index(indexName).delete();
35
+ return task;
36
+ }
37
+ };
38
+ __decorateClass([
39
+ Inject("MEILI_CLIENT")
40
+ ], SearchClient.prototype, "meili", 2);
41
+ SearchClient = __decorateClass([
42
+ Injectable()
43
+ ], SearchClient);
44
+ export {
45
+ SearchClient
46
+ };