@holo-js/cli 0.1.9 → 0.2.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.
Files changed (46) hide show
  1. package/dist/bin/holo.mjs +165 -81
  2. package/dist/broadcast-WI6PJS5P.mjs +203 -0
  3. package/dist/broadcast-YWS4N5QU.mjs +203 -0
  4. package/dist/{cache-ETOIQ5IG.mjs → cache-KWNQECAA.mjs} +6 -6
  5. package/dist/cache-QARFSW4F.mjs +66 -0
  6. package/dist/{cache-migrations-2GGI4TJK.mjs → cache-migrations-3OXR4FN5.mjs} +50 -30
  7. package/dist/cache-migrations-MDFMDVTK.mjs +173 -0
  8. package/dist/{chunk-IMOGEKB4.mjs → chunk-2DKQKZML.mjs} +188 -106
  9. package/dist/{chunk-7JR73TOH.mjs → chunk-2RGJTPYF.mjs} +36 -25
  10. package/dist/{chunk-ASTSSSL2.mjs → chunk-EWYXSN2C.mjs} +75 -122
  11. package/dist/{chunk-F4MT6GBK.mjs → chunk-FGQ2I2YH.mjs} +1 -1
  12. package/dist/chunk-I7QBCEV7.mjs +33 -0
  13. package/dist/{chunk-R6BWRY3E.mjs → chunk-ILU426CF.mjs} +3 -1
  14. package/dist/{chunk-HB4Q7VYK.mjs → chunk-IUDD5FYL.mjs} +28 -273
  15. package/dist/{chunk-WRZFATUT.mjs → chunk-KWRIBHC3.mjs} +229 -142
  16. package/dist/{chunk-57SJ566R.mjs → chunk-LBJAJLKU.mjs} +1 -1
  17. package/dist/{chunk-BAFQ2GOA.mjs → chunk-LXGQCG56.mjs} +1 -1
  18. package/dist/{chunk-SRPGIWCF.mjs → chunk-ONKESAQA.mjs} +2 -2
  19. package/dist/chunk-QA7TP5EO.mjs +448 -0
  20. package/dist/chunk-UPZH6KCF.mjs +3306 -0
  21. package/dist/{chunk-5EU32E7X.mjs → chunk-VRGB6DIS.mjs} +116 -12
  22. package/dist/{config-ARLE6PKR.mjs → config-TWEO2R4N.mjs} +3 -3
  23. package/dist/{dev-6RG5SSZ7.mjs → dev-2OULECTU.mjs} +7 -7
  24. package/dist/dev-PJMEGTAC.mjs +42 -0
  25. package/dist/{discovery-FCVGQQVD.mjs → discovery-7FXND7Y6.mjs} +3 -3
  26. package/dist/{generators-UI2LJK3O.mjs → generators-4BP7B47W.mjs} +11 -34
  27. package/dist/generators-Z4XLSMC7.mjs +520 -0
  28. package/dist/index.mjs +167 -83
  29. package/dist/{media-migrations-JQSDCC7S.mjs → media-migrations-BFEL7NFG.mjs} +9 -20
  30. package/dist/media-migrations-VR7DLLR6.mjs +106 -0
  31. package/dist/{queue-BY3PLH4I.mjs → queue-SVOJPTRO.mjs} +10 -10
  32. package/dist/queue-YCBQTCYI.mjs +625 -0
  33. package/dist/{queue-migrations-YZUKEZK7.mjs → queue-migrations-HPXOO3NA.mjs} +13 -12
  34. package/dist/queue-migrations-X4P7FZKJ.mjs +167 -0
  35. package/dist/{runtime-BI343WHS.mjs → runtime-CPKR663Y.mjs} +9 -9
  36. package/dist/runtime-GIE56H47.mjs +57 -0
  37. package/dist/{runtime-ZKD6URAV.mjs → runtime-GSXF4NB3.mjs} +1 -1
  38. package/dist/runtime-worker.d.ts +2 -0
  39. package/dist/runtime-worker.mjs +242 -0
  40. package/dist/{scaffold-UBOS2NZR.mjs → scaffold-3QPGYQEQ.mjs} +9 -5
  41. package/dist/scaffold-RGAAHC6I.mjs +139 -0
  42. package/dist/{security-TYPVOYGF.mjs → security-7H5TNHZY.mjs} +6 -6
  43. package/dist/security-BZGD6ONY.mjs +71 -0
  44. package/package.json +9 -7
  45. package/dist/broadcast-VR46UZEL.mjs +0 -84
  46. package/dist/chunk-ZXDU7RHU.mjs +0 -9
package/dist/bin/holo.mjs CHANGED
@@ -4,35 +4,38 @@ import {
4
4
  SUPPORTED_INSTALL_TARGETS,
5
5
  SUPPORTED_QUEUE_INSTALL_DRIVERS,
6
6
  collectMultiStringFlag,
7
- confirm,
8
7
  ensureRequiredArg,
9
8
  isInteractive,
10
9
  normalizeChoice,
11
10
  normalizeOptionalPackages,
12
11
  parseNumberFlag,
13
12
  parseTokens,
13
+ promptChoice,
14
+ promptMultiChoice,
14
15
  resolveBooleanFlag,
15
16
  resolveNewProjectInput,
16
17
  resolveStringFlag,
17
18
  splitCsv
18
- } from "../chunk-5EU32E7X.mjs";
19
+ } from "../chunk-VRGB6DIS.mjs";
19
20
  import {
20
21
  hasProjectDependency
21
- } from "../chunk-F4MT6GBK.mjs";
22
+ } from "../chunk-FGQ2I2YH.mjs";
22
23
  import {
24
+ runWithSpinner,
25
+ supportsSpinner,
23
26
  writeLine
24
- } from "../chunk-ZXDU7RHU.mjs";
27
+ } from "../chunk-I7QBCEV7.mjs";
25
28
  import {
26
29
  fileExists
27
- } from "../chunk-57SJ566R.mjs";
30
+ } from "../chunk-LBJAJLKU.mjs";
28
31
  import "../chunk-D7O4SU6N.mjs";
29
- import "../chunk-7JR73TOH.mjs";
30
- import "../chunk-WRZFATUT.mjs";
31
- import "../chunk-SRPGIWCF.mjs";
32
- import "../chunk-IMOGEKB4.mjs";
32
+ import "../chunk-2RGJTPYF.mjs";
33
+ import "../chunk-UPZH6KCF.mjs";
34
+ import "../chunk-ONKESAQA.mjs";
35
+ import "../chunk-2DKQKZML.mjs";
33
36
  import {
34
37
  SUPPORTED_AUTH_SOCIAL_PROVIDERS
35
- } from "../chunk-R6BWRY3E.mjs";
38
+ } from "../chunk-ILU426CF.mjs";
36
39
 
37
40
  // src/cli.ts
38
41
  import { resolve as resolve2 } from "path";
@@ -105,6 +108,10 @@ async function generateProjectAppKey(projectRoot) {
105
108
  }
106
109
 
107
110
  // src/cli.ts
111
+ var AUTH_INSTALL_FEATURES = ["social", "workos", "clerk"];
112
+ var AUTH_SOCIAL_PROVIDER_MODES = ["default", "specific"];
113
+ var EVENTS_QUEUE_ACTIONS = ["skip", "enable"];
114
+ var MODEL_GENERATOR_OPTIONS = ["migration", "observer", "seeder", "factory"];
108
115
  var runtimeModulePromise;
109
116
  var queueModulePromise;
110
117
  var cacheModulePromise;
@@ -120,59 +127,59 @@ var projectDiscoveryModulePromise;
120
127
  var projectRuntimeModulePromise;
121
128
  var projectScaffoldModulePromise;
122
129
  function loadRuntimeModule() {
123
- runtimeModulePromise ??= import("../runtime-BI343WHS.mjs");
130
+ runtimeModulePromise ??= import("../runtime-CPKR663Y.mjs");
124
131
  return runtimeModulePromise;
125
132
  }
126
133
  function loadQueueModule() {
127
- queueModulePromise ??= import("../queue-BY3PLH4I.mjs");
134
+ queueModulePromise ??= import("../queue-SVOJPTRO.mjs");
128
135
  return queueModulePromise;
129
136
  }
130
137
  function loadCacheModule() {
131
- cacheModulePromise ??= import("../cache-ETOIQ5IG.mjs");
138
+ cacheModulePromise ??= import("../cache-QARFSW4F.mjs");
132
139
  return cacheModulePromise;
133
140
  }
134
141
  function loadQueueMigrationsModule() {
135
- queueMigrationsModulePromise ??= import("../queue-migrations-YZUKEZK7.mjs");
142
+ queueMigrationsModulePromise ??= import("../queue-migrations-HPXOO3NA.mjs");
136
143
  return queueMigrationsModulePromise;
137
144
  }
138
145
  function loadCacheMigrationsModule() {
139
- cacheMigrationsModulePromise ??= import("../cache-migrations-2GGI4TJK.mjs");
146
+ cacheMigrationsModulePromise ??= import("../cache-migrations-3OXR4FN5.mjs");
140
147
  return cacheMigrationsModulePromise;
141
148
  }
142
149
  function loadMediaMigrationsModule() {
143
- mediaMigrationsModulePromise ??= import("../media-migrations-JQSDCC7S.mjs");
150
+ mediaMigrationsModulePromise ??= import("../media-migrations-VR7DLLR6.mjs");
144
151
  return mediaMigrationsModulePromise;
145
152
  }
146
153
  function loadGeneratorsModule() {
147
- generatorsModulePromise ??= import("../generators-UI2LJK3O.mjs");
154
+ generatorsModulePromise ??= import("../generators-4BP7B47W.mjs");
148
155
  return generatorsModulePromise;
149
156
  }
150
157
  function loadBroadcastModule() {
151
- broadcastModulePromise ??= import("../broadcast-VR46UZEL.mjs");
158
+ broadcastModulePromise ??= import("../broadcast-YWS4N5QU.mjs");
152
159
  return broadcastModulePromise;
153
160
  }
154
161
  function loadSecurityModule() {
155
- securityModulePromise ??= import("../security-TYPVOYGF.mjs");
162
+ securityModulePromise ??= import("../security-7H5TNHZY.mjs");
156
163
  return securityModulePromise;
157
164
  }
158
165
  function loadDevModule() {
159
- devModulePromise ??= import("../dev-6RG5SSZ7.mjs");
166
+ devModulePromise ??= import("../dev-2OULECTU.mjs");
160
167
  return devModulePromise;
161
168
  }
162
169
  function loadProjectConfigModule() {
163
- projectConfigModulePromise ??= import("../config-ARLE6PKR.mjs");
170
+ projectConfigModulePromise ??= import("../config-TWEO2R4N.mjs");
164
171
  return projectConfigModulePromise;
165
172
  }
166
173
  function loadProjectDiscoveryModule() {
167
- projectDiscoveryModulePromise ??= import("../discovery-FCVGQQVD.mjs");
174
+ projectDiscoveryModulePromise ??= import("../discovery-7FXND7Y6.mjs");
168
175
  return projectDiscoveryModulePromise;
169
176
  }
170
177
  function loadProjectRuntimeModule() {
171
- projectRuntimeModulePromise ??= import("../runtime-ZKD6URAV.mjs");
178
+ projectRuntimeModulePromise ??= import("../runtime-GSXF4NB3.mjs");
172
179
  return projectRuntimeModulePromise;
173
180
  }
174
181
  function loadProjectScaffoldModule() {
175
- projectScaffoldModulePromise ??= import("../scaffold-UBOS2NZR.mjs");
182
+ projectScaffoldModulePromise ??= import("../scaffold-3QPGYQEQ.mjs");
176
183
  return projectScaffoldModulePromise;
177
184
  }
178
185
  async function resolveRuntimeExecutor(runtimeExecutor) {
@@ -184,12 +191,15 @@ var projectExecutorLoaders = {
184
191
  runProjectLifecycleScript: async () => (await loadDevModule()).runProjectLifecycleScript,
185
192
  runProjectDependencyInstall: async () => (await loadDevModule()).runProjectDependencyInstall
186
193
  };
187
- async function resolveProjectExecutor(projectExecutors, key) {
188
- const existing = projectExecutors[key];
194
+ async function resolveExecutor(executors, loaders, key) {
195
+ const existing = executors[key];
189
196
  if (existing) {
190
197
  return existing;
191
198
  }
192
- return projectExecutorLoaders[key]();
199
+ return await loaders[key]();
200
+ }
201
+ async function resolveProjectExecutor(projectExecutors, key) {
202
+ return await resolveExecutor(projectExecutors, projectExecutorLoaders, key);
193
203
  }
194
204
  var queueExecutorLoaders = {
195
205
  runQueueFailedTableCommand: async () => (await loadQueueMigrationsModule()).runQueueFailedTableCommand,
@@ -215,32 +225,16 @@ var broadcastExecutorLoaders = {
215
225
  runBroadcastWorkCommand: async () => (await loadBroadcastModule()).runBroadcastWorkCommand
216
226
  };
217
227
  async function resolveQueueExecutor(queueExecutors, key) {
218
- const existing = queueExecutors[key];
219
- if (existing) {
220
- return existing;
221
- }
222
- return queueExecutorLoaders[key]();
228
+ return await resolveExecutor(queueExecutors, queueExecutorLoaders, key);
223
229
  }
224
230
  async function resolveCacheExecutor(cacheExecutors, key) {
225
- const existing = cacheExecutors[key];
226
- if (existing) {
227
- return existing;
228
- }
229
- return cacheExecutorLoaders[key]();
231
+ return await resolveExecutor(cacheExecutors, cacheExecutorLoaders, key);
230
232
  }
231
233
  async function resolveMediaExecutor(mediaExecutors, key) {
232
- const existing = mediaExecutors[key];
233
- if (existing) {
234
- return existing;
235
- }
236
- return mediaExecutorLoaders[key]();
234
+ return await resolveExecutor(mediaExecutors, mediaExecutorLoaders, key);
237
235
  }
238
236
  async function resolveBroadcastExecutor(broadcastExecutors, key) {
239
- const existing = broadcastExecutors[key];
240
- if (existing) {
241
- return existing;
242
- }
243
- return broadcastExecutorLoaders[key]();
237
+ return await resolveExecutor(broadcastExecutors, broadcastExecutorLoaders, key);
244
238
  }
245
239
  async function resolveGeneratorCommand(key) {
246
240
  return (await loadGeneratorsModule())[key];
@@ -295,10 +289,12 @@ async function runProjectDependencyInstallAfterPackageJsonUpdate(context, projec
295
289
  const runProjectPrepare = await resolveProjectExecutor(projectExecutors, "runProjectPrepare");
296
290
  await runProjectPrepare(context.projectRoot, context);
297
291
  }
298
- async function runProjectDependencyInstallForProject(context, projectExecutors, projectRoot) {
292
+ async function runProjectDependencyInstallForProject(context, projectExecutors, projectRoot, options = {}) {
299
293
  const runProjectDependencyInstall = await resolveProjectExecutor(projectExecutors, "runProjectDependencyInstall");
300
294
  await runProjectDependencyInstall(context, projectRoot);
301
- writeLine(context.stdout, " - installed dependencies");
295
+ if (options.writeStatus ?? true) {
296
+ writeLine(context.stdout, " - installed dependencies");
297
+ }
302
298
  }
303
299
  function createInternalCommands(context, runtimeExecutor, queueExecutors = {}, projectExecutors = {}, broadcastExecutors = {}, securityExecutors = {}, cacheExecutors = {}, mediaExecutors = {}) {
304
300
  return [
@@ -317,7 +313,7 @@ function createInternalCommands(context, runtimeExecutor, queueExecutors = {}, p
317
313
  {
318
314
  name: "new",
319
315
  description: "Scaffold a new Holo project",
320
- usage: "holo new <name> [--framework <nuxt|next|sveltekit>] [--database <sqlite|mysql|postgres>] [--package-manager <bun|npm|pnpm|yarn>] [--package <storage|events|queue|validation|forms|auth|authorization|notifications|mail|broadcast|security|cache>] [--storage-default-disk <local|public>]",
316
+ usage: "holo new <name> [--framework <nuxt|next|sveltekit>] [--database <sqlite|mysql|postgres>] [--package-manager <bun|npm|pnpm|yarn>] [--package <storage|events|queue|validation|forms|auth|authorization|notifications|mail|broadcast|realtime|security|cache>] [--storage-default-disk <local|public>]",
321
317
  source: "internal",
322
318
  async prepare(input) {
323
319
  const resolved = await resolveNewProjectInput(context, input);
@@ -343,16 +339,28 @@ function createInternalCommands(context, runtimeExecutor, queueExecutors = {}, p
343
339
  );
344
340
  const targetDir = resolve2(commandContext.cwd, projectName);
345
341
  const { scaffoldProject } = await loadProjectScaffoldModule();
346
- await scaffoldProject(targetDir, {
347
- projectName,
348
- framework,
349
- databaseDriver,
350
- packageManager,
351
- storageDefaultDisk,
352
- optionalPackages
353
- });
342
+ await runWithSpinner(
343
+ context,
344
+ "Creating project files...",
345
+ () => scaffoldProject(targetDir, {
346
+ projectName,
347
+ framework,
348
+ databaseDriver,
349
+ packageManager,
350
+ storageDefaultDisk,
351
+ optionalPackages
352
+ }),
353
+ "Project files created."
354
+ );
354
355
  writeLine(context.stdout, `Created Holo project: ${targetDir}`);
355
- await runProjectDependencyInstallForProject(context, projectExecutors, targetDir);
356
+ await runWithSpinner(
357
+ context,
358
+ "Installing dependencies...",
359
+ () => runProjectDependencyInstallForProject(context, projectExecutors, targetDir, {
360
+ writeStatus: !supportsSpinner(context)
361
+ }),
362
+ "Dependencies installed."
363
+ );
356
364
  writeLine(context.stdout);
357
365
  writeLine(context.stdout, "Next steps");
358
366
  writeLine(context.stdout, ` cd ${projectName}`);
@@ -378,11 +386,13 @@ function createInternalCommands(context, runtimeExecutor, queueExecutors = {}, p
378
386
  {
379
387
  name: "install",
380
388
  description: "Install first-party Holo support into an existing project.",
381
- usage: "holo install <queue|events|auth|authorization|notifications|mail|broadcast|security|cache|media> [--driver <queue: sync|file|redis|database; cache: file|redis|database>] [--social] [--provider <google|github|discord|facebook|apple|linkedin>] [--workos] [--clerk]",
389
+ usage: "holo install <queue|events|auth|authorization|notifications|mail|broadcast|realtime|security|cache|media> [--driver <queue: sync|file|redis|database; cache: file|redis|database>] [--social] [--provider <google|github|discord|facebook|apple|linkedin>] [--workos] [--clerk]",
382
390
  source: "internal",
383
391
  async prepare(input) {
392
+ const interactive = isInteractive(context, input.flags);
393
+ const requestedTarget = input.args[0]?.trim();
384
394
  const target = normalizeChoice(
385
- await ensureRequiredArg(context, input, 0, "Install target"),
395
+ requestedTarget || (interactive ? await promptChoice(context, "Install target", SUPPORTED_INSTALL_TARGETS, "queue") : await ensureRequiredArg(context, input, 0, "Install target")),
386
396
  SUPPORTED_INSTALL_TARGETS,
387
397
  "install target"
388
398
  );
@@ -405,17 +415,65 @@ function createInternalCommands(context, runtimeExecutor, queueExecutors = {}, p
405
415
  if (target === "broadcast" && requestedDriver) {
406
416
  throw new Error("The broadcast installer does not support --driver.");
407
417
  }
418
+ if (target === "realtime" && requestedDriver) {
419
+ throw new Error("The realtime installer does not support --driver.");
420
+ }
408
421
  if (target === "security" && requestedDriver) {
409
422
  throw new Error("The security installer does not support --driver.");
410
423
  }
411
424
  if (target === "media" && requestedDriver) {
412
425
  throw new Error("The media installer does not support --driver.");
413
426
  }
414
- const driver = target === "queue" ? requestedDriver ? normalizeChoice(requestedDriver, SUPPORTED_QUEUE_INSTALL_DRIVERS, "queue driver") : "sync" : target === "cache" ? requestedDriver ? normalizeChoice(requestedDriver, SUPPORTED_CACHE_INSTALL_DRIVERS, "cache driver") : "file" : void 0;
415
- const socialProviders = target === "auth" ? (collectMultiStringFlag(input.flags, "provider") ?? []).flatMap((entry) => splitCsv(entry) ?? []).map((provider) => normalizeChoice(provider, SUPPORTED_AUTH_SOCIAL_PROVIDERS, "auth social provider")) : [];
416
- const social = target === "auth" ? resolveBooleanFlag(input.flags, "social") === true || socialProviders.length > 0 : false;
417
- const workos = target === "auth" ? resolveBooleanFlag(input.flags, "workos") === true : false;
418
- const clerk = target === "auth" ? resolveBooleanFlag(input.flags, "clerk") === true : false;
427
+ const driver = target === "queue" ? requestedDriver ? normalizeChoice(requestedDriver, SUPPORTED_QUEUE_INSTALL_DRIVERS, "queue driver") : interactive ? await promptChoice(context, "Queue driver", SUPPORTED_QUEUE_INSTALL_DRIVERS, "sync") : "sync" : target === "cache" ? requestedDriver ? normalizeChoice(requestedDriver, SUPPORTED_CACHE_INSTALL_DRIVERS, "cache driver") : interactive ? await promptChoice(context, "Cache driver", SUPPORTED_CACHE_INSTALL_DRIVERS, "file") : "file" : void 0;
428
+ let socialProviders = target === "auth" ? (collectMultiStringFlag(input.flags, "provider") ?? []).flatMap((entry) => splitCsv(entry) ?? []).map((provider) => normalizeChoice(provider, SUPPORTED_AUTH_SOCIAL_PROVIDERS, "auth social provider")) : [];
429
+ let social = target === "auth" ? resolveBooleanFlag(input.flags, "social") === true || socialProviders.length > 0 : false;
430
+ let workos = target === "auth" ? resolveBooleanFlag(input.flags, "workos") === true : false;
431
+ let clerk = target === "auth" ? resolveBooleanFlag(input.flags, "clerk") === true : false;
432
+ const authFlagsProvided = "social" in input.flags || "provider" in input.flags || "workos" in input.flags || "clerk" in input.flags;
433
+ if (target === "auth" && interactive && !authFlagsProvided) {
434
+ const features = await promptMultiChoice(
435
+ context,
436
+ "Auth providers",
437
+ AUTH_INSTALL_FEATURES,
438
+ {
439
+ labels: {
440
+ social: "Social OAuth",
441
+ workos: "WorkOS",
442
+ clerk: "Clerk"
443
+ },
444
+ hints: {
445
+ social: "Google, GitHub, Discord, Facebook, Apple, or LinkedIn"
446
+ }
447
+ }
448
+ );
449
+ social = features.includes("social");
450
+ workos = features.includes("workos");
451
+ clerk = features.includes("clerk");
452
+ if (social) {
453
+ const providerMode = await promptChoice(
454
+ context,
455
+ "Social provider setup",
456
+ AUTH_SOCIAL_PROVIDER_MODES,
457
+ "default",
458
+ {
459
+ labels: {
460
+ default: "Default social setup",
461
+ specific: "Choose specific providers"
462
+ }
463
+ }
464
+ );
465
+ if (providerMode === "specific") {
466
+ socialProviders = [
467
+ ...await promptMultiChoice(
468
+ context,
469
+ "Social providers",
470
+ SUPPORTED_AUTH_SOCIAL_PROVIDERS,
471
+ { required: true }
472
+ )
473
+ ];
474
+ }
475
+ }
476
+ }
419
477
  return {
420
478
  args: [target],
421
479
  flags: {
@@ -439,12 +497,19 @@ function createInternalCommands(context, runtimeExecutor, queueExecutors = {}, p
439
497
  const eventsResult = await installEventsIntoProject(context.projectRoot);
440
498
  let queueResult;
441
499
  if (!queueConfigured && isInteractive(context, commandContext.flags)) {
442
- const enableQueuedListeners = await confirm(
500
+ const queueAction = await promptChoice(
443
501
  context,
444
- "Enable queued listeners too?",
445
- false
502
+ "Queued listeners",
503
+ EVENTS_QUEUE_ACTIONS,
504
+ "skip",
505
+ {
506
+ labels: {
507
+ skip: "Skip queued listeners",
508
+ enable: "Enable queued listeners"
509
+ }
510
+ }
446
511
  );
447
- if (enableQueuedListeners) {
512
+ if (queueAction === "enable") {
448
513
  queueResult = await installQueueIntoProject2(context.projectRoot, { driver: "sync" });
449
514
  }
450
515
  }
@@ -545,6 +610,17 @@ function createInternalCommands(context, runtimeExecutor, queueExecutors = {}, p
545
610
  await runProjectDependencyInstallAfterPackageJsonUpdate(context, projectExecutors, result2.updatedPackageJson);
546
611
  return;
547
612
  }
613
+ if (target === "realtime") {
614
+ const { installRealtimeIntoProject } = await loadProjectScaffoldModule();
615
+ const result2 = await installRealtimeIntoProject(context.projectRoot);
616
+ const changed2 = result2.updatedPackageJson || result2.createdRealtimeDirectory || result2.createdFrameworkSetup;
617
+ writeLine(context.stdout, changed2 ? "Installed realtime support." : "Realtime support is already installed.");
618
+ if (result2.updatedPackageJson) writeLine(context.stdout, " - updated package.json");
619
+ if (result2.createdRealtimeDirectory) writeLine(context.stdout, " - created server/realtime");
620
+ if (result2.createdFrameworkSetup) writeLine(context.stdout, " - created realtime framework setup");
621
+ await runProjectDependencyInstallAfterPackageJsonUpdate(context, projectExecutors, result2.updatedPackageJson);
622
+ return;
623
+ }
548
624
  if (target === "security") {
549
625
  const { installSecurityIntoProject } = await loadProjectScaffoldModule();
550
626
  const result2 = await installSecurityIntoProject(context.projectRoot);
@@ -1041,17 +1117,25 @@ function createInternalCommands(context, runtimeExecutor, queueExecutors = {}, p
1041
1117
  };
1042
1118
  if (isInteractive(context, input.flags)) {
1043
1119
  const noneSelected = [flags.migration, flags.observer, flags.seeder, flags.factory].every((value) => value !== true);
1044
- if (noneSelected && await confirm(context, "Generate a migration?", true)) {
1045
- flags.migration = true;
1046
- }
1047
- if (!flags.observer && await confirm(context, "Generate an observer?")) {
1048
- flags.observer = true;
1049
- }
1050
- if (!flags.seeder && await confirm(context, "Generate a seeder?")) {
1051
- flags.seeder = true;
1052
- }
1053
- if (!flags.factory && await confirm(context, "Generate a factory?")) {
1054
- flags.factory = true;
1120
+ if (noneSelected) {
1121
+ const selectedArtifacts = await promptMultiChoice(
1122
+ context,
1123
+ "Model artifacts",
1124
+ MODEL_GENERATOR_OPTIONS,
1125
+ {
1126
+ initialValues: ["migration"],
1127
+ labels: {
1128
+ migration: "Migration",
1129
+ observer: "Observer",
1130
+ seeder: "Seeder",
1131
+ factory: "Factory"
1132
+ }
1133
+ }
1134
+ );
1135
+ flags.migration = selectedArtifacts.includes("migration");
1136
+ flags.observer = selectedArtifacts.includes("observer");
1137
+ flags.seeder = selectedArtifacts.includes("seeder");
1138
+ flags.factory = selectedArtifacts.includes("factory");
1055
1139
  }
1056
1140
  }
1057
1141
  return {
@@ -0,0 +1,203 @@
1
+ import {
2
+ initializeProjectRuntime
3
+ } from "./chunk-IUDD5FYL.mjs";
4
+ import "./chunk-LBJAJLKU.mjs";
5
+ import {
6
+ writeLine
7
+ } from "./chunk-I7QBCEV7.mjs";
8
+ import "./chunk-D7O4SU6N.mjs";
9
+ import {
10
+ prepareProjectDiscovery
11
+ } from "./chunk-2RGJTPYF.mjs";
12
+ import "./chunk-KWRIBHC3.mjs";
13
+ import {
14
+ loadProjectConfig
15
+ } from "./chunk-ONKESAQA.mjs";
16
+ import {
17
+ loadGeneratedProjectRegistry
18
+ } from "./chunk-2DKQKZML.mjs";
19
+ import {
20
+ importProjectModule,
21
+ resolveProjectPackageImportSpecifier
22
+ } from "./chunk-ILU426CF.mjs";
23
+
24
+ // src/broadcast.ts
25
+ import { basename, extname, resolve } from "path";
26
+ import { readFile } from "fs/promises";
27
+ import { loadConfigDirectory } from "@holo-js/config";
28
+ function hasLoadedRedisConfigSection(loadedFiles) {
29
+ return Array.isArray(loadedFiles) && loadedFiles.some((filePath) => {
30
+ return basename(filePath, extname(filePath)) === "redis";
31
+ });
32
+ }
33
+ async function hasProjectPackageDependency(projectRoot, packageName) {
34
+ try {
35
+ const manifest = JSON.parse(await readFile(resolve(projectRoot, "package.json"), "utf8"));
36
+ return Boolean(
37
+ manifest.dependencies?.[packageName] || manifest.devDependencies?.[packageName] || manifest.optionalDependencies?.[packageName] || manifest.peerDependencies?.[packageName]
38
+ );
39
+ } catch {
40
+ return false;
41
+ }
42
+ }
43
+ async function loadBroadcastCliModule(projectRoot) {
44
+ try {
45
+ return await import(resolveProjectPackageImportSpecifier(projectRoot, "@holo-js/broadcast"));
46
+ } catch (error) {
47
+ const details = error instanceof Error ? error.message : String(error);
48
+ throw new Error(
49
+ `Unable to load @holo-js/broadcast from ${projectRoot}. Install it with "holo install broadcast". ${details}`
50
+ );
51
+ }
52
+ }
53
+ async function loadRealtimeServerModule(projectRoot) {
54
+ const specifier = resolveProjectPackageImportSpecifier(projectRoot, "@holo-js/realtime/server");
55
+ try {
56
+ return await import(specifier);
57
+ } catch (error) {
58
+ const details = error instanceof Error ? error.message : String(error);
59
+ if (/Cannot find module|ERR_MODULE_NOT_FOUND|MODULE_NOT_FOUND/i.test(details) && details.includes(specifier)) {
60
+ return null;
61
+ }
62
+ throw error;
63
+ }
64
+ }
65
+ function safeDecodeCookieSegment(value) {
66
+ try {
67
+ return decodeURIComponent(value);
68
+ } catch {
69
+ return value;
70
+ }
71
+ }
72
+ function readCookieFromHeader(header, name) {
73
+ for (const segment of header?.split(";") ?? []) {
74
+ const separator = segment.indexOf("=");
75
+ if (separator <= 0) {
76
+ continue;
77
+ }
78
+ const cookieName = safeDecodeCookieSegment(segment.slice(0, separator).trim());
79
+ if (cookieName === name) {
80
+ return safeDecodeCookieSegment(segment.slice(separator + 1).trim());
81
+ }
82
+ }
83
+ return void 0;
84
+ }
85
+ function createRealtimeAuthRequestAccessors(headers) {
86
+ return {
87
+ async getCookie(name) {
88
+ return readCookieFromHeader(headers.get("cookie"), name);
89
+ },
90
+ async getHeader(name) {
91
+ return headers.get(name) ?? void 0;
92
+ },
93
+ async appendResponseCookie(_cookie) {
94
+ },
95
+ async redirectResponse(url) {
96
+ throw new Error(`Realtime auth attempted to redirect to "${url}". Realtime requests cannot redirect.`);
97
+ }
98
+ };
99
+ }
100
+ async function createRealtimeWorkerBindings(projectRoot) {
101
+ if (!await hasProjectPackageDependency(projectRoot, "@holo-js/realtime")) {
102
+ return void 0;
103
+ }
104
+ const realtime = await loadRealtimeServerModule(projectRoot);
105
+ if (!realtime) {
106
+ return void 0;
107
+ }
108
+ const runtime = await initializeProjectRuntime(projectRoot);
109
+ realtime.configureRealtimeRuntime?.({
110
+ async runWithAuthRequestAccessors(accessors, callback) {
111
+ const runner = runtime.runWithAuthRequestAccessors;
112
+ return runner ? await runner(accessors, callback) : await callback();
113
+ }
114
+ });
115
+ const definitions = /* @__PURE__ */ new Map();
116
+ const resolveDefinition = async (name) => {
117
+ const cached = definitions.get(name);
118
+ if (cached) {
119
+ return await cached;
120
+ }
121
+ const resolved = realtime.resolveRealtimeDefinition(name, {
122
+ projectRoot,
123
+ importModule: async (absolutePath) => await importProjectModule(projectRoot, absolutePath)
124
+ }).catch((error) => {
125
+ definitions.delete(name);
126
+ throw error;
127
+ });
128
+ definitions.set(name, resolved);
129
+ return await resolved;
130
+ };
131
+ const withRealtimeRequest = async (context, callback) => {
132
+ return await callback(createRealtimeAuthRequestAccessors(context.headers));
133
+ };
134
+ return {
135
+ async query(name, args, context) {
136
+ return await withRealtimeRequest(context, async (authRequest) => {
137
+ return await realtime.executeRealtimeQuery(await resolveDefinition(name), args, { authRequest });
138
+ });
139
+ },
140
+ async mutate(name, args, context) {
141
+ return await withRealtimeRequest(context, async (authRequest) => {
142
+ return await realtime.executeRealtimeMutation(await resolveDefinition(name), args, { authRequest });
143
+ });
144
+ },
145
+ async subscribe(name, args, options) {
146
+ return await withRealtimeRequest(options.context, async (authRequest) => {
147
+ return await realtime.subscribeRealtimeQuery(await resolveDefinition(name), args, {
148
+ onData: options.onData,
149
+ onError: options.onError
150
+ }, { authRequest });
151
+ });
152
+ }
153
+ };
154
+ }
155
+ async function runBroadcastWorkCommand(io, projectRoot, dependencies = {}) {
156
+ const loadConfig = dependencies.loadConfig ?? loadConfigDirectory;
157
+ const loadModule = dependencies.loadModule ?? loadBroadcastCliModule;
158
+ const config = await loadConfig(projectRoot);
159
+ const project = await loadProjectConfig(projectRoot);
160
+ const loadRegistry = dependencies.loadRegistry ?? loadGeneratedProjectRegistry;
161
+ await loadRegistry(projectRoot).catch(() => void 0);
162
+ const registry = await prepareProjectDiscovery(projectRoot, project.config);
163
+ const broadcastModule = await loadModule(projectRoot);
164
+ const realtime = await createRealtimeWorkerBindings(projectRoot);
165
+ const worker = await broadcastModule.startBroadcastWorker({
166
+ config: config.broadcast,
167
+ queue: config.queue,
168
+ ...hasLoadedRedisConfigSection(config.loadedFiles) ? { redis: config.redis } : {},
169
+ ...registry ? {
170
+ channelAuth: {
171
+ registry: {
172
+ projectRoot,
173
+ channels: registry.channels
174
+ },
175
+ importModule: async (absolutePath) => await importProjectModule(projectRoot, absolutePath)
176
+ }
177
+ } : {},
178
+ ...realtime ? { realtime } : {}
179
+ });
180
+ writeLine(io.stdout, `[broadcast] Worker listening on ${worker.host}:${worker.port}`);
181
+ await new Promise((resolvePromise) => {
182
+ let stopped = false;
183
+ const stop = async () => {
184
+ if (stopped) {
185
+ return;
186
+ }
187
+ stopped = true;
188
+ process.off("SIGINT", onSignal);
189
+ process.off("SIGTERM", onSignal);
190
+ await worker.stop();
191
+ resolvePromise();
192
+ };
193
+ const onSignal = () => {
194
+ void stop();
195
+ };
196
+ process.on("SIGINT", onSignal);
197
+ process.on("SIGTERM", onSignal);
198
+ });
199
+ }
200
+ export {
201
+ loadBroadcastCliModule,
202
+ runBroadcastWorkCommand
203
+ };