@holo-js/cache 0.2.6 → 0.3.0
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.
- package/dist/chunk-7FH4KYTX.mjs +152 -0
- package/dist/chunk-FRE6NONR.mjs +31 -0
- package/dist/chunk-NZGSTXGZ.mjs +119 -0
- package/dist/config.d.ts +96 -0
- package/dist/config.mjs +24 -0
- package/dist/contracts.d.ts +3 -1
- package/dist/driver-registry-YQMWF4CC.mjs +11 -0
- package/dist/index.d.ts +31 -5
- package/dist/index.mjs +125 -86
- package/dist/plugins-JHYNVE7O.mjs +10 -0
- package/package.json +9 -2
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// src/config.ts
|
|
2
|
+
import { registerConfigNormalizer } from "@holo-js/config/registry";
|
|
3
|
+
var DEFAULT_CACHE_DRIVER = "file";
|
|
4
|
+
var DEFAULT_CACHE_PREFIX = "";
|
|
5
|
+
var DEFAULT_CACHE_FILE_PATH = "./storage/framework/cache/data";
|
|
6
|
+
var DEFAULT_CACHE_REDIS_CONNECTION = "default";
|
|
7
|
+
var DEFAULT_CACHE_DATABASE_CONNECTION = "default";
|
|
8
|
+
var DEFAULT_CACHE_DATABASE_TABLE = "cache";
|
|
9
|
+
var DEFAULT_CACHE_DATABASE_LOCK_TABLE = "cache_locks";
|
|
10
|
+
var holoCacheDefaults = Object.freeze({
|
|
11
|
+
default: DEFAULT_CACHE_DRIVER,
|
|
12
|
+
prefix: DEFAULT_CACHE_PREFIX,
|
|
13
|
+
drivers: Object.freeze({
|
|
14
|
+
file: Object.freeze({
|
|
15
|
+
name: "file",
|
|
16
|
+
driver: "file",
|
|
17
|
+
path: DEFAULT_CACHE_FILE_PATH,
|
|
18
|
+
prefix: DEFAULT_CACHE_PREFIX
|
|
19
|
+
}),
|
|
20
|
+
memory: Object.freeze({
|
|
21
|
+
name: "memory",
|
|
22
|
+
driver: "memory",
|
|
23
|
+
maxEntries: void 0,
|
|
24
|
+
prefix: DEFAULT_CACHE_PREFIX
|
|
25
|
+
})
|
|
26
|
+
})
|
|
27
|
+
});
|
|
28
|
+
function normalizeOptionalString(value) {
|
|
29
|
+
const normalized = value?.trim();
|
|
30
|
+
return normalized || void 0;
|
|
31
|
+
}
|
|
32
|
+
function normalizeName(value, label) {
|
|
33
|
+
const normalized = value?.trim();
|
|
34
|
+
if (!normalized) {
|
|
35
|
+
throw new Error(`[Holo Cache] ${label} must be a non-empty string.`);
|
|
36
|
+
}
|
|
37
|
+
return normalized;
|
|
38
|
+
}
|
|
39
|
+
function parseOptionalInteger(value, label) {
|
|
40
|
+
if (typeof value === "undefined") return void 0;
|
|
41
|
+
const normalized = typeof value === "number" ? value : value.trim() ? Number(value.trim()) : Number.NaN;
|
|
42
|
+
if (!Number.isFinite(normalized) || !Number.isInteger(normalized)) {
|
|
43
|
+
throw new Error(`[Holo Cache] ${label} must be an integer.`);
|
|
44
|
+
}
|
|
45
|
+
if (normalized < 1) {
|
|
46
|
+
throw new Error(`[Holo Cache] ${label} must be greater than or equal to 1.`);
|
|
47
|
+
}
|
|
48
|
+
return normalized;
|
|
49
|
+
}
|
|
50
|
+
function resolvePrefix(globalPrefix, localPrefix) {
|
|
51
|
+
return normalizeOptionalString(localPrefix) ?? globalPrefix;
|
|
52
|
+
}
|
|
53
|
+
function normalizeDriverConfig(name, config, globalPrefix, defaultRedisConnection, defaultDatabaseConnection) {
|
|
54
|
+
switch (config.driver) {
|
|
55
|
+
case "memory": {
|
|
56
|
+
const memoryConfig = config;
|
|
57
|
+
return Object.freeze({
|
|
58
|
+
name,
|
|
59
|
+
driver: "memory",
|
|
60
|
+
prefix: resolvePrefix(globalPrefix, memoryConfig.prefix),
|
|
61
|
+
maxEntries: parseOptionalInteger(memoryConfig.maxEntries, `cache driver "${name}" maxEntries`)
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
case "file": {
|
|
65
|
+
const fileConfig = config;
|
|
66
|
+
return Object.freeze({
|
|
67
|
+
name,
|
|
68
|
+
driver: "file",
|
|
69
|
+
path: normalizeOptionalString(fileConfig.path) || DEFAULT_CACHE_FILE_PATH,
|
|
70
|
+
prefix: resolvePrefix(globalPrefix, fileConfig.prefix)
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
case "redis": {
|
|
74
|
+
const redisConfig = config;
|
|
75
|
+
return Object.freeze({
|
|
76
|
+
name,
|
|
77
|
+
driver: "redis",
|
|
78
|
+
connection: normalizeOptionalString(redisConfig.connection) ?? defaultRedisConnection,
|
|
79
|
+
prefix: resolvePrefix(globalPrefix, redisConfig.prefix)
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
case "database": {
|
|
83
|
+
const databaseConfig = config;
|
|
84
|
+
return Object.freeze({
|
|
85
|
+
name,
|
|
86
|
+
driver: "database",
|
|
87
|
+
connection: normalizeOptionalString(databaseConfig.connection) ?? defaultDatabaseConnection,
|
|
88
|
+
table: normalizeOptionalString(databaseConfig.table) || DEFAULT_CACHE_DATABASE_TABLE,
|
|
89
|
+
lockTable: normalizeOptionalString(databaseConfig.lockTable) || DEFAULT_CACHE_DATABASE_LOCK_TABLE,
|
|
90
|
+
prefix: resolvePrefix(globalPrefix, databaseConfig.prefix)
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
default: {
|
|
94
|
+
const { driver, prefix, ...options } = config;
|
|
95
|
+
return Object.freeze({
|
|
96
|
+
...options,
|
|
97
|
+
name,
|
|
98
|
+
driver: normalizeName(driver, `Cache driver "${name}" driver`),
|
|
99
|
+
prefix: resolvePrefix(globalPrefix, prefix)
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function normalizeCacheConfig(config = {}, options = {}) {
|
|
105
|
+
const prefix = normalizeOptionalString(config.prefix) ?? DEFAULT_CACHE_PREFIX;
|
|
106
|
+
const defaultRedisConnection = options.redis?.default ?? DEFAULT_CACHE_REDIS_CONNECTION;
|
|
107
|
+
const defaultDatabaseConnection = options.database?.defaultConnection ?? DEFAULT_CACHE_DATABASE_CONNECTION;
|
|
108
|
+
const driverEntries = !config.drivers || Object.keys(config.drivers).length === 0 ? Object.entries(holoCacheDefaults.drivers) : Object.entries(config.drivers);
|
|
109
|
+
const normalizedDriverEntries = driverEntries.map(([name, driver]) => {
|
|
110
|
+
const normalizedName = normalizeName(name, "Cache driver name");
|
|
111
|
+
return [normalizedName, normalizeDriverConfig(
|
|
112
|
+
normalizedName,
|
|
113
|
+
driver,
|
|
114
|
+
prefix,
|
|
115
|
+
defaultRedisConnection,
|
|
116
|
+
defaultDatabaseConnection
|
|
117
|
+
)];
|
|
118
|
+
});
|
|
119
|
+
const drivers = Object.freeze(Object.fromEntries(normalizedDriverEntries));
|
|
120
|
+
const configuredDefault = normalizeOptionalString(config.default);
|
|
121
|
+
if (configuredDefault && !Object.hasOwn(drivers, configuredDefault)) {
|
|
122
|
+
throw new Error(`[Holo Cache] default cache driver "${configuredDefault}" is not configured.`);
|
|
123
|
+
}
|
|
124
|
+
const defaultDriver = configuredDefault ?? normalizedDriverEntries.find(([name]) => name === DEFAULT_CACHE_DRIVER)?.[0] ?? normalizedDriverEntries[0][0];
|
|
125
|
+
return Object.freeze({ default: defaultDriver, prefix, drivers });
|
|
126
|
+
}
|
|
127
|
+
function defineCacheConfig(config) {
|
|
128
|
+
return Object.freeze({ ...config });
|
|
129
|
+
}
|
|
130
|
+
registerConfigNormalizer({
|
|
131
|
+
name: "cache",
|
|
132
|
+
dependencies: ["database", "redis"],
|
|
133
|
+
normalize(config, context) {
|
|
134
|
+
return normalizeCacheConfig(config, {
|
|
135
|
+
database: context.get("database"),
|
|
136
|
+
redis: context.has("redis") ? context.get("redis") : void 0
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
export {
|
|
142
|
+
DEFAULT_CACHE_DRIVER,
|
|
143
|
+
DEFAULT_CACHE_PREFIX,
|
|
144
|
+
DEFAULT_CACHE_FILE_PATH,
|
|
145
|
+
DEFAULT_CACHE_REDIS_CONNECTION,
|
|
146
|
+
DEFAULT_CACHE_DATABASE_CONNECTION,
|
|
147
|
+
DEFAULT_CACHE_DATABASE_TABLE,
|
|
148
|
+
DEFAULT_CACHE_DATABASE_LOCK_TABLE,
|
|
149
|
+
holoCacheDefaults,
|
|
150
|
+
normalizeCacheConfig,
|
|
151
|
+
defineCacheConfig
|
|
152
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CacheOptionalPackageError
|
|
3
|
+
} from "./chunk-KIYULZES.mjs";
|
|
4
|
+
|
|
5
|
+
// src/driver-registry.ts
|
|
6
|
+
var cacheDriverRuntime = globalThis;
|
|
7
|
+
cacheDriverRuntime.__holoCacheDriverFactories__ ??= /* @__PURE__ */ new Map();
|
|
8
|
+
var factories = cacheDriverRuntime.__holoCacheDriverFactories__;
|
|
9
|
+
function registerCacheDriverFactory(factory) {
|
|
10
|
+
const driver = factory.driver.trim();
|
|
11
|
+
if (!driver) throw new TypeError("Cache driver factories require a non-empty driver name.");
|
|
12
|
+
const existing = factories.get(driver);
|
|
13
|
+
if (existing && existing !== factory && (!factory.registrationKey || existing.registrationKey !== factory.registrationKey)) {
|
|
14
|
+
throw new Error(`Cache driver factory "${driver}" is already registered.`);
|
|
15
|
+
}
|
|
16
|
+
factories.set(driver, factory);
|
|
17
|
+
}
|
|
18
|
+
function unregisterCacheDriverFactory(factory) {
|
|
19
|
+
if (factories.get(factory.driver.trim()) === factory) factories.delete(factory.driver.trim());
|
|
20
|
+
}
|
|
21
|
+
function requireCacheDriverFactory(driver, message) {
|
|
22
|
+
const factory = factories.get(driver);
|
|
23
|
+
if (!factory) throw new CacheOptionalPackageError(message);
|
|
24
|
+
return factory;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export {
|
|
28
|
+
registerCacheDriverFactory,
|
|
29
|
+
unregisterCacheDriverFactory,
|
|
30
|
+
requireCacheDriverFactory
|
|
31
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// src/plugins.ts
|
|
2
|
+
import { resolve } from "path";
|
|
3
|
+
import {
|
|
4
|
+
loadHoloPluginContributionModules,
|
|
5
|
+
loadHoloPluginDefinitions
|
|
6
|
+
} from "@holo-js/kernel";
|
|
7
|
+
var loadedContractsByProjectRoot = /* @__PURE__ */ new Map();
|
|
8
|
+
var failedLoadsByProjectRoot = /* @__PURE__ */ new Map();
|
|
9
|
+
function isRecord(value) {
|
|
10
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
11
|
+
}
|
|
12
|
+
function resolvePluginCandidate(moduleValue) {
|
|
13
|
+
return isRecord(moduleValue) && typeof moduleValue.default !== "undefined" ? moduleValue.default : isRecord(moduleValue) && typeof moduleValue.driver !== "undefined" ? moduleValue.driver : moduleValue;
|
|
14
|
+
}
|
|
15
|
+
function isCachePluginDriverFactory(candidate, driverName) {
|
|
16
|
+
return isRecord(candidate) && candidate.driver === driverName && typeof candidate.create === "function";
|
|
17
|
+
}
|
|
18
|
+
function assertCacheDriverContract(candidate, packageName, driverName, expectedName) {
|
|
19
|
+
if (!isRecord(candidate) || candidate.driver !== driverName || candidate.name !== expectedName || typeof candidate.get !== "function" || typeof candidate.put !== "function" || typeof candidate.add !== "function" || typeof candidate.forget !== "function" || typeof candidate.flush !== "function" || typeof candidate.increment !== "function" || typeof candidate.decrement !== "function" || typeof candidate.lock !== "function") {
|
|
20
|
+
throw new Error(`[@holo-js/cache] Plugin ${packageName} cache driver "${driverName}" must export a matching CacheDriverContract.`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function resolveCacheDriver(moduleValue, packageName, driverName) {
|
|
24
|
+
const candidate = resolvePluginCandidate(moduleValue);
|
|
25
|
+
assertCacheDriverContract(candidate, packageName, driverName, driverName);
|
|
26
|
+
return candidate;
|
|
27
|
+
}
|
|
28
|
+
function resolveConfiguredCacheDriver(moduleValue, packageName, driverName, config) {
|
|
29
|
+
const candidate = resolvePluginCandidate(moduleValue);
|
|
30
|
+
if (isCachePluginDriverFactory(candidate, driverName)) {
|
|
31
|
+
const driver = candidate.create(config);
|
|
32
|
+
assertCacheDriverContract(driver, packageName, driverName, config.name);
|
|
33
|
+
return driver;
|
|
34
|
+
}
|
|
35
|
+
assertCacheDriverContract(candidate, packageName, driverName, driverName);
|
|
36
|
+
Object.defineProperties(candidate, {
|
|
37
|
+
name: {
|
|
38
|
+
value: config.name,
|
|
39
|
+
enumerable: true,
|
|
40
|
+
configurable: true
|
|
41
|
+
},
|
|
42
|
+
driver: {
|
|
43
|
+
value: driverName,
|
|
44
|
+
enumerable: true,
|
|
45
|
+
configurable: true
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
return Object.freeze(candidate);
|
|
49
|
+
}
|
|
50
|
+
function assertConfiguredCacheDriverContributions(configs, contributions) {
|
|
51
|
+
const availableDrivers = new Set(contributions.map((contribution) => contribution.name));
|
|
52
|
+
const missingDrivers = Array.from(new Set(
|
|
53
|
+
configs.map((config) => config.driver).filter((driver) => !availableDrivers.has(driver))
|
|
54
|
+
));
|
|
55
|
+
if (missingDrivers.length === 0) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const available = contributions.length > 0 ? contributions.map((contribution) => `"${contribution.name}"`).join(", ") : "none";
|
|
59
|
+
throw new Error(
|
|
60
|
+
`[@holo-js/cache] Configured cache plugin driver ${missingDrivers.map((driver) => `"${driver}"`).join(", ")} has no matching plugin contribution. Available cache plugin driver contributions: ${available}.`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
async function loadCachePluginDriverContracts(projectRoot = process.cwd(), pluginNames = []) {
|
|
64
|
+
const root = resolve(projectRoot);
|
|
65
|
+
const cacheKey = `${root}\0${[...pluginNames].sort().join("\0")}`;
|
|
66
|
+
const loadedContracts = loadedContractsByProjectRoot.get(cacheKey);
|
|
67
|
+
if (loadedContracts) {
|
|
68
|
+
return loadedContracts;
|
|
69
|
+
}
|
|
70
|
+
if (failedLoadsByProjectRoot.has(cacheKey)) {
|
|
71
|
+
throw failedLoadsByProjectRoot.get(cacheKey);
|
|
72
|
+
}
|
|
73
|
+
const plugins = await loadHoloPluginDefinitions(root, pluginNames);
|
|
74
|
+
const contributions = await loadHoloPluginContributionModules(root, plugins, "cache", "drivers");
|
|
75
|
+
let drivers;
|
|
76
|
+
try {
|
|
77
|
+
drivers = Object.freeze(contributions.map((contribution) => resolveCacheDriver(
|
|
78
|
+
contribution.module,
|
|
79
|
+
contribution.plugin.packageName,
|
|
80
|
+
contribution.name
|
|
81
|
+
)));
|
|
82
|
+
} catch (error) {
|
|
83
|
+
failedLoadsByProjectRoot.set(cacheKey, error);
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
loadedContractsByProjectRoot.set(cacheKey, drivers);
|
|
87
|
+
return drivers;
|
|
88
|
+
}
|
|
89
|
+
async function loadConfiguredCachePluginDriverContracts(projectRoot, pluginNames, configs) {
|
|
90
|
+
if (configs.length === 0) {
|
|
91
|
+
return Object.freeze([]);
|
|
92
|
+
}
|
|
93
|
+
const plugins = await loadHoloPluginDefinitions(projectRoot, pluginNames);
|
|
94
|
+
const contributions = await loadHoloPluginContributionModules(projectRoot, plugins, "cache", "drivers");
|
|
95
|
+
assertConfiguredCacheDriverContributions(configs, contributions);
|
|
96
|
+
const drivers = [];
|
|
97
|
+
for (const contribution of contributions) {
|
|
98
|
+
const matchingConfigs = configs.filter((config) => config.driver === contribution.name);
|
|
99
|
+
for (const config of matchingConfigs) {
|
|
100
|
+
drivers.push(resolveConfiguredCacheDriver(
|
|
101
|
+
contribution.module,
|
|
102
|
+
contribution.plugin.packageName,
|
|
103
|
+
contribution.name,
|
|
104
|
+
config
|
|
105
|
+
));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return Object.freeze(drivers);
|
|
109
|
+
}
|
|
110
|
+
function resetCachePluginDriverContracts() {
|
|
111
|
+
loadedContractsByProjectRoot.clear();
|
|
112
|
+
failedLoadsByProjectRoot.clear();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export {
|
|
116
|
+
loadCachePluginDriverContracts,
|
|
117
|
+
loadConfiguredCachePluginDriverContracts,
|
|
118
|
+
resetCachePluginDriverContracts
|
|
119
|
+
};
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { NormalizedHoloDatabaseConfig } from '@holo-js/db';
|
|
2
|
+
import { NormalizedHoloRedisConfig } from '@holo-js/kernel';
|
|
3
|
+
|
|
4
|
+
type CacheDriver = 'memory' | 'file' | 'redis' | 'database' | (string & {});
|
|
5
|
+
declare module '@holo-js/config' {
|
|
6
|
+
interface HoloConfigRegistry {
|
|
7
|
+
cache: NormalizedHoloCacheConfig;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
interface CacheMemoryDriverConfig {
|
|
11
|
+
readonly driver: 'memory';
|
|
12
|
+
readonly maxEntries?: number | string;
|
|
13
|
+
readonly prefix?: string;
|
|
14
|
+
}
|
|
15
|
+
interface CacheFileDriverConfig {
|
|
16
|
+
readonly driver: 'file';
|
|
17
|
+
readonly path?: string;
|
|
18
|
+
readonly prefix?: string;
|
|
19
|
+
}
|
|
20
|
+
interface CacheRedisDriverConfig {
|
|
21
|
+
readonly driver: 'redis';
|
|
22
|
+
readonly connection?: string;
|
|
23
|
+
readonly prefix?: string;
|
|
24
|
+
}
|
|
25
|
+
interface CacheDatabaseDriverConfig {
|
|
26
|
+
readonly driver: 'database';
|
|
27
|
+
readonly connection?: string;
|
|
28
|
+
readonly table?: string;
|
|
29
|
+
readonly lockTable?: string;
|
|
30
|
+
readonly prefix?: string;
|
|
31
|
+
}
|
|
32
|
+
interface CachePluginDriverConfig {
|
|
33
|
+
readonly driver: string;
|
|
34
|
+
readonly prefix?: string;
|
|
35
|
+
readonly [key: string]: unknown;
|
|
36
|
+
}
|
|
37
|
+
type CacheDriverConfig = CacheMemoryDriverConfig | CacheFileDriverConfig | CacheRedisDriverConfig | CacheDatabaseDriverConfig | CachePluginDriverConfig;
|
|
38
|
+
interface HoloCacheConfig {
|
|
39
|
+
readonly default?: string;
|
|
40
|
+
readonly prefix?: string;
|
|
41
|
+
readonly drivers?: Readonly<Record<string, CacheDriverConfig>>;
|
|
42
|
+
}
|
|
43
|
+
interface NormalizedCacheMemoryDriverConfig {
|
|
44
|
+
readonly name: string;
|
|
45
|
+
readonly driver: 'memory';
|
|
46
|
+
readonly prefix: string;
|
|
47
|
+
readonly maxEntries?: number;
|
|
48
|
+
}
|
|
49
|
+
interface NormalizedCacheFileDriverConfig {
|
|
50
|
+
readonly name: string;
|
|
51
|
+
readonly driver: 'file';
|
|
52
|
+
readonly path: string;
|
|
53
|
+
readonly prefix: string;
|
|
54
|
+
}
|
|
55
|
+
interface NormalizedCacheRedisDriverConfig {
|
|
56
|
+
readonly name: string;
|
|
57
|
+
readonly driver: 'redis';
|
|
58
|
+
readonly connection: string;
|
|
59
|
+
readonly prefix: string;
|
|
60
|
+
}
|
|
61
|
+
interface NormalizedCacheDatabaseDriverConfig {
|
|
62
|
+
readonly name: string;
|
|
63
|
+
readonly driver: 'database';
|
|
64
|
+
readonly connection: string;
|
|
65
|
+
readonly table: string;
|
|
66
|
+
readonly lockTable: string;
|
|
67
|
+
readonly prefix: string;
|
|
68
|
+
}
|
|
69
|
+
interface NormalizedCachePluginDriverConfig {
|
|
70
|
+
readonly name: string;
|
|
71
|
+
readonly driver: string;
|
|
72
|
+
readonly prefix: string;
|
|
73
|
+
readonly [key: string]: unknown;
|
|
74
|
+
}
|
|
75
|
+
type NormalizedCacheDriverConfig = NormalizedCacheMemoryDriverConfig | NormalizedCacheFileDriverConfig | NormalizedCacheRedisDriverConfig | NormalizedCacheDatabaseDriverConfig | NormalizedCachePluginDriverConfig;
|
|
76
|
+
interface NormalizedHoloCacheConfig {
|
|
77
|
+
readonly default: string;
|
|
78
|
+
readonly prefix: string;
|
|
79
|
+
readonly drivers: Readonly<Record<string, NormalizedCacheDriverConfig>>;
|
|
80
|
+
}
|
|
81
|
+
type CacheNormalizationOptions = {
|
|
82
|
+
readonly database?: NormalizedHoloDatabaseConfig;
|
|
83
|
+
readonly redis?: NormalizedHoloRedisConfig;
|
|
84
|
+
};
|
|
85
|
+
declare const DEFAULT_CACHE_DRIVER = "file";
|
|
86
|
+
declare const DEFAULT_CACHE_PREFIX = "";
|
|
87
|
+
declare const DEFAULT_CACHE_FILE_PATH = "./storage/framework/cache/data";
|
|
88
|
+
declare const DEFAULT_CACHE_REDIS_CONNECTION = "default";
|
|
89
|
+
declare const DEFAULT_CACHE_DATABASE_CONNECTION = "default";
|
|
90
|
+
declare const DEFAULT_CACHE_DATABASE_TABLE = "cache";
|
|
91
|
+
declare const DEFAULT_CACHE_DATABASE_LOCK_TABLE = "cache_locks";
|
|
92
|
+
declare const holoCacheDefaults: Readonly<NormalizedHoloCacheConfig>;
|
|
93
|
+
declare function normalizeCacheConfig(config?: HoloCacheConfig, options?: CacheNormalizationOptions): NormalizedHoloCacheConfig;
|
|
94
|
+
declare function defineCacheConfig<TConfig extends HoloCacheConfig>(config: TConfig): Readonly<TConfig>;
|
|
95
|
+
|
|
96
|
+
export { type CacheDatabaseDriverConfig, type CacheDriver, type CacheDriverConfig, type CacheFileDriverConfig, type CacheMemoryDriverConfig, type CacheNormalizationOptions, type CachePluginDriverConfig, type CacheRedisDriverConfig, DEFAULT_CACHE_DATABASE_CONNECTION, DEFAULT_CACHE_DATABASE_LOCK_TABLE, DEFAULT_CACHE_DATABASE_TABLE, DEFAULT_CACHE_DRIVER, DEFAULT_CACHE_FILE_PATH, DEFAULT_CACHE_PREFIX, DEFAULT_CACHE_REDIS_CONNECTION, type HoloCacheConfig, type NormalizedCacheDatabaseDriverConfig, type NormalizedCacheDriverConfig, type NormalizedCacheFileDriverConfig, type NormalizedCacheMemoryDriverConfig, type NormalizedCachePluginDriverConfig, type NormalizedCacheRedisDriverConfig, type NormalizedHoloCacheConfig, defineCacheConfig, holoCacheDefaults, normalizeCacheConfig };
|
package/dist/config.mjs
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_CACHE_DATABASE_CONNECTION,
|
|
3
|
+
DEFAULT_CACHE_DATABASE_LOCK_TABLE,
|
|
4
|
+
DEFAULT_CACHE_DATABASE_TABLE,
|
|
5
|
+
DEFAULT_CACHE_DRIVER,
|
|
6
|
+
DEFAULT_CACHE_FILE_PATH,
|
|
7
|
+
DEFAULT_CACHE_PREFIX,
|
|
8
|
+
DEFAULT_CACHE_REDIS_CONNECTION,
|
|
9
|
+
defineCacheConfig,
|
|
10
|
+
holoCacheDefaults,
|
|
11
|
+
normalizeCacheConfig
|
|
12
|
+
} from "./chunk-7FH4KYTX.mjs";
|
|
13
|
+
export {
|
|
14
|
+
DEFAULT_CACHE_DATABASE_CONNECTION,
|
|
15
|
+
DEFAULT_CACHE_DATABASE_LOCK_TABLE,
|
|
16
|
+
DEFAULT_CACHE_DATABASE_TABLE,
|
|
17
|
+
DEFAULT_CACHE_DRIVER,
|
|
18
|
+
DEFAULT_CACHE_FILE_PATH,
|
|
19
|
+
DEFAULT_CACHE_PREFIX,
|
|
20
|
+
DEFAULT_CACHE_REDIS_CONNECTION,
|
|
21
|
+
defineCacheConfig,
|
|
22
|
+
holoCacheDefaults,
|
|
23
|
+
normalizeCacheConfig
|
|
24
|
+
};
|
package/dist/contracts.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { HoloCacheConfig, NormalizedHoloCacheConfig
|
|
1
|
+
import { HoloCacheConfig, NormalizedHoloCacheConfig } from './config.js';
|
|
2
|
+
import { HoloDatabaseConfig, NormalizedHoloDatabaseConfig } from '@holo-js/db';
|
|
3
|
+
import { HoloRedisConfig, NormalizedHoloRedisConfig } from '@holo-js/kernel';
|
|
2
4
|
|
|
3
5
|
declare const cacheKeyBrand: unique symbol;
|
|
4
6
|
type CacheKey<TValue> = Readonly<{
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {
|
|
2
|
+
registerCacheDriverFactory,
|
|
3
|
+
requireCacheDriverFactory,
|
|
4
|
+
unregisterCacheDriverFactory
|
|
5
|
+
} from "./chunk-FRE6NONR.mjs";
|
|
6
|
+
import "./chunk-KIYULZES.mjs";
|
|
7
|
+
export {
|
|
8
|
+
registerCacheDriverFactory,
|
|
9
|
+
requireCacheDriverFactory,
|
|
10
|
+
unregisterCacheDriverFactory
|
|
11
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { CacheFlexibleTtlInput, CacheFacade, CacheRepository, CacheFallback, CacheValueResolver, CacheOptionalPackageError, CacheDriverContract, CacheDependencyIndex, CacheQueryBridge, CacheKeyInput, CacheDependencyDescriptor, CacheRuntimeBindings, CacheKey, CacheTtlInput, CacheLockContract, defineCacheKey, normalizeCacheTtl, serializeCacheValue, deserializeCacheValue } from './contracts.js';
|
|
2
2
|
export { CacheConfigError, CacheDriverGetResult, CacheDriverPutInput, CacheDriverResolutionError, CacheError, CacheErrorCode, CacheFallbackResolver, CacheInvalidNumericMutationError, CacheInvalidTtlError, CacheLockAcquisitionError, CacheQueryIntegrationError, CacheRuntimeNotConfiguredError, CacheSerializationError, NormalizedCacheTtl, cacheContractsInternals, isCacheKey, resolveCacheKey } from './contracts.js';
|
|
3
|
-
import {
|
|
4
|
-
export { CacheDatabaseDriverConfig, CacheDriver, CacheDriverConfig, CacheFileDriverConfig, CacheMemoryDriverConfig,
|
|
3
|
+
import { NormalizedHoloCacheConfig, HoloCacheConfig, NormalizedCachePluginDriverConfig } from './config.js';
|
|
4
|
+
export { CacheDatabaseDriverConfig, CacheDriver, CacheDriverConfig, CacheFileDriverConfig, CacheMemoryDriverConfig, CachePluginDriverConfig, CacheRedisDriverConfig, NormalizedCacheDatabaseDriverConfig, NormalizedCacheDriverConfig, NormalizedCacheFileDriverConfig, NormalizedCacheMemoryDriverConfig, NormalizedCacheRedisDriverConfig, defineCacheConfig, holoCacheDefaults, normalizeCacheConfig } from './config.js';
|
|
5
|
+
import { HoloDatabaseConnectionConfig, HoloDatabaseConfig, NormalizedHoloDatabaseConfig } from '@holo-js/db';
|
|
6
|
+
import { mkdir, readdir, rmdir, writeFile } from 'node:fs/promises';
|
|
7
|
+
import { NormalizedHoloRedisConnectionConfig, HoloRedisConfig, NormalizedHoloRedisConfig } from '@holo-js/kernel';
|
|
5
8
|
|
|
6
9
|
type FlexibleEnvelope<TValue> = {
|
|
7
10
|
readonly __holo_cache_flexible: true;
|
|
@@ -56,7 +59,7 @@ declare function resetDatabaseDriverModuleLoader(): void;
|
|
|
56
59
|
declare const cacheDbInternals: {
|
|
57
60
|
isModuleNotFoundError: typeof isModuleNotFoundError$1;
|
|
58
61
|
isNormalizedDatabaseConfig: typeof isNormalizedDatabaseConfig;
|
|
59
|
-
loadDatabaseDriverModule:
|
|
62
|
+
loadDatabaseDriverModule: () => Promise<DatabaseCacheDriverModule>;
|
|
60
63
|
normalizeDatabaseModuleLoadError: typeof normalizeDatabaseModuleLoadError;
|
|
61
64
|
normalizeRuntimeDatabaseConfig: typeof normalizeRuntimeDatabaseConfig;
|
|
62
65
|
resolveSharedDatabaseConnection: typeof resolveSharedDatabaseConnection;
|
|
@@ -74,6 +77,12 @@ type FileCacheLockEnvelope = {
|
|
|
74
77
|
owner: string;
|
|
75
78
|
expiresAt: number;
|
|
76
79
|
};
|
|
80
|
+
type FileSystemOperations = {
|
|
81
|
+
readonly mkdir: typeof mkdir;
|
|
82
|
+
readonly readdir: typeof readdir;
|
|
83
|
+
readonly rmdir: typeof rmdir;
|
|
84
|
+
readonly writeFile: typeof writeFile;
|
|
85
|
+
};
|
|
77
86
|
declare function hashCacheKey(key: string): string;
|
|
78
87
|
declare function resolveDriverRoot(path: string): string;
|
|
79
88
|
declare function resolveEntryFilePath(rootPath: string, key: string): string;
|
|
@@ -87,6 +96,8 @@ declare const fileDriverInternals: {
|
|
|
87
96
|
resolveDriverRoot: typeof resolveDriverRoot;
|
|
88
97
|
resolveEntryFilePath: typeof resolveEntryFilePath;
|
|
89
98
|
resolveLockFilePath: typeof resolveLockFilePath;
|
|
99
|
+
resetFileSystemOperations(): void;
|
|
100
|
+
setFileSystemOperations(operations: Partial<FileSystemOperations>): void;
|
|
90
101
|
};
|
|
91
102
|
|
|
92
103
|
type DependencyIndexState = {
|
|
@@ -133,7 +144,7 @@ declare function resetRedisDriverModuleLoader(): void;
|
|
|
133
144
|
declare const cacheRedisInternals: {
|
|
134
145
|
isModuleNotFoundError: typeof isModuleNotFoundError;
|
|
135
146
|
isNormalizedRedisConfig: typeof isNormalizedRedisConfig;
|
|
136
|
-
loadRedisDriverModule:
|
|
147
|
+
loadRedisDriverModule: () => Promise<RedisCacheDriverModule>;
|
|
137
148
|
normalizeRedisModuleLoadError: typeof normalizeRedisModuleLoadError;
|
|
138
149
|
normalizeRuntimeRedisConfig: typeof normalizeRuntimeRedisConfig;
|
|
139
150
|
resolveSharedRedisConnection: typeof resolveSharedRedisConnection;
|
|
@@ -141,6 +152,15 @@ declare const cacheRedisInternals: {
|
|
|
141
152
|
setRedisDriverModuleLoader: typeof setRedisDriverModuleLoader;
|
|
142
153
|
};
|
|
143
154
|
|
|
155
|
+
interface CacheDriverFactory<TOptions> {
|
|
156
|
+
readonly driver: string;
|
|
157
|
+
readonly registrationKey?: string;
|
|
158
|
+
create(options: TOptions): CacheDriverContract;
|
|
159
|
+
}
|
|
160
|
+
declare function registerCacheDriverFactory<TOptions extends object>(factory: CacheDriverFactory<TOptions>): void;
|
|
161
|
+
declare function unregisterCacheDriverFactory<TOptions extends object>(factory: CacheDriverFactory<TOptions>): void;
|
|
162
|
+
declare function requireCacheDriverFactory<TOptions extends object>(driver: string, message: string): CacheDriverFactory<TOptions>;
|
|
163
|
+
|
|
144
164
|
type CacheRuntimeFacade = {
|
|
145
165
|
readonly config: NormalizedHoloCacheConfig;
|
|
146
166
|
readonly databaseConfig?: NormalizedHoloDatabaseConfig;
|
|
@@ -160,6 +180,7 @@ declare function getCacheRuntime(): CacheRuntimeFacade;
|
|
|
160
180
|
declare function resolveConfiguredDriver(facade: CacheRuntimeFacade, requestedName?: string): CacheDriverContract;
|
|
161
181
|
|
|
162
182
|
declare function configureCacheRuntime$1(bindings?: CacheRuntimeBindings): void;
|
|
183
|
+
declare function loadCachePluginDrivers(projectRoot?: string, pluginNames?: readonly string[]): Promise<void>;
|
|
163
184
|
declare const cacheRuntimeInternals: {
|
|
164
185
|
getCacheRuntimeState: typeof getCacheRuntimeState;
|
|
165
186
|
isNormalizedCacheConfig: typeof isNormalizedCacheConfig;
|
|
@@ -167,6 +188,10 @@ declare const cacheRuntimeInternals: {
|
|
|
167
188
|
resolveConfiguredDriver: typeof resolveConfiguredDriver;
|
|
168
189
|
};
|
|
169
190
|
|
|
191
|
+
declare function loadCachePluginDriverContracts(projectRoot?: string, pluginNames?: readonly string[]): Promise<readonly CacheDriverContract[]>;
|
|
192
|
+
declare function loadConfiguredCachePluginDriverContracts(projectRoot: string, pluginNames: readonly string[], configs: readonly NormalizedCachePluginDriverConfig[]): Promise<readonly CacheDriverContract[]>;
|
|
193
|
+
declare function resetCachePluginDriverContracts(): void;
|
|
194
|
+
|
|
170
195
|
declare function configureCacheRuntime(...parameters: Parameters<typeof configureCacheRuntime$1>): void;
|
|
171
196
|
declare function resetCacheRuntime(): void;
|
|
172
197
|
declare const cache: Readonly<{
|
|
@@ -195,7 +220,8 @@ declare const cache: Readonly<{
|
|
|
195
220
|
configureCacheRuntime: typeof configureCacheRuntime;
|
|
196
221
|
getCacheRuntime: typeof getCacheRuntime;
|
|
197
222
|
getCacheRuntimeBindings: typeof getCacheRuntimeBindings;
|
|
223
|
+
loadCachePluginDrivers: typeof loadCachePluginDrivers;
|
|
198
224
|
resetCacheRuntime: typeof resetCacheRuntime;
|
|
199
225
|
}>;
|
|
200
226
|
|
|
201
|
-
export { CacheDependencyDescriptor, CacheDependencyIndex, CacheDriverContract, CacheFacade, CacheFallback, CacheFlexibleTtlInput, CacheKey, CacheKeyInput, CacheLockContract, CacheOptionalPackageError, CacheQueryBridge, CacheRepository, CacheRuntimeBindings, CacheTtlInput, CacheValueResolver, cacheDbInternals, cacheFacade, cacheFacadeInternals, cacheQueryBridgeInternals, cacheRedisInternals, cacheRuntimeInternals, configureCacheRuntime, cache as default, defineCacheKey, deserializeCacheValue, fileDriverInternals, getCacheRuntime, getCacheRuntimeBindings, normalizeCacheTtl, resetCacheRuntime, serializeCacheValue };
|
|
227
|
+
export { CacheDependencyDescriptor, CacheDependencyIndex, CacheDriverContract, type CacheDriverFactory, CacheFacade, CacheFallback, CacheFlexibleTtlInput, CacheKey, CacheKeyInput, CacheLockContract, CacheOptionalPackageError, CacheQueryBridge, CacheRepository, CacheRuntimeBindings, CacheTtlInput, CacheValueResolver, type DatabaseCacheDriverOptions, HoloCacheConfig, NormalizedCachePluginDriverConfig, NormalizedHoloCacheConfig, type RedisCacheDriverOptions, cacheDbInternals, cacheFacade, cacheFacadeInternals, cacheQueryBridgeInternals, cacheRedisInternals, cacheRuntimeInternals, configureCacheRuntime, cache as default, defineCacheKey, deserializeCacheValue, fileDriverInternals, getCacheRuntime, getCacheRuntimeBindings, loadCachePluginDriverContracts, loadCachePluginDrivers, loadConfiguredCachePluginDriverContracts, normalizeCacheTtl, registerCacheDriverFactory, requireCacheDriverFactory, resetCachePluginDriverContracts, resetCacheRuntime, serializeCacheValue, unregisterCacheDriverFactory };
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineCacheConfig,
|
|
3
|
+
holoCacheDefaults,
|
|
4
|
+
normalizeCacheConfig
|
|
5
|
+
} from "./chunk-7FH4KYTX.mjs";
|
|
6
|
+
import {
|
|
7
|
+
registerCacheDriverFactory,
|
|
8
|
+
requireCacheDriverFactory,
|
|
9
|
+
unregisterCacheDriverFactory
|
|
10
|
+
} from "./chunk-FRE6NONR.mjs";
|
|
1
11
|
import {
|
|
2
12
|
CacheConfigError,
|
|
3
13
|
CacheDriverResolutionError,
|
|
@@ -17,9 +27,11 @@ import {
|
|
|
17
27
|
resolveCacheKey,
|
|
18
28
|
serializeCacheValue
|
|
19
29
|
} from "./chunk-KIYULZES.mjs";
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
30
|
+
import {
|
|
31
|
+
loadCachePluginDriverContracts,
|
|
32
|
+
loadConfiguredCachePluginDriverContracts,
|
|
33
|
+
resetCachePluginDriverContracts
|
|
34
|
+
} from "./chunk-NZGSTXGZ.mjs";
|
|
23
35
|
|
|
24
36
|
// src/flexible.ts
|
|
25
37
|
function normalizeFlexibleTtl(ttl) {
|
|
@@ -93,21 +105,12 @@ async function resolveFlexibleCachedValue(options) {
|
|
|
93
105
|
return options.refresh(normalizedTtl);
|
|
94
106
|
}
|
|
95
107
|
|
|
96
|
-
// src/runtime-shared.ts
|
|
97
|
-
import {
|
|
98
|
-
holoCacheDefaults,
|
|
99
|
-
normalizeCacheConfig
|
|
100
|
-
} from "@holo-js/config";
|
|
101
|
-
|
|
102
108
|
// src/db.ts
|
|
103
109
|
import {
|
|
104
110
|
normalizeDatabaseConfig
|
|
105
|
-
} from "@holo-js/
|
|
111
|
+
} from "@holo-js/db";
|
|
106
112
|
|
|
107
113
|
// src/optional-driver.ts
|
|
108
|
-
import { createRequire } from "module";
|
|
109
|
-
import { join } from "path";
|
|
110
|
-
import { pathToFileURL } from "url";
|
|
111
114
|
var CACHE_DRIVER_DISPOSE_SYMBOL = /* @__PURE__ */ Symbol.for("holo.cache.driver.dispose");
|
|
112
115
|
function escapeRegExp(value) {
|
|
113
116
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -138,29 +141,6 @@ function normalizeOptionalDriverModuleLoadError(error, expectedSpecifier, messag
|
|
|
138
141
|
}
|
|
139
142
|
return error;
|
|
140
143
|
}
|
|
141
|
-
async function importOptionalDriverModuleFromProject(specifier) {
|
|
142
|
-
const projectRequire = createRequire(join(process.cwd(), "package.json"));
|
|
143
|
-
return await import(pathToFileURL(projectRequire.resolve(specifier)).href);
|
|
144
|
-
}
|
|
145
|
-
function createOptionalDriverModuleLoader(specifier, missingPackageMessage) {
|
|
146
|
-
return async () => {
|
|
147
|
-
try {
|
|
148
|
-
return await import(
|
|
149
|
-
/* webpackIgnore: true */
|
|
150
|
-
specifier
|
|
151
|
-
);
|
|
152
|
-
} catch (error) {
|
|
153
|
-
if (!isOptionalDriverModuleNotFoundError(error, specifier)) {
|
|
154
|
-
throw normalizeOptionalDriverModuleLoadError(error, specifier, missingPackageMessage);
|
|
155
|
-
}
|
|
156
|
-
try {
|
|
157
|
-
return await importOptionalDriverModuleFromProject(specifier);
|
|
158
|
-
} catch (fallbackError) {
|
|
159
|
-
throw normalizeOptionalDriverModuleLoadError(fallbackError, specifier, missingPackageMessage);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
144
|
var LazyOptionalCacheDriver = class {
|
|
165
145
|
constructor(lazyOptions) {
|
|
166
146
|
this.lazyOptions = lazyOptions;
|
|
@@ -260,7 +240,6 @@ function createLazyOptionalCacheDriver(options) {
|
|
|
260
240
|
}
|
|
261
241
|
|
|
262
242
|
// src/db.ts
|
|
263
|
-
var DATABASE_CACHE_PACKAGE = "@holo-js/cache-db";
|
|
264
243
|
var DATABASE_CACHE_MISSING_MESSAGE = "[@holo-js/cache] Database cache support requires @holo-js/cache-db to be installed.";
|
|
265
244
|
function isNormalizedDatabaseConfig(config) {
|
|
266
245
|
return typeof config === "object" && config !== null && typeof config.connections === "object" && config.connections !== null;
|
|
@@ -288,10 +267,11 @@ function isModuleNotFoundError(error, expectedSpecifier = "@holo-js/cache-db") {
|
|
|
288
267
|
function normalizeDatabaseModuleLoadError(error, expectedSpecifier = "@holo-js/cache-db") {
|
|
289
268
|
return normalizeOptionalDriverModuleLoadError(error, expectedSpecifier, DATABASE_CACHE_MISSING_MESSAGE);
|
|
290
269
|
}
|
|
291
|
-
var loadDatabaseDriverModule =
|
|
292
|
-
|
|
293
|
-
DATABASE_CACHE_MISSING_MESSAGE
|
|
294
|
-
);
|
|
270
|
+
var loadDatabaseDriverModule = async () => {
|
|
271
|
+
const { requireCacheDriverFactory: requireCacheDriverFactory2 } = await import("./driver-registry-YQMWF4CC.mjs");
|
|
272
|
+
const factory = requireCacheDriverFactory2("database", DATABASE_CACHE_MISSING_MESSAGE);
|
|
273
|
+
return { createDatabaseCacheDriver: (options) => factory.create(options) };
|
|
274
|
+
};
|
|
295
275
|
var databaseDriverModuleLoader = loadDatabaseDriverModule;
|
|
296
276
|
function setDatabaseDriverModuleLoader(loader) {
|
|
297
277
|
databaseDriverModuleLoader = loader;
|
|
@@ -321,8 +301,24 @@ var cacheDbInternals = {
|
|
|
321
301
|
|
|
322
302
|
// src/file.ts
|
|
323
303
|
import { createHash, randomUUID } from "crypto";
|
|
324
|
-
import {
|
|
325
|
-
|
|
304
|
+
import {
|
|
305
|
+
mkdir as defaultMkdir,
|
|
306
|
+
open,
|
|
307
|
+
readFile,
|
|
308
|
+
readdir as defaultReaddir,
|
|
309
|
+
rename,
|
|
310
|
+
rm,
|
|
311
|
+
rmdir as defaultRmdir,
|
|
312
|
+
writeFile as defaultWriteFile
|
|
313
|
+
} from "fs/promises";
|
|
314
|
+
import { dirname, join, resolve } from "path";
|
|
315
|
+
var defaultFileSystemOperations = {
|
|
316
|
+
mkdir: defaultMkdir,
|
|
317
|
+
readdir: defaultReaddir,
|
|
318
|
+
rmdir: defaultRmdir,
|
|
319
|
+
writeFile: defaultWriteFile
|
|
320
|
+
};
|
|
321
|
+
var fileSystemOperations = defaultFileSystemOperations;
|
|
326
322
|
var MALFORMED_FILE = /* @__PURE__ */ Symbol("MALFORMED_FILE");
|
|
327
323
|
function defaultSleep(milliseconds) {
|
|
328
324
|
return new Promise((resolveDelay) => {
|
|
@@ -347,14 +343,14 @@ function resolveDriverRoot(path) {
|
|
|
347
343
|
}
|
|
348
344
|
function resolveEntryFilePath(rootPath, key) {
|
|
349
345
|
const hash = hashCacheKey(key);
|
|
350
|
-
return
|
|
346
|
+
return join(rootPath, "entries", hash.slice(0, 2), `${hash}.json`);
|
|
351
347
|
}
|
|
352
348
|
function resolveLockFilePath(rootPath, name) {
|
|
353
349
|
const hash = hashCacheKey(name);
|
|
354
|
-
return
|
|
350
|
+
return join(rootPath, "locks", hash.slice(0, 2), `${hash}.lock`);
|
|
355
351
|
}
|
|
356
352
|
function resolveLockMarkerFilePath(lockPath, owner) {
|
|
357
|
-
return
|
|
353
|
+
return join(lockPath, `${hashCacheKey(owner)}.json`);
|
|
358
354
|
}
|
|
359
355
|
function isPositiveTimestamp(value) {
|
|
360
356
|
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
@@ -374,14 +370,14 @@ function isFileCacheLockEnvelope(value) {
|
|
|
374
370
|
return typeof lock.name === "string" && typeof lock.owner === "string" && isPositiveTimestamp(lock.expiresAt);
|
|
375
371
|
}
|
|
376
372
|
async function ensureParentDirectory(filePath) {
|
|
377
|
-
await mkdir(dirname(filePath), { recursive: true });
|
|
373
|
+
await fileSystemOperations.mkdir(dirname(filePath), { recursive: true });
|
|
378
374
|
}
|
|
379
375
|
async function removeFileIfPresent(filePath) {
|
|
380
376
|
await rm(filePath, { force: true });
|
|
381
377
|
}
|
|
382
378
|
async function removeEmptyDirectoryIfPresent(path) {
|
|
383
379
|
try {
|
|
384
|
-
await rmdir(path);
|
|
380
|
+
await fileSystemOperations.rmdir(path);
|
|
385
381
|
} catch (error) {
|
|
386
382
|
if (error instanceof Error && "code" in error && (error.code === "ENOENT" || error.code === "ENOTEMPTY" || error.code === "ENOTDIR")) {
|
|
387
383
|
return;
|
|
@@ -402,7 +398,7 @@ async function readFileIfPresent(filePath) {
|
|
|
402
398
|
async function writeFileAtomically(filePath, contents) {
|
|
403
399
|
await ensureParentDirectory(filePath);
|
|
404
400
|
const temporaryPath = `${filePath}.${process.pid}.${randomUUID()}.tmp`;
|
|
405
|
-
await writeFile(temporaryPath, contents, "utf8");
|
|
401
|
+
await fileSystemOperations.writeFile(temporaryPath, contents, "utf8");
|
|
406
402
|
try {
|
|
407
403
|
await rename(temporaryPath, filePath);
|
|
408
404
|
} catch (error) {
|
|
@@ -438,9 +434,9 @@ async function readJsonFile(filePath) {
|
|
|
438
434
|
}
|
|
439
435
|
async function listFiles(rootPath) {
|
|
440
436
|
try {
|
|
441
|
-
const entries = await readdir(rootPath, { withFileTypes: true });
|
|
437
|
+
const entries = await fileSystemOperations.readdir(rootPath, { withFileTypes: true });
|
|
442
438
|
const nested = await Promise.all(entries.map(async (entry) => {
|
|
443
|
-
const entryPath =
|
|
439
|
+
const entryPath = join(rootPath, entry.name);
|
|
444
440
|
if (entry.isDirectory()) return listFiles(entryPath);
|
|
445
441
|
return [entryPath];
|
|
446
442
|
}));
|
|
@@ -468,7 +464,7 @@ async function removeScopedCacheFiles(rootPath, prefix, isEnvelope, resolveName)
|
|
|
468
464
|
}
|
|
469
465
|
if (!prefix) {
|
|
470
466
|
await rm(rootPath, { recursive: true, force: true });
|
|
471
|
-
await mkdir(rootPath, { recursive: true });
|
|
467
|
+
await fileSystemOperations.mkdir(rootPath, { recursive: true });
|
|
472
468
|
return;
|
|
473
469
|
}
|
|
474
470
|
for (const filePath of await listFiles(rootPath)) {
|
|
@@ -501,8 +497,8 @@ async function readLock(rootPath, name, now) {
|
|
|
501
497
|
const filePath = resolveLockFilePath(rootPath, name);
|
|
502
498
|
let markerFilePaths;
|
|
503
499
|
try {
|
|
504
|
-
const entries = await readdir(filePath, { withFileTypes: true });
|
|
505
|
-
markerFilePaths = entries.filter((entry) => entry.isFile()).map((entry) =>
|
|
500
|
+
const entries = await fileSystemOperations.readdir(filePath, { withFileTypes: true });
|
|
501
|
+
markerFilePaths = entries.filter((entry) => entry.isFile()).map((entry) => join(filePath, entry.name));
|
|
506
502
|
} catch (error) {
|
|
507
503
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
508
504
|
return {
|
|
@@ -585,7 +581,7 @@ function createFileLock(rootPath, name, seconds, now, sleep, ownerFactory) {
|
|
|
585
581
|
async function writeLockDirectory(filePath, envelope) {
|
|
586
582
|
await ensureParentDirectory(filePath);
|
|
587
583
|
try {
|
|
588
|
-
await mkdir(filePath);
|
|
584
|
+
await fileSystemOperations.mkdir(filePath);
|
|
589
585
|
} catch (error) {
|
|
590
586
|
if (error instanceof Error && "code" in error && error.code === "EEXIST") {
|
|
591
587
|
return false;
|
|
@@ -593,7 +589,7 @@ function createFileLock(rootPath, name, seconds, now, sleep, ownerFactory) {
|
|
|
593
589
|
throw error;
|
|
594
590
|
}
|
|
595
591
|
try {
|
|
596
|
-
await writeFile(resolveLockMarkerFilePath(filePath, owner), envelope, "utf8");
|
|
592
|
+
await fileSystemOperations.writeFile(resolveLockMarkerFilePath(filePath, owner), envelope, "utf8");
|
|
597
593
|
} catch (error) {
|
|
598
594
|
await removeFileIfPresent(resolveLockMarkerFilePath(filePath, owner));
|
|
599
595
|
await removeEmptyDirectoryIfPresent(filePath);
|
|
@@ -747,13 +743,13 @@ function createFileCacheDriver(options) {
|
|
|
747
743
|
},
|
|
748
744
|
async flush() {
|
|
749
745
|
await removeScopedCacheFiles(
|
|
750
|
-
|
|
746
|
+
join(rootPath, "entries"),
|
|
751
747
|
prefix,
|
|
752
748
|
isFileCacheEntryEnvelope,
|
|
753
749
|
(entry) => entry.key
|
|
754
750
|
);
|
|
755
751
|
await removeScopedCacheFiles(
|
|
756
|
-
|
|
752
|
+
join(rootPath, "locks"),
|
|
757
753
|
prefix,
|
|
758
754
|
isFileCacheLockEnvelope,
|
|
759
755
|
(lock) => lock.name
|
|
@@ -776,7 +772,13 @@ var fileDriverInternals = {
|
|
|
776
772
|
isFileCacheLockEnvelope,
|
|
777
773
|
resolveDriverRoot,
|
|
778
774
|
resolveEntryFilePath,
|
|
779
|
-
resolveLockFilePath
|
|
775
|
+
resolveLockFilePath,
|
|
776
|
+
resetFileSystemOperations() {
|
|
777
|
+
fileSystemOperations = defaultFileSystemOperations;
|
|
778
|
+
},
|
|
779
|
+
setFileSystemOperations(operations) {
|
|
780
|
+
fileSystemOperations = { ...defaultFileSystemOperations, ...operations };
|
|
781
|
+
}
|
|
780
782
|
};
|
|
781
783
|
|
|
782
784
|
// src/memory.ts
|
|
@@ -969,8 +971,7 @@ function createMemoryCacheDriver(options) {
|
|
|
969
971
|
// src/redis.ts
|
|
970
972
|
import {
|
|
971
973
|
normalizeRedisConfig
|
|
972
|
-
} from "@holo-js/
|
|
973
|
-
var REDIS_CACHE_PACKAGE = "@holo-js/cache-redis";
|
|
974
|
+
} from "@holo-js/kernel";
|
|
974
975
|
var REDIS_CACHE_MISSING_MESSAGE = "[@holo-js/cache] Redis cache support requires @holo-js/cache-redis to be installed.";
|
|
975
976
|
function isNormalizedRedisConfig(config) {
|
|
976
977
|
return typeof config.default === "string" && typeof config.connections === "object" && config.connections !== null && Object.values(config.connections).every((connection) => {
|
|
@@ -1000,10 +1001,11 @@ function isModuleNotFoundError2(error, expectedSpecifier = "@holo-js/cache-redis
|
|
|
1000
1001
|
function normalizeRedisModuleLoadError(error, expectedSpecifier = "@holo-js/cache-redis") {
|
|
1001
1002
|
return normalizeOptionalDriverModuleLoadError(error, expectedSpecifier, REDIS_CACHE_MISSING_MESSAGE);
|
|
1002
1003
|
}
|
|
1003
|
-
var loadRedisDriverModule =
|
|
1004
|
-
|
|
1005
|
-
REDIS_CACHE_MISSING_MESSAGE
|
|
1006
|
-
);
|
|
1004
|
+
var loadRedisDriverModule = async () => {
|
|
1005
|
+
const { requireCacheDriverFactory: requireCacheDriverFactory2 } = await import("./driver-registry-YQMWF4CC.mjs");
|
|
1006
|
+
const factory = requireCacheDriverFactory2("redis", REDIS_CACHE_MISSING_MESSAGE);
|
|
1007
|
+
return { createRedisCacheDriver: (options) => factory.create(options) };
|
|
1008
|
+
};
|
|
1007
1009
|
var redisDriverModuleLoader = loadRedisDriverModule;
|
|
1008
1010
|
function setRedisDriverModuleLoader(loader) {
|
|
1009
1011
|
redisDriverModuleLoader = loader;
|
|
@@ -1093,45 +1095,55 @@ function resolveConfiguredDriver(facade, requestedName) {
|
|
|
1093
1095
|
}
|
|
1094
1096
|
switch (driverConfig.driver) {
|
|
1095
1097
|
case "file": {
|
|
1098
|
+
const fileConfig = driverConfig;
|
|
1096
1099
|
return cacheResolvedDriver(facade, driverName, createFileCacheDriver({
|
|
1097
|
-
name:
|
|
1098
|
-
path:
|
|
1099
|
-
prefix:
|
|
1100
|
+
name: fileConfig.name,
|
|
1101
|
+
path: fileConfig.path,
|
|
1102
|
+
prefix: fileConfig.prefix
|
|
1100
1103
|
}));
|
|
1101
1104
|
}
|
|
1102
1105
|
case "memory": {
|
|
1106
|
+
const memoryConfig = driverConfig;
|
|
1103
1107
|
return cacheResolvedDriver(facade, driverName, createMemoryCacheDriver({
|
|
1104
|
-
name:
|
|
1105
|
-
maxEntries:
|
|
1108
|
+
name: memoryConfig.name,
|
|
1109
|
+
maxEntries: memoryConfig.maxEntries
|
|
1106
1110
|
}));
|
|
1107
1111
|
}
|
|
1108
1112
|
case "redis": {
|
|
1113
|
+
const redisConfig = driverConfig;
|
|
1109
1114
|
const connection = cacheRedisInternals.resolveSharedRedisConnection(
|
|
1110
1115
|
facade.redisConfig,
|
|
1111
|
-
|
|
1116
|
+
redisConfig.connection
|
|
1112
1117
|
);
|
|
1113
1118
|
return cacheResolvedDriver(facade, driverName, createRedisCacheDriver({
|
|
1114
|
-
name:
|
|
1119
|
+
name: redisConfig.name,
|
|
1115
1120
|
connectionName: connection.name,
|
|
1116
|
-
prefix:
|
|
1121
|
+
prefix: redisConfig.prefix,
|
|
1117
1122
|
redis: connection
|
|
1118
1123
|
}));
|
|
1119
1124
|
}
|
|
1120
1125
|
case "database": {
|
|
1126
|
+
const databaseConfig = driverConfig;
|
|
1121
1127
|
const connection = cacheDbInternals.resolveSharedDatabaseConnection(
|
|
1122
1128
|
facade.databaseConfig,
|
|
1123
|
-
|
|
1129
|
+
databaseConfig.connection
|
|
1124
1130
|
);
|
|
1125
1131
|
return cacheResolvedDriver(facade, driverName, createDatabaseCacheDriver({
|
|
1126
|
-
name:
|
|
1127
|
-
connectionName:
|
|
1128
|
-
table:
|
|
1129
|
-
lockTable:
|
|
1130
|
-
prefix:
|
|
1132
|
+
name: databaseConfig.name,
|
|
1133
|
+
connectionName: databaseConfig.connection,
|
|
1134
|
+
table: databaseConfig.table,
|
|
1135
|
+
lockTable: databaseConfig.lockTable,
|
|
1136
|
+
prefix: databaseConfig.prefix,
|
|
1131
1137
|
connection
|
|
1132
1138
|
}));
|
|
1133
1139
|
}
|
|
1134
1140
|
default:
|
|
1141
|
+
if (typeof driverConfig.driver === "string") {
|
|
1142
|
+
const pluginDriver = facade.drivers.get(driverConfig.driver);
|
|
1143
|
+
if (pluginDriver) {
|
|
1144
|
+
return cacheResolvedDriver(facade, driverName, pluginDriver);
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1135
1147
|
throw new CacheDriverResolutionError(
|
|
1136
1148
|
`[@holo-js/cache] Cache driver "${driverName}" uses unsupported driver "${String(driverConfig.driver)}" in this phase.`
|
|
1137
1149
|
);
|
|
@@ -1205,14 +1217,11 @@ function resetDefaultDependencyIndex() {
|
|
|
1205
1217
|
function resolveDriverContext(driverName) {
|
|
1206
1218
|
const runtime = getCacheRuntime();
|
|
1207
1219
|
const configuredDriverName = driverName?.trim() || runtime.config.default;
|
|
1208
|
-
const
|
|
1209
|
-
|
|
1210
|
-
if (typeof driverConfig?.prefix === "string") {
|
|
1211
|
-
normalizedKeyPrefix = driverConfig.prefix;
|
|
1212
|
-
}
|
|
1220
|
+
const driver = resolveConfiguredDriver(runtime, configuredDriverName);
|
|
1221
|
+
const normalizedKeyPrefix = runtime.config.drivers[configuredDriverName].prefix;
|
|
1213
1222
|
return Object.freeze({
|
|
1214
1223
|
driverName: configuredDriverName,
|
|
1215
|
-
driver
|
|
1224
|
+
driver,
|
|
1216
1225
|
normalizedKeyPrefix
|
|
1217
1226
|
});
|
|
1218
1227
|
}
|
|
@@ -1370,6 +1379,26 @@ function resetCacheRuntime() {
|
|
|
1370
1379
|
getCacheRuntimeState().bindings = void 0;
|
|
1371
1380
|
resetDefaultDependencyIndex();
|
|
1372
1381
|
setGlobalDatabaseQueryCacheBridge(void 0);
|
|
1382
|
+
resetCachePluginDriverContracts();
|
|
1383
|
+
}
|
|
1384
|
+
async function loadCachePluginDrivers(projectRoot = process.cwd(), pluginNames = []) {
|
|
1385
|
+
const bindings = getCacheRuntimeState().bindings;
|
|
1386
|
+
if (!bindings) {
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
const pluginDriverConfigs = Object.values(bindings.config.drivers).filter((driver) => {
|
|
1390
|
+
return driver.driver !== "memory" && driver.driver !== "file" && driver.driver !== "redis" && driver.driver !== "database";
|
|
1391
|
+
});
|
|
1392
|
+
for (const driver of await loadConfiguredCachePluginDriverContracts(projectRoot, pluginNames, pluginDriverConfigs)) {
|
|
1393
|
+
bindings.drivers.set(driver.name, driver);
|
|
1394
|
+
}
|
|
1395
|
+
if (pluginDriverConfigs.length > 0) {
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1398
|
+
const { loadCachePluginDriverContracts: loadCachePluginDriverContracts2 } = await import("./plugins-JHYNVE7O.mjs");
|
|
1399
|
+
for (const driver of await loadCachePluginDriverContracts2(projectRoot, pluginNames)) {
|
|
1400
|
+
bindings.drivers.set(driver.name, driver);
|
|
1401
|
+
}
|
|
1373
1402
|
}
|
|
1374
1403
|
var cacheRuntimeInternals = {
|
|
1375
1404
|
getCacheRuntimeState,
|
|
@@ -1605,6 +1634,7 @@ var cache = Object.freeze({
|
|
|
1605
1634
|
configureCacheRuntime: configureCacheRuntime2,
|
|
1606
1635
|
getCacheRuntime,
|
|
1607
1636
|
getCacheRuntimeBindings,
|
|
1637
|
+
loadCachePluginDrivers,
|
|
1608
1638
|
resetCacheRuntime: resetCacheRuntime2,
|
|
1609
1639
|
...cacheFacade
|
|
1610
1640
|
});
|
|
@@ -1635,9 +1665,18 @@ export {
|
|
|
1635
1665
|
fileDriverInternals,
|
|
1636
1666
|
getCacheRuntime,
|
|
1637
1667
|
getCacheRuntimeBindings,
|
|
1668
|
+
holoCacheDefaults,
|
|
1638
1669
|
isCacheKey,
|
|
1670
|
+
loadCachePluginDriverContracts,
|
|
1671
|
+
loadCachePluginDrivers,
|
|
1672
|
+
loadConfiguredCachePluginDriverContracts,
|
|
1673
|
+
normalizeCacheConfig,
|
|
1639
1674
|
normalizeCacheTtl,
|
|
1675
|
+
registerCacheDriverFactory,
|
|
1676
|
+
requireCacheDriverFactory,
|
|
1677
|
+
resetCachePluginDriverContracts,
|
|
1640
1678
|
resetCacheRuntime2 as resetCacheRuntime,
|
|
1641
1679
|
resolveCacheKey,
|
|
1642
|
-
serializeCacheValue
|
|
1680
|
+
serializeCacheValue,
|
|
1681
|
+
unregisterCacheDriverFactory
|
|
1643
1682
|
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
loadCachePluginDriverContracts,
|
|
3
|
+
loadConfiguredCachePluginDriverContracts,
|
|
4
|
+
resetCachePluginDriverContracts
|
|
5
|
+
} from "./chunk-NZGSTXGZ.mjs";
|
|
6
|
+
export {
|
|
7
|
+
loadCachePluginDriverContracts,
|
|
8
|
+
loadConfiguredCachePluginDriverContracts,
|
|
9
|
+
resetCachePluginDriverContracts
|
|
10
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@holo-js/cache",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Holo-JS Framework - cache contracts, config helpers, serialization, and runtime seams",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -10,6 +10,11 @@
|
|
|
10
10
|
"import": "./dist/index.mjs",
|
|
11
11
|
"default": "./dist/index.mjs"
|
|
12
12
|
},
|
|
13
|
+
"./config": {
|
|
14
|
+
"types": "./dist/config.d.ts",
|
|
15
|
+
"import": "./dist/config.mjs",
|
|
16
|
+
"default": "./dist/config.mjs"
|
|
17
|
+
},
|
|
13
18
|
"./contracts": {
|
|
14
19
|
"types": "./dist/contracts.d.ts",
|
|
15
20
|
"import": "./dist/contracts.mjs",
|
|
@@ -28,7 +33,9 @@
|
|
|
28
33
|
"test": "vitest --run"
|
|
29
34
|
},
|
|
30
35
|
"dependencies": {
|
|
31
|
-
"@holo-js/config": "^0.
|
|
36
|
+
"@holo-js/config": "^0.3.0",
|
|
37
|
+
"@holo-js/db": "^0.3.0",
|
|
38
|
+
"@holo-js/kernel": "^0.3.0"
|
|
32
39
|
},
|
|
33
40
|
"devDependencies": {
|
|
34
41
|
"@types/node": "^22.10.2",
|