@holo-js/cli 0.1.4 → 0.1.6
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 +192 -35
- package/dist/{broadcast-CSSARTSA.mjs → broadcast-2AZIC5ZP.mjs} +5 -5
- package/dist/{cache-4G6QGIZO.mjs → cache-5OROX4GL.mjs} +5 -5
- package/dist/{cache-migrations-NATT5WPQ.mjs → cache-migrations-7XFVLTOC.mjs} +15 -16
- package/dist/{chunk-EUIVXVJL.mjs → chunk-57SJ566R.mjs} +1 -1
- package/dist/chunk-5BLEC66P.mjs +284 -0
- package/dist/{chunk-JX2ZH6XY.mjs → chunk-5EU32E7X.mjs} +3 -3
- package/dist/{chunk-Q5F6C2D4.mjs → chunk-BAFQ2GOA.mjs} +1 -1
- package/dist/{chunk-CUL4RJTG.mjs → chunk-F4MT6GBK.mjs} +1 -1
- package/dist/{chunk-3OTCSFDG.mjs → chunk-MXKNQACM.mjs} +544 -82
- package/dist/{chunk-ZLRO7HXY.mjs → chunk-ODJA3TFG.mjs} +156 -15
- package/dist/{chunk-QYLSMF7V.mjs → chunk-OZUDZEAW.mjs} +142 -28
- package/dist/{chunk-66FHW725.mjs → chunk-R6BWRY3E.mjs} +28 -2
- package/dist/{chunk-MZXN2YMI.mjs → chunk-USACXIIB.mjs} +3544 -2522
- package/dist/{chunk-VT5IDQG6.mjs → chunk-UZTDQKIY.mjs} +61 -44
- package/dist/{config-LS5USBRB.mjs → config-5JSC6KJG.mjs} +3 -3
- package/dist/{dev-LZ3O2E3U.mjs → dev-F6QUWNCR.mjs} +7 -7
- package/dist/{discovery-GBLAUTXS.mjs → discovery-JLT2EOGH.mjs} +3 -3
- package/dist/{generators-DSN4GWJI.mjs → generators-WVKJLAYB.mjs} +134 -16
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +189 -32
- package/dist/media-migrations-DU7WEKAY.mjs +117 -0
- package/dist/{queue-FV35LLPR.mjs → queue-NOLVWPCH.mjs} +14 -14
- package/dist/{queue-migrations-SSIYKK5S.mjs → queue-migrations-HXNTZMGL.mjs} +24 -20
- package/dist/{runtime-EFZ5H5IL.mjs → runtime-462O2BDR.mjs} +9 -7
- package/dist/{runtime-OOSJ5JBY.mjs → runtime-ZKD6URAV.mjs} +1 -1
- package/dist/{scaffold-7OTDH4UR.mjs → scaffold-WOJV2ZZI.mjs} +18 -5
- package/dist/{security-ATKDC26E.mjs → security-5VGM467J.mjs} +10 -7
- package/package.json +13 -12
- package/dist/broadcast-YSIJCL3R.mjs +0 -85
- package/dist/cache-OWQY4E7W.mjs +0 -67
- package/dist/cache-migrations-RVEA6CEU.mjs +0 -155
- package/dist/chunk-BWW5TDFI.mjs +0 -4
- package/dist/chunk-D4GG556Y.mjs +0 -23
- package/dist/chunk-DMH2B4UQ.mjs +0 -343
- package/dist/chunk-ET7UXHHQ.mjs +0 -166
- package/dist/chunk-G5ADO27Q.mjs +0 -463
- package/dist/chunk-GSQ3HTRO.mjs +0 -165
- package/dist/chunk-H7TJ4FB3.mjs +0 -848
- package/dist/chunk-ICJR7TS4.mjs +0 -66
- package/dist/chunk-M7J3YTHR.mjs +0 -26
- package/dist/chunk-QFUSWV3J.mjs +0 -3237
- package/dist/chunk-S7P7EBM3.mjs +0 -787
- package/dist/chunk-SRWJU3A5.mjs +0 -11
- package/dist/chunk-URK7C3VQ.mjs +0 -538
- package/dist/chunk-XUYKPU5Q.mjs +0 -272
- package/dist/config-DMWBMMGD.mjs +0 -26
- package/dist/dev-KQFT7RHR.mjs +0 -43
- package/dist/discovery-R733D2PO.mjs +0 -29
- package/dist/generators-WX45BI4U.mjs +0 -426
- package/dist/queue-6OG7VJ34.mjs +0 -626
- package/dist/queue-migrations-NK2EYX3J.mjs +0 -163
- package/dist/runtime-4BV3JODY.mjs +0 -56
- package/dist/runtime-ANBO7VQM.mjs +0 -33
- package/dist/scaffold-DRKBGS2K.mjs +0 -120
- package/dist/security-R7VH6W5H.mjs +0 -69
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import {
|
|
2
|
+
loadGeneratedProjectRegistry
|
|
3
|
+
} from "./chunk-MXKNQACM.mjs";
|
|
4
|
+
import {
|
|
5
|
+
APP_CONFIG_FILE_NAMES,
|
|
6
|
+
DATABASE_CONFIG_FILE_NAMES,
|
|
7
|
+
bundleProjectModule,
|
|
8
|
+
isModulePackage,
|
|
9
|
+
pathExists,
|
|
10
|
+
resolveFirstExistingPath
|
|
11
|
+
} from "./chunk-R6BWRY3E.mjs";
|
|
12
|
+
|
|
13
|
+
// src/project/config.ts
|
|
14
|
+
import { createHash } from "crypto";
|
|
15
|
+
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
16
|
+
import { dirname, extname, join, resolve } from "path";
|
|
17
|
+
import { pathToFileURL } from "url";
|
|
18
|
+
import {
|
|
19
|
+
loadConfigDirectory,
|
|
20
|
+
holoAppDefaults,
|
|
21
|
+
holoDatabaseDefaults,
|
|
22
|
+
loadEnvironment,
|
|
23
|
+
normalizeAppConfig,
|
|
24
|
+
normalizeDatabaseConfig
|
|
25
|
+
} from "@holo-js/config";
|
|
26
|
+
import {
|
|
27
|
+
DEFAULT_HOLO_PROJECT_PATHS,
|
|
28
|
+
normalizeHoloProjectConfig,
|
|
29
|
+
renderGeneratedSchemaPlaceholder
|
|
30
|
+
} from "@holo-js/db";
|
|
31
|
+
function isObject(value) {
|
|
32
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
33
|
+
}
|
|
34
|
+
function resolveConfigExport(moduleValue) {
|
|
35
|
+
if (isObject(moduleValue) && isObject(moduleValue.default)) {
|
|
36
|
+
return moduleValue.default;
|
|
37
|
+
}
|
|
38
|
+
if (isObject(moduleValue) && isObject(moduleValue.config)) {
|
|
39
|
+
return moduleValue.config;
|
|
40
|
+
}
|
|
41
|
+
if (isObject(moduleValue) && ("default" in moduleValue || "config" in moduleValue)) {
|
|
42
|
+
return {};
|
|
43
|
+
}
|
|
44
|
+
if (isObject(moduleValue)) {
|
|
45
|
+
return moduleValue;
|
|
46
|
+
}
|
|
47
|
+
return {};
|
|
48
|
+
}
|
|
49
|
+
var projectConfigImportStates = /* @__PURE__ */ new Map();
|
|
50
|
+
var projectConfigImportLock = Promise.resolve();
|
|
51
|
+
var projectConfigImportNonce = 0;
|
|
52
|
+
async function withProjectConfigImportLock(callback) {
|
|
53
|
+
const previousLock = projectConfigImportLock;
|
|
54
|
+
let releaseLock = () => {
|
|
55
|
+
};
|
|
56
|
+
projectConfigImportLock = new Promise((resolveLock) => {
|
|
57
|
+
releaseLock = resolveLock;
|
|
58
|
+
});
|
|
59
|
+
await previousLock;
|
|
60
|
+
try {
|
|
61
|
+
return await callback();
|
|
62
|
+
} finally {
|
|
63
|
+
releaseLock();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function hashProjectConfigImportInputs(fileContents, environmentValues) {
|
|
67
|
+
const hash = createHash("sha256").update(fileContents).update("\0");
|
|
68
|
+
const keys = Object.keys(environmentValues).sort();
|
|
69
|
+
for (const key of keys) {
|
|
70
|
+
hash.update(key).update("\0").update(environmentValues[key] ?? "").update("\0");
|
|
71
|
+
}
|
|
72
|
+
return hash.digest("hex").slice(0, 16);
|
|
73
|
+
}
|
|
74
|
+
async function resolveProjectConfigImportUrl(filePath, environmentValues) {
|
|
75
|
+
const fileUrl = pathToFileURL(filePath).href;
|
|
76
|
+
const hash = hashProjectConfigImportInputs(await readFile(filePath, "utf8"), environmentValues);
|
|
77
|
+
const previous = projectConfigImportStates.get(filePath);
|
|
78
|
+
if (previous?.hash === hash) {
|
|
79
|
+
return `${fileUrl}?t=${previous.nonce}`;
|
|
80
|
+
}
|
|
81
|
+
projectConfigImportNonce += 1;
|
|
82
|
+
const next = {
|
|
83
|
+
hash,
|
|
84
|
+
nonce: projectConfigImportNonce
|
|
85
|
+
};
|
|
86
|
+
projectConfigImportStates.set(filePath, next);
|
|
87
|
+
return `${fileUrl}?t=${next.nonce}`;
|
|
88
|
+
}
|
|
89
|
+
async function importProjectConfigFile(projectRoot, filePath, environmentValues) {
|
|
90
|
+
return withProjectConfigImportLock(async () => {
|
|
91
|
+
const previousEnvEntries = /* @__PURE__ */ new Map();
|
|
92
|
+
const importUrl = await resolveProjectConfigImportUrl(filePath, environmentValues);
|
|
93
|
+
const configExtension = extname(filePath);
|
|
94
|
+
const bundled = configExtension === ".ts" || configExtension === ".mts" ? await bundleProjectModule(projectRoot, filePath) : void 0;
|
|
95
|
+
const resolvedImportUrl = bundled ? `${pathToFileURL(bundled.path).href}${new URL(importUrl).search}` : importUrl;
|
|
96
|
+
try {
|
|
97
|
+
for (const [key, value] of Object.entries(environmentValues)) {
|
|
98
|
+
previousEnvEntries.set(key, process.env[key]);
|
|
99
|
+
process.env[key] = value;
|
|
100
|
+
}
|
|
101
|
+
return resolveConfigExport(await import(resolvedImportUrl));
|
|
102
|
+
} finally {
|
|
103
|
+
for (const [key, value] of previousEnvEntries) {
|
|
104
|
+
if (typeof value === "string") {
|
|
105
|
+
process.env[key] = value;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
Reflect.deleteProperty(process.env, key);
|
|
109
|
+
}
|
|
110
|
+
await bundled?.cleanup();
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
async function loadCachedProjectSourceConfig(projectRoot, environmentName) {
|
|
115
|
+
const cachePath = join(projectRoot, ".holo-js/generated/config-cache.json");
|
|
116
|
+
if (environmentName !== "production" || !await pathExists(cachePath)) {
|
|
117
|
+
return void 0;
|
|
118
|
+
}
|
|
119
|
+
const loaded = await loadConfigDirectory(projectRoot, {
|
|
120
|
+
processEnv: process.env
|
|
121
|
+
});
|
|
122
|
+
return {
|
|
123
|
+
app: loaded.app,
|
|
124
|
+
database: loaded.database
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
async function loadProjectConfig(projectRoot, options = {}) {
|
|
128
|
+
const appConfigPath = await resolveFirstExistingPath(projectRoot, APP_CONFIG_FILE_NAMES);
|
|
129
|
+
if (!appConfigPath) {
|
|
130
|
+
if (options.required) {
|
|
131
|
+
throw new Error(`Missing config/app.(ts|mts|js|mjs) in ${projectRoot}. Run a generator command first to create it.`);
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
config: normalizeHoloProjectConfig()
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
const databaseConfigPath = await resolveFirstExistingPath(projectRoot, DATABASE_CONFIG_FILE_NAMES);
|
|
138
|
+
const environment = await loadEnvironment({
|
|
139
|
+
cwd: projectRoot,
|
|
140
|
+
processEnv: process.env
|
|
141
|
+
});
|
|
142
|
+
const cachedConfig = await loadCachedProjectSourceConfig(projectRoot, environment.name);
|
|
143
|
+
const app = cachedConfig?.app ?? normalizeAppConfig(await importProjectConfigFile(projectRoot, appConfigPath, environment.values));
|
|
144
|
+
const database = cachedConfig?.database ?? normalizeDatabaseConfig(databaseConfigPath ? await importProjectConfigFile(projectRoot, databaseConfigPath, environment.values) : void 0);
|
|
145
|
+
const baseConfig = normalizeHoloProjectConfig({
|
|
146
|
+
paths: app.paths,
|
|
147
|
+
models: app.models,
|
|
148
|
+
migrations: app.migrations,
|
|
149
|
+
seeders: app.seeders,
|
|
150
|
+
database
|
|
151
|
+
});
|
|
152
|
+
const registry = await loadGeneratedProjectRegistry(projectRoot);
|
|
153
|
+
return {
|
|
154
|
+
manifestPath: appConfigPath,
|
|
155
|
+
config: registry ? normalizeHoloProjectConfig({
|
|
156
|
+
paths: baseConfig.paths,
|
|
157
|
+
models: [.../* @__PURE__ */ new Set([
|
|
158
|
+
...baseConfig.models,
|
|
159
|
+
...registry.models.map((entry) => entry.sourcePath)
|
|
160
|
+
])],
|
|
161
|
+
migrations: [.../* @__PURE__ */ new Set([
|
|
162
|
+
...baseConfig.migrations,
|
|
163
|
+
...registry.migrations.map((entry) => entry.sourcePath)
|
|
164
|
+
])],
|
|
165
|
+
seeders: [.../* @__PURE__ */ new Set([
|
|
166
|
+
...baseConfig.seeders,
|
|
167
|
+
...registry.seeders.map((entry) => entry.sourcePath)
|
|
168
|
+
])],
|
|
169
|
+
database
|
|
170
|
+
}) : baseConfig
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
async function serializeProjectConfig(projectRoot, config, manifestPath) {
|
|
174
|
+
const loaded = await loadConfigDirectory(projectRoot, {
|
|
175
|
+
processEnv: process.env
|
|
176
|
+
}).catch(() => void 0);
|
|
177
|
+
const appConfig = loaded?.app ?? holoAppDefaults;
|
|
178
|
+
const contents = JSON.stringify({
|
|
179
|
+
name: appConfig.name,
|
|
180
|
+
key: appConfig.key,
|
|
181
|
+
url: appConfig.url,
|
|
182
|
+
debug: appConfig.debug,
|
|
183
|
+
env: appConfig.env,
|
|
184
|
+
paths: config.paths
|
|
185
|
+
}, null, 2);
|
|
186
|
+
const extension = extname(manifestPath);
|
|
187
|
+
const isCommonJs = extension === ".js" && !await isModulePackage(projectRoot);
|
|
188
|
+
if (isCommonJs) {
|
|
189
|
+
return [
|
|
190
|
+
"const { defineAppConfig } = require('@holo-js/config')",
|
|
191
|
+
"",
|
|
192
|
+
"module.exports = defineAppConfig(",
|
|
193
|
+
contents,
|
|
194
|
+
")",
|
|
195
|
+
""
|
|
196
|
+
].join("\n");
|
|
197
|
+
}
|
|
198
|
+
return [
|
|
199
|
+
"import { defineAppConfig } from '@holo-js/config'",
|
|
200
|
+
"",
|
|
201
|
+
"export default defineAppConfig(",
|
|
202
|
+
contents,
|
|
203
|
+
")",
|
|
204
|
+
""
|
|
205
|
+
].join("\n");
|
|
206
|
+
}
|
|
207
|
+
async function serializeDatabaseConfig(projectRoot, _targetPath) {
|
|
208
|
+
const loaded = await loadConfigDirectory(projectRoot, {
|
|
209
|
+
processEnv: process.env
|
|
210
|
+
}).catch(() => void 0);
|
|
211
|
+
const databaseConfig = loaded?.database ?? holoDatabaseDefaults;
|
|
212
|
+
const contents = JSON.stringify({
|
|
213
|
+
defaultConnection: databaseConfig.defaultConnection,
|
|
214
|
+
connections: databaseConfig.connections
|
|
215
|
+
}, null, 2);
|
|
216
|
+
return [
|
|
217
|
+
"import { defineDatabaseConfig } from '@holo-js/config'",
|
|
218
|
+
"",
|
|
219
|
+
"export default defineDatabaseConfig(",
|
|
220
|
+
contents,
|
|
221
|
+
")",
|
|
222
|
+
""
|
|
223
|
+
].join("\n");
|
|
224
|
+
}
|
|
225
|
+
async function writeProjectConfig(projectRoot, config, manifestPath) {
|
|
226
|
+
const targetPath = manifestPath ?? join(projectRoot, "config/app.ts");
|
|
227
|
+
await mkdir(dirname(targetPath), { recursive: true });
|
|
228
|
+
await writeFile(targetPath, await serializeProjectConfig(projectRoot, config, targetPath), "utf8");
|
|
229
|
+
return targetPath;
|
|
230
|
+
}
|
|
231
|
+
function resolveGeneratedSchemaPath(projectRoot, config) {
|
|
232
|
+
return resolve(projectRoot, config.paths.generatedSchema);
|
|
233
|
+
}
|
|
234
|
+
async function ensureGeneratedSchemaPlaceholder(projectRoot, config) {
|
|
235
|
+
const filePath = resolveGeneratedSchemaPath(projectRoot, config);
|
|
236
|
+
if (await pathExists(filePath)) {
|
|
237
|
+
return filePath;
|
|
238
|
+
}
|
|
239
|
+
await mkdir(dirname(filePath), { recursive: true });
|
|
240
|
+
await writeFile(filePath, renderGeneratedSchemaPlaceholder(), "utf8");
|
|
241
|
+
return filePath;
|
|
242
|
+
}
|
|
243
|
+
async function ensureProjectConfig(projectRoot) {
|
|
244
|
+
const loaded = await loadProjectConfig(projectRoot);
|
|
245
|
+
if (loaded.manifestPath) {
|
|
246
|
+
await ensureDatabaseConfig(projectRoot);
|
|
247
|
+
return loaded;
|
|
248
|
+
}
|
|
249
|
+
const manifestPath = await writeProjectConfig(projectRoot, normalizeHoloProjectConfig());
|
|
250
|
+
await ensureDatabaseConfig(projectRoot);
|
|
251
|
+
return {
|
|
252
|
+
manifestPath,
|
|
253
|
+
config: normalizeHoloProjectConfig()
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
async function ensureDatabaseConfig(projectRoot) {
|
|
257
|
+
const existingPath = await resolveFirstExistingPath(projectRoot, DATABASE_CONFIG_FILE_NAMES);
|
|
258
|
+
if (existingPath) {
|
|
259
|
+
return existingPath;
|
|
260
|
+
}
|
|
261
|
+
const targetPath = join(projectRoot, "config/database.ts");
|
|
262
|
+
await mkdir(dirname(targetPath), { recursive: true });
|
|
263
|
+
await writeFile(targetPath, await serializeDatabaseConfig(projectRoot, targetPath), "utf8");
|
|
264
|
+
return targetPath;
|
|
265
|
+
}
|
|
266
|
+
function defaultProjectConfig() {
|
|
267
|
+
return normalizeHoloProjectConfig({
|
|
268
|
+
paths: DEFAULT_HOLO_PROJECT_PATHS,
|
|
269
|
+
models: [],
|
|
270
|
+
migrations: [],
|
|
271
|
+
seeders: []
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export {
|
|
276
|
+
loadProjectConfig,
|
|
277
|
+
serializeProjectConfig,
|
|
278
|
+
serializeDatabaseConfig,
|
|
279
|
+
writeProjectConfig,
|
|
280
|
+
resolveGeneratedSchemaPath,
|
|
281
|
+
ensureGeneratedSchemaPlaceholder,
|
|
282
|
+
ensureProjectConfig,
|
|
283
|
+
defaultProjectConfig
|
|
284
|
+
};
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import { createInterface } from "readline/promises";
|
|
3
3
|
var SUPPORTED_NEW_FRAMEWORKS = ["nuxt", "next", "sveltekit"];
|
|
4
4
|
var SUPPORTED_NEW_DATABASE_DRIVERS = ["sqlite", "mysql", "postgres"];
|
|
5
|
-
var SUPPORTED_NEW_PACKAGE_MANAGERS = ["
|
|
5
|
+
var SUPPORTED_NEW_PACKAGE_MANAGERS = ["npm", "pnpm", "yarn", "bun"];
|
|
6
6
|
var SUPPORTED_NEW_STORAGE_DISKS = ["local", "public"];
|
|
7
7
|
var SUPPORTED_NEW_OPTIONAL_PACKAGES = ["storage", "events", "queue", "validation", "forms", "auth", "authorization", "notifications", "mail", "broadcast", "security", "cache"];
|
|
8
|
-
var SUPPORTED_INSTALL_TARGETS = ["queue", "events", "auth", "authorization", "notifications", "mail", "broadcast", "security", "cache"];
|
|
8
|
+
var SUPPORTED_INSTALL_TARGETS = ["queue", "events", "auth", "authorization", "notifications", "mail", "broadcast", "security", "cache", "media"];
|
|
9
9
|
var SUPPORTED_QUEUE_INSTALL_DRIVERS = ["sync", "redis", "database"];
|
|
10
10
|
var SUPPORTED_CACHE_INSTALL_DRIVERS = ["file", "redis", "database"];
|
|
11
11
|
function parseTokens(tokens) {
|
|
@@ -161,7 +161,7 @@ async function resolveNewProjectInput(io, input, prompts = {
|
|
|
161
161
|
}
|
|
162
162
|
const framework = resolveStringFlag(input.flags, "framework") ? normalizeChoice(resolveStringFlag(input.flags, "framework"), SUPPORTED_NEW_FRAMEWORKS, "framework") : interactive ? await prompts.choose("Framework", SUPPORTED_NEW_FRAMEWORKS, "nuxt") : "nuxt";
|
|
163
163
|
const databaseDriver = resolveStringFlag(input.flags, "database") ? normalizeChoice(resolveStringFlag(input.flags, "database"), SUPPORTED_NEW_DATABASE_DRIVERS, "database driver") : interactive ? await prompts.choose("Database driver", SUPPORTED_NEW_DATABASE_DRIVERS, "sqlite") : "sqlite";
|
|
164
|
-
const packageManager = resolveStringFlag(input.flags, "package-manager") ? normalizeChoice(resolveStringFlag(input.flags, "package-manager"), SUPPORTED_NEW_PACKAGE_MANAGERS, "package manager") : interactive ? await prompts.choose("Package manager", SUPPORTED_NEW_PACKAGE_MANAGERS, "
|
|
164
|
+
const packageManager = resolveStringFlag(input.flags, "package-manager") ? normalizeChoice(resolveStringFlag(input.flags, "package-manager"), SUPPORTED_NEW_PACKAGE_MANAGERS, "package manager") : interactive ? await prompts.choose("Package manager", SUPPORTED_NEW_PACKAGE_MANAGERS, "npm") : "npm";
|
|
165
165
|
const requestedOptionalPackages = collectMultiStringFlag(input.flags, "package");
|
|
166
166
|
let optionalPackages;
|
|
167
167
|
if (requestedOptionalPackages) {
|