@holo-js/cli 0.1.9 → 0.2.1
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 +179 -81
- package/dist/broadcast-III5MB3R.mjs +203 -0
- package/dist/broadcast-ZIFYFOUQ.mjs +203 -0
- package/dist/{cache-ETOIQ5IG.mjs → cache-634WUR3T.mjs} +6 -6
- package/dist/cache-7J7DIOP6.mjs +66 -0
- package/dist/{cache-migrations-2GGI4TJK.mjs → cache-migrations-2NBEUF2T.mjs} +50 -30
- package/dist/cache-migrations-S2LJMDOQ.mjs +173 -0
- package/dist/{chunk-WRZFATUT.mjs → chunk-4OHJC3GL.mjs} +232 -143
- package/dist/{chunk-ASTSSSL2.mjs → chunk-5TEH2QPK.mjs} +99 -122
- package/dist/{chunk-F4MT6GBK.mjs → chunk-FGQ2I2YH.mjs} +1 -1
- package/dist/chunk-I7QBCEV7.mjs +33 -0
- package/dist/{chunk-R6BWRY3E.mjs → chunk-ILU426CF.mjs} +3 -1
- package/dist/{chunk-IMOGEKB4.mjs → chunk-J76GH2DR.mjs} +229 -119
- package/dist/{chunk-HB4Q7VYK.mjs → chunk-KS5TWO75.mjs} +30 -273
- package/dist/{chunk-57SJ566R.mjs → chunk-LBJAJLKU.mjs} +1 -1
- package/dist/{chunk-BAFQ2GOA.mjs → chunk-LXGQCG56.mjs} +1 -1
- package/dist/chunk-MCVRN7KX.mjs +3308 -0
- package/dist/chunk-SFRAGRHY.mjs +472 -0
- package/dist/{chunk-7JR73TOH.mjs → chunk-VP2E62DF.mjs} +36 -25
- package/dist/{chunk-5EU32E7X.mjs → chunk-VRGB6DIS.mjs} +116 -12
- package/dist/{chunk-SRPGIWCF.mjs → chunk-YEFJBN56.mjs} +2 -2
- package/dist/{config-ARLE6PKR.mjs → config-MD27U4FM.mjs} +3 -3
- package/dist/{dev-6RG5SSZ7.mjs → dev-M2GGURAX.mjs} +9 -7
- package/dist/dev-PBNFQK6Y.mjs +44 -0
- package/dist/{discovery-FCVGQQVD.mjs → discovery-GWTBF5RZ.mjs} +3 -3
- package/dist/{generators-UI2LJK3O.mjs → generators-BZJ53PUU.mjs} +13 -36
- package/dist/generators-DEPLONDJ.mjs +520 -0
- package/dist/index.mjs +181 -83
- package/dist/{media-migrations-JQSDCC7S.mjs → media-migrations-5EISZBSD.mjs} +9 -20
- package/dist/media-migrations-NMUWBEKE.mjs +106 -0
- package/dist/{queue-BY3PLH4I.mjs → queue-FRAVPNFJ.mjs} +12 -12
- package/dist/queue-GY7BWGTX.mjs +625 -0
- package/dist/{queue-migrations-YZUKEZK7.mjs → queue-migrations-J7YPIKRB.mjs} +13 -12
- package/dist/queue-migrations-O24ERNFF.mjs +167 -0
- package/dist/{runtime-BI343WHS.mjs → runtime-2AA7ZLJ6.mjs} +9 -9
- package/dist/{runtime-ZKD6URAV.mjs → runtime-GSXF4NB3.mjs} +1 -1
- package/dist/runtime-HGK2MWSC.mjs +57 -0
- package/dist/runtime-worker.d.ts +2 -0
- package/dist/runtime-worker.mjs +276 -0
- package/dist/{scaffold-UBOS2NZR.mjs → scaffold-DEOTRALR.mjs} +9 -5
- package/dist/scaffold-Y232IGYS.mjs +139 -0
- package/dist/{security-TYPVOYGF.mjs → security-MZW2CJKS.mjs} +6 -6
- package/dist/security-XVG673UR.mjs +71 -0
- package/package.json +9 -7
- package/dist/broadcast-VR46UZEL.mjs +0 -84
- package/dist/chunk-ZXDU7RHU.mjs +0 -9
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import {
|
|
2
|
+
runProjectPrepare
|
|
3
|
+
} from "./chunk-SFRAGRHY.mjs";
|
|
4
|
+
import "./chunk-FGQ2I2YH.mjs";
|
|
5
|
+
import {
|
|
6
|
+
getRegistryMigrationSlug,
|
|
7
|
+
hasRegisteredCreateTableMigration,
|
|
8
|
+
hasRegisteredMigrationSlug,
|
|
9
|
+
nextMigrationTemplate
|
|
10
|
+
} from "./chunk-LXGQCG56.mjs";
|
|
11
|
+
import "./chunk-LBJAJLKU.mjs";
|
|
12
|
+
import {
|
|
13
|
+
writeLine
|
|
14
|
+
} from "./chunk-I7QBCEV7.mjs";
|
|
15
|
+
import "./chunk-D7O4SU6N.mjs";
|
|
16
|
+
import {
|
|
17
|
+
prepareProjectDiscovery
|
|
18
|
+
} from "./chunk-VP2E62DF.mjs";
|
|
19
|
+
import "./chunk-MCVRN7KX.mjs";
|
|
20
|
+
import {
|
|
21
|
+
ensureProjectConfig
|
|
22
|
+
} from "./chunk-YEFJBN56.mjs";
|
|
23
|
+
import {
|
|
24
|
+
loadGeneratedProjectRegistry
|
|
25
|
+
} from "./chunk-J76GH2DR.mjs";
|
|
26
|
+
import {
|
|
27
|
+
makeProjectRelativePath,
|
|
28
|
+
resolveDefaultArtifactPath,
|
|
29
|
+
writeTextFile
|
|
30
|
+
} from "./chunk-ILU426CF.mjs";
|
|
31
|
+
|
|
32
|
+
// src/queue-migrations.ts
|
|
33
|
+
import { resolve } from "path";
|
|
34
|
+
import { loadConfigDirectory } from "@holo-js/config";
|
|
35
|
+
import { normalizeMigrationSlug } from "@holo-js/db";
|
|
36
|
+
var DEFAULT_DATABASE_QUEUE_TABLE = "jobs";
|
|
37
|
+
var DEFAULT_FAILED_JOBS_TABLE = "failed_jobs";
|
|
38
|
+
async function loadQueueConfig(projectRoot) {
|
|
39
|
+
return (await loadConfigDirectory(projectRoot)).queue;
|
|
40
|
+
}
|
|
41
|
+
function normalizeQueueMigrationName(tableName) {
|
|
42
|
+
return normalizeMigrationSlug(`create_${tableName.replaceAll(".", "_")}_table`);
|
|
43
|
+
}
|
|
44
|
+
function renderQueueTableMigration(tableName) {
|
|
45
|
+
const tableNameLiteral = JSON.stringify(tableName);
|
|
46
|
+
const indexPrefix = tableName.replaceAll(".", "_");
|
|
47
|
+
return [
|
|
48
|
+
"import { defineMigration, type MigrationContext } from '@holo-js/db'",
|
|
49
|
+
"",
|
|
50
|
+
"export default defineMigration({",
|
|
51
|
+
" async up({ schema }: MigrationContext) {",
|
|
52
|
+
` await schema.createTable(${tableNameLiteral}, (table) => {`,
|
|
53
|
+
" table.string('id').primaryKey()",
|
|
54
|
+
" table.string('job')",
|
|
55
|
+
" table.string('connection')",
|
|
56
|
+
" table.string('queue')",
|
|
57
|
+
" table.text('payload')",
|
|
58
|
+
" table.integer('attempts').default(0)",
|
|
59
|
+
" table.integer('max_attempts').default(1)",
|
|
60
|
+
" table.bigInteger('available_at')",
|
|
61
|
+
" table.bigInteger('reserved_at').nullable()",
|
|
62
|
+
" table.string('reservation_id').nullable()",
|
|
63
|
+
" table.bigInteger('created_at')",
|
|
64
|
+
` table.index(['queue', 'available_at'], ${JSON.stringify(`${indexPrefix}_queue_available_at_index`)})`,
|
|
65
|
+
` table.index(['queue', 'reserved_at'], ${JSON.stringify(`${indexPrefix}_queue_reserved_at_index`)})`,
|
|
66
|
+
` table.index(['reservation_id'], ${JSON.stringify(`${indexPrefix}_reservation_id_index`)})`,
|
|
67
|
+
" })",
|
|
68
|
+
" },",
|
|
69
|
+
" async down({ schema }: MigrationContext) {",
|
|
70
|
+
` await schema.dropTable(${tableNameLiteral})`,
|
|
71
|
+
" },",
|
|
72
|
+
"})",
|
|
73
|
+
""
|
|
74
|
+
].join("\n");
|
|
75
|
+
}
|
|
76
|
+
function renderFailedJobsTableMigration(tableName) {
|
|
77
|
+
const tableNameLiteral = JSON.stringify(tableName);
|
|
78
|
+
const indexPrefix = tableName.replaceAll(".", "_");
|
|
79
|
+
return [
|
|
80
|
+
"import { defineMigration, type MigrationContext } from '@holo-js/db'",
|
|
81
|
+
"",
|
|
82
|
+
"export default defineMigration({",
|
|
83
|
+
" async up({ schema }: MigrationContext) {",
|
|
84
|
+
` await schema.createTable(${tableNameLiteral}, (table) => {`,
|
|
85
|
+
" table.string('id').primaryKey()",
|
|
86
|
+
" table.string('job_id')",
|
|
87
|
+
" table.string('job')",
|
|
88
|
+
" table.string('connection')",
|
|
89
|
+
" table.string('queue')",
|
|
90
|
+
" table.text('payload')",
|
|
91
|
+
" table.text('exception')",
|
|
92
|
+
" table.bigInteger('failed_at')",
|
|
93
|
+
` table.index(['job_id'], ${JSON.stringify(`${indexPrefix}_job_id_index`)})`,
|
|
94
|
+
` table.index(['failed_at'], ${JSON.stringify(`${indexPrefix}_failed_at_index`)})`,
|
|
95
|
+
" })",
|
|
96
|
+
" },",
|
|
97
|
+
" async down({ schema }: MigrationContext) {",
|
|
98
|
+
` await schema.dropTable(${tableNameLiteral})`,
|
|
99
|
+
" },",
|
|
100
|
+
"})",
|
|
101
|
+
""
|
|
102
|
+
].join("\n");
|
|
103
|
+
}
|
|
104
|
+
function resolveDatabaseQueueTables(queueConfig) {
|
|
105
|
+
const configured = Object.values(queueConfig.connections).filter((connection) => connection.driver === "database").map((connection) => connection.table);
|
|
106
|
+
return Object.freeze(configured.length > 0 ? [...new Set(configured)] : [DEFAULT_DATABASE_QUEUE_TABLE]);
|
|
107
|
+
}
|
|
108
|
+
async function runQueueTableCommand(io, projectRoot) {
|
|
109
|
+
const project = await ensureProjectConfig(projectRoot);
|
|
110
|
+
const registry = await loadGeneratedProjectRegistry(projectRoot) ?? await prepareProjectDiscovery(projectRoot, project.config);
|
|
111
|
+
const queueConfig = await loadQueueConfig(projectRoot);
|
|
112
|
+
const migrationsDir = resolve(projectRoot, project.config.paths.migrations);
|
|
113
|
+
const createdFiles = [];
|
|
114
|
+
const tableNames = resolveDatabaseQueueTables(queueConfig);
|
|
115
|
+
for (const tableName of tableNames) {
|
|
116
|
+
const migrationName = normalizeQueueMigrationName(tableName);
|
|
117
|
+
if (hasRegisteredMigrationSlug(registry, migrationName) || hasRegisteredCreateTableMigration(registry, tableName)) {
|
|
118
|
+
throw new Error(`A migration for table "${tableName}" already exists.`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
for (const tableName of tableNames) {
|
|
122
|
+
const migrationTemplate = await nextMigrationTemplate(normalizeQueueMigrationName(tableName), migrationsDir);
|
|
123
|
+
const migrationFilePath = resolveDefaultArtifactPath(projectRoot, project.config.paths.migrations, migrationTemplate.fileName);
|
|
124
|
+
await writeTextFile(migrationFilePath, renderQueueTableMigration(tableName));
|
|
125
|
+
createdFiles.push(migrationFilePath);
|
|
126
|
+
}
|
|
127
|
+
await runProjectPrepare(projectRoot);
|
|
128
|
+
for (const filePath of createdFiles) {
|
|
129
|
+
writeLine(io.stdout, `Created migration: ${makeProjectRelativePath(projectRoot, filePath)}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async function runQueueFailedTableCommand(io, projectRoot) {
|
|
133
|
+
const project = await ensureProjectConfig(projectRoot);
|
|
134
|
+
const registry = await loadGeneratedProjectRegistry(projectRoot) ?? await prepareProjectDiscovery(projectRoot, project.config);
|
|
135
|
+
const queueConfig = await loadQueueConfig(projectRoot);
|
|
136
|
+
const tableName = queueConfig.failed === false ? DEFAULT_FAILED_JOBS_TABLE : queueConfig.failed.table;
|
|
137
|
+
const migrationName = normalizeQueueMigrationName(tableName);
|
|
138
|
+
if (hasRegisteredMigrationSlug(registry, migrationName) || hasRegisteredCreateTableMigration(registry, tableName)) {
|
|
139
|
+
throw new Error(`A migration for table "${tableName}" already exists.`);
|
|
140
|
+
}
|
|
141
|
+
const migrationTemplate = await nextMigrationTemplate(
|
|
142
|
+
migrationName,
|
|
143
|
+
resolve(projectRoot, project.config.paths.migrations)
|
|
144
|
+
);
|
|
145
|
+
const migrationFilePath = resolveDefaultArtifactPath(projectRoot, project.config.paths.migrations, migrationTemplate.fileName);
|
|
146
|
+
await writeTextFile(migrationFilePath, renderFailedJobsTableMigration(tableName));
|
|
147
|
+
await runProjectPrepare(projectRoot);
|
|
148
|
+
writeLine(io.stdout, `Created migration: ${makeProjectRelativePath(projectRoot, migrationFilePath)}`);
|
|
149
|
+
}
|
|
150
|
+
var queueMigrationInternals = {
|
|
151
|
+
getRegistryMigrationSlug,
|
|
152
|
+
hasRegisteredMigrationSlug,
|
|
153
|
+
hasRegisteredCreateTableMigration,
|
|
154
|
+
nextMigrationTemplate
|
|
155
|
+
};
|
|
156
|
+
export {
|
|
157
|
+
DEFAULT_DATABASE_QUEUE_TABLE,
|
|
158
|
+
DEFAULT_FAILED_JOBS_TABLE,
|
|
159
|
+
loadQueueConfig,
|
|
160
|
+
normalizeQueueMigrationName,
|
|
161
|
+
queueMigrationInternals,
|
|
162
|
+
renderFailedJobsTableMigration,
|
|
163
|
+
renderQueueTableMigration,
|
|
164
|
+
resolveDatabaseQueueTables,
|
|
165
|
+
runQueueFailedTableCommand,
|
|
166
|
+
runQueueTableCommand
|
|
167
|
+
};
|
|
@@ -14,22 +14,22 @@ import {
|
|
|
14
14
|
initializeProjectRuntime,
|
|
15
15
|
isDefined,
|
|
16
16
|
mergeRuntimeDatabaseConfig,
|
|
17
|
-
nodeRuntimeScript,
|
|
18
17
|
normalizeRuntimeConnectionInput,
|
|
19
18
|
normalizeRuntimeMigration,
|
|
20
19
|
parseBooleanEnv,
|
|
21
20
|
resolveConfigModuleUrl,
|
|
22
21
|
resolvePackageRootFromSpecifier,
|
|
22
|
+
resolveRuntimeWorkerPath,
|
|
23
23
|
runRuntimeInvocation,
|
|
24
24
|
withRuntimeEnvironment
|
|
25
|
-
} from "./chunk-
|
|
26
|
-
import "./chunk-
|
|
25
|
+
} from "./chunk-KS5TWO75.mjs";
|
|
26
|
+
import "./chunk-LBJAJLKU.mjs";
|
|
27
27
|
import "./chunk-D7O4SU6N.mjs";
|
|
28
|
-
import "./chunk-
|
|
29
|
-
import "./chunk-
|
|
30
|
-
import "./chunk-
|
|
31
|
-
import "./chunk-
|
|
32
|
-
import "./chunk-
|
|
28
|
+
import "./chunk-VP2E62DF.mjs";
|
|
29
|
+
import "./chunk-MCVRN7KX.mjs";
|
|
30
|
+
import "./chunk-YEFJBN56.mjs";
|
|
31
|
+
import "./chunk-J76GH2DR.mjs";
|
|
32
|
+
import "./chunk-ILU426CF.mjs";
|
|
33
33
|
export {
|
|
34
34
|
RUNTIME_MIGRATION_NAME_PATTERN,
|
|
35
35
|
cacheProjectConfig,
|
|
@@ -46,12 +46,12 @@ export {
|
|
|
46
46
|
initializeProjectRuntime,
|
|
47
47
|
isDefined,
|
|
48
48
|
mergeRuntimeDatabaseConfig,
|
|
49
|
-
nodeRuntimeScript,
|
|
50
49
|
normalizeRuntimeConnectionInput,
|
|
51
50
|
normalizeRuntimeMigration,
|
|
52
51
|
parseBooleanEnv,
|
|
53
52
|
resolveConfigModuleUrl,
|
|
54
53
|
resolvePackageRootFromSpecifier,
|
|
54
|
+
resolveRuntimeWorkerPath,
|
|
55
55
|
runRuntimeInvocation,
|
|
56
56
|
withRuntimeEnvironment
|
|
57
57
|
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import {
|
|
2
|
+
RUNTIME_MIGRATION_NAME_PATTERN,
|
|
3
|
+
cacheProjectConfig,
|
|
4
|
+
cleanupRuntimeDependencyLink,
|
|
5
|
+
compileFreshDropIdentifierPath,
|
|
6
|
+
createEnvRuntimeConfig,
|
|
7
|
+
createRuntimeInvocation,
|
|
8
|
+
dropAllTablesForFresh,
|
|
9
|
+
ensureRuntimeDependencyLink,
|
|
10
|
+
filterDefinedRuntimeConnectionInput,
|
|
11
|
+
getRuntimeEnvironment,
|
|
12
|
+
getRuntimeFailureMessage,
|
|
13
|
+
inferRuntimeMigrationName,
|
|
14
|
+
initializeProjectRuntime,
|
|
15
|
+
isDefined,
|
|
16
|
+
mergeRuntimeDatabaseConfig,
|
|
17
|
+
normalizeRuntimeConnectionInput,
|
|
18
|
+
normalizeRuntimeMigration,
|
|
19
|
+
parseBooleanEnv,
|
|
20
|
+
resolveConfigModuleUrl,
|
|
21
|
+
resolvePackageRootFromSpecifier,
|
|
22
|
+
resolveRuntimeWorkerPath,
|
|
23
|
+
runRuntimeInvocation,
|
|
24
|
+
withRuntimeEnvironment
|
|
25
|
+
} from "./chunk-KS5TWO75.mjs";
|
|
26
|
+
import "./chunk-LBJAJLKU.mjs";
|
|
27
|
+
import "./chunk-D7O4SU6N.mjs";
|
|
28
|
+
import "./chunk-VP2E62DF.mjs";
|
|
29
|
+
import "./chunk-4OHJC3GL.mjs";
|
|
30
|
+
import "./chunk-YEFJBN56.mjs";
|
|
31
|
+
import "./chunk-J76GH2DR.mjs";
|
|
32
|
+
import "./chunk-ILU426CF.mjs";
|
|
33
|
+
export {
|
|
34
|
+
RUNTIME_MIGRATION_NAME_PATTERN,
|
|
35
|
+
cacheProjectConfig,
|
|
36
|
+
cleanupRuntimeDependencyLink,
|
|
37
|
+
compileFreshDropIdentifierPath,
|
|
38
|
+
createEnvRuntimeConfig,
|
|
39
|
+
createRuntimeInvocation,
|
|
40
|
+
dropAllTablesForFresh,
|
|
41
|
+
ensureRuntimeDependencyLink,
|
|
42
|
+
filterDefinedRuntimeConnectionInput,
|
|
43
|
+
getRuntimeEnvironment,
|
|
44
|
+
getRuntimeFailureMessage,
|
|
45
|
+
inferRuntimeMigrationName,
|
|
46
|
+
initializeProjectRuntime,
|
|
47
|
+
isDefined,
|
|
48
|
+
mergeRuntimeDatabaseConfig,
|
|
49
|
+
normalizeRuntimeConnectionInput,
|
|
50
|
+
normalizeRuntimeMigration,
|
|
51
|
+
parseBooleanEnv,
|
|
52
|
+
resolveConfigModuleUrl,
|
|
53
|
+
resolvePackageRootFromSpecifier,
|
|
54
|
+
resolveRuntimeWorkerPath,
|
|
55
|
+
runRuntimeInvocation,
|
|
56
|
+
withRuntimeEnvironment
|
|
57
|
+
};
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
// src/runtime-worker.ts
|
|
2
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
3
|
+
import { dirname } from "path";
|
|
4
|
+
import {
|
|
5
|
+
configureDB,
|
|
6
|
+
createMigrationService,
|
|
7
|
+
createSchemaService,
|
|
8
|
+
createSeederService,
|
|
9
|
+
registerGeneratedTables,
|
|
10
|
+
renderGeneratedSchemaModule,
|
|
11
|
+
renderGeneratedSchemaRuntimeModule,
|
|
12
|
+
resetDB,
|
|
13
|
+
resolveRuntimeConnectionManagerOptions
|
|
14
|
+
} from "@holo-js/db";
|
|
15
|
+
var payload = JSON.parse(process.env.HOLO_RUNTIME_PAYLOAD ?? "{}");
|
|
16
|
+
if (typeof payload.projectRoot === "string") {
|
|
17
|
+
process.chdir(payload.projectRoot);
|
|
18
|
+
}
|
|
19
|
+
function isRecord(value) {
|
|
20
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
21
|
+
}
|
|
22
|
+
async function loadModule(path) {
|
|
23
|
+
return import(`${path}?t=${Date.now()}`);
|
|
24
|
+
}
|
|
25
|
+
function resolveExport(moduleValue, matcher) {
|
|
26
|
+
if (isRecord(moduleValue) && matcher(moduleValue.default)) {
|
|
27
|
+
return moduleValue.default;
|
|
28
|
+
}
|
|
29
|
+
if (isRecord(moduleValue)) {
|
|
30
|
+
for (const value of Object.values(moduleValue)) {
|
|
31
|
+
if (matcher(value)) {
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return void 0;
|
|
37
|
+
}
|
|
38
|
+
function isModel(value) {
|
|
39
|
+
return isRecord(value) && isRecord(value.definition) && value.definition.kind === "model" && typeof value.definition.name === "string" && typeof value.prune === "function";
|
|
40
|
+
}
|
|
41
|
+
function isMigration(value) {
|
|
42
|
+
return isRecord(value) && typeof value.up === "function";
|
|
43
|
+
}
|
|
44
|
+
function isSeeder(value) {
|
|
45
|
+
return isRecord(value) && typeof value.name === "string" && typeof value.run === "function";
|
|
46
|
+
}
|
|
47
|
+
function isTable(value) {
|
|
48
|
+
return isRecord(value) && value.kind === "table" && typeof value.tableName === "string" && isRecord(value.columns) && Array.isArray(value.indexes);
|
|
49
|
+
}
|
|
50
|
+
function extractTables(moduleValue) {
|
|
51
|
+
if (isRecord(moduleValue) && isRecord(moduleValue.tables)) {
|
|
52
|
+
return Object.values(moduleValue.tables).filter(isTable);
|
|
53
|
+
}
|
|
54
|
+
if (isRecord(moduleValue) && isTable(moduleValue.default)) {
|
|
55
|
+
return [moduleValue.default];
|
|
56
|
+
}
|
|
57
|
+
if (isRecord(moduleValue)) {
|
|
58
|
+
return Object.values(moduleValue).filter(isTable);
|
|
59
|
+
}
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
var RUNTIME_MIGRATION_NAME_PATTERN = /^\d{4}_\d{2}_\d{2}_\d{6}_[a-z0-9_]+$/;
|
|
63
|
+
function inferRuntimeMigrationName(entry) {
|
|
64
|
+
const fileName = entry.split("/").pop()?.replace(/\.[^.]+$/, "");
|
|
65
|
+
if (!fileName || !RUNTIME_MIGRATION_NAME_PATTERN.test(fileName)) {
|
|
66
|
+
throw new Error(`Registered migration "${entry}" must use a timestamped file name matching YYYY_MM_DD_HHMMSS_description.`);
|
|
67
|
+
}
|
|
68
|
+
return fileName;
|
|
69
|
+
}
|
|
70
|
+
function normalizeRuntimeMigration(entry, migration) {
|
|
71
|
+
return {
|
|
72
|
+
...migration,
|
|
73
|
+
name: typeof migration.name === "string" ? migration.name : inferRuntimeMigrationName(entry)
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function compileFreshDropIdentifierPath(quoteIdentifier, identifier) {
|
|
77
|
+
if (!identifier.includes(".")) {
|
|
78
|
+
return quoteIdentifier(identifier);
|
|
79
|
+
}
|
|
80
|
+
return identifier.split(".").map((part) => quoteIdentifier(part)).join(".");
|
|
81
|
+
}
|
|
82
|
+
async function dropAllTablesForFresh(connection, schema) {
|
|
83
|
+
const tables = await schema.getTables();
|
|
84
|
+
if (connection.getDialect().name === "postgres") {
|
|
85
|
+
const schemaName = connection.getSchemaName();
|
|
86
|
+
const quoteIdentifier = connection.getDialect().quoteIdentifier;
|
|
87
|
+
for (const tableName of tables) {
|
|
88
|
+
const qualifiedTableName = schemaName ? `${schemaName}.${tableName}` : tableName;
|
|
89
|
+
await connection.executeCompiled({
|
|
90
|
+
sql: `DROP TABLE IF EXISTS ${compileFreshDropIdentifierPath(quoteIdentifier, qualifiedTableName)} CASCADE`,
|
|
91
|
+
source: `schema:dropTableFresh:${qualifiedTableName}`
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
await schema.withoutForeignKeyConstraints(async () => {
|
|
97
|
+
for (const tableName of tables) {
|
|
98
|
+
await schema.dropTable(tableName);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
async function preloadGeneratedSchema(manager2, entry) {
|
|
103
|
+
if (!entry) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const tables = extractTables(await loadModule(entry));
|
|
107
|
+
for (const table of tables) {
|
|
108
|
+
manager2.connection().getSchemaRegistry().replace(table);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
async function writeGeneratedSchemaArtifact(manager2, outputPath, runtimeOutputPath) {
|
|
112
|
+
if (!outputPath && !runtimeOutputPath) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const tables = manager2.connection().getSchemaRegistry().list();
|
|
116
|
+
if (outputPath) {
|
|
117
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
118
|
+
await writeFile(outputPath, renderGeneratedSchemaModule(tables), "utf8");
|
|
119
|
+
}
|
|
120
|
+
if (runtimeOutputPath) {
|
|
121
|
+
await mkdir(dirname(runtimeOutputPath), { recursive: true });
|
|
122
|
+
await writeFile(runtimeOutputPath, renderGeneratedSchemaRuntimeModule(tables), "utf8");
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function syncGeneratedSchemaFromManager(manager2) {
|
|
126
|
+
registerGeneratedTables(Object.fromEntries(
|
|
127
|
+
manager2.connection().getSchemaRegistry().list().map((table) => [table.tableName, table])
|
|
128
|
+
));
|
|
129
|
+
}
|
|
130
|
+
async function hydrateGeneratedSchemaFromRanMigrations(manager2, migrations) {
|
|
131
|
+
const migrationService = createMigrationService(manager2.connection(), migrations);
|
|
132
|
+
const ranNames = new Set(
|
|
133
|
+
(await migrationService.status()).filter((status) => status.status === "ran").map((status) => status.name)
|
|
134
|
+
);
|
|
135
|
+
if (ranNames.size === 0) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const realConnection = manager2.connection();
|
|
139
|
+
const dryRunConnection = {
|
|
140
|
+
getDialect: () => realConnection.getDialect(),
|
|
141
|
+
getCapabilities: () => realConnection.getCapabilities(),
|
|
142
|
+
getSchemaName: () => realConnection.getSchemaName(),
|
|
143
|
+
getSchemaRegistry: () => realConnection.getSchemaRegistry(),
|
|
144
|
+
executeCompiled: async () => void 0,
|
|
145
|
+
introspectCompiled: async () => ({ rows: [], rowCount: 0 }),
|
|
146
|
+
transaction: async (callback) => callback(dryRunConnection)
|
|
147
|
+
};
|
|
148
|
+
const schema = createSchemaService(dryRunConnection);
|
|
149
|
+
for (const migration of [...migrations].sort((left, right) => left.name.localeCompare(right.name))) {
|
|
150
|
+
if (ranNames.has(migration.name)) {
|
|
151
|
+
await migration.up({ db: dryRunConnection, schema });
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async function loadRuntimeItems(entries, matcher, label) {
|
|
156
|
+
const items = [];
|
|
157
|
+
for (const entry of entries) {
|
|
158
|
+
const item = resolveExport(await loadModule(entry), matcher);
|
|
159
|
+
if (!item) {
|
|
160
|
+
throw new Error(`Registered ${label} "${entry}" does not export a Holo ${label}.`);
|
|
161
|
+
}
|
|
162
|
+
items.push(item);
|
|
163
|
+
}
|
|
164
|
+
return items;
|
|
165
|
+
}
|
|
166
|
+
async function loadMigrations(entries) {
|
|
167
|
+
const migrations = await loadRuntimeItems(entries, isMigration, "migration");
|
|
168
|
+
return migrations.map((migration, index) => normalizeRuntimeMigration(entries[index] ?? "", migration));
|
|
169
|
+
}
|
|
170
|
+
async function loadSeeders(entries) {
|
|
171
|
+
return loadRuntimeItems(entries, isSeeder, "seeder");
|
|
172
|
+
}
|
|
173
|
+
function printExecutedItems(items, emptyMessage, header) {
|
|
174
|
+
if (items.length === 0) {
|
|
175
|
+
writeOutput(emptyMessage);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
writeOutput(header);
|
|
179
|
+
for (const item of items) {
|
|
180
|
+
writeOutput(` ${item.name}`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function payloadEntries(entries) {
|
|
184
|
+
return entries ?? [];
|
|
185
|
+
}
|
|
186
|
+
function resolveRuntimeConfig(runtimeConfig) {
|
|
187
|
+
if (!runtimeConfig) {
|
|
188
|
+
throw new Error("Runtime payload is missing database configuration.");
|
|
189
|
+
}
|
|
190
|
+
return runtimeConfig;
|
|
191
|
+
}
|
|
192
|
+
function writeOutput(message) {
|
|
193
|
+
process.stdout.write(`${message}
|
|
194
|
+
`);
|
|
195
|
+
}
|
|
196
|
+
var manager = resolveRuntimeConnectionManagerOptions(resolveRuntimeConfig(payload.runtimeConfig));
|
|
197
|
+
configureDB(manager);
|
|
198
|
+
try {
|
|
199
|
+
await manager.initializeAll();
|
|
200
|
+
if (payload.kind === "migrate") {
|
|
201
|
+
await preloadGeneratedSchema(manager, payload.generatedSchema);
|
|
202
|
+
const migrations = await loadMigrations(payloadEntries(payload.migrations));
|
|
203
|
+
await hydrateGeneratedSchemaFromRanMigrations(manager, migrations);
|
|
204
|
+
const executed = await createMigrationService(manager.connection(), migrations).migrate(payload.options ?? {});
|
|
205
|
+
await writeGeneratedSchemaArtifact(manager, payload.generatedSchemaOutputPath, payload.generatedSchemaRuntimeOutputPath);
|
|
206
|
+
printExecutedItems(executed, "No migrations were executed.", "Migrations executed:");
|
|
207
|
+
} else if (payload.kind === "fresh") {
|
|
208
|
+
const migrations = await loadMigrations(payloadEntries(payload.migrations));
|
|
209
|
+
const schema = createSchemaService(manager.connection());
|
|
210
|
+
await dropAllTablesForFresh(manager.connection(), schema);
|
|
211
|
+
manager.connection().getSchemaRegistry().clear();
|
|
212
|
+
const executed = await createMigrationService(manager.connection(), migrations).migrate({});
|
|
213
|
+
await writeGeneratedSchemaArtifact(manager, payload.generatedSchemaOutputPath, payload.generatedSchemaRuntimeOutputPath);
|
|
214
|
+
syncGeneratedSchemaFromManager(manager);
|
|
215
|
+
printExecutedItems(executed, "No migrations were executed.", "Migrations executed:");
|
|
216
|
+
if (payload.options?.seed) {
|
|
217
|
+
const seeded = await createSeederService(manager.connection(), await loadSeeders(payloadEntries(payload.seeders))).seed({
|
|
218
|
+
...Array.isArray(payload.options.only) ? { only: payload.options.only } : {},
|
|
219
|
+
quietly: payload.options.quietly === true,
|
|
220
|
+
force: payload.options.force === true,
|
|
221
|
+
environment: typeof payload.options.environment === "string" ? payload.options.environment : "development"
|
|
222
|
+
});
|
|
223
|
+
printExecutedItems(seeded, "No seeders were executed.", "Seeders executed:");
|
|
224
|
+
}
|
|
225
|
+
} else if (payload.kind === "rollback") {
|
|
226
|
+
await preloadGeneratedSchema(manager, payload.generatedSchema);
|
|
227
|
+
const migrations = await loadMigrations(payloadEntries(payload.migrations));
|
|
228
|
+
await hydrateGeneratedSchemaFromRanMigrations(manager, migrations);
|
|
229
|
+
const rolledBack = await createMigrationService(manager.connection(), migrations).rollback(payload.options ?? {});
|
|
230
|
+
await writeGeneratedSchemaArtifact(manager, payload.generatedSchemaOutputPath, payload.generatedSchemaRuntimeOutputPath);
|
|
231
|
+
printExecutedItems(rolledBack, "No migrations were rolled back.", "Migrations rolled back:");
|
|
232
|
+
} else if (payload.kind === "seed") {
|
|
233
|
+
await preloadGeneratedSchema(manager, payload.generatedSchema);
|
|
234
|
+
const executed = await createSeederService(manager.connection(), await loadSeeders(payloadEntries(payload.seeders))).seed(payload.options ?? {});
|
|
235
|
+
printExecutedItems(executed, "No seeders were executed.", "Seeders executed:");
|
|
236
|
+
} else if (payload.kind === "prune") {
|
|
237
|
+
const models = await loadRuntimeItems(payloadEntries(payload.models), isModel, "model");
|
|
238
|
+
const byName = new Map(models.map((model) => [model.definition.name, model]));
|
|
239
|
+
const requested = Array.isArray(payload.options?.models) ? payload.options.models : [];
|
|
240
|
+
const selected = [];
|
|
241
|
+
if (requested.length === 0) {
|
|
242
|
+
selected.push(...models.filter((model) => Boolean(model.definition.prunable)));
|
|
243
|
+
} else {
|
|
244
|
+
for (const name of requested) {
|
|
245
|
+
if (typeof name !== "string") {
|
|
246
|
+
console.warn(`Ignoring non-string prunable model name: ${JSON.stringify(name)}`);
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
const model = byName.get(name);
|
|
250
|
+
if (!model) {
|
|
251
|
+
throw new Error(`Unknown model "${name}".`);
|
|
252
|
+
}
|
|
253
|
+
if (!model.definition.prunable) {
|
|
254
|
+
throw new Error(`Model "${name}" does not define a prunable query.`);
|
|
255
|
+
}
|
|
256
|
+
selected.push(model);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (selected.length === 0) {
|
|
260
|
+
writeOutput("No prunable models were registered.");
|
|
261
|
+
} else {
|
|
262
|
+
let total = 0;
|
|
263
|
+
for (const model of selected) {
|
|
264
|
+
const deleted = await model.prune();
|
|
265
|
+
total += deleted;
|
|
266
|
+
writeOutput(`${model.definition.name}: deleted ${deleted}`);
|
|
267
|
+
}
|
|
268
|
+
writeOutput(`Total deleted: ${total}`);
|
|
269
|
+
}
|
|
270
|
+
} else {
|
|
271
|
+
throw new Error(`Unknown runtime command "${payload.kind}".`);
|
|
272
|
+
}
|
|
273
|
+
} finally {
|
|
274
|
+
await manager.disconnectAll();
|
|
275
|
+
resetDB();
|
|
276
|
+
}
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
installMediaIntoProject,
|
|
15
15
|
installNotificationsIntoProject,
|
|
16
16
|
installQueueIntoProject,
|
|
17
|
+
installRealtimeIntoProject,
|
|
17
18
|
installSecurityIntoProject,
|
|
18
19
|
normalizeScaffoldEnvSegments,
|
|
19
20
|
publishAuthNotificationsIntoProject,
|
|
@@ -55,19 +56,20 @@ import {
|
|
|
55
56
|
upsertMediaPackageDependency,
|
|
56
57
|
upsertNotificationsPackageDependency,
|
|
57
58
|
upsertSecurityPackageDependency
|
|
58
|
-
} from "./chunk-
|
|
59
|
-
import "./chunk-
|
|
59
|
+
} from "./chunk-MCVRN7KX.mjs";
|
|
60
|
+
import "./chunk-YEFJBN56.mjs";
|
|
60
61
|
import {
|
|
61
62
|
renderAuthProviderRouteFiles,
|
|
62
63
|
renderFrameworkFiles,
|
|
63
|
-
renderFrameworkRunner
|
|
64
|
-
|
|
64
|
+
renderFrameworkRunner,
|
|
65
|
+
renderNextBroadcastConfigRoute
|
|
66
|
+
} from "./chunk-J76GH2DR.mjs";
|
|
65
67
|
import {
|
|
66
68
|
isSupportedCacheInstallerDriver,
|
|
67
69
|
isSupportedQueueInstallerDriver,
|
|
68
70
|
normalizeScaffoldOptionalPackages,
|
|
69
71
|
sanitizePackageName
|
|
70
|
-
} from "./chunk-
|
|
72
|
+
} from "./chunk-ILU426CF.mjs";
|
|
71
73
|
export {
|
|
72
74
|
authFeaturesRequireConfigUpdate,
|
|
73
75
|
detectAuthInstallFeaturesFromConfig,
|
|
@@ -84,6 +86,7 @@ export {
|
|
|
84
86
|
installMediaIntoProject,
|
|
85
87
|
installNotificationsIntoProject,
|
|
86
88
|
installQueueIntoProject,
|
|
89
|
+
installRealtimeIntoProject,
|
|
87
90
|
installSecurityIntoProject,
|
|
88
91
|
isSupportedCacheInstallerDriver,
|
|
89
92
|
isSupportedQueueInstallerDriver,
|
|
@@ -104,6 +107,7 @@ export {
|
|
|
104
107
|
renderMailConfig,
|
|
105
108
|
renderMailEnvFiles,
|
|
106
109
|
renderMediaConfig,
|
|
110
|
+
renderNextBroadcastConfigRoute,
|
|
107
111
|
renderNotificationsConfig,
|
|
108
112
|
renderNotificationsMigration,
|
|
109
113
|
renderQueueConfig,
|