@holo-js/cli 0.1.1 → 0.1.3
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/bin/holo.mjs +533 -4616
- package/dist/broadcast-YZS4OFCM.mjs +84 -0
- package/dist/broadcast-ZYFKUFM5.mjs +85 -0
- package/dist/cache-ODBZT6IP.mjs +67 -0
- package/dist/cache-V43YMG4K.mjs +66 -0
- package/dist/cache-migrations-KPOEH6GP.mjs +155 -0
- package/dist/cache-migrations-ZUOI2A7N.mjs +154 -0
- package/dist/chunk-3OTCSFDG.mjs +849 -0
- package/dist/chunk-66FHW725.mjs +465 -0
- package/dist/chunk-BWW5TDFI.mjs +4 -0
- package/dist/chunk-CUL4RJTG.mjs +22 -0
- package/dist/chunk-D4GG556Y.mjs +23 -0
- package/dist/chunk-D7O4SU6N.mjs +2 -0
- package/dist/chunk-ET7UXHHQ.mjs +166 -0
- package/dist/chunk-EUIVXVJL.mjs +25 -0
- package/dist/chunk-G5ADO27Q.mjs +463 -0
- package/dist/chunk-GSQ3HTRO.mjs +165 -0
- package/dist/chunk-H7TJ4FB3.mjs +848 -0
- package/dist/chunk-HE6FYNVN.mjs +3203 -0
- package/dist/chunk-ICJR7TS4.mjs +66 -0
- package/dist/chunk-ICKN56JY.mjs +342 -0
- package/dist/chunk-JX2ZH6XY.mjs +270 -0
- package/dist/chunk-M7J3YTHR.mjs +26 -0
- package/dist/chunk-Q5F6C2D4.mjs +65 -0
- package/dist/chunk-QYLSMF7V.mjs +539 -0
- package/dist/chunk-RB65DLR4.mjs +343 -0
- package/dist/chunk-S7P7EBM3.mjs +787 -0
- package/dist/chunk-SRWJU3A5.mjs +11 -0
- package/dist/chunk-T4OVZZEE.mjs +3204 -0
- package/dist/chunk-URK7C3VQ.mjs +538 -0
- package/dist/chunk-VT5IDQG6.mjs +788 -0
- package/dist/chunk-XUYKPU5Q.mjs +272 -0
- package/dist/chunk-ZXDU7RHU.mjs +9 -0
- package/dist/config-DMWBMMGD.mjs +26 -0
- package/dist/config-LS5USBRB.mjs +25 -0
- package/dist/dev-KGRIGLJY.mjs +42 -0
- package/dist/dev-LVHDCPVS.mjs +43 -0
- package/dist/discovery-GBLAUTXS.mjs +28 -0
- package/dist/discovery-R733D2PO.mjs +29 -0
- package/dist/generators-32R45P6Z.mjs +426 -0
- package/dist/generators-WSF23UKM.mjs +425 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +536 -4618
- package/dist/queue-6N7HQMRL.mjs +625 -0
- package/dist/queue-QG5EXOG4.mjs +626 -0
- package/dist/queue-migrations-JWKU45Y3.mjs +163 -0
- package/dist/queue-migrations-O6QSSDPQ.mjs +162 -0
- package/dist/runtime-ANBO7VQM.mjs +33 -0
- package/dist/runtime-OOSJ5JBY.mjs +32 -0
- package/dist/runtime-RI4OWTIT.mjs +55 -0
- package/dist/runtime-ZRPK5DIT.mjs +56 -0
- package/dist/scaffold-IYWZKT3W.mjs +120 -0
- package/dist/scaffold-ULATB4CA.mjs +121 -0
- package/dist/security-AE6LGNC4.mjs +68 -0
- package/dist/security-OCOPEH2V.mjs +69 -0
- package/package.json +10 -9
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import {
|
|
2
|
+
writeLine
|
|
3
|
+
} from "./chunk-ZXDU7RHU.mjs";
|
|
4
|
+
import "./chunk-D7O4SU6N.mjs";
|
|
5
|
+
import {
|
|
6
|
+
prepareProjectDiscovery
|
|
7
|
+
} from "./chunk-S7P7EBM3.mjs";
|
|
8
|
+
import "./chunk-HE6FYNVN.mjs";
|
|
9
|
+
import {
|
|
10
|
+
loadProjectConfig
|
|
11
|
+
} from "./chunk-GSQ3HTRO.mjs";
|
|
12
|
+
import {
|
|
13
|
+
loadGeneratedProjectRegistry
|
|
14
|
+
} from "./chunk-H7TJ4FB3.mjs";
|
|
15
|
+
import {
|
|
16
|
+
importProjectModule,
|
|
17
|
+
resolveProjectPackageImportSpecifier
|
|
18
|
+
} from "./chunk-G5ADO27Q.mjs";
|
|
19
|
+
|
|
20
|
+
// src/broadcast.ts
|
|
21
|
+
import { basename, extname } from "path";
|
|
22
|
+
import { loadConfigDirectory } from "@holo-js/config";
|
|
23
|
+
function hasLoadedRedisConfigSection(loadedFiles) {
|
|
24
|
+
return Array.isArray(loadedFiles) && loadedFiles.some((filePath) => {
|
|
25
|
+
return basename(filePath, extname(filePath)) === "redis";
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
async function loadBroadcastCliModule(projectRoot) {
|
|
29
|
+
try {
|
|
30
|
+
return await import(resolveProjectPackageImportSpecifier(projectRoot, "@holo-js/broadcast"));
|
|
31
|
+
} catch (error) {
|
|
32
|
+
const details = error instanceof Error ? error.message : String(error);
|
|
33
|
+
throw new Error(
|
|
34
|
+
`Unable to load @holo-js/broadcast from ${projectRoot}. Install it with "holo install broadcast". ${details}`
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async function runBroadcastWorkCommand(io, projectRoot, dependencies = {}) {
|
|
39
|
+
const loadConfig = dependencies.loadConfig ?? loadConfigDirectory;
|
|
40
|
+
const loadModule = dependencies.loadModule ?? loadBroadcastCliModule;
|
|
41
|
+
const config = await loadConfig(projectRoot);
|
|
42
|
+
const project = await loadProjectConfig(projectRoot);
|
|
43
|
+
const loadRegistry = dependencies.loadRegistry ?? loadGeneratedProjectRegistry;
|
|
44
|
+
await loadRegistry(projectRoot).catch(() => void 0);
|
|
45
|
+
const registry = await prepareProjectDiscovery(projectRoot, project.config);
|
|
46
|
+
const broadcastModule = await loadModule(projectRoot);
|
|
47
|
+
const worker = await broadcastModule.startBroadcastWorker({
|
|
48
|
+
config: config.broadcast,
|
|
49
|
+
queue: config.queue,
|
|
50
|
+
...hasLoadedRedisConfigSection(config.loadedFiles) ? { redis: config.redis } : {},
|
|
51
|
+
...registry ? {
|
|
52
|
+
channelAuth: {
|
|
53
|
+
registry: {
|
|
54
|
+
projectRoot,
|
|
55
|
+
channels: registry.channels
|
|
56
|
+
},
|
|
57
|
+
importModule: async (absolutePath) => await importProjectModule(projectRoot, absolutePath)
|
|
58
|
+
}
|
|
59
|
+
} : {}
|
|
60
|
+
});
|
|
61
|
+
writeLine(io.stdout, `[broadcast] Worker listening on ${worker.host}:${worker.port}`);
|
|
62
|
+
await new Promise((resolvePromise) => {
|
|
63
|
+
let stopped = false;
|
|
64
|
+
const stop = async () => {
|
|
65
|
+
if (stopped) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
stopped = true;
|
|
69
|
+
process.off("SIGINT", onSignal);
|
|
70
|
+
process.off("SIGTERM", onSignal);
|
|
71
|
+
await worker.stop();
|
|
72
|
+
resolvePromise();
|
|
73
|
+
};
|
|
74
|
+
const onSignal = () => {
|
|
75
|
+
void stop();
|
|
76
|
+
};
|
|
77
|
+
process.on("SIGINT", onSignal);
|
|
78
|
+
process.on("SIGTERM", onSignal);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
export {
|
|
82
|
+
loadBroadcastCliModule,
|
|
83
|
+
runBroadcastWorkCommand
|
|
84
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
writeLine
|
|
4
|
+
} from "./chunk-SRWJU3A5.mjs";
|
|
5
|
+
import "./chunk-BWW5TDFI.mjs";
|
|
6
|
+
import {
|
|
7
|
+
prepareProjectDiscovery
|
|
8
|
+
} from "./chunk-VT5IDQG6.mjs";
|
|
9
|
+
import "./chunk-T4OVZZEE.mjs";
|
|
10
|
+
import {
|
|
11
|
+
loadProjectConfig
|
|
12
|
+
} from "./chunk-ET7UXHHQ.mjs";
|
|
13
|
+
import {
|
|
14
|
+
loadGeneratedProjectRegistry
|
|
15
|
+
} from "./chunk-3OTCSFDG.mjs";
|
|
16
|
+
import {
|
|
17
|
+
importProjectModule,
|
|
18
|
+
resolveProjectPackageImportSpecifier
|
|
19
|
+
} from "./chunk-66FHW725.mjs";
|
|
20
|
+
|
|
21
|
+
// src/broadcast.ts
|
|
22
|
+
import { basename, extname } from "path";
|
|
23
|
+
import { loadConfigDirectory } from "@holo-js/config";
|
|
24
|
+
function hasLoadedRedisConfigSection(loadedFiles) {
|
|
25
|
+
return Array.isArray(loadedFiles) && loadedFiles.some((filePath) => {
|
|
26
|
+
return basename(filePath, extname(filePath)) === "redis";
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
async function loadBroadcastCliModule(projectRoot) {
|
|
30
|
+
try {
|
|
31
|
+
return await import(resolveProjectPackageImportSpecifier(projectRoot, "@holo-js/broadcast"));
|
|
32
|
+
} catch (error) {
|
|
33
|
+
const details = error instanceof Error ? error.message : String(error);
|
|
34
|
+
throw new Error(
|
|
35
|
+
`Unable to load @holo-js/broadcast from ${projectRoot}. Install it with "holo install broadcast". ${details}`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async function runBroadcastWorkCommand(io, projectRoot, dependencies = {}) {
|
|
40
|
+
const loadConfig = dependencies.loadConfig ?? loadConfigDirectory;
|
|
41
|
+
const loadModule = dependencies.loadModule ?? loadBroadcastCliModule;
|
|
42
|
+
const config = await loadConfig(projectRoot);
|
|
43
|
+
const project = await loadProjectConfig(projectRoot);
|
|
44
|
+
const loadRegistry = dependencies.loadRegistry ?? loadGeneratedProjectRegistry;
|
|
45
|
+
await loadRegistry(projectRoot).catch(() => void 0);
|
|
46
|
+
const registry = await prepareProjectDiscovery(projectRoot, project.config);
|
|
47
|
+
const broadcastModule = await loadModule(projectRoot);
|
|
48
|
+
const worker = await broadcastModule.startBroadcastWorker({
|
|
49
|
+
config: config.broadcast,
|
|
50
|
+
queue: config.queue,
|
|
51
|
+
...hasLoadedRedisConfigSection(config.loadedFiles) ? { redis: config.redis } : {},
|
|
52
|
+
...registry ? {
|
|
53
|
+
channelAuth: {
|
|
54
|
+
registry: {
|
|
55
|
+
projectRoot,
|
|
56
|
+
channels: registry.channels
|
|
57
|
+
},
|
|
58
|
+
importModule: async (absolutePath) => await importProjectModule(projectRoot, absolutePath)
|
|
59
|
+
}
|
|
60
|
+
} : {}
|
|
61
|
+
});
|
|
62
|
+
writeLine(io.stdout, `[broadcast] Worker listening on ${worker.host}:${worker.port}`);
|
|
63
|
+
await new Promise((resolvePromise) => {
|
|
64
|
+
let stopped = false;
|
|
65
|
+
const stop = async () => {
|
|
66
|
+
if (stopped) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
stopped = true;
|
|
70
|
+
process.off("SIGINT", onSignal);
|
|
71
|
+
process.off("SIGTERM", onSignal);
|
|
72
|
+
await worker.stop();
|
|
73
|
+
resolvePromise();
|
|
74
|
+
};
|
|
75
|
+
const onSignal = () => {
|
|
76
|
+
void stop();
|
|
77
|
+
};
|
|
78
|
+
process.on("SIGINT", onSignal);
|
|
79
|
+
process.on("SIGTERM", onSignal);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
export {
|
|
83
|
+
loadBroadcastCliModule,
|
|
84
|
+
runBroadcastWorkCommand
|
|
85
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
writeLine
|
|
4
|
+
} from "./chunk-SRWJU3A5.mjs";
|
|
5
|
+
import "./chunk-BWW5TDFI.mjs";
|
|
6
|
+
import "./chunk-VT5IDQG6.mjs";
|
|
7
|
+
import "./chunk-T4OVZZEE.mjs";
|
|
8
|
+
import "./chunk-ET7UXHHQ.mjs";
|
|
9
|
+
import "./chunk-3OTCSFDG.mjs";
|
|
10
|
+
import {
|
|
11
|
+
resolveProjectPackageImportSpecifier
|
|
12
|
+
} from "./chunk-66FHW725.mjs";
|
|
13
|
+
|
|
14
|
+
// src/cache.ts
|
|
15
|
+
import { loadConfigDirectory } from "@holo-js/config";
|
|
16
|
+
function resolveCacheFacade(cacheModule) {
|
|
17
|
+
const candidate = cacheModule.default;
|
|
18
|
+
if (candidate) {
|
|
19
|
+
return candidate;
|
|
20
|
+
}
|
|
21
|
+
return cacheModule;
|
|
22
|
+
}
|
|
23
|
+
async function loadCacheCliModule(projectRoot) {
|
|
24
|
+
return await import(resolveProjectPackageImportSpecifier(projectRoot, "@holo-js/cache"));
|
|
25
|
+
}
|
|
26
|
+
async function initializeCacheMaintenanceEnvironment(projectRoot) {
|
|
27
|
+
const loadedConfig = await loadConfigDirectory(projectRoot);
|
|
28
|
+
const cacheModule = await loadCacheCliModule(projectRoot);
|
|
29
|
+
const cache = resolveCacheFacade(cacheModule);
|
|
30
|
+
cache.configureCacheRuntime({
|
|
31
|
+
config: loadedConfig.cache,
|
|
32
|
+
databaseConfig: loadedConfig.database,
|
|
33
|
+
redisConfig: loadedConfig.redis
|
|
34
|
+
});
|
|
35
|
+
return {
|
|
36
|
+
cache,
|
|
37
|
+
async cleanup() {
|
|
38
|
+
cache.resetCacheRuntime();
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
async function runCacheClearCommand(io, projectRoot, driverName, dependencies = {}) {
|
|
43
|
+
const environment = await (dependencies.initializeCache ?? initializeCacheMaintenanceEnvironment)(projectRoot);
|
|
44
|
+
try {
|
|
45
|
+
const repository = driverName?.trim() ? environment.cache.driver(driverName) : environment.cache;
|
|
46
|
+
await (dependencies.flush ?? (async (target) => await target.flush()))(repository);
|
|
47
|
+
writeLine(io.stdout, driverName?.trim() ? `[cache] Cleared cache store "${driverName}".` : "[cache] Cleared the default cache store.");
|
|
48
|
+
} finally {
|
|
49
|
+
await environment.cleanup();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async function runCacheForgetCommand(io, projectRoot, key, driverName, dependencies = {}) {
|
|
53
|
+
const environment = await (dependencies.initializeCache ?? initializeCacheMaintenanceEnvironment)(projectRoot);
|
|
54
|
+
try {
|
|
55
|
+
const repository = driverName?.trim() ? environment.cache.driver(driverName) : environment.cache;
|
|
56
|
+
const forgotten = await (dependencies.forget ?? (async (target, targetKey) => await target.forget(targetKey)))(repository, key);
|
|
57
|
+
writeLine(io.stdout, forgotten ? `[cache] Forgot key "${key}".` : `[cache] Key "${key}" was not present.`);
|
|
58
|
+
} finally {
|
|
59
|
+
await environment.cleanup();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export {
|
|
63
|
+
initializeCacheMaintenanceEnvironment,
|
|
64
|
+
loadCacheCliModule,
|
|
65
|
+
runCacheClearCommand,
|
|
66
|
+
runCacheForgetCommand
|
|
67
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import {
|
|
2
|
+
writeLine
|
|
3
|
+
} from "./chunk-ZXDU7RHU.mjs";
|
|
4
|
+
import "./chunk-D7O4SU6N.mjs";
|
|
5
|
+
import "./chunk-S7P7EBM3.mjs";
|
|
6
|
+
import "./chunk-HE6FYNVN.mjs";
|
|
7
|
+
import "./chunk-GSQ3HTRO.mjs";
|
|
8
|
+
import "./chunk-H7TJ4FB3.mjs";
|
|
9
|
+
import {
|
|
10
|
+
resolveProjectPackageImportSpecifier
|
|
11
|
+
} from "./chunk-G5ADO27Q.mjs";
|
|
12
|
+
|
|
13
|
+
// src/cache.ts
|
|
14
|
+
import { loadConfigDirectory } from "@holo-js/config";
|
|
15
|
+
function resolveCacheFacade(cacheModule) {
|
|
16
|
+
const candidate = cacheModule.default;
|
|
17
|
+
if (candidate) {
|
|
18
|
+
return candidate;
|
|
19
|
+
}
|
|
20
|
+
return cacheModule;
|
|
21
|
+
}
|
|
22
|
+
async function loadCacheCliModule(projectRoot) {
|
|
23
|
+
return await import(resolveProjectPackageImportSpecifier(projectRoot, "@holo-js/cache"));
|
|
24
|
+
}
|
|
25
|
+
async function initializeCacheMaintenanceEnvironment(projectRoot) {
|
|
26
|
+
const loadedConfig = await loadConfigDirectory(projectRoot);
|
|
27
|
+
const cacheModule = await loadCacheCliModule(projectRoot);
|
|
28
|
+
const cache = resolveCacheFacade(cacheModule);
|
|
29
|
+
cache.configureCacheRuntime({
|
|
30
|
+
config: loadedConfig.cache,
|
|
31
|
+
databaseConfig: loadedConfig.database,
|
|
32
|
+
redisConfig: loadedConfig.redis
|
|
33
|
+
});
|
|
34
|
+
return {
|
|
35
|
+
cache,
|
|
36
|
+
async cleanup() {
|
|
37
|
+
cache.resetCacheRuntime();
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
async function runCacheClearCommand(io, projectRoot, driverName, dependencies = {}) {
|
|
42
|
+
const environment = await (dependencies.initializeCache ?? initializeCacheMaintenanceEnvironment)(projectRoot);
|
|
43
|
+
try {
|
|
44
|
+
const repository = driverName?.trim() ? environment.cache.driver(driverName) : environment.cache;
|
|
45
|
+
await (dependencies.flush ?? (async (target) => await target.flush()))(repository);
|
|
46
|
+
writeLine(io.stdout, driverName?.trim() ? `[cache] Cleared cache store "${driverName}".` : "[cache] Cleared the default cache store.");
|
|
47
|
+
} finally {
|
|
48
|
+
await environment.cleanup();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async function runCacheForgetCommand(io, projectRoot, key, driverName, dependencies = {}) {
|
|
52
|
+
const environment = await (dependencies.initializeCache ?? initializeCacheMaintenanceEnvironment)(projectRoot);
|
|
53
|
+
try {
|
|
54
|
+
const repository = driverName?.trim() ? environment.cache.driver(driverName) : environment.cache;
|
|
55
|
+
const forgotten = await (dependencies.forget ?? (async (target, targetKey) => await target.forget(targetKey)))(repository, key);
|
|
56
|
+
writeLine(io.stdout, forgotten ? `[cache] Forgot key "${key}".` : `[cache] Key "${key}" was not present.`);
|
|
57
|
+
} finally {
|
|
58
|
+
await environment.cleanup();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export {
|
|
62
|
+
initializeCacheMaintenanceEnvironment,
|
|
63
|
+
loadCacheCliModule,
|
|
64
|
+
runCacheClearCommand,
|
|
65
|
+
runCacheForgetCommand
|
|
66
|
+
};
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
getRegistryMigrationSlug,
|
|
4
|
+
hasRegisteredCreateTableMigration,
|
|
5
|
+
hasRegisteredMigrationSlug,
|
|
6
|
+
nextMigrationTemplate
|
|
7
|
+
} from "./chunk-ICJR7TS4.mjs";
|
|
8
|
+
import {
|
|
9
|
+
writeLine
|
|
10
|
+
} from "./chunk-SRWJU3A5.mjs";
|
|
11
|
+
import "./chunk-M7J3YTHR.mjs";
|
|
12
|
+
import {
|
|
13
|
+
runProjectPrepare
|
|
14
|
+
} from "./chunk-RB65DLR4.mjs";
|
|
15
|
+
import "./chunk-D4GG556Y.mjs";
|
|
16
|
+
import "./chunk-BWW5TDFI.mjs";
|
|
17
|
+
import {
|
|
18
|
+
prepareProjectDiscovery
|
|
19
|
+
} from "./chunk-VT5IDQG6.mjs";
|
|
20
|
+
import "./chunk-T4OVZZEE.mjs";
|
|
21
|
+
import {
|
|
22
|
+
ensureProjectConfig
|
|
23
|
+
} from "./chunk-ET7UXHHQ.mjs";
|
|
24
|
+
import {
|
|
25
|
+
loadGeneratedProjectRegistry
|
|
26
|
+
} from "./chunk-3OTCSFDG.mjs";
|
|
27
|
+
import {
|
|
28
|
+
makeProjectRelativePath,
|
|
29
|
+
resolveDefaultArtifactPath,
|
|
30
|
+
writeTextFile
|
|
31
|
+
} from "./chunk-66FHW725.mjs";
|
|
32
|
+
|
|
33
|
+
// src/cache-migrations.ts
|
|
34
|
+
import { resolve } from "path";
|
|
35
|
+
import { loadConfigDirectory } from "@holo-js/config";
|
|
36
|
+
import { normalizeMigrationSlug } from "@holo-js/db";
|
|
37
|
+
var DEFAULT_CACHE_DATABASE_TABLE = "cache";
|
|
38
|
+
var DEFAULT_CACHE_DATABASE_LOCK_TABLE = "cache_locks";
|
|
39
|
+
async function loadCacheConfig(projectRoot) {
|
|
40
|
+
const loadedConfig = await loadConfigDirectory(projectRoot);
|
|
41
|
+
if (!loadedConfig || typeof loadedConfig !== "object" || !("cache" in loadedConfig) || !loadedConfig.cache || typeof loadedConfig.cache !== "object" || !("drivers" in loadedConfig.cache) || typeof loadedConfig.cache.drivers !== "object" || loadedConfig.cache.drivers === null || Array.isArray(loadedConfig.cache.drivers)) {
|
|
42
|
+
throw new Error("Cache config is missing or malformed. Expected a cache config object with a drivers property.");
|
|
43
|
+
}
|
|
44
|
+
const cacheConfig = loadedConfig.cache;
|
|
45
|
+
for (const [driverName, driverConfig] of Object.entries(cacheConfig.drivers)) {
|
|
46
|
+
if (driverConfig.driver !== "database") {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const databaseDriver = driverConfig;
|
|
50
|
+
if (typeof databaseDriver.table !== "string" || !databaseDriver.table.trim() || typeof databaseDriver.lockTable !== "string" || !databaseDriver.lockTable.trim()) {
|
|
51
|
+
throw new Error(`Database cache driver "${driverName}" must define non-empty "table" and "lockTable" strings.`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return cacheConfig;
|
|
55
|
+
}
|
|
56
|
+
function normalizeCacheMigrationName(tableName) {
|
|
57
|
+
return normalizeMigrationSlug(`create_${tableName.replaceAll(".", "_")}_cache_table`);
|
|
58
|
+
}
|
|
59
|
+
function escapeSingleQuotedString(value) {
|
|
60
|
+
return value.replaceAll("\\", "\\\\").replaceAll("'", "\\'");
|
|
61
|
+
}
|
|
62
|
+
function renderCacheTableMigration(tableName = DEFAULT_CACHE_DATABASE_TABLE, lockTableName = DEFAULT_CACHE_DATABASE_LOCK_TABLE) {
|
|
63
|
+
const escapedTableName = escapeSingleQuotedString(tableName);
|
|
64
|
+
const escapedLockTableName = escapeSingleQuotedString(lockTableName);
|
|
65
|
+
const escapedTableIndexName = escapeSingleQuotedString(`${tableName.replaceAll(".", "_")}_expires_at_index`);
|
|
66
|
+
const escapedLockTableIndexName = escapeSingleQuotedString(`${lockTableName.replaceAll(".", "_")}_expires_at_index`);
|
|
67
|
+
return [
|
|
68
|
+
"import { defineMigration, type MigrationContext } from '@holo-js/db'",
|
|
69
|
+
"",
|
|
70
|
+
"export default defineMigration({",
|
|
71
|
+
" async up({ schema }: MigrationContext) {",
|
|
72
|
+
` await schema.createTable('${escapedTableName}', (table) => {`,
|
|
73
|
+
" table.string('key').primaryKey()",
|
|
74
|
+
" table.text('payload')",
|
|
75
|
+
" table.bigInteger('expires_at').nullable()",
|
|
76
|
+
` table.index(['expires_at'], '${escapedTableIndexName}')`,
|
|
77
|
+
" })",
|
|
78
|
+
` await schema.createTable('${escapedLockTableName}', (table) => {`,
|
|
79
|
+
" table.string('name').primaryKey()",
|
|
80
|
+
" table.string('owner')",
|
|
81
|
+
" table.bigInteger('expires_at')",
|
|
82
|
+
` table.index(['expires_at'], '${escapedLockTableIndexName}')`,
|
|
83
|
+
" })",
|
|
84
|
+
" },",
|
|
85
|
+
" async down({ schema }: MigrationContext) {",
|
|
86
|
+
` await schema.dropTable('${escapedLockTableName}')`,
|
|
87
|
+
` await schema.dropTable('${escapedTableName}')`,
|
|
88
|
+
" },",
|
|
89
|
+
"})",
|
|
90
|
+
""
|
|
91
|
+
].join("\n");
|
|
92
|
+
}
|
|
93
|
+
function resolveDatabaseCacheTables(cacheConfig) {
|
|
94
|
+
const configured = Object.values(cacheConfig.drivers).filter((driver) => driver.driver === "database").map((driver) => ({
|
|
95
|
+
table: driver.table,
|
|
96
|
+
lockTable: driver.lockTable
|
|
97
|
+
}));
|
|
98
|
+
if (configured.length === 0) {
|
|
99
|
+
throw new Error("The configured cache drivers do not use the database driver.");
|
|
100
|
+
}
|
|
101
|
+
return Object.freeze(configured);
|
|
102
|
+
}
|
|
103
|
+
async function runCacheTableCommand(io, projectRoot) {
|
|
104
|
+
const project = await ensureProjectConfig(projectRoot);
|
|
105
|
+
const registry = await loadGeneratedProjectRegistry(projectRoot) ?? await prepareProjectDiscovery(projectRoot, project.config);
|
|
106
|
+
const cacheConfig = await loadCacheConfig(projectRoot);
|
|
107
|
+
const migrationsDir = resolve(projectRoot, project.config.paths.migrations);
|
|
108
|
+
const createdFiles = [];
|
|
109
|
+
const resolvedTables = resolveDatabaseCacheTables(cacheConfig);
|
|
110
|
+
const seenTables = /* @__PURE__ */ new Set();
|
|
111
|
+
const seenLockTables = /* @__PURE__ */ new Set();
|
|
112
|
+
const seenSlugs = /* @__PURE__ */ new Map();
|
|
113
|
+
for (const { table, lockTable } of resolvedTables) {
|
|
114
|
+
const migrationName = normalizeCacheMigrationName(table);
|
|
115
|
+
const previousTable = seenSlugs.get(migrationName);
|
|
116
|
+
if (seenTables.has(table) || seenLockTables.has(lockTable) || previousTable && previousTable !== table) {
|
|
117
|
+
throw new Error(`A migration for cache tables "${table}" and "${lockTable}" already exists.`);
|
|
118
|
+
}
|
|
119
|
+
seenTables.add(table);
|
|
120
|
+
seenLockTables.add(lockTable);
|
|
121
|
+
seenSlugs.set(migrationName, table);
|
|
122
|
+
}
|
|
123
|
+
for (const { table, lockTable } of resolvedTables) {
|
|
124
|
+
const migrationName = normalizeCacheMigrationName(table);
|
|
125
|
+
if (hasRegisteredMigrationSlug(registry, migrationName) || hasRegisteredCreateTableMigration(registry, table) || hasRegisteredCreateTableMigration(registry, lockTable)) {
|
|
126
|
+
throw new Error(`A migration for cache tables "${table}" and "${lockTable}" already exists.`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
for (const { table, lockTable } of resolvedTables) {
|
|
130
|
+
const migrationTemplate = await nextMigrationTemplate(normalizeCacheMigrationName(table), migrationsDir);
|
|
131
|
+
const migrationFilePath = resolveDefaultArtifactPath(projectRoot, project.config.paths.migrations, migrationTemplate.fileName);
|
|
132
|
+
await writeTextFile(migrationFilePath, renderCacheTableMigration(table, lockTable));
|
|
133
|
+
createdFiles.push(migrationFilePath);
|
|
134
|
+
}
|
|
135
|
+
await runProjectPrepare(projectRoot);
|
|
136
|
+
for (const filePath of createdFiles) {
|
|
137
|
+
writeLine(io.stdout, `Created migration: ${makeProjectRelativePath(projectRoot, filePath)}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
var cacheMigrationInternals = {
|
|
141
|
+
getRegistryMigrationSlug,
|
|
142
|
+
hasRegisteredMigrationSlug,
|
|
143
|
+
hasRegisteredCreateTableMigration,
|
|
144
|
+
nextMigrationTemplate
|
|
145
|
+
};
|
|
146
|
+
export {
|
|
147
|
+
DEFAULT_CACHE_DATABASE_LOCK_TABLE,
|
|
148
|
+
DEFAULT_CACHE_DATABASE_TABLE,
|
|
149
|
+
cacheMigrationInternals,
|
|
150
|
+
loadCacheConfig,
|
|
151
|
+
normalizeCacheMigrationName,
|
|
152
|
+
renderCacheTableMigration,
|
|
153
|
+
resolveDatabaseCacheTables,
|
|
154
|
+
runCacheTableCommand
|
|
155
|
+
};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getRegistryMigrationSlug,
|
|
3
|
+
hasRegisteredCreateTableMigration,
|
|
4
|
+
hasRegisteredMigrationSlug,
|
|
5
|
+
nextMigrationTemplate
|
|
6
|
+
} from "./chunk-Q5F6C2D4.mjs";
|
|
7
|
+
import {
|
|
8
|
+
writeLine
|
|
9
|
+
} from "./chunk-ZXDU7RHU.mjs";
|
|
10
|
+
import "./chunk-EUIVXVJL.mjs";
|
|
11
|
+
import {
|
|
12
|
+
runProjectPrepare
|
|
13
|
+
} from "./chunk-ICKN56JY.mjs";
|
|
14
|
+
import "./chunk-CUL4RJTG.mjs";
|
|
15
|
+
import "./chunk-D7O4SU6N.mjs";
|
|
16
|
+
import {
|
|
17
|
+
prepareProjectDiscovery
|
|
18
|
+
} from "./chunk-S7P7EBM3.mjs";
|
|
19
|
+
import "./chunk-HE6FYNVN.mjs";
|
|
20
|
+
import {
|
|
21
|
+
ensureProjectConfig
|
|
22
|
+
} from "./chunk-GSQ3HTRO.mjs";
|
|
23
|
+
import {
|
|
24
|
+
loadGeneratedProjectRegistry
|
|
25
|
+
} from "./chunk-H7TJ4FB3.mjs";
|
|
26
|
+
import {
|
|
27
|
+
makeProjectRelativePath,
|
|
28
|
+
resolveDefaultArtifactPath,
|
|
29
|
+
writeTextFile
|
|
30
|
+
} from "./chunk-G5ADO27Q.mjs";
|
|
31
|
+
|
|
32
|
+
// src/cache-migrations.ts
|
|
33
|
+
import { resolve } from "path";
|
|
34
|
+
import { loadConfigDirectory } from "@holo-js/config";
|
|
35
|
+
import { normalizeMigrationSlug } from "@holo-js/db";
|
|
36
|
+
var DEFAULT_CACHE_DATABASE_TABLE = "cache";
|
|
37
|
+
var DEFAULT_CACHE_DATABASE_LOCK_TABLE = "cache_locks";
|
|
38
|
+
async function loadCacheConfig(projectRoot) {
|
|
39
|
+
const loadedConfig = await loadConfigDirectory(projectRoot);
|
|
40
|
+
if (!loadedConfig || typeof loadedConfig !== "object" || !("cache" in loadedConfig) || !loadedConfig.cache || typeof loadedConfig.cache !== "object" || !("drivers" in loadedConfig.cache) || typeof loadedConfig.cache.drivers !== "object" || loadedConfig.cache.drivers === null || Array.isArray(loadedConfig.cache.drivers)) {
|
|
41
|
+
throw new Error("Cache config is missing or malformed. Expected a cache config object with a drivers property.");
|
|
42
|
+
}
|
|
43
|
+
const cacheConfig = loadedConfig.cache;
|
|
44
|
+
for (const [driverName, driverConfig] of Object.entries(cacheConfig.drivers)) {
|
|
45
|
+
if (driverConfig.driver !== "database") {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const databaseDriver = driverConfig;
|
|
49
|
+
if (typeof databaseDriver.table !== "string" || !databaseDriver.table.trim() || typeof databaseDriver.lockTable !== "string" || !databaseDriver.lockTable.trim()) {
|
|
50
|
+
throw new Error(`Database cache driver "${driverName}" must define non-empty "table" and "lockTable" strings.`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return cacheConfig;
|
|
54
|
+
}
|
|
55
|
+
function normalizeCacheMigrationName(tableName) {
|
|
56
|
+
return normalizeMigrationSlug(`create_${tableName.replaceAll(".", "_")}_cache_table`);
|
|
57
|
+
}
|
|
58
|
+
function escapeSingleQuotedString(value) {
|
|
59
|
+
return value.replaceAll("\\", "\\\\").replaceAll("'", "\\'");
|
|
60
|
+
}
|
|
61
|
+
function renderCacheTableMigration(tableName = DEFAULT_CACHE_DATABASE_TABLE, lockTableName = DEFAULT_CACHE_DATABASE_LOCK_TABLE) {
|
|
62
|
+
const escapedTableName = escapeSingleQuotedString(tableName);
|
|
63
|
+
const escapedLockTableName = escapeSingleQuotedString(lockTableName);
|
|
64
|
+
const escapedTableIndexName = escapeSingleQuotedString(`${tableName.replaceAll(".", "_")}_expires_at_index`);
|
|
65
|
+
const escapedLockTableIndexName = escapeSingleQuotedString(`${lockTableName.replaceAll(".", "_")}_expires_at_index`);
|
|
66
|
+
return [
|
|
67
|
+
"import { defineMigration, type MigrationContext } from '@holo-js/db'",
|
|
68
|
+
"",
|
|
69
|
+
"export default defineMigration({",
|
|
70
|
+
" async up({ schema }: MigrationContext) {",
|
|
71
|
+
` await schema.createTable('${escapedTableName}', (table) => {`,
|
|
72
|
+
" table.string('key').primaryKey()",
|
|
73
|
+
" table.text('payload')",
|
|
74
|
+
" table.bigInteger('expires_at').nullable()",
|
|
75
|
+
` table.index(['expires_at'], '${escapedTableIndexName}')`,
|
|
76
|
+
" })",
|
|
77
|
+
` await schema.createTable('${escapedLockTableName}', (table) => {`,
|
|
78
|
+
" table.string('name').primaryKey()",
|
|
79
|
+
" table.string('owner')",
|
|
80
|
+
" table.bigInteger('expires_at')",
|
|
81
|
+
` table.index(['expires_at'], '${escapedLockTableIndexName}')`,
|
|
82
|
+
" })",
|
|
83
|
+
" },",
|
|
84
|
+
" async down({ schema }: MigrationContext) {",
|
|
85
|
+
` await schema.dropTable('${escapedLockTableName}')`,
|
|
86
|
+
` await schema.dropTable('${escapedTableName}')`,
|
|
87
|
+
" },",
|
|
88
|
+
"})",
|
|
89
|
+
""
|
|
90
|
+
].join("\n");
|
|
91
|
+
}
|
|
92
|
+
function resolveDatabaseCacheTables(cacheConfig) {
|
|
93
|
+
const configured = Object.values(cacheConfig.drivers).filter((driver) => driver.driver === "database").map((driver) => ({
|
|
94
|
+
table: driver.table,
|
|
95
|
+
lockTable: driver.lockTable
|
|
96
|
+
}));
|
|
97
|
+
if (configured.length === 0) {
|
|
98
|
+
throw new Error("The configured cache drivers do not use the database driver.");
|
|
99
|
+
}
|
|
100
|
+
return Object.freeze(configured);
|
|
101
|
+
}
|
|
102
|
+
async function runCacheTableCommand(io, projectRoot) {
|
|
103
|
+
const project = await ensureProjectConfig(projectRoot);
|
|
104
|
+
const registry = await loadGeneratedProjectRegistry(projectRoot) ?? await prepareProjectDiscovery(projectRoot, project.config);
|
|
105
|
+
const cacheConfig = await loadCacheConfig(projectRoot);
|
|
106
|
+
const migrationsDir = resolve(projectRoot, project.config.paths.migrations);
|
|
107
|
+
const createdFiles = [];
|
|
108
|
+
const resolvedTables = resolveDatabaseCacheTables(cacheConfig);
|
|
109
|
+
const seenTables = /* @__PURE__ */ new Set();
|
|
110
|
+
const seenLockTables = /* @__PURE__ */ new Set();
|
|
111
|
+
const seenSlugs = /* @__PURE__ */ new Map();
|
|
112
|
+
for (const { table, lockTable } of resolvedTables) {
|
|
113
|
+
const migrationName = normalizeCacheMigrationName(table);
|
|
114
|
+
const previousTable = seenSlugs.get(migrationName);
|
|
115
|
+
if (seenTables.has(table) || seenLockTables.has(lockTable) || previousTable && previousTable !== table) {
|
|
116
|
+
throw new Error(`A migration for cache tables "${table}" and "${lockTable}" already exists.`);
|
|
117
|
+
}
|
|
118
|
+
seenTables.add(table);
|
|
119
|
+
seenLockTables.add(lockTable);
|
|
120
|
+
seenSlugs.set(migrationName, table);
|
|
121
|
+
}
|
|
122
|
+
for (const { table, lockTable } of resolvedTables) {
|
|
123
|
+
const migrationName = normalizeCacheMigrationName(table);
|
|
124
|
+
if (hasRegisteredMigrationSlug(registry, migrationName) || hasRegisteredCreateTableMigration(registry, table) || hasRegisteredCreateTableMigration(registry, lockTable)) {
|
|
125
|
+
throw new Error(`A migration for cache tables "${table}" and "${lockTable}" already exists.`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
for (const { table, lockTable } of resolvedTables) {
|
|
129
|
+
const migrationTemplate = await nextMigrationTemplate(normalizeCacheMigrationName(table), migrationsDir);
|
|
130
|
+
const migrationFilePath = resolveDefaultArtifactPath(projectRoot, project.config.paths.migrations, migrationTemplate.fileName);
|
|
131
|
+
await writeTextFile(migrationFilePath, renderCacheTableMigration(table, lockTable));
|
|
132
|
+
createdFiles.push(migrationFilePath);
|
|
133
|
+
}
|
|
134
|
+
await runProjectPrepare(projectRoot);
|
|
135
|
+
for (const filePath of createdFiles) {
|
|
136
|
+
writeLine(io.stdout, `Created migration: ${makeProjectRelativePath(projectRoot, filePath)}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
var cacheMigrationInternals = {
|
|
140
|
+
getRegistryMigrationSlug,
|
|
141
|
+
hasRegisteredMigrationSlug,
|
|
142
|
+
hasRegisteredCreateTableMigration,
|
|
143
|
+
nextMigrationTemplate
|
|
144
|
+
};
|
|
145
|
+
export {
|
|
146
|
+
DEFAULT_CACHE_DATABASE_LOCK_TABLE,
|
|
147
|
+
DEFAULT_CACHE_DATABASE_TABLE,
|
|
148
|
+
cacheMigrationInternals,
|
|
149
|
+
loadCacheConfig,
|
|
150
|
+
normalizeCacheMigrationName,
|
|
151
|
+
renderCacheTableMigration,
|
|
152
|
+
resolveDatabaseCacheTables,
|
|
153
|
+
runCacheTableCommand
|
|
154
|
+
};
|