"use strict";
/* Socket Lib - Built with rolldown */
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const require_primordials_error = require('../../primordials/error.js');
const require_primordials_string = require('../../primordials/string.js');
const require_primordials_math = require('../../primordials/math.js');
const require_primordials_regexp = require('../../primordials/regexp.js');
const require_primordials_map_set = require('../../primordials/map-set.js');
const require_primordials_date = require('../../primordials/date.js');
const require_primordials_json = require('../../primordials/json.js');
const require_cacache_clear = require('../../cacache/clear.js');
const require_cacache_read = require('../../cacache/read.js');
const require_cacache_write = require('../../cacache/write.js');

//#region src/cache/ttl/store.ts
/**
* @file `createTtlCache` — generic TTL-based cache built on top of cacache
*   (persistent) plus an in-memory LRU memo layer. Two-tier caching: hot data
*   lives in `memoCache` (Map<string, TtlCacheEntry>) capped at `memoMaxSize`
*   entries with LRU eviction via Map insertion-order semantics. Persistent
*   storage uses cacache so cached values survive process restarts. Key
*   features:
*
*   - Per-key namespacing via `prefix` so multiple caches share one cacache
*     directory without conflicting.
*   - `getOrFetch` deduplicates concurrent requests for the same key
*     (thundering-herd protection via `inflightRequests` map).
*   - Wildcard support for `getAll` / `deleteAll` (single-key methods throw on
*     `*`).
*   - Clock-skew detection: entries with suspiciously-far-future `expiresAt` are
*     treated as expired.
*/
const DEFAULT_TTL_MS = 300 * 1e3;
const DEFAULT_PREFIX = "ttl-cache";
const DEFAULT_MEMO_MAX_SIZE = 1e3;
/**
* Create a TTL-based cache instance.
*
* @example
*   ;```typescript
*   const cache = createTtlCache({ ttl: 60_000, prefix: 'my-app' })
*   await cache.set('key', { value: 42 })
*   const data = await cache.get('key') // { value: 42 }
*   ```
*/
function createTtlCache(options) {
	const opts = {
		__proto__: null,
		memoize: true,
		memoMaxSize: DEFAULT_MEMO_MAX_SIZE,
		prefix: DEFAULT_PREFIX,
		ttl: DEFAULT_TTL_MS,
		...options
	};
	if (opts.prefix?.includes("*")) throw new require_primordials_error.TypeErrorCtor("Cache prefix cannot contain wildcards (*). Use clear({ prefix: \"pattern*\" }) for wildcard matching.");
	const memoCache = new require_primordials_map_set.MapCtor();
	const memoMaxSize = require_primordials_math.MathMax(1, opts.memoMaxSize ?? DEFAULT_MEMO_MAX_SIZE);
	function memoSet(fullKey, entry) {
		/* c8 ignore start */
		if (memoCache.has(fullKey)) memoCache.delete(fullKey);
		else if (memoCache.size >= memoMaxSize) {
			const oldest = memoCache.keys().next().value;
			if (oldest !== void 0) memoCache.delete(oldest);
		}
		/* c8 ignore stop */
		memoCache.set(fullKey, entry);
	}
	/* c8 ignore next */
	const ttl = opts.ttl ?? DEFAULT_TTL_MS;
	/**
	* Build full cache key with prefix.
	*/
	function buildKey(key) {
		return `${opts.prefix}:${key}`;
	}
	/**
	* Check if entry is expired. Also detects clock skew by treating suspiciously
	* far-future expiresAt as expired.
	*/
	function isExpired(entry) {
		const now = require_primordials_date.DateNow();
		if (entry.expiresAt > now + ttl + 1e4) return true;
		return now > entry.expiresAt;
	}
	/**
	* Create a matcher function for a pattern (with wildcard support). Returns a
	* function that tests if a key matches the pattern.
	*/
	function createMatcher(pattern) {
		const fullPattern = buildKey(pattern);
		if (!pattern.includes("*")) return (key) => require_primordials_string.StringPrototypeStartsWith(key, fullPattern);
		const regex = new require_primordials_regexp.RegExpCtor(`^${require_primordials_string.StringPrototypeReplaceAll(require_primordials_string.StringPrototypeReplaceAll(fullPattern, /[.+?^${}()|[\]\\]/g, "\\$&"), "*", ".*")}$`);
		return (key) => require_primordials_regexp.RegExpPrototypeTest(regex, key);
	}
	async function get(key) {
		if (require_primordials_string.StringPrototypeIncludes(key, "*")) throw new require_primordials_error.TypeErrorCtor("Cache key cannot contain wildcards (*). Use getAll(pattern) to retrieve multiple entries.");
		const fullKey = buildKey(key);
		if (opts.memoize) {
			const memoEntry = memoCache.get(fullKey);
			if (memoEntry && !isExpired(memoEntry)) {
				memoSet(fullKey, memoEntry);
				return memoEntry.data;
			}
			if (memoEntry) memoCache.delete(fullKey);
		}
		const cacheEntry = await require_cacache_read.safeGet(fullKey);
		if (cacheEntry) {
			let entry;
			try {
				entry = require_primordials_json.JSONParse(cacheEntry.data.toString("utf8"));
			} catch {
				try {
					await require_cacache_write.remove(fullKey);
				} catch {}
				return;
			}
			if (!isExpired(entry)) {
				if (opts.memoize) memoSet(fullKey, entry);
				return entry.data;
			}
			/* c8 ignore start */
			try {
				await require_cacache_write.remove(fullKey);
			} catch {}
		}
	}
	async function getAll(pattern) {
		const results = new require_primordials_map_set.MapCtor();
		const matches = createMatcher(pattern);
		/* c8 ignore start */
		if (opts.memoize) for (const [key, entry] of memoCache.entries()) {
			if (!matches(key)) continue;
			if (isExpired(entry)) {
				memoCache.delete(key);
				continue;
			}
			const originalKey = opts.prefix ? require_primordials_string.StringPrototypeSlice(key, opts.prefix.length + 1) : key;
			results.set(originalKey, entry.data);
		}
		/* c8 ignore stop */
		const cacheDir = (await Promise.resolve().then(() => require("../../paths/socket.js"))).getSocketCacacheDir();
		const stream = (await Promise.resolve().then(() => require("../../cacache/_internal.js"))).getCacache().ls.stream(cacheDir);
		for await (const cacheEntry of stream) {
			if (!cacheEntry.key.startsWith(`${opts.prefix}:`)) continue;
			if (!matches(cacheEntry.key)) continue;
			const originalKey = opts.prefix ? cacheEntry.key.slice(opts.prefix.length + 1) : cacheEntry.key;
			if (results.has(originalKey)) continue;
			try {
				const entry = await require_cacache_read.safeGet(cacheEntry.key);
				if (!entry) continue;
				const parsed = require_primordials_json.JSONParse(entry.data.toString("utf8"));
				if (isExpired(parsed)) {
					await require_cacache_write.remove(cacheEntry.key);
					continue;
				}
				results.set(originalKey, parsed.data);
				if (opts.memoize) memoSet(cacheEntry.key, parsed);
			} catch {}
		}
		return results;
	}
	async function set(key, data) {
		if (require_primordials_string.StringPrototypeIncludes(key, "*")) throw new require_primordials_error.TypeErrorCtor("Cache key cannot contain wildcards (*). Wildcards are only supported in clear({ prefix: \"pattern*\" }).");
		const fullKey = buildKey(key);
		const entry = {
			data,
			expiresAt: require_primordials_date.DateNow() + ttl
		};
		if (opts.memoize) memoSet(fullKey, entry);
		try {
			await require_cacache_write.put(fullKey, require_primordials_json.JSONStringify(entry), { metadata: { expiresAt: entry.expiresAt } });
		} catch {}
	}
	const inflightRequests = new require_primordials_map_set.MapCtor();
	async function getOrFetch(key, fetcher) {
		const fullKey = buildKey(key);
		/* c8 ignore start */
		const preexisting = inflightRequests.get(fullKey);
		if (preexisting) return await preexisting;
		/* c8 ignore stop */
		const cached = await get(key);
		if (cached !== void 0) return cached;
		/* c8 ignore start */
		const rechecked = inflightRequests.get(fullKey);
		if (rechecked) return await rechecked;
		/* c8 ignore stop */
		const promise = (async () => {
			try {
				const data = await fetcher();
				await set(key, data);
				return data;
			} finally {
				inflightRequests.delete(fullKey);
			}
		})();
		inflightRequests.set(fullKey, promise);
		return await promise;
	}
	async function deleteEntry(key) {
		if (require_primordials_string.StringPrototypeIncludes(key, "*")) throw new require_primordials_error.TypeErrorCtor("Cache key cannot contain wildcards (*). Use deleteAll(pattern) to remove multiple entries.");
		const fullKey = buildKey(key);
		memoCache.delete(fullKey);
		try {
			await require_cacache_write.remove(fullKey);
		} catch {}
	}
	async function deleteAll(pattern) {
		const fullPrefix = pattern ? `${opts.prefix}:${pattern}` : `${opts.prefix}:`;
		if (!pattern) memoCache.clear();
		else {
			const matches = createMatcher(pattern);
			for (const key of memoCache.keys()) if (matches(key)) memoCache.delete(key);
		}
		return await require_cacache_clear.clear({ prefix: fullPrefix }) ?? 0;
	}
	async function clear$1(options) {
		const opts = {
			__proto__: null,
			...options
		};
		memoCache.clear();
		if (opts.memoOnly) return;
		await deleteAll();
	}
	return {
		clear: clear$1,
		delete: deleteEntry,
		deleteAll,
		get,
		getAll,
		getOrFetch,
		set
	};
}

//#endregion
exports.createTtlCache = createTtlCache;