@holo-js/cli 0.1.2 → 0.1.4

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.
Files changed (56) hide show
  1. package/dist/bin/holo.mjs +533 -4616
  2. package/dist/broadcast-CSSARTSA.mjs +84 -0
  3. package/dist/broadcast-YSIJCL3R.mjs +85 -0
  4. package/dist/cache-4G6QGIZO.mjs +66 -0
  5. package/dist/cache-OWQY4E7W.mjs +67 -0
  6. package/dist/cache-migrations-NATT5WPQ.mjs +154 -0
  7. package/dist/cache-migrations-RVEA6CEU.mjs +155 -0
  8. package/dist/chunk-3OTCSFDG.mjs +849 -0
  9. package/dist/chunk-66FHW725.mjs +465 -0
  10. package/dist/chunk-BWW5TDFI.mjs +4 -0
  11. package/dist/chunk-CUL4RJTG.mjs +22 -0
  12. package/dist/chunk-D4GG556Y.mjs +23 -0
  13. package/dist/chunk-D7O4SU6N.mjs +2 -0
  14. package/dist/chunk-DMH2B4UQ.mjs +343 -0
  15. package/dist/chunk-ET7UXHHQ.mjs +166 -0
  16. package/dist/chunk-EUIVXVJL.mjs +25 -0
  17. package/dist/chunk-G5ADO27Q.mjs +463 -0
  18. package/dist/chunk-GSQ3HTRO.mjs +165 -0
  19. package/dist/chunk-H7TJ4FB3.mjs +848 -0
  20. package/dist/chunk-ICJR7TS4.mjs +66 -0
  21. package/dist/chunk-JX2ZH6XY.mjs +270 -0
  22. package/dist/chunk-M7J3YTHR.mjs +26 -0
  23. package/dist/chunk-MZXN2YMI.mjs +3236 -0
  24. package/dist/chunk-Q5F6C2D4.mjs +65 -0
  25. package/dist/chunk-QFUSWV3J.mjs +3237 -0
  26. package/dist/chunk-QYLSMF7V.mjs +539 -0
  27. package/dist/chunk-S7P7EBM3.mjs +787 -0
  28. package/dist/chunk-SRWJU3A5.mjs +11 -0
  29. package/dist/chunk-URK7C3VQ.mjs +538 -0
  30. package/dist/chunk-VT5IDQG6.mjs +788 -0
  31. package/dist/chunk-XUYKPU5Q.mjs +272 -0
  32. package/dist/chunk-ZLRO7HXY.mjs +342 -0
  33. package/dist/chunk-ZXDU7RHU.mjs +9 -0
  34. package/dist/config-DMWBMMGD.mjs +26 -0
  35. package/dist/config-LS5USBRB.mjs +25 -0
  36. package/dist/dev-KQFT7RHR.mjs +43 -0
  37. package/dist/dev-LZ3O2E3U.mjs +42 -0
  38. package/dist/discovery-GBLAUTXS.mjs +28 -0
  39. package/dist/discovery-R733D2PO.mjs +29 -0
  40. package/dist/generators-DSN4GWJI.mjs +425 -0
  41. package/dist/generators-WX45BI4U.mjs +426 -0
  42. package/dist/index.d.ts +1 -0
  43. package/dist/index.mjs +536 -4618
  44. package/dist/queue-6OG7VJ34.mjs +626 -0
  45. package/dist/queue-FV35LLPR.mjs +625 -0
  46. package/dist/queue-migrations-NK2EYX3J.mjs +163 -0
  47. package/dist/queue-migrations-SSIYKK5S.mjs +162 -0
  48. package/dist/runtime-4BV3JODY.mjs +56 -0
  49. package/dist/runtime-ANBO7VQM.mjs +33 -0
  50. package/dist/runtime-EFZ5H5IL.mjs +55 -0
  51. package/dist/runtime-OOSJ5JBY.mjs +32 -0
  52. package/dist/scaffold-7OTDH4UR.mjs +121 -0
  53. package/dist/scaffold-DRKBGS2K.mjs +120 -0
  54. package/dist/security-ATKDC26E.mjs +68 -0
  55. package/dist/security-R7VH6W5H.mjs +69 -0
  56. package/package.json +12 -11
@@ -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-MZXN2YMI.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-QFUSWV3J.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,66 @@
1
+ import {
2
+ writeLine
3
+ } from "./chunk-ZXDU7RHU.mjs";
4
+ import "./chunk-D7O4SU6N.mjs";
5
+ import "./chunk-S7P7EBM3.mjs";
6
+ import "./chunk-MZXN2YMI.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,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-QFUSWV3J.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,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-ZLRO7HXY.mjs";
14
+ import "./chunk-CUL4RJTG.mjs";
15
+ import "./chunk-D7O4SU6N.mjs";
16
+ import {
17
+ prepareProjectDiscovery
18
+ } from "./chunk-S7P7EBM3.mjs";
19
+ import "./chunk-MZXN2YMI.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
+ };
@@ -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-DMH2B4UQ.mjs";
15
+ import "./chunk-D4GG556Y.mjs";
16
+ import "./chunk-BWW5TDFI.mjs";
17
+ import {
18
+ prepareProjectDiscovery
19
+ } from "./chunk-VT5IDQG6.mjs";
20
+ import "./chunk-QFUSWV3J.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
+ };