@holo-js/cli 0.2.5 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-skills-MSEMQUXT.mjs → agent-skills-CHAXS2YN.mjs} +13 -6
- package/dist/bin/holo.mjs +436 -109
- package/dist/{broadcast-5MJ3GJK7.mjs → broadcast-5VZM5SGQ.mjs} +13 -10
- package/dist/{broadcast-MRJGFCFH.mjs → broadcast-AABT52BK.mjs} +13 -10
- package/dist/cache-A42JSVYA.mjs +138 -0
- package/dist/cache-DUVBBOZU.mjs +138 -0
- package/dist/{cache-migrations-CPYQC7T6.mjs → cache-migrations-4WKSEN2Q.mjs} +12 -10
- package/dist/{cache-migrations-APDFSFEX.mjs → cache-migrations-PD2T5AV4.mjs} +14 -12
- package/dist/chunk-3RFRE7XG.mjs +491 -0
- package/dist/{chunk-PT72AMV7.mjs → chunk-6BHJLCAO.mjs} +256 -392
- package/dist/{chunk-KS5TWO75.mjs → chunk-EQUFFLRG.mjs} +7 -7
- package/dist/chunk-HX6MOYBO.mjs +2 -0
- package/dist/{chunk-YEFJBN56.mjs → chunk-JVLZ3SOW.mjs} +11 -8
- package/dist/{chunk-UPXQONEH.mjs → chunk-KRADH7PK.mjs} +55 -51
- package/dist/chunk-LALDNNPH.mjs +428 -0
- package/dist/chunk-LHK5YUR4.mjs +156 -0
- package/dist/{chunk-LBJAJLKU.mjs → chunk-M3IPUCTM.mjs} +1 -1
- package/dist/{chunk-TWITVSFZ.mjs → chunk-OI54DOHK.mjs} +256 -392
- package/dist/{chunk-LXGQCG56.mjs → chunk-OLZEMIDQ.mjs} +1 -1
- package/dist/{chunk-VP2E62DF.mjs → chunk-QSVMXMTQ.mjs} +49 -349
- package/dist/{chunk-J76GH2DR.mjs → chunk-R4ZYMEDU.mjs} +129 -86
- package/dist/{chunk-XDRCZ3Z5.mjs → chunk-TH5YCOZB.mjs} +57 -53
- package/dist/chunk-TRYHX5S4.mjs +360 -0
- package/dist/chunk-XBOVM6LO.mjs +41 -0
- package/dist/{chunk-ILU426CF.mjs → chunk-YACY2572.mjs} +482 -2
- package/dist/{config-MD27U4FM.mjs → config-BZHQK532.mjs} +3 -3
- package/dist/{dev-CT4DRTLN.mjs → dev-7KGRV56X.mjs} +10 -8
- package/dist/{dev-QDLR6C7K.mjs → dev-GQT37XJU.mjs} +10 -8
- package/dist/{discovery-GWTBF5RZ.mjs → discovery-HNH3BLDL.mjs} +8 -6
- package/dist/{generators-PUN5TFP5.mjs → generators-3FVW4AEJ.mjs} +18 -15
- package/dist/{generators-WQHI7DBW.mjs → generators-JWVNGUUE.mjs} +14 -11
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +434 -107
- package/dist/{media-migrations-D3CDNMPT.mjs → media-migrations-EG34NYAG.mjs} +13 -11
- package/dist/{media-migrations-IWCSCKSA.mjs → media-migrations-LGI7R7AR.mjs} +11 -9
- package/dist/plugins-ZGLB6JO6.mjs +24 -0
- package/dist/{queue-O3OSLGOV.mjs → queue-BEZDCZCY.mjs} +54 -16
- package/dist/{queue-GRB2IH5M.mjs → queue-R54DUUYA.mjs} +54 -16
- package/dist/{queue-migrations-7T42S4FX.mjs → queue-migrations-AM3AKT76.mjs} +16 -11
- package/dist/{queue-migrations-HFZB64OG.mjs → queue-migrations-U477YSFD.mjs} +18 -13
- package/dist/{runtime-TTRP2DGL.mjs → runtime-4TJYZLQV.mjs} +10 -8
- package/dist/{runtime-M3G5OKQV.mjs → runtime-MSRQD5W5.mjs} +10 -8
- package/dist/{runtime-GSXF4NB3.mjs → runtime-VR5BDPYQ.mjs} +1 -1
- package/dist/runtime-worker.mjs +7 -1
- package/dist/{scaffold-5BOVJYF3.mjs → scaffold-ASEX5LEX.mjs} +8 -4
- package/dist/{scaffold-NY3MWUZF.mjs → scaffold-ZAD3XUSD.mjs} +8 -4
- package/dist/{security-ST6ED7EK.mjs → security-4QLV7QCH.mjs} +8 -6
- package/dist/{security-H7AGDFBX.mjs → security-KYTLP4DF.mjs} +8 -6
- package/package.json +35 -8
- package/dist/cache-KVRYC7FB.mjs +0 -66
- package/dist/cache-WWE4Q4YE.mjs +0 -66
- package/dist/chunk-D7O4SU6N.mjs +0 -2
- package/dist/chunk-FGQ2I2YH.mjs +0 -22
|
@@ -1,349 +1,56 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadGeneratedProjectRegistry,
|
|
3
3
|
writeGeneratedProjectRegistry
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-R4ZYMEDU.mjs";
|
|
5
|
+
import {
|
|
6
|
+
assertUniqueCommandTokens,
|
|
7
|
+
assertUniqueEntries,
|
|
8
|
+
captureAuthorizationDefinitionNames,
|
|
9
|
+
collectFiles,
|
|
10
|
+
deriveBroadcastNameFromPath,
|
|
11
|
+
deriveChannelPatternFromPath,
|
|
12
|
+
deriveCommandNameFromPath,
|
|
13
|
+
deriveEventNameFromPath,
|
|
14
|
+
deriveJobNameFromPath,
|
|
15
|
+
deriveListenerIdFromPath,
|
|
16
|
+
findAddedAuthorizationDefinitionNames,
|
|
17
|
+
inferMigrationNameFromEntry,
|
|
18
|
+
isCliModelReference,
|
|
19
|
+
isInactiveGeneratedModelModule,
|
|
20
|
+
isMigrationDefinition,
|
|
21
|
+
isMissingGeneratedSchemaModelError,
|
|
22
|
+
isSeederDefinition,
|
|
23
|
+
normalizeCommandAliases,
|
|
24
|
+
resolveAuthorizationTargetName,
|
|
25
|
+
resolveBroadcastArtifactsPath,
|
|
26
|
+
resolveCommandExport,
|
|
27
|
+
resolveDiscoveredJobMetadata,
|
|
28
|
+
resolveListenerEventNamesForDiscovery,
|
|
29
|
+
resolveListenerEventNamesFromSource,
|
|
30
|
+
resolveNamedExport,
|
|
31
|
+
resolveNamedExportEntry,
|
|
32
|
+
resolveRegisteredPath,
|
|
33
|
+
unregisterAuthorizationDefinitionNames,
|
|
34
|
+
validateMigrationName
|
|
35
|
+
} from "./chunk-TRYHX5S4.mjs";
|
|
5
36
|
import {
|
|
6
|
-
COMMAND_FILE_PATTERN,
|
|
7
|
-
MIGRATION_NAME_PATTERN,
|
|
8
37
|
hasEventDefinitionMarker,
|
|
9
38
|
hasListenerDefinitionMarker,
|
|
10
39
|
importProjectModule,
|
|
11
|
-
isRecord,
|
|
12
40
|
loadAuthorizationDiscoveryModule,
|
|
13
41
|
loadBroadcastDiscoveryModule,
|
|
14
42
|
loadEventsDiscoveryModule,
|
|
15
43
|
loadQueueDiscoveryModule,
|
|
16
44
|
makeProjectRelativePath,
|
|
17
|
-
pathExists
|
|
18
|
-
|
|
19
|
-
toPosixPath
|
|
20
|
-
} from "./chunk-ILU426CF.mjs";
|
|
45
|
+
pathExists
|
|
46
|
+
} from "./chunk-YACY2572.mjs";
|
|
21
47
|
|
|
22
48
|
// src/project/discovery.ts
|
|
23
|
-
import { resolve
|
|
49
|
+
import { resolve } from "path";
|
|
24
50
|
import { loadConfigDirectory } from "@holo-js/config";
|
|
25
51
|
import {
|
|
26
52
|
normalizeHoloProjectConfig
|
|
27
|
-
} from "@holo-js/
|
|
28
|
-
|
|
29
|
-
// src/project/discovery-helpers.ts
|
|
30
|
-
import { readdir } from "fs/promises";
|
|
31
|
-
import { basename, dirname, extname, join, relative, resolve } from "path";
|
|
32
|
-
async function collectFiles(root) {
|
|
33
|
-
if (!await pathExists(root)) {
|
|
34
|
-
return [];
|
|
35
|
-
}
|
|
36
|
-
const entries = await readdir(root, { withFileTypes: true });
|
|
37
|
-
const files = [];
|
|
38
|
-
for (const entry of entries) {
|
|
39
|
-
const target = join(root, entry.name);
|
|
40
|
-
if (entry.isDirectory()) {
|
|
41
|
-
files.push(...await collectFiles(target));
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
if (entry.isFile() && COMMAND_FILE_PATTERN.test(entry.name)) {
|
|
45
|
-
files.push(target);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
return files;
|
|
49
|
-
}
|
|
50
|
-
function deriveCommandNameFromPath(commandsRoot, sourcePath) {
|
|
51
|
-
const relativePath = toPosixPath(relative(commandsRoot, sourcePath));
|
|
52
|
-
return relativePath.replace(COMMAND_FILE_PATTERN, "").split("/").filter(Boolean).join(":");
|
|
53
|
-
}
|
|
54
|
-
function deriveJobNameFromPath(jobsRoot, sourcePath) {
|
|
55
|
-
const relativePath = toPosixPath(relative(jobsRoot, sourcePath));
|
|
56
|
-
return relativePath.replace(COMMAND_FILE_PATTERN, "").split("/").filter(Boolean).join(".");
|
|
57
|
-
}
|
|
58
|
-
function deriveDottedNameFromPath(root, sourcePath, emptyMessage) {
|
|
59
|
-
const relativePath = toPosixPath(relative(root, sourcePath)).replace(COMMAND_FILE_PATTERN, "");
|
|
60
|
-
const derived = relativePath.split("/").map((part) => part.trim()).filter(Boolean).join(".");
|
|
61
|
-
if (!derived) {
|
|
62
|
-
throw new Error(emptyMessage);
|
|
63
|
-
}
|
|
64
|
-
return derived;
|
|
65
|
-
}
|
|
66
|
-
function deriveEventNameFromPath(eventsRoot, sourcePath) {
|
|
67
|
-
return deriveDottedNameFromPath(eventsRoot, sourcePath, "[Holo Events] Derived event names require a non-empty source path.");
|
|
68
|
-
}
|
|
69
|
-
function deriveListenerIdFromPath(listenersRoot, sourcePath) {
|
|
70
|
-
return deriveDottedNameFromPath(listenersRoot, sourcePath, "[Holo Events] Derived listener identifiers require a non-empty source path.");
|
|
71
|
-
}
|
|
72
|
-
function deriveBroadcastNameFromPath(root, sourcePath) {
|
|
73
|
-
return deriveDottedNameFromPath(root, sourcePath, "[Holo Broadcast] Derived broadcast names require a non-empty source path.");
|
|
74
|
-
}
|
|
75
|
-
function deriveChannelPatternFromPath(root, sourcePath) {
|
|
76
|
-
return deriveDottedNameFromPath(root, sourcePath, "[Holo Broadcast] Derived channel patterns require a non-empty source path.");
|
|
77
|
-
}
|
|
78
|
-
function resolveDiscoveredJobMetadata(job, sourcePath, derivedName, queueConfig) {
|
|
79
|
-
const connection = job.connection ?? queueConfig.default;
|
|
80
|
-
let queue = job.queue;
|
|
81
|
-
if (!queue) {
|
|
82
|
-
const configuredConnection = queueConfig.connections[connection];
|
|
83
|
-
queue = configuredConnection ? configuredConnection.queue : "default";
|
|
84
|
-
}
|
|
85
|
-
return {
|
|
86
|
-
sourcePath,
|
|
87
|
-
name: derivedName,
|
|
88
|
-
connection,
|
|
89
|
-
queue,
|
|
90
|
-
...typeof job.tries === "number" ? { tries: job.tries } : {},
|
|
91
|
-
...typeof job.backoff !== "undefined" ? { backoff: job.backoff } : {},
|
|
92
|
-
...typeof job.timeout === "number" ? { timeout: job.timeout } : {}
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
function isAppCommand(value) {
|
|
96
|
-
return isRecord(value) && typeof value.description === "string" && typeof value.run === "function";
|
|
97
|
-
}
|
|
98
|
-
function resolveCommandExport(moduleValue) {
|
|
99
|
-
if (isRecord(moduleValue) && isAppCommand(moduleValue.default)) {
|
|
100
|
-
return moduleValue.default;
|
|
101
|
-
}
|
|
102
|
-
if (isRecord(moduleValue)) {
|
|
103
|
-
for (const value of Object.values(moduleValue)) {
|
|
104
|
-
if (isAppCommand(value)) {
|
|
105
|
-
return value;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return void 0;
|
|
110
|
-
}
|
|
111
|
-
function normalizeCommandAliases(value) {
|
|
112
|
-
if (!value) {
|
|
113
|
-
return void 0;
|
|
114
|
-
}
|
|
115
|
-
const normalized = [...new Set(value.map((alias) => alias.trim()).filter(Boolean))];
|
|
116
|
-
return normalized.length > 0 ? normalized : void 0;
|
|
117
|
-
}
|
|
118
|
-
function assertUniqueEntries(kind, entries) {
|
|
119
|
-
const seen = /* @__PURE__ */ new Map();
|
|
120
|
-
for (const entry of entries) {
|
|
121
|
-
const existing = seen.get(entry.name);
|
|
122
|
-
if (existing) {
|
|
123
|
-
throw new Error(`Discovered duplicate ${kind} "${entry.name}" in "${existing}" and "${entry.sourcePath}".`);
|
|
124
|
-
}
|
|
125
|
-
seen.set(entry.name, entry.sourcePath);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
function assertUniqueCommandTokens(entries) {
|
|
129
|
-
const seen = /* @__PURE__ */ new Map();
|
|
130
|
-
for (const entry of entries) {
|
|
131
|
-
for (const token of [entry.name, ...entry.aliases]) {
|
|
132
|
-
const existing = seen.get(token);
|
|
133
|
-
if (existing) {
|
|
134
|
-
throw new Error(`Discovered duplicate command token "${token}" in "${existing}" and "${entry.sourcePath}".`);
|
|
135
|
-
}
|
|
136
|
-
seen.set(token, entry.sourcePath);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
function resolveRegisteredPath(projectRoot, entry) {
|
|
141
|
-
return resolve(projectRoot, entry);
|
|
142
|
-
}
|
|
143
|
-
function resolveNamedExport(moduleValue, matcher) {
|
|
144
|
-
if (!isRecord(moduleValue)) return void 0;
|
|
145
|
-
if (matcher(moduleValue.default)) return moduleValue.default;
|
|
146
|
-
for (const value of Object.values(moduleValue)) {
|
|
147
|
-
if (matcher(value)) return value;
|
|
148
|
-
}
|
|
149
|
-
return void 0;
|
|
150
|
-
}
|
|
151
|
-
function resolveNamedExportEntry(moduleValue, matcher) {
|
|
152
|
-
if (!isRecord(moduleValue)) return void 0;
|
|
153
|
-
if (matcher(moduleValue.default)) {
|
|
154
|
-
return { exportName: "default", value: moduleValue.default };
|
|
155
|
-
}
|
|
156
|
-
for (const [exportName, value] of Object.entries(moduleValue)) {
|
|
157
|
-
if (matcher(value)) return { exportName, value };
|
|
158
|
-
}
|
|
159
|
-
return void 0;
|
|
160
|
-
}
|
|
161
|
-
function isCliModelReference(value) {
|
|
162
|
-
return isRecord(value) && isRecord(value.definition) && value.definition.kind === "model" && typeof value.definition.name === "string" && typeof value.prune === "function";
|
|
163
|
-
}
|
|
164
|
-
function isMissingGeneratedSchemaModelError(error) {
|
|
165
|
-
return error instanceof Error && error.message.includes("is not present in the generated schema registry");
|
|
166
|
-
}
|
|
167
|
-
function isInactiveGeneratedModelModule(value) {
|
|
168
|
-
return isRecord(value) && value.holoModelPendingSchema === true;
|
|
169
|
-
}
|
|
170
|
-
function isMigrationDefinition(value) {
|
|
171
|
-
return isRecord(value) && typeof value.up === "function";
|
|
172
|
-
}
|
|
173
|
-
function isSeederDefinition(value) {
|
|
174
|
-
return isRecord(value) && typeof value.name === "string" && typeof value.run === "function";
|
|
175
|
-
}
|
|
176
|
-
function resolveListenerEventNamesForDiscovery(listener, eventNamesByReference = /* @__PURE__ */ new Map()) {
|
|
177
|
-
return Object.freeze([...new Set(listener.listensTo.map((reference) => {
|
|
178
|
-
if (typeof reference === "string") {
|
|
179
|
-
return reference.trim();
|
|
180
|
-
}
|
|
181
|
-
if (typeof reference.name === "string" && reference.name.trim()) {
|
|
182
|
-
return reference.name.trim();
|
|
183
|
-
}
|
|
184
|
-
if (eventNamesByReference.has(reference)) {
|
|
185
|
-
return eventNamesByReference.get(reference);
|
|
186
|
-
}
|
|
187
|
-
throw new Error("[Holo Events] Listener event references must resolve to explicit event names before discovery registration.");
|
|
188
|
-
}))]);
|
|
189
|
-
}
|
|
190
|
-
function resolveAuthorizationTargetName(target) {
|
|
191
|
-
const modelFacadeTarget = target;
|
|
192
|
-
if (typeof modelFacadeTarget.definition?.name === "string" && modelFacadeTarget.definition.name.trim()) {
|
|
193
|
-
return modelFacadeTarget.definition.name.trim();
|
|
194
|
-
}
|
|
195
|
-
const namedTarget = target;
|
|
196
|
-
return typeof namedTarget.name === "string" && namedTarget.name.trim() ? namedTarget.name.trim() : void 0;
|
|
197
|
-
}
|
|
198
|
-
function captureAuthorizationDefinitionNames(definitions) {
|
|
199
|
-
return new Set(definitions.keys());
|
|
200
|
-
}
|
|
201
|
-
function findAddedAuthorizationDefinitionNames(definitions, existingNames) {
|
|
202
|
-
return [...definitions.keys()].filter((name) => !existingNames.has(name));
|
|
203
|
-
}
|
|
204
|
-
function unregisterAuthorizationDefinitionNames(authorizationDiscovery, policyNames, abilityNames) {
|
|
205
|
-
if (typeof authorizationDiscovery.authorizationInternals.unregisterPolicyDefinition !== "function" || typeof authorizationDiscovery.authorizationInternals.unregisterAbilityDefinition !== "function") {
|
|
206
|
-
authorizationDiscovery.authorizationInternals.resetAuthorizationRuntimeState?.();
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
|
-
for (const policyName of policyNames) {
|
|
210
|
-
authorizationDiscovery.authorizationInternals.unregisterPolicyDefinition(policyName);
|
|
211
|
-
}
|
|
212
|
-
for (const abilityName of abilityNames) {
|
|
213
|
-
authorizationDiscovery.authorizationInternals.unregisterAbilityDefinition(abilityName);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
function collectImportedBindingsBySource(sourceText) {
|
|
217
|
-
const bindings = /* @__PURE__ */ new Map();
|
|
218
|
-
const importPattern = /import\s+([\s\S]*?)\s+from\s+['"]([^'"]+)['"]/g;
|
|
219
|
-
for (const match of sourceText.matchAll(importPattern)) {
|
|
220
|
-
const clause = match[1]?.trim();
|
|
221
|
-
const source = match[2]?.trim();
|
|
222
|
-
if (!clause || !source) {
|
|
223
|
-
continue;
|
|
224
|
-
}
|
|
225
|
-
const namedMatch = clause.match(/\{([\s\S]+)\}/);
|
|
226
|
-
const defaultClause = clause.replace(/\{[\s\S]+\}/, "").replace(/,$/, "").trim();
|
|
227
|
-
if (defaultClause && defaultClause !== "*") {
|
|
228
|
-
bindings.set(defaultClause, source);
|
|
229
|
-
}
|
|
230
|
-
if (namedMatch?.[1]) {
|
|
231
|
-
for (const specifier of namedMatch[1].split(",")) {
|
|
232
|
-
const trimmed = specifier.trim();
|
|
233
|
-
if (!trimmed) {
|
|
234
|
-
continue;
|
|
235
|
-
}
|
|
236
|
-
const [imported, local] = trimmed.split(/\s+as\s+/);
|
|
237
|
-
const bindingName = (local ?? imported)?.trim();
|
|
238
|
-
if (bindingName) {
|
|
239
|
-
bindings.set(bindingName, source);
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
return bindings;
|
|
245
|
-
}
|
|
246
|
-
function extractListensToItems(sourceText) {
|
|
247
|
-
const markerIndex = sourceText.indexOf("listensTo");
|
|
248
|
-
if (markerIndex < 0) {
|
|
249
|
-
return [];
|
|
250
|
-
}
|
|
251
|
-
const colonIndex = sourceText.indexOf(":", markerIndex);
|
|
252
|
-
if (colonIndex < 0) {
|
|
253
|
-
return [];
|
|
254
|
-
}
|
|
255
|
-
let cursor = colonIndex + 1;
|
|
256
|
-
while (cursor < sourceText.length && /\s/.test(sourceText[cursor])) {
|
|
257
|
-
cursor += 1;
|
|
258
|
-
}
|
|
259
|
-
const startChar = sourceText[cursor];
|
|
260
|
-
let depth = 0;
|
|
261
|
-
let inString;
|
|
262
|
-
let expression = "";
|
|
263
|
-
for (; cursor < sourceText.length; cursor += 1) {
|
|
264
|
-
const char = sourceText[cursor];
|
|
265
|
-
expression += char;
|
|
266
|
-
if (inString) {
|
|
267
|
-
if (char === inString && sourceText[cursor - 1] !== "\\") {
|
|
268
|
-
inString = void 0;
|
|
269
|
-
}
|
|
270
|
-
continue;
|
|
271
|
-
}
|
|
272
|
-
if (char === "'" || char === '"' || char === "`") {
|
|
273
|
-
inString = char;
|
|
274
|
-
continue;
|
|
275
|
-
}
|
|
276
|
-
if (char === "[" || char === "{" || char === "(") {
|
|
277
|
-
depth += 1;
|
|
278
|
-
continue;
|
|
279
|
-
}
|
|
280
|
-
if (char === "]" || char === "}" || char === ")") {
|
|
281
|
-
depth -= 1;
|
|
282
|
-
if (depth === 0 && startChar === "[") {
|
|
283
|
-
break;
|
|
284
|
-
}
|
|
285
|
-
continue;
|
|
286
|
-
}
|
|
287
|
-
if (depth === 0 && startChar !== "[" && (char === "," || char === "\n" || char === "\r")) {
|
|
288
|
-
expression = expression.slice(0, -1);
|
|
289
|
-
break;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
if (startChar !== "[") {
|
|
293
|
-
const item = expression.trim().replace(/\s+as\s+const$/, "");
|
|
294
|
-
return item ? [item] : [];
|
|
295
|
-
}
|
|
296
|
-
return expression.slice(1, -1).split(",").map((item) => item.trim().replace(/\s+as\s+const$/, "")).filter(Boolean);
|
|
297
|
-
}
|
|
298
|
-
async function resolveListenerEventNamesFromSource(projectRoot, listenerPath, discoveredEventNamesBySourcePath) {
|
|
299
|
-
const sourceText = await readTextFile(listenerPath) ?? "";
|
|
300
|
-
const bindingsByName = collectImportedBindingsBySource(sourceText);
|
|
301
|
-
const discoveredEventNamesByExtensionlessSourcePath = new Map(
|
|
302
|
-
[...discoveredEventNamesBySourcePath.entries()].map(([sourcePath, eventName]) => {
|
|
303
|
-
return [sourcePath.replace(/\.[^.]+$/, ""), eventName];
|
|
304
|
-
})
|
|
305
|
-
);
|
|
306
|
-
const resolvedEventNames = [];
|
|
307
|
-
for (const item of extractListensToItems(sourceText)) {
|
|
308
|
-
const quoted = item.match(/^['"](.+)['"]$/);
|
|
309
|
-
if (quoted) {
|
|
310
|
-
resolvedEventNames.push(quoted[1].trim());
|
|
311
|
-
continue;
|
|
312
|
-
}
|
|
313
|
-
const importSource = bindingsByName.get(item);
|
|
314
|
-
if (!importSource) {
|
|
315
|
-
throw new Error("[Holo Events] Listener event references must resolve to explicit event names before discovery registration.");
|
|
316
|
-
}
|
|
317
|
-
const importedPath = makeProjectRelativePath(projectRoot, resolve(dirname(listenerPath), importSource));
|
|
318
|
-
const eventName = discoveredEventNamesBySourcePath.get(importedPath) ?? discoveredEventNamesByExtensionlessSourcePath.get(importedPath.replace(/\.[^.]+$/, ""));
|
|
319
|
-
if (!eventName) {
|
|
320
|
-
throw new Error("[Holo Events] Listener event references must resolve to explicit event names before discovery registration.");
|
|
321
|
-
}
|
|
322
|
-
resolvedEventNames.push(eventName);
|
|
323
|
-
}
|
|
324
|
-
return Object.freeze([...new Set(resolvedEventNames)]);
|
|
325
|
-
}
|
|
326
|
-
function resolveBroadcastArtifactsPath(config, key) {
|
|
327
|
-
const configuredPaths = config.paths;
|
|
328
|
-
return configuredPaths[key] ?? `server/${key}`;
|
|
329
|
-
}
|
|
330
|
-
function inferMigrationNameFromEntry(entry) {
|
|
331
|
-
const fileName = basename(entry, extname(entry));
|
|
332
|
-
return validateMigrationName(
|
|
333
|
-
fileName,
|
|
334
|
-
`Registered migration "${entry}" must use a timestamped file name matching YYYY_MM_DD_HHMMSS_description.`
|
|
335
|
-
);
|
|
336
|
-
}
|
|
337
|
-
function validateMigrationName(name, message) {
|
|
338
|
-
if (!MIGRATION_NAME_PATTERN.test(name)) {
|
|
339
|
-
throw new Error(
|
|
340
|
-
message ?? `Migration name "${name}" must match YYYY_MM_DD_HHMMSS_description.`
|
|
341
|
-
);
|
|
342
|
-
}
|
|
343
|
-
return name;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// src/project/discovery.ts
|
|
53
|
+
} from "@holo-js/kernel";
|
|
347
54
|
function resolveBroadcastExportEntry(moduleValue, discovery) {
|
|
348
55
|
if (!moduleValue || typeof moduleValue !== "object") {
|
|
349
56
|
return void 0;
|
|
@@ -370,20 +77,20 @@ async function prepareProjectDiscovery(projectRoot, config = normalizeHoloProjec
|
|
|
370
77
|
const loadedConfig = await loadConfigDirectory(projectRoot, {
|
|
371
78
|
processEnv: process.env
|
|
372
79
|
});
|
|
373
|
-
const modelsRoot =
|
|
374
|
-
const migrationsRoot =
|
|
375
|
-
const seedersRoot =
|
|
376
|
-
const commandsRoot =
|
|
377
|
-
const jobsRoot =
|
|
378
|
-
const eventsRoot =
|
|
379
|
-
const listenersRoot =
|
|
80
|
+
const modelsRoot = resolve(projectRoot, config.paths.models);
|
|
81
|
+
const migrationsRoot = resolve(projectRoot, config.paths.migrations);
|
|
82
|
+
const seedersRoot = resolve(projectRoot, config.paths.seeders);
|
|
83
|
+
const commandsRoot = resolve(projectRoot, config.paths.commands);
|
|
84
|
+
const jobsRoot = resolve(projectRoot, config.paths.jobs);
|
|
85
|
+
const eventsRoot = resolve(projectRoot, config.paths.events);
|
|
86
|
+
const listenersRoot = resolve(projectRoot, config.paths.listeners);
|
|
380
87
|
const broadcastPath = resolveBroadcastArtifactsPath(config, "broadcast");
|
|
381
88
|
const channelsPath = resolveBroadcastArtifactsPath(config, "channels");
|
|
382
|
-
const broadcastRoot =
|
|
383
|
-
const channelsRoot =
|
|
384
|
-
const policiesRoot =
|
|
385
|
-
const abilitiesRoot =
|
|
386
|
-
const generatedSchemaPath =
|
|
89
|
+
const broadcastRoot = resolve(projectRoot, broadcastPath);
|
|
90
|
+
const channelsRoot = resolve(projectRoot, channelsPath);
|
|
91
|
+
const policiesRoot = resolve(projectRoot, config.paths.authorizationPolicies ?? "server/policies");
|
|
92
|
+
const abilitiesRoot = resolve(projectRoot, config.paths.authorizationAbilities ?? "server/abilities");
|
|
93
|
+
const generatedSchemaPath = resolve(projectRoot, config.paths.generatedSchema);
|
|
387
94
|
if (await pathExists(generatedSchemaPath)) {
|
|
388
95
|
await importProjectModule(projectRoot, generatedSchemaPath);
|
|
389
96
|
}
|
|
@@ -751,7 +458,7 @@ async function discoverAppCommands(projectRoot, config = normalizeHoloProjectCon
|
|
|
751
458
|
description: entry.description,
|
|
752
459
|
...entry.usage ? { usage: entry.usage } : {},
|
|
753
460
|
async load() {
|
|
754
|
-
const moduleValue = await importProjectModule(projectRoot,
|
|
461
|
+
const moduleValue = await importProjectModule(projectRoot, resolve(projectRoot, entry.sourcePath));
|
|
755
462
|
const command = resolveCommandExport(moduleValue);
|
|
756
463
|
if (!command) {
|
|
757
464
|
throw new Error(`Discovered command "${entry.sourcePath}" does not export a Holo command.`);
|
|
@@ -801,13 +508,6 @@ async function loadRegisteredSeeders(projectRoot, config) {
|
|
|
801
508
|
}
|
|
802
509
|
|
|
803
510
|
export {
|
|
804
|
-
collectFiles,
|
|
805
|
-
resolveNamedExport,
|
|
806
|
-
resolveNamedExportEntry,
|
|
807
|
-
resolveListenerEventNamesForDiscovery,
|
|
808
|
-
collectImportedBindingsBySource,
|
|
809
|
-
extractListensToItems,
|
|
810
|
-
resolveListenerEventNamesFromSource,
|
|
811
511
|
prepareProjectDiscovery,
|
|
812
512
|
discoverAppCommands,
|
|
813
513
|
loadRegisteredModels,
|