"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { KeyvMongo: () => KeyvMongo, default: () => src_default }); module.exports = __toCommonJS(src_exports); var import_events = __toESM(require("events"), 1); var import_buffer = require("buffer"); var import_mongodb = require("mongodb"); var keyvMongoKeys = /* @__PURE__ */ new Set(["url", "collection", "namespace", "serialize", "deserialize", "uri", "useGridFS", "dialect"]); var KeyvMongo = class extends import_events.default { ttlSupport = false; opts; connect; namespace; constructor(url, options) { super(); url ??= {}; if (typeof url === "string") { url = { url }; } if (url.uri) { url = { url: url.uri, ...url }; } this.opts = { url: "mongodb://127.0.0.1:27017", collection: "keyv", ...url, ...options }; delete this.opts.emitErrors; const mongoOptions = Object.fromEntries( Object.entries(this.opts).filter( ([k]) => !keyvMongoKeys.has(k) ) ); this.opts = Object.fromEntries( Object.entries(this.opts).filter( ([k]) => keyvMongoKeys.has(k) ) ); this.connect = new Promise(async (resolve, reject) => { try { let url2 = ""; if (this.opts.url) { url2 = this.opts.url; } const client = new import_mongodb.MongoClient(url2, mongoOptions); await client.connect(); const database = client.db(this.opts.db); if (this.opts.useGridFS) { const bucket = new import_mongodb.GridFSBucket(database, { readPreference: this.opts.readPreference, bucketName: this.opts.collection }); const store = database.collection(`${this.opts.collection}.files`); await store.createIndex({ uploadDate: -1 }); await store.createIndex({ "metadata.expiresAt": 1 }); await store.createIndex({ "metadata.lastAccessed": 1 }); await store.createIndex({ "metadata.filename": 1 }); resolve({ bucket, store, db: database, mongoClient: client }); } else { let collection = "keyv"; if (this.opts.collection) { collection = this.opts.collection; } const store = database.collection(collection); await store.createIndex({ key: 1 }, { unique: true, background: true }); await store.createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0, background: true }); resolve({ store, mongoClient: client }); } } catch (error) { this.emit("error", error); reject(error); } }); } async get(key) { const client = await this.connect; if (this.opts.useGridFS) { await client.store.updateOne({ filename: key }, { $set: { "metadata.lastAccessed": /* @__PURE__ */ new Date() } }); const stream = client.bucket.openDownloadStreamByName(key); return new Promise((resolve) => { const resp = []; stream.on("error", () => { resolve(void 0); }); stream.on("end", () => { const data = import_buffer.Buffer.concat(resp).toString("utf8"); resolve(data); }); stream.on("data", (chunk) => { resp.push(chunk); }); }); } const document = await client.store.findOne({ key: { $eq: key } }); if (!document) { return void 0; } return document.value; } async getMany(keys) { if (this.opts.useGridFS) { const promises = []; for (const key of keys) { promises.push(this.get(key)); } const values2 = await Promise.allSettled(promises); const data = []; for (const value of values2) { data.push(value.value); } return data; } const connect = await this.connect; const values = await connect.store.s.db.collection(this.opts.collection).find({ key: { $in: keys } }).project({ _id: 0, value: 1, key: 1 }).toArray(); const results = [...keys]; let i = 0; for (const key of keys) { const rowIndex = values.findIndex((row) => row.key === key); results[i] = rowIndex > -1 ? values[rowIndex].value : void 0; i++; } return results; } async set(key, value, ttl) { const expiresAt = typeof ttl === "number" ? new Date(Date.now() + ttl) : null; if (this.opts.useGridFS) { const client2 = await this.connect; const stream = client2.bucket.openUploadStream(key, { metadata: { expiresAt, lastAccessed: /* @__PURE__ */ new Date() } }); return new Promise((resolve) => { stream.on("finish", () => { resolve(stream); }); stream.end(value); }); } const client = await this.connect; await client.store.updateOne( { key: { $eq: key } }, { $set: { key, value, expiresAt } }, { upsert: true } ); } async delete(key) { if (typeof key !== "string") { return false; } const client = await this.connect; if (this.opts.useGridFS) { try { const connection = client.db; const bucket = new import_mongodb.GridFSBucket(connection, { bucketName: this.opts.collection }); const files = await bucket.find({ filename: key }).toArray(); await client.bucket.delete(files[0]._id); return true; } catch { return false; } } const object = await client.store.deleteOne({ key: { $eq: key } }); return object.deletedCount > 0; } async deleteMany(keys) { const client = await this.connect; if (this.opts.useGridFS) { const connection = client.db; const bucket = new import_mongodb.GridFSBucket(connection, { bucketName: this.opts.collection }); const files = await bucket.find({ filename: { $in: keys } }).toArray(); if (files.length === 0) { return false; } await Promise.all(files.map(async (file) => client.bucket.delete(file._id))); return true; } const object = await client.store.deleteMany({ key: { $in: keys } }); return object.deletedCount > 0; } async clear() { const client = await this.connect; if (this.opts.useGridFS) { try { await client.bucket.drop(); } catch (error) { if (!(error instanceof import_mongodb.MongoServerError && error.code === 26)) { throw error; } } } await client.store.deleteMany({ key: { $regex: this.namespace ? `^${this.namespace}:*` : "" } }); } async clearExpired() { if (!this.opts.useGridFS) { return false; } return this.connect.then(async (client) => { const connection = client.db; const bucket = new import_mongodb.GridFSBucket(connection, { bucketName: this.opts.collection }); return bucket.find({ "metadata.expiresAt": { $lte: new Date(Date.now()) } }).toArray().then(async (expiredFiles) => Promise.all(expiredFiles.map(async (file) => client.bucket.delete(file._id))).then(() => true)); }); } async clearUnusedFor(seconds) { if (!this.opts.useGridFS) { return false; } const client = await this.connect; const connection = client.db; const bucket = new import_mongodb.GridFSBucket(connection, { bucketName: this.opts.collection }); const lastAccessedFiles = await bucket.find({ "metadata.lastAccessed": { $lte: new Date(Date.now() - seconds * 1e3) } }).toArray(); await Promise.all(lastAccessedFiles.map(async (file) => client.bucket.delete(file._id))); return true; } async *iterator(namespace) { const client = await this.connect; const regexp = new RegExp(`^${namespace ? namespace + ":" : ".*"}`); const iterator = this.opts.useGridFS ? client.store.find({ filename: regexp }).map(async (x) => [x.filename, await this.get(x.filename)]) : client.store.find({ key: regexp }).map((x) => [x.key, x.value]); yield* iterator; } async has(key) { const client = await this.connect; const filter = { [this.opts.useGridFS ? "filename" : "key"]: { $eq: key } }; const document = await client.store.count(filter); return document !== 0; } async disconnect() { const client = await this.connect; await client.mongoClient.close(); } }; var src_default = KeyvMongo; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { KeyvMongo });