@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.
Files changed (53) hide show
  1. package/dist/{agent-skills-MSEMQUXT.mjs → agent-skills-CHAXS2YN.mjs} +13 -6
  2. package/dist/bin/holo.mjs +436 -109
  3. package/dist/{broadcast-5MJ3GJK7.mjs → broadcast-5VZM5SGQ.mjs} +13 -10
  4. package/dist/{broadcast-MRJGFCFH.mjs → broadcast-AABT52BK.mjs} +13 -10
  5. package/dist/cache-A42JSVYA.mjs +138 -0
  6. package/dist/cache-DUVBBOZU.mjs +138 -0
  7. package/dist/{cache-migrations-CPYQC7T6.mjs → cache-migrations-4WKSEN2Q.mjs} +12 -10
  8. package/dist/{cache-migrations-APDFSFEX.mjs → cache-migrations-PD2T5AV4.mjs} +14 -12
  9. package/dist/chunk-3RFRE7XG.mjs +491 -0
  10. package/dist/{chunk-PT72AMV7.mjs → chunk-6BHJLCAO.mjs} +256 -392
  11. package/dist/{chunk-KS5TWO75.mjs → chunk-EQUFFLRG.mjs} +7 -7
  12. package/dist/chunk-HX6MOYBO.mjs +2 -0
  13. package/dist/{chunk-YEFJBN56.mjs → chunk-JVLZ3SOW.mjs} +11 -8
  14. package/dist/{chunk-UPXQONEH.mjs → chunk-KRADH7PK.mjs} +55 -51
  15. package/dist/chunk-LALDNNPH.mjs +428 -0
  16. package/dist/chunk-LHK5YUR4.mjs +156 -0
  17. package/dist/{chunk-LBJAJLKU.mjs → chunk-M3IPUCTM.mjs} +1 -1
  18. package/dist/{chunk-TWITVSFZ.mjs → chunk-OI54DOHK.mjs} +256 -392
  19. package/dist/{chunk-LXGQCG56.mjs → chunk-OLZEMIDQ.mjs} +1 -1
  20. package/dist/{chunk-VP2E62DF.mjs → chunk-QSVMXMTQ.mjs} +49 -349
  21. package/dist/{chunk-J76GH2DR.mjs → chunk-R4ZYMEDU.mjs} +129 -86
  22. package/dist/{chunk-XDRCZ3Z5.mjs → chunk-TH5YCOZB.mjs} +57 -53
  23. package/dist/chunk-TRYHX5S4.mjs +360 -0
  24. package/dist/chunk-XBOVM6LO.mjs +41 -0
  25. package/dist/{chunk-ILU426CF.mjs → chunk-YACY2572.mjs} +482 -2
  26. package/dist/{config-MD27U4FM.mjs → config-BZHQK532.mjs} +3 -3
  27. package/dist/{dev-CT4DRTLN.mjs → dev-7KGRV56X.mjs} +10 -8
  28. package/dist/{dev-QDLR6C7K.mjs → dev-GQT37XJU.mjs} +10 -8
  29. package/dist/{discovery-GWTBF5RZ.mjs → discovery-HNH3BLDL.mjs} +8 -6
  30. package/dist/{generators-PUN5TFP5.mjs → generators-3FVW4AEJ.mjs} +18 -15
  31. package/dist/{generators-WQHI7DBW.mjs → generators-JWVNGUUE.mjs} +14 -11
  32. package/dist/index.d.ts +1 -1
  33. package/dist/index.mjs +434 -107
  34. package/dist/{media-migrations-D3CDNMPT.mjs → media-migrations-EG34NYAG.mjs} +13 -11
  35. package/dist/{media-migrations-IWCSCKSA.mjs → media-migrations-LGI7R7AR.mjs} +11 -9
  36. package/dist/plugins-ZGLB6JO6.mjs +24 -0
  37. package/dist/{queue-O3OSLGOV.mjs → queue-BEZDCZCY.mjs} +54 -16
  38. package/dist/{queue-GRB2IH5M.mjs → queue-R54DUUYA.mjs} +54 -16
  39. package/dist/{queue-migrations-7T42S4FX.mjs → queue-migrations-AM3AKT76.mjs} +16 -11
  40. package/dist/{queue-migrations-HFZB64OG.mjs → queue-migrations-U477YSFD.mjs} +18 -13
  41. package/dist/{runtime-TTRP2DGL.mjs → runtime-4TJYZLQV.mjs} +10 -8
  42. package/dist/{runtime-M3G5OKQV.mjs → runtime-MSRQD5W5.mjs} +10 -8
  43. package/dist/{runtime-GSXF4NB3.mjs → runtime-VR5BDPYQ.mjs} +1 -1
  44. package/dist/runtime-worker.mjs +7 -1
  45. package/dist/{scaffold-5BOVJYF3.mjs → scaffold-ASEX5LEX.mjs} +8 -4
  46. package/dist/{scaffold-NY3MWUZF.mjs → scaffold-ZAD3XUSD.mjs} +8 -4
  47. package/dist/{security-ST6ED7EK.mjs → security-4QLV7QCH.mjs} +8 -6
  48. package/dist/{security-H7AGDFBX.mjs → security-KYTLP4DF.mjs} +8 -6
  49. package/package.json +35 -8
  50. package/dist/cache-KVRYC7FB.mjs +0 -66
  51. package/dist/cache-WWE4Q4YE.mjs +0 -66
  52. package/dist/chunk-D7O4SU6N.mjs +0 -2
  53. package/dist/chunk-FGQ2I2YH.mjs +0 -22
@@ -1,26 +1,26 @@
1
1
  import {
2
2
  loadProjectConfig,
3
3
  resolveGeneratedSchemaPath
4
- } from "./chunk-YEFJBN56.mjs";
4
+ } from "./chunk-JVLZ3SOW.mjs";
5
5
  import {
6
6
  loadGeneratedProjectRegistry,
7
7
  relativeImportPath,
8
8
  renderAuthProviderRouteFiles,
9
9
  renderAuthRouteFiles,
10
+ renderBroadcastAuthSupportFrameworkFiles,
11
+ renderBroadcastInstallFrameworkFiles,
10
12
  renderFrameworkFiles,
11
13
  renderFrameworkRunner,
12
14
  renderGeneratedModelTypes,
13
- renderNextBroadcastAuthRoute,
14
- renderNextBroadcastConfigRoute,
15
- renderNextGeneratedBroadcastAuthRoute,
16
- renderNextGeneratedBroadcastConfigRoute,
15
+ renderManagedHostedAuthRouteFiles,
17
16
  renderNextGeneratedRealtimeDefinitions,
18
17
  renderNextHoloHelper,
19
- renderNextManagedHostedAuthRouteFiles,
20
18
  renderNextRuntimeBootstrap,
21
- renderSvelteHoloHelper,
22
19
  renderSvelteViteConfig
23
- } from "./chunk-J76GH2DR.mjs";
20
+ } from "./chunk-R4ZYMEDU.mjs";
21
+ import {
22
+ loadProjectPluginFrameworkDescriptors
23
+ } from "./chunk-3RFRE7XG.mjs";
24
24
  import {
25
25
  AUTH_CONFIG_FILE_NAMES,
26
26
  AUTH_SOCIAL_PROVIDER_PACKAGE_NAMES,
@@ -28,16 +28,31 @@ import {
28
28
  CACHE_CONFIG_FILE_NAMES,
29
29
  CORS_CONFIG_FILE_NAMES,
30
30
  DB_DRIVER_PACKAGE_NAMES,
31
+ ESBUILD_PACKAGE_VERSION,
31
32
  GENERATED_MODEL_TYPES_PATH,
33
+ HOLO_PACKAGE_VERSION,
34
+ IOREDIS_PACKAGE_VERSION,
32
35
  MAIL_CONFIG_FILE_NAMES,
33
36
  MEDIA_CONFIG_FILE_NAMES,
34
37
  NOTIFICATIONS_CONFIG_FILE_NAMES,
35
38
  QUEUE_CONFIG_FILE_NAMES,
36
39
  REDIS_CONFIG_FILE_NAMES,
40
+ SCAFFOLD_BASE_DEV_DEPENDENCY_VERSIONS,
41
+ SCAFFOLD_PACKAGE_MANAGER_VERSIONS,
37
42
  SECURITY_CONFIG_FILE_NAMES,
38
43
  SESSION_CONFIG_FILE_NAMES,
39
44
  SUPPORTED_AUTH_SOCIAL_PROVIDERS,
45
+ detectFrameworkDescriptorFromPackageJson,
46
+ frameworkDescriptorSupportsManagedBroadcastAuthRoute,
47
+ getFrameworkBroadcastPackages,
48
+ getFrameworkBroadcastPackagesFromDescriptor,
49
+ getFrameworkDescriptor,
50
+ getFrameworkDescriptorsWith,
51
+ getFrameworkRuntimeDependencyVersion,
52
+ getManagedFrameworkPackageNames,
53
+ importProjectModule,
40
54
  isSupportedCacheInstallerDriver,
55
+ isSupportedFrameworkId,
41
56
  isSupportedQueueInstallerDriver,
42
57
  normalizeScaffoldOptionalPackages,
43
58
  pathExists,
@@ -45,7 +60,7 @@ import {
45
60
  resolveFirstExistingPath,
46
61
  sanitizePackageName,
47
62
  writeTextFile
48
- } from "./chunk-ILU426CF.mjs";
63
+ } from "./chunk-YACY2572.mjs";
49
64
 
50
65
  // src/project/scaffold.ts
51
66
  import { mkdir as mkdir3, readdir as readdir2 } from "fs/promises";
@@ -55,224 +70,16 @@ import { loadConfigDirectory as loadConfigDirectory2 } from "@holo-js/config";
55
70
  // src/project/scaffold/config-renderers.ts
56
71
  import { appendFile, mkdir } from "fs/promises";
57
72
  import { extname, resolve as resolve2 } from "path";
58
- import { holoStorageDefaults } from "@holo-js/config";
73
+ import { holoStorageDefaults } from "@holo-js/storage";
59
74
 
60
75
  // src/project/scaffold/dependencies.ts
61
76
  import { resolve } from "path";
62
- import { loadConfigDirectory } from "@holo-js/config";
63
-
64
- // package.json
65
- var package_default = {
66
- name: "@holo-js/cli",
67
- version: "0.2.5",
68
- description: "Holo-JS Framework - project creation, discovery, and operational CLI",
69
- type: "module",
70
- license: "MIT",
71
- bin: {
72
- holo: "./dist/bin/holo.mjs",
73
- "holo-js": "./dist/bin/holo.mjs"
74
- },
75
- exports: {
76
- ".": {
77
- types: "./dist/index.d.ts",
78
- import: "./dist/index.mjs"
79
- }
80
- },
81
- main: "./dist/index.mjs",
82
- types: "./dist/index.d.ts",
83
- files: [
84
- "dist"
85
- ],
86
- scripts: {
87
- build: "node ../../scripts/generate-cli-workspace-catalog.mjs && tsup",
88
- stub: "node ../../scripts/generate-cli-workspace-catalog.mjs && tsup --watch",
89
- typecheck: "tsc -p tsconfig.json --noEmit",
90
- test: "vitest --run && HOLO_CLI_INCLUDE_INTEGRATION=1 vitest --run tests/cli.test.ts",
91
- "test:integration": "HOLO_CLI_INCLUDE_INTEGRATION=1 vitest --run tests/cli.test.ts"
92
- },
93
- dependencies: {
94
- "@clack/prompts": "catalog:",
95
- "@holo-js/cache-db": "catalog:",
96
- "@holo-js/config": "catalog:",
97
- "@holo-js/core": "catalog:",
98
- "@holo-js/db": "catalog:",
99
- esbuild: "catalog:",
100
- inflection: "catalog:"
101
- },
102
- devDependencies: {
103
- "@holo-js/events": "catalog:",
104
- "@holo-js/queue": "catalog:",
105
- "@holo-js/queue-db": "catalog:",
106
- "@types/node": "catalog:",
107
- tsup: "catalog:",
108
- typescript: "catalog:",
109
- vitest: "catalog:"
110
- },
111
- engines: {
112
- node: ">=20.11.0"
113
- }
114
- };
115
-
116
- // src/generated/workspaceCatalog.ts
117
- var WORKSPACE_CATALOG = Object.freeze({
118
- "@clerk/backend": "^3.4.7",
119
- "@clack/prompts": "^1.5.1",
120
- "@eslint/js": "^9.17.0",
121
- "@holo-js/adapter-next": "^0.2.5",
122
- "@holo-js/adapter-nuxt": "^0.2.5",
123
- "@holo-js/adapter-sveltekit": "^0.2.5",
124
- "@holo-js/auth": "^0.2.5",
125
- "@holo-js/auth-clerk": "^0.2.5",
126
- "@holo-js/auth-social": "^0.2.5",
127
- "@holo-js/auth-social-apple": "^0.2.5",
128
- "@holo-js/auth-social-discord": "^0.2.5",
129
- "@holo-js/auth-social-facebook": "^0.2.5",
130
- "@holo-js/auth-social-github": "^0.2.5",
131
- "@holo-js/auth-social-google": "^0.2.5",
132
- "@holo-js/auth-social-linkedin": "^0.2.5",
133
- "@holo-js/auth-workos": "^0.2.5",
134
- "@holo-js/authorization": "^0.2.5",
135
- "@holo-js/broadcast": "^0.2.5",
136
- "@holo-js/cache": "^0.2.5",
137
- "@holo-js/cache-db": "^0.2.5",
138
- "@holo-js/cache-redis": "^0.2.5",
139
- "@holo-js/cli": "^0.2.5",
140
- "@holo-js/config": "^0.2.5",
141
- "@holo-js/core": "^0.2.5",
142
- "@holo-js/db": "^0.2.5",
143
- "@holo-js/db-mysql": "^0.2.5",
144
- "@holo-js/db-postgres": "^0.2.5",
145
- "@holo-js/db-sqlite": "^0.2.5",
146
- "@holo-js/events": "^0.2.5",
147
- "@holo-js/flux": "^0.2.5",
148
- "@holo-js/flux-react": "^0.2.5",
149
- "@holo-js/flux-svelte": "^0.2.5",
150
- "@holo-js/flux-vue": "^0.2.5",
151
- "@holo-js/forms": "^0.2.5",
152
- "@holo-js/mail": "^0.2.5",
153
- "@holo-js/media": "^0.2.5",
154
- "@holo-js/notifications": "^0.2.5",
155
- "@holo-js/queue": "^0.2.5",
156
- "@holo-js/queue-db": "^0.2.5",
157
- "@holo-js/queue-redis": "^0.2.5",
158
- "@holo-js/realtime": "^0.2.5",
159
- "@holo-js/security": "^0.2.5",
160
- "@holo-js/session": "^0.2.5",
161
- "@holo-js/storage": "^0.2.5",
162
- "@holo-js/storage-s3": "^0.2.5",
163
- "@holo-js/validation": "^0.2.5",
164
- "@nuxt/kit": "^4.4.4",
165
- "@nuxt/module-builder": "^1.0.2",
166
- "@sveltejs/adapter-node": "^5.5.4",
167
- "@sveltejs/kit": "^2.59.1",
168
- "@sveltejs/vite-plugin-svelte": "^7.1.0",
169
- "@types/better-sqlite3": "^7.6.12",
170
- "@types/node": "^22.10.2",
171
- "@types/pg": "^8.11.0",
172
- "@types/react": "^19.2.14",
173
- "@types/react-dom": "^19.2.3",
174
- "@types/react-test-renderer": "^19.1.0",
175
- "@types/ws": "^8.18.1",
176
- "@vitest/coverage-istanbul": "^4.1.5",
177
- "@vitest/coverage-v8": "^4.1.5",
178
- "better-sqlite3": "^11.7.0",
179
- "bullmq": "^5.71.0",
180
- "create-holo-js": "^0.2.5",
181
- "esbuild": "^0.27.4",
182
- "eslint": "^9.17.0",
183
- "fast-check": "^4.5.3",
184
- "globals": "^15.14.0",
185
- "h3": "^1.15.11",
186
- "inflection": "^3.0.2",
187
- "ioredis": "^5.4.2",
188
- "mysql2": "^3.17.1",
189
- "next": "^16.2.4",
190
- "nodemailer": "^6.10.1",
191
- "nuxt": "^4.4.4",
192
- "pg": "^8.13.0",
193
- "playwright": "^1.57.0",
194
- "react": "^19.2.6",
195
- "react-dom": "^19.2.6",
196
- "react-test-renderer": "^19.2.6",
197
- "sharp": "^0.34.4",
198
- "svelte": "^5.55.5",
199
- "svelte-check": "^4.4.6",
200
- "tslib": "^2.8.1",
201
- "tsup": "^8.3.5",
202
- "typescript": "^5.7.2",
203
- "typescript-eslint": "^8.30.1",
204
- "ulid": "^3.0.1",
205
- "uuid": "^12.0.0",
206
- "valibot": "^1.1.0",
207
- "vite": "^8.0.10",
208
- "vitepress": "^1.6.3",
209
- "vitest": "^4.1.5",
210
- "vue": "^3.5.13",
211
- "vue-router": "^5.0.4",
212
- "vue-tsc": "^2.2.0",
213
- "ws": "^8.18.3"
214
- });
215
-
216
- // src/metadata.ts
217
- var HOLO_PACKAGE_VERSION = package_default.version;
218
- var HOLO_PACKAGE_RANGE = `^${HOLO_PACKAGE_VERSION}`;
219
- function catalogVersion(packageName) {
220
- return WORKSPACE_CATALOG[packageName];
221
- }
222
- var ESBUILD_PACKAGE_VERSION = catalogVersion("esbuild");
223
- var SCAFFOLD_PACKAGE_MANAGER_VERSIONS = Object.freeze({
224
- npm: "npm@latest",
225
- pnpm: "pnpm@latest",
226
- yarn: "yarn@stable",
227
- bun: "bun@1.3.9"
228
- });
229
- var SCAFFOLD_FRAMEWORK_VERSIONS = Object.freeze({
230
- nuxt: catalogVersion("nuxt"),
231
- next: catalogVersion("next"),
232
- sveltekit: catalogVersion("@sveltejs/kit")
233
- });
234
- var SCAFFOLD_NEXT_REACT_VERSIONS = Object.freeze({
235
- react: catalogVersion("react"),
236
- "react-dom": catalogVersion("react-dom"),
237
- "@types/react": catalogVersion("@types/react"),
238
- "@types/react-dom": catalogVersion("@types/react-dom")
239
- });
240
- var SCAFFOLD_BASE_DEV_DEPENDENCY_VERSIONS = Object.freeze({
241
- typescript: catalogVersion("typescript"),
242
- "@types/node": catalogVersion("@types/node"),
243
- eslint: catalogVersion("eslint")
244
- });
245
- var SCAFFOLD_NUXT_DEPENDENCY_VERSIONS = Object.freeze({
246
- vue: catalogVersion("vue"),
247
- "vue-router": catalogVersion("vue-router"),
248
- "vue-tsc": catalogVersion("vue-tsc")
249
- });
250
- var SCAFFOLD_SVELTEKIT_DEPENDENCY_VERSIONS = Object.freeze({
251
- "@sveltejs/adapter-node": catalogVersion("@sveltejs/adapter-node"),
252
- "@sveltejs/vite-plugin-svelte": catalogVersion("@sveltejs/vite-plugin-svelte"),
253
- svelte: catalogVersion("svelte"),
254
- "svelte-check": catalogVersion("svelte-check"),
255
- vite: catalogVersion("vite")
256
- });
257
- var IOREDIS_PACKAGE_VERSION = catalogVersion("ioredis");
258
- var SCAFFOLD_FRAMEWORK_ADAPTER_VERSIONS = Object.freeze({
259
- nuxt: HOLO_PACKAGE_RANGE,
260
- next: HOLO_PACKAGE_RANGE,
261
- sveltekit: HOLO_PACKAGE_RANGE
262
- });
263
- var SCAFFOLD_FRAMEWORK_RUNTIME_VERSIONS = Object.freeze({
264
- nuxt: {
265
- "@holo-js/storage": HOLO_PACKAGE_RANGE
266
- },
267
- next: {
268
- "@holo-js/storage": HOLO_PACKAGE_RANGE
269
- },
270
- sveltekit: {
271
- "@holo-js/storage": HOLO_PACKAGE_RANGE
272
- }
273
- });
274
-
275
- // src/project/scaffold/dependencies.ts
77
+ import {
78
+ configureEnvRuntime,
79
+ loadConfigDirectory,
80
+ loadEnvironment,
81
+ resolveEnvPlaceholders
82
+ } from "@holo-js/config";
276
83
  function normalizeDependencyMap(value) {
277
84
  if (!value || typeof value !== "object" || Array.isArray(value)) {
278
85
  return {};
@@ -295,6 +102,48 @@ function resolveManagedHoloPackageVersion(packageName, dependencies, devDependen
295
102
  }).find(([dependencyName, dependencyVersion]) => dependencyName.startsWith("@holo-js/") && isWorkspaceDependencyVersion(dependencyVersion))?.[1];
296
103
  return workspaceVersion ?? `^${HOLO_PACKAGE_VERSION}`;
297
104
  }
105
+ function resolveQueueConfigModuleValue(moduleValue) {
106
+ if (!moduleValue || typeof moduleValue !== "object" || Array.isArray(moduleValue)) {
107
+ return void 0;
108
+ }
109
+ const exports = moduleValue;
110
+ const value = typeof exports.default !== "undefined" ? exports.default : exports.queue;
111
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
112
+ return void 0;
113
+ }
114
+ return value;
115
+ }
116
+ async function loadQueueConfigFile(projectRoot, queueConfigPath) {
117
+ const environment = await loadEnvironment({
118
+ cwd: projectRoot,
119
+ processEnv: process.env
120
+ });
121
+ const previousEnvEntries = /* @__PURE__ */ new Map();
122
+ try {
123
+ configureEnvRuntime(environment.values);
124
+ for (const [key, value] of Object.entries(environment.values)) {
125
+ previousEnvEntries.set(key, process.env[key]);
126
+ process.env[key] = value;
127
+ }
128
+ const rawQueueConfig = resolveQueueConfigModuleValue(await importProjectModule(projectRoot, queueConfigPath));
129
+ if (!rawQueueConfig) {
130
+ return void 0;
131
+ }
132
+ return resolveEnvPlaceholders(rawQueueConfig, environment.values);
133
+ } finally {
134
+ configureEnvRuntime(void 0);
135
+ for (const [key, value] of previousEnvEntries) {
136
+ if (typeof value === "string") {
137
+ process.env[key] = value;
138
+ continue;
139
+ }
140
+ Reflect.deleteProperty(process.env, key);
141
+ }
142
+ }
143
+ }
144
+ function queueConnectionUsesDriver(connection, driver) {
145
+ return typeof connection === "object" && connection !== null && !Array.isArray(connection) && connection.driver === driver;
146
+ }
298
147
  async function readPackageJsonDependencyState(projectRoot) {
299
148
  const packageJsonPath = resolve(projectRoot, "package.json");
300
149
  const existing = await readTextFile(packageJsonPath);
@@ -373,16 +222,16 @@ function registryHasAuthorizationDefinitions(registry) {
373
222
  return (registry?.authorizationPolicies.length ?? 0) > 0 || (registry?.authorizationAbilities.length ?? 0) > 0;
374
223
  }
375
224
  function authConfigUsesSocialProviders(loaded) {
376
- return Object.keys(loaded.auth.social).length > 0;
225
+ return Object.keys(loaded.auth?.social ?? {}).length > 0;
377
226
  }
378
227
  function authConfigUsesWorkosProviders(loaded) {
379
- return Object.entries(loaded.auth.workos).some(([name, provider]) => name !== "provider" && typeof provider === "object" && provider !== null);
228
+ return Object.entries(loaded.auth?.workos ?? {}).some(([name, provider]) => name !== "provider" && typeof provider === "object" && provider !== null);
380
229
  }
381
230
  function authConfigUsesClerkProviders(loaded) {
382
- return Object.keys(loaded.auth.clerk).length > 0;
231
+ return Object.keys(loaded.auth?.clerk ?? {}).length > 0;
383
232
  }
384
233
  function mailConfigUsesQueue(loaded) {
385
- return loaded.mail.queue.queued || Object.values(loaded.mail.mailers).some((mailer) => mailer.queue.queued);
234
+ return loaded.mail?.queue.queued === true || Object.values(loaded.mail?.mailers ?? {}).some((mailer) => mailer.queue.queued);
386
235
  }
387
236
  async function projectHasAuthorizationScaffold(projectRoot) {
388
237
  const project = await loadProjectConfig(projectRoot);
@@ -427,7 +276,12 @@ async function syncManagedDriverDependencies(projectRoot, registry) {
427
276
  } = await readPackageJsonDependencyState(projectRoot);
428
277
  const cachePackageInstalled = typeof dependencies["@holo-js/cache"] !== "undefined" || typeof devDependencies["@holo-js/cache"] !== "undefined";
429
278
  const cacheDesired = cacheConfigured || cachePackageInstalled;
279
+ const framework = await detectProjectFrameworkDescriptor(projectRoot, dependencies, devDependencies);
430
280
  requiredPackages.add("@holo-js/core");
281
+ requiredPackages.add("@holo-js/kernel");
282
+ if (framework) {
283
+ requiredPackages.add(framework.adapterPackage);
284
+ }
431
285
  for (const connection of Object.values(loaded.database.connections)) {
432
286
  const inferredDriver = inferConnectionDriver(connection);
433
287
  if (inferredDriver) {
@@ -444,7 +298,7 @@ async function syncManagedDriverDependencies(projectRoot, registry) {
444
298
  requiredPackages.add("@holo-js/auth");
445
299
  if (authConfigUsesSocialProviders(loaded)) {
446
300
  requiredPackages.add("@holo-js/auth-social");
447
- for (const [providerName, provider] of Object.entries(loaded.auth.social)) {
301
+ for (const [providerName, provider] of Object.entries(loaded.auth?.social ?? {})) {
448
302
  if (typeof provider.runtime === "string" && provider.runtime.trim()) {
449
303
  continue;
450
304
  }
@@ -471,7 +325,7 @@ async function syncManagedDriverDependencies(projectRoot, registry) {
471
325
  requiredPackages.add("@holo-js/cache");
472
326
  }
473
327
  if (cacheConfigured) {
474
- const cacheDrivers = Object.values(loaded.cache.drivers);
328
+ const cacheDrivers = Object.values(loaded.cache?.drivers ?? {});
475
329
  if (cacheDrivers.some((driver) => driver.driver === "redis")) {
476
330
  requiredPackages.add("@holo-js/cache-redis");
477
331
  }
@@ -485,16 +339,10 @@ async function syncManagedDriverDependencies(projectRoot, registry) {
485
339
  if (broadcastConfigured || registryHasBroadcastDefinitions(discoveredRegistry) || hasRealtimeScaffold) {
486
340
  requiredPackages.add("@holo-js/broadcast");
487
341
  requiredPackages.add("@holo-js/flux");
488
- const framework = detectProjectFrameworkFromPackageJson(dependencies, devDependencies);
489
- if (framework === "next") {
490
- requiredPackages.add("@holo-js/flux-react");
491
- requiredPackages.add("@holo-js/adapter-next");
492
- } else if (framework === "nuxt") {
493
- requiredPackages.add("@holo-js/flux-vue");
494
- requiredPackages.add("@holo-js/adapter-nuxt");
495
- } else if (framework === "sveltekit") {
496
- requiredPackages.add("@holo-js/flux-svelte");
497
- requiredPackages.add("@holo-js/adapter-sveltekit");
342
+ if (framework) {
343
+ for (const packageName of getFrameworkBroadcastPackagesFromDescriptor(framework)) {
344
+ requiredPackages.add(packageName);
345
+ }
498
346
  }
499
347
  }
500
348
  if (hasRealtimeScaffold) {
@@ -507,14 +355,14 @@ async function syncManagedDriverDependencies(projectRoot, registry) {
507
355
  requiredPackages.add("@holo-js/events");
508
356
  requiredPackages.add("@holo-js/queue");
509
357
  }
510
- if (queueConfigured || registryHasJobs(discoveredRegistry) || mailConfigUsesQueue(loaded)) {
358
+ if (queueConfigured || registryHasJobs(discoveredRegistry) || mailConfigured && mailConfigUsesQueue(loaded)) {
511
359
  requiredPackages.add("@holo-js/queue");
512
360
  if (queueConfigured) {
513
- const queueConnections = Object.values(loaded.queue.connections);
361
+ const queueConnections = Object.values(loaded.queue?.connections ?? {});
514
362
  if (queueConnections.some((connection) => connection.driver === "redis")) {
515
363
  requiredPackages.add("@holo-js/queue-redis");
516
364
  }
517
- if (queueConnections.some((connection) => connection.driver === "database") || loaded.queue.failed !== false) {
365
+ if (queueConnections.some((connection) => connection.driver === "database") || loaded.queue?.failed !== false) {
518
366
  requiredPackages.add("@holo-js/queue-db");
519
367
  }
520
368
  }
@@ -524,13 +372,14 @@ async function syncManagedDriverDependencies(projectRoot, registry) {
524
372
  }
525
373
  if (storageConfigured) {
526
374
  requiredPackages.add("@holo-js/storage");
527
- if (Object.values(loaded.storage.disks).some((disk) => disk.driver === "s3")) {
375
+ if (Object.values(loaded.storage?.disks ?? {}).some((disk) => disk.driver === "s3")) {
528
376
  requiredPackages.add("@holo-js/storage-s3");
529
377
  }
530
378
  }
531
379
  let changed = false;
532
380
  const removableManagedPackages = /* @__PURE__ */ new Set([
533
381
  "@holo-js/core",
382
+ "@holo-js/kernel",
534
383
  ...Object.values(DB_DRIVER_PACKAGE_NAMES),
535
384
  "@holo-js/auth",
536
385
  "@holo-js/auth-clerk",
@@ -542,9 +391,7 @@ async function syncManagedDriverDependencies(projectRoot, registry) {
542
391
  "@holo-js/cache-redis",
543
392
  "@holo-js/events",
544
393
  "@holo-js/flux",
545
- "@holo-js/flux-react",
546
- "@holo-js/flux-svelte",
547
- "@holo-js/flux-vue",
394
+ ...getManagedFrameworkPackageNames(),
548
395
  "@holo-js/mail",
549
396
  "@holo-js/media",
550
397
  "@holo-js/notifications",
@@ -589,18 +436,17 @@ async function syncManagedDriverDependencies(projectRoot, registry) {
589
436
  async function upsertQueuePackageDependency(projectRoot, driver) {
590
437
  const { packageJsonPath, parsed, dependencies, devDependencies } = await readPackageJsonDependencyState(projectRoot);
591
438
  const queueConfigPath = await resolveFirstExistingPath(projectRoot, ["config/queue.ts", "config/queue.mts", "config/queue.js", "config/queue.mjs", "config/queue.cts", "config/queue.cjs"]);
592
- const loadedQueueConfig = queueConfigPath ? loadConfigDirectory(projectRoot, {
593
- preferCache: false,
594
- processEnv: process.env
595
- }).then((config) => config.queue).catch(() => void 0) : Promise.resolve(void 0);
439
+ const loadedQueueConfig = queueConfigPath ? loadQueueConfigFile(projectRoot, queueConfigPath).catch(() => void 0) : Promise.resolve(void 0);
596
440
  const nextVersion = resolveManagedHoloPackageVersion("@holo-js/queue", dependencies, devDependencies);
597
441
  const nextQueueDbVersion = resolveManagedHoloPackageVersion("@holo-js/queue-db", dependencies, devDependencies);
598
442
  const nextQueueRedisVersion = resolveManagedHoloPackageVersion("@holo-js/queue-redis", dependencies, devDependencies);
599
443
  const nextEsbuildVersion = ESBUILD_PACKAGE_VERSION;
600
444
  const queueConfig = typeof driver === "undefined" ? await loadedQueueConfig : void 0;
601
- const resolvedQueueDriver = driver && driver !== "sync" ? driver : queueConfig?.connections[queueConfig.default]?.driver ?? driver;
602
- const requiresQueueDb = resolvedQueueDriver === "database" || (queueConfig?.failed ?? false) !== false || Object.values(queueConfig?.connections ?? {}).some((connection) => connection.driver === "database");
603
- const requiresQueueRedis = resolvedQueueDriver === "redis" || Object.values(queueConfig?.connections ?? {}).some((connection) => connection.driver === "redis");
445
+ const queueConnections = Object.values(queueConfig?.connections ?? {});
446
+ const configuredDefaultQueueDriver = queueConfig?.default ? queueConfig.connections?.[queueConfig.default]?.driver : void 0;
447
+ const resolvedQueueDriver = driver && driver !== "sync" ? driver : configuredDefaultQueueDriver ?? driver;
448
+ const requiresQueueDb = resolvedQueueDriver === "database" || (queueConfig ? (queueConfig.failed ?? true) !== false : false) || queueConnections.some((connection) => queueConnectionUsesDriver(connection, "database"));
449
+ const requiresQueueRedis = resolvedQueueDriver === "redis" || queueConnections.some((connection) => queueConnectionUsesDriver(connection, "redis"));
604
450
  const currentVersion = dependencies["@holo-js/queue"];
605
451
  const currentQueueDbVersion = dependencies["@holo-js/queue-db"];
606
452
  const currentQueueRedisVersion = dependencies["@holo-js/queue-redis"];
@@ -713,44 +559,31 @@ async function upsertCachePackageDependencies(projectRoot, driver = "file") {
713
559
  return true;
714
560
  }
715
561
  function detectProjectFrameworkFromPackageJson(dependencies, devDependencies) {
716
- if (dependencies.next || devDependencies.next) {
717
- return "next";
718
- }
719
- if (dependencies.nuxt || devDependencies.nuxt) {
720
- return "nuxt";
721
- }
722
- if (dependencies["@sveltejs/kit"] || devDependencies["@sveltejs/kit"]) {
723
- return "sveltekit";
724
- }
725
- return void 0;
562
+ return detectFrameworkDescriptorFromPackageJson(dependencies, devDependencies)?.id;
563
+ }
564
+ async function detectProjectFrameworkDescriptor(projectRoot, dependencies, devDependencies) {
565
+ const pluginDescriptors = await loadProjectPluginFrameworkDescriptors(projectRoot);
566
+ return detectFrameworkDescriptorFromPackageJson(
567
+ dependencies,
568
+ devDependencies,
569
+ getFrameworkDescriptorsWith(pluginDescriptors)
570
+ );
726
571
  }
727
572
  async function upsertBroadcastPackageDependencies(projectRoot) {
728
573
  const { packageJsonPath, parsed, dependencies, devDependencies } = await readPackageJsonDependencyState(projectRoot);
729
574
  const nextVersion = resolveManagedHoloPackageVersion("@holo-js/broadcast", dependencies, devDependencies);
730
- const framework = detectProjectFrameworkFromPackageJson(dependencies, devDependencies);
575
+ const framework = await detectProjectFrameworkDescriptor(projectRoot, dependencies, devDependencies);
731
576
  let changed = false;
732
577
  const requestedPackages = /* @__PURE__ */ new Set([
733
578
  "@holo-js/broadcast",
734
579
  "@holo-js/flux"
735
580
  ]);
736
- if (framework === "next") {
737
- requestedPackages.add("@holo-js/flux-react");
738
- requestedPackages.add("@holo-js/adapter-next");
739
- } else if (framework === "nuxt") {
740
- requestedPackages.add("@holo-js/flux-vue");
741
- requestedPackages.add("@holo-js/adapter-nuxt");
742
- } else if (framework === "sveltekit") {
743
- requestedPackages.add("@holo-js/flux-svelte");
744
- requestedPackages.add("@holo-js/adapter-sveltekit");
745
- }
746
- const frameworkPackages = /* @__PURE__ */ new Set([
747
- "@holo-js/flux-react",
748
- "@holo-js/adapter-next",
749
- "@holo-js/flux-vue",
750
- "@holo-js/adapter-nuxt",
751
- "@holo-js/flux-svelte",
752
- "@holo-js/adapter-sveltekit"
753
- ]);
581
+ if (framework) {
582
+ for (const packageName of getFrameworkBroadcastPackagesFromDescriptor(framework)) {
583
+ requestedPackages.add(packageName);
584
+ }
585
+ }
586
+ const frameworkPackages = new Set(getManagedFrameworkPackageNames());
754
587
  const managedPackages = /* @__PURE__ */ new Set([
755
588
  ...requestedPackages,
756
589
  ...frameworkPackages
@@ -773,13 +606,13 @@ async function upsertBroadcastPackageDependencies(projectRoot) {
773
606
  if (!changed) {
774
607
  return {
775
608
  updated: false,
776
- framework
609
+ framework: framework?.id
777
610
  };
778
611
  }
779
612
  await writePackageJsonDependencyState(packageJsonPath, parsed, dependencies, devDependencies);
780
613
  return {
781
614
  updated: true,
782
- framework
615
+ framework: framework?.id
783
616
  };
784
617
  }
785
618
  async function upsertAuthPackageDependencies(projectRoot, features = {}) {
@@ -865,7 +698,8 @@ async function upsertRealtimePackageDependency(projectRoot) {
865
698
  // src/project/scaffold/config-renderers.ts
866
699
  function renderStorageConfig() {
867
700
  return [
868
- "import { defineStorageConfig, env } from '@holo-js/config'",
701
+ "import { defineStorageConfig } from '@holo-js/storage'",
702
+ "import { env } from '@holo-js/config'",
869
703
  "",
870
704
  "export default defineStorageConfig({",
871
705
  ` defaultDisk: env('STORAGE_DEFAULT_DISK', '${holoStorageDefaults.defaultDisk}'),`,
@@ -887,7 +721,7 @@ function renderStorageConfig() {
887
721
  }
888
722
  function renderMediaConfig() {
889
723
  return [
890
- "import { defineMediaConfig } from '@holo-js/config'",
724
+ "import { defineMediaConfig } from '@holo-js/media/config'",
891
725
  "",
892
726
  "export default defineMediaConfig({})",
893
727
  ""
@@ -898,7 +732,8 @@ function renderQueueConfig(options = {}) {
898
732
  const defaultDatabaseConnection = options.defaultDatabaseConnection?.trim() || "default";
899
733
  if (driver === "redis") {
900
734
  return [
901
- "import { defineQueueConfig, env } from '@holo-js/config'",
735
+ "import { defineQueueConfig } from '@holo-js/queue'",
736
+ "import { env } from '@holo-js/config'",
902
737
  "",
903
738
  "export default defineQueueConfig({",
904
739
  " default: 'redis',",
@@ -918,7 +753,7 @@ function renderQueueConfig(options = {}) {
918
753
  }
919
754
  if (driver === "database") {
920
755
  return [
921
- "import { defineQueueConfig } from '@holo-js/config'",
756
+ "import { defineQueueConfig } from '@holo-js/queue'",
922
757
  "",
923
758
  "export default defineQueueConfig({",
924
759
  " default: 'database',",
@@ -942,7 +777,7 @@ function renderQueueConfig(options = {}) {
942
777
  ].join("\n");
943
778
  }
944
779
  return [
945
- "import { defineQueueConfig } from '@holo-js/config'",
780
+ "import { defineQueueConfig } from '@holo-js/queue'",
946
781
  "",
947
782
  "export default defineQueueConfig({",
948
783
  " default: 'sync',",
@@ -959,7 +794,8 @@ function renderQueueConfig(options = {}) {
959
794
  }
960
795
  function renderCacheConfig(driver = "file", defaultDatabaseConnection = "default", defaultRedisConnection = "default") {
961
796
  const lines = [
962
- "import { defineCacheConfig, env } from '@holo-js/config'",
797
+ "import { defineCacheConfig } from '@holo-js/cache'",
798
+ "import { env } from '@holo-js/config'",
963
799
  "",
964
800
  "export default defineCacheConfig({",
965
801
  ` default: '${driver}',`,
@@ -1002,7 +838,8 @@ function renderCacheConfig(driver = "file", defaultDatabaseConnection = "default
1002
838
  }
1003
839
  function renderRedisConfig() {
1004
840
  return [
1005
- "import { defineRedisConfig, env } from '@holo-js/config'",
841
+ "import { env } from '@holo-js/config'",
842
+ "import { defineRedisConfig } from '@holo-js/kernel'",
1006
843
  "",
1007
844
  "export default defineRedisConfig({",
1008
845
  " default: 'default',",
@@ -1030,7 +867,7 @@ async function ensureRedisConfigFile(projectRoot) {
1030
867
  }
1031
868
  function renderNotificationsConfig() {
1032
869
  return [
1033
- "import { defineNotificationsConfig } from '@holo-js/config'",
870
+ "import { defineNotificationsConfig } from '@holo-js/notifications'",
1034
871
  "",
1035
872
  "export default defineNotificationsConfig({",
1036
873
  " table: 'notifications',",
@@ -1043,7 +880,8 @@ function renderNotificationsConfig() {
1043
880
  }
1044
881
  function renderMailConfig() {
1045
882
  return [
1046
- "import { defineMailConfig, env } from '@holo-js/config'",
883
+ "import { defineMailConfig } from '@holo-js/mail'",
884
+ "import { env } from '@holo-js/config'",
1047
885
  "",
1048
886
  "export default defineMailConfig({",
1049
887
  " default: env('MAIL_MAILER', 'preview'),",
@@ -1110,7 +948,8 @@ function renderSecurityConfig() {
1110
948
  }
1111
949
  function renderCorsConfig() {
1112
950
  return [
1113
- "import { defineCorsConfig, env } from '@holo-js/config'",
951
+ "import { env } from '@holo-js/config'",
952
+ "import { defineCorsConfig } from '@holo-js/security'",
1114
953
  "",
1115
954
  "export default defineCorsConfig({",
1116
955
  " paths: ['/api/*', '/broadcasting/auth'],",
@@ -1166,12 +1005,16 @@ function renderBroadcastConfig(moduleFormat, includeAuthEndpoint, useTypeScriptS
1166
1005
  };
1167
1006
  if (moduleFormat === "cjs") {
1168
1007
  return [
1169
- "const { defineBroadcastConfig, env } = require('@holo-js/config')",
1008
+ "const { defineBroadcastConfig } = require('@holo-js/broadcast')",
1009
+ "const { env } = require('@holo-js/config')",
1170
1010
  "",
1171
1011
  `const broadcastScheme = ${renderBroadcastScheme()}`,
1172
1012
  "",
1173
1013
  "module.exports = defineBroadcastConfig({",
1174
1014
  " default: env('BROADCAST_CONNECTION', 'holo'),",
1015
+ " worker: {",
1016
+ " allowedOrigins: [env('APP_URL', 'http://localhost:3000')],",
1017
+ " },",
1175
1018
  " connections: {",
1176
1019
  " holo: {",
1177
1020
  " driver: 'holo',",
@@ -1202,12 +1045,16 @@ function renderBroadcastConfig(moduleFormat, includeAuthEndpoint, useTypeScriptS
1202
1045
  ].join("\n");
1203
1046
  }
1204
1047
  return [
1205
- "import { defineBroadcastConfig, env } from '@holo-js/config'",
1048
+ "import { defineBroadcastConfig } from '@holo-js/broadcast'",
1049
+ "import { env } from '@holo-js/config'",
1206
1050
  "",
1207
1051
  `const broadcastScheme = ${renderBroadcastScheme()}`,
1208
1052
  "",
1209
1053
  "export default defineBroadcastConfig({",
1210
1054
  " default: env('BROADCAST_CONNECTION', 'holo'),",
1055
+ " worker: {",
1056
+ " allowedOrigins: [env('APP_URL', 'http://localhost:3000')],",
1057
+ " },",
1211
1058
  " connections: {",
1212
1059
  " holo: {",
1213
1060
  " driver: 'holo',",
@@ -1309,11 +1156,12 @@ function renderBroadcastEnvFiles() {
1309
1156
  }
1310
1157
  async function syncBroadcastAuthSupportAfterAuthInstall(projectRoot) {
1311
1158
  const { dependencies, devDependencies } = await readPackageJsonDependencyState(projectRoot);
1312
- const framework = detectProjectFrameworkFromPackageJson(dependencies, devDependencies);
1313
- const canCreateBroadcastAuthRoute = framework === "next" || framework === "nuxt" || framework === "sveltekit";
1159
+ const framework = await detectProjectFrameworkDescriptor(projectRoot, dependencies, devDependencies);
1160
+ const canCreateBroadcastAuthRoute = frameworkDescriptorSupportsManagedBroadcastAuthRoute(framework);
1161
+ const frameworkId = framework && isSupportedFrameworkId(framework.id) ? framework.id : void 0;
1314
1162
  const authConfigPath = await resolveFirstExistingPath(projectRoot, AUTH_CONFIG_FILE_NAMES);
1315
1163
  const broadcastConfigPath = await resolveFirstExistingPath(projectRoot, BROADCAST_CONFIG_FILE_NAMES);
1316
- if (!authConfigPath || !broadcastConfigPath || !canCreateBroadcastAuthRoute) {
1164
+ if (!authConfigPath || !broadcastConfigPath || !frameworkId || !canCreateBroadcastAuthRoute) {
1317
1165
  return {
1318
1166
  updatedBroadcastConfig: false,
1319
1167
  createdBroadcastAuthRoute: false
@@ -1338,24 +1186,16 @@ async function syncBroadcastAuthSupportAfterAuthInstall(projectRoot) {
1338
1186
  updatedBroadcastConfig = true;
1339
1187
  }
1340
1188
  }
1341
- if (framework === "next") {
1342
- const authRoutePath = resolve2(projectRoot, "app/broadcasting/auth/route.ts");
1343
- const holoHelperPath = resolve2(projectRoot, ".holo-js/generated/next/holo.ts");
1344
- const generatedRoutePath = resolve2(projectRoot, ".holo-js/generated/next/broadcast-auth-route.ts");
1345
- if (!await pathExists(authRoutePath)) {
1346
- await writeTextFile(authRoutePath, renderNextBroadcastAuthRoute());
1189
+ for (const file of renderBroadcastAuthSupportFrameworkFiles(frameworkId)) {
1190
+ const filePath = resolve2(projectRoot, file.path);
1191
+ const generated = file.path.startsWith(".holo-js/generated/");
1192
+ if (!generated && await pathExists(filePath)) {
1193
+ continue;
1194
+ }
1195
+ if (!generated) {
1347
1196
  createdBroadcastAuthRoute = true;
1348
1197
  }
1349
- await writeTextFile(holoHelperPath, renderNextHoloHelper());
1350
- await writeTextFile(generatedRoutePath, renderNextGeneratedBroadcastAuthRoute());
1351
- return {
1352
- updatedBroadcastConfig,
1353
- createdBroadcastAuthRoute
1354
- };
1355
- }
1356
- if (framework === "sveltekit") {
1357
- const holoHelperPath = resolve2(projectRoot, ".holo-js/generated/sveltekit/holo.ts");
1358
- await writeTextFile(holoHelperPath, renderSvelteHoloHelper());
1198
+ await writeTextFile(filePath, file.contents);
1359
1199
  }
1360
1200
  return {
1361
1201
  updatedBroadcastConfig,
@@ -1364,7 +1204,8 @@ async function syncBroadcastAuthSupportAfterAuthInstall(projectRoot) {
1364
1204
  }
1365
1205
  function renderSessionConfig(defaultDatabaseConnection = "default") {
1366
1206
  return [
1367
- "import { defineSessionConfig, env } from '@holo-js/config'",
1207
+ "import { defineSessionConfig } from '@holo-js/session'",
1208
+ "import { env } from '@holo-js/config'",
1368
1209
  "",
1369
1210
  "const sessionSameSite = env('SESSION_SAME_SITE') === 'strict'",
1370
1211
  " ? 'strict'",
@@ -1409,10 +1250,17 @@ function renderAuthConfig(features = {}, moduleFormat = "esm") {
1409
1250
  };
1410
1251
  const socialEnabled = features.social === true || (features.socialProviders?.length ?? 0) > 0;
1411
1252
  const socialProviders = features.socialProviders && features.socialProviders.length > 0 ? features.socialProviders : socialEnabled ? ["google"] : [];
1412
- const lines = [
1413
- moduleFormat === "cjs" ? "module.exports = {" : "import { defineAuthConfig, env } from '@holo-js/config'",
1253
+ const envRequired = socialProviders.length > 0 || features.workos === true || features.clerk === true;
1254
+ const lines = moduleFormat === "cjs" ? [
1255
+ "module.exports = {",
1256
+ ""
1257
+ ] : [
1258
+ "import { defineAuthConfig } from '@holo-js/auth'",
1259
+ ...envRequired ? ["import { env } from '@holo-js/config'"] : [],
1414
1260
  "",
1415
- ...moduleFormat === "cjs" ? [] : ["export default defineAuthConfig({"],
1261
+ "export default defineAuthConfig({"
1262
+ ];
1263
+ lines.push(
1416
1264
  " defaults: {",
1417
1265
  " guard: 'web',",
1418
1266
  " passwords: 'users',",
@@ -1450,7 +1298,7 @@ function renderAuthConfig(features = {}, moduleFormat = "esm") {
1450
1298
  " required: false,",
1451
1299
  " route: '/verify-email',",
1452
1300
  " },"
1453
- ];
1301
+ );
1454
1302
  if (socialProviders.length > 0) {
1455
1303
  lines.push(" social: {");
1456
1304
  for (const provider of socialProviders) {
@@ -1548,9 +1396,9 @@ function mergeInstalledAuthFeatures(current, requested) {
1548
1396
  import { mkdir as mkdir2, readdir, writeFile } from "fs/promises";
1549
1397
  import { dirname, resolve as resolve3 } from "path";
1550
1398
  import {
1551
- normalizeHoloProjectConfig,
1552
- renderGeneratedSchemaPlaceholder
1553
- } from "@holo-js/db";
1399
+ normalizeHoloProjectConfig
1400
+ } from "@holo-js/kernel";
1401
+ import { renderGeneratedSchemaPlaceholder } from "@holo-js/db";
1554
1402
 
1555
1403
  // src/project/scaffold/project-renderers.ts
1556
1404
  import {
@@ -1913,7 +1761,7 @@ function createNotificationsMigrationFiles(date = /* @__PURE__ */ new Date()) {
1913
1761
  }];
1914
1762
  }
1915
1763
  function resolveFrameworkDefaultUrl(framework) {
1916
- return framework === "sveltekit" ? "http://localhost:5173" : "http://localhost:3000";
1764
+ return framework ? getFrameworkDescriptor(framework).scaffold.defaultUrl : "http://localhost:3000";
1917
1765
  }
1918
1766
  function renderScaffoldAppConfig(projectName, framework) {
1919
1767
  const defaultUrl = resolveFrameworkDefaultUrl(framework);
@@ -1950,7 +1798,8 @@ function renderScaffoldDatabaseConfig(options) {
1950
1798
  const packageName = sanitizePackageName(options.projectName) || "holo-app";
1951
1799
  if (options.databaseDriver === "sqlite") {
1952
1800
  return [
1953
- "import { defineDatabaseConfig, env } from '@holo-js/config'",
1801
+ "import { defineDatabaseConfig } from '@holo-js/db'",
1802
+ "import { env } from '@holo-js/config'",
1954
1803
  "",
1955
1804
  "export default defineDatabaseConfig({",
1956
1805
  " defaultConnection: 'main',",
@@ -1968,7 +1817,8 @@ function renderScaffoldDatabaseConfig(options) {
1968
1817
  const username = options.databaseDriver === "mysql" ? "root" : "postgres";
1969
1818
  const schemaLine = options.databaseDriver === "postgres" ? " schema: env('DB_SCHEMA', 'public')," : void 0;
1970
1819
  return [
1971
- "import { defineDatabaseConfig, env } from '@holo-js/config'",
1820
+ "import { defineDatabaseConfig } from '@holo-js/db'",
1821
+ "import { env } from '@holo-js/config'",
1972
1822
  "",
1973
1823
  "export default defineDatabaseConfig({",
1974
1824
  " defaultConnection: 'main',",
@@ -2194,6 +2044,46 @@ function upsertEnvContents(existingContents, additions) {
2194
2044
  }
2195
2045
 
2196
2046
  // src/project/scaffold/workspace-renderers.ts
2047
+ function renderScaffoldEslintConfig() {
2048
+ return [
2049
+ "import js from '@eslint/js'",
2050
+ "import globals from 'globals'",
2051
+ "import tseslint from 'typescript-eslint'",
2052
+ "",
2053
+ "export default tseslint.config(",
2054
+ " {",
2055
+ " ignores: [",
2056
+ " '.holo-js/**',",
2057
+ " '.next/**',",
2058
+ " '.nuxt/**',",
2059
+ " '.output/**',",
2060
+ " '.svelte-kit/**',",
2061
+ " 'build/**',",
2062
+ " 'coverage/**',",
2063
+ " 'node_modules/**',",
2064
+ " ],",
2065
+ " },",
2066
+ " js.configs.recommended,",
2067
+ " ...tseslint.configs.recommended,",
2068
+ " {",
2069
+ " files: ['**/*.{js,mjs,cjs,ts,tsx,mts,cts}'],",
2070
+ " languageOptions: {",
2071
+ " globals: globals.node,",
2072
+ " },",
2073
+ " rules: {",
2074
+ " 'no-var': 'error',",
2075
+ " 'prefer-const': 'error',",
2076
+ " eqeqeq: ['error', 'always', { null: 'ignore' }],",
2077
+ " '@typescript-eslint/consistent-type-imports': ['error', {",
2078
+ " prefer: 'type-imports',",
2079
+ " fixStyle: 'inline-type-imports',",
2080
+ " }],",
2081
+ " },",
2082
+ " },",
2083
+ ")",
2084
+ ""
2085
+ ].join("\n");
2086
+ }
2197
2087
  function renderScaffoldGitignore() {
2198
2088
  return [
2199
2089
  "# Dependencies",
@@ -2254,13 +2144,14 @@ function renderScaffoldGitignore() {
2254
2144
  ].join("\n");
2255
2145
  }
2256
2146
  function renderScaffoldTsconfig(options) {
2257
- if (options.framework === "nuxt") {
2147
+ const framework = getFrameworkDescriptor(options.framework);
2148
+ if (framework.scaffold.tsconfig === "nuxt") {
2258
2149
  return `${JSON.stringify({
2259
2150
  extends: "./.nuxt/tsconfig.json"
2260
2151
  }, null, 2)}
2261
2152
  `;
2262
2153
  }
2263
- if (options.framework === "sveltekit") {
2154
+ if (framework.scaffold.tsconfig === "sveltekit") {
2264
2155
  return `${JSON.stringify({
2265
2156
  extends: "./.svelte-kit/tsconfig.json",
2266
2157
  compilerOptions: {
@@ -2301,14 +2192,15 @@ function renderScaffoldTsconfig(options) {
2301
2192
  `;
2302
2193
  }
2303
2194
  function renderVSCodeSettings(options) {
2304
- if (options.framework !== "nuxt" && options.framework !== "sveltekit") {
2195
+ const framework = getFrameworkDescriptor(options.framework);
2196
+ if (!framework.scaffold.vscodeVueHybridMode && framework.scaffold.tsconfig !== "sveltekit") {
2305
2197
  return void 0;
2306
2198
  }
2307
2199
  const settings = {
2308
2200
  "typescript.tsdk": "node_modules/typescript/lib",
2309
2201
  "typescript.enablePromptUseWorkspaceTsdk": true
2310
2202
  };
2311
- if (options.framework === "nuxt") {
2203
+ if (framework.scaffold.vscodeVueHybridMode) {
2312
2204
  settings["vue.server.hybridMode"] = true;
2313
2205
  }
2314
2206
  return `${JSON.stringify(settings, null, 2)}
@@ -2322,45 +2214,28 @@ function resolvePackageManagerVersion(value) {
2322
2214
  function renderScaffoldPackageJson(options) {
2323
2215
  const packageName = sanitizePackageName(options.projectName) || "holo-app";
2324
2216
  const optionalPackages = normalizeScaffoldOptionalPackages(options.optionalPackages);
2217
+ const framework = getFrameworkDescriptor(options.framework);
2325
2218
  const dependencies = {
2326
2219
  "@holo-js/cli": `^${HOLO_PACKAGE_VERSION}`,
2327
2220
  "@holo-js/config": `^${HOLO_PACKAGE_VERSION}`,
2328
2221
  "@holo-js/core": `^${HOLO_PACKAGE_VERSION}`,
2329
2222
  "@holo-js/db": `^${HOLO_PACKAGE_VERSION}`,
2223
+ "@holo-js/kernel": `^${HOLO_PACKAGE_VERSION}`,
2330
2224
  [DB_DRIVER_PACKAGE_NAMES[options.databaseDriver]]: `^${HOLO_PACKAGE_VERSION}`,
2331
- esbuild: ESBUILD_PACKAGE_VERSION
2225
+ esbuild: ESBUILD_PACKAGE_VERSION,
2226
+ ...framework.scaffold.dependencies
2332
2227
  };
2333
2228
  const devDependencies = {
2334
2229
  typescript: SCAFFOLD_BASE_DEV_DEPENDENCY_VERSIONS.typescript,
2335
2230
  "@types/node": SCAFFOLD_BASE_DEV_DEPENDENCY_VERSIONS["@types/node"],
2336
- eslint: SCAFFOLD_BASE_DEV_DEPENDENCY_VERSIONS.eslint
2231
+ "@eslint/js": SCAFFOLD_BASE_DEV_DEPENDENCY_VERSIONS["@eslint/js"],
2232
+ eslint: SCAFFOLD_BASE_DEV_DEPENDENCY_VERSIONS.eslint,
2233
+ globals: SCAFFOLD_BASE_DEV_DEPENDENCY_VERSIONS.globals,
2234
+ "typescript-eslint": SCAFFOLD_BASE_DEV_DEPENDENCY_VERSIONS["typescript-eslint"],
2235
+ ...framework.scaffold.devDependencies
2337
2236
  };
2338
- if (options.framework === "nuxt") {
2339
- dependencies.nuxt = SCAFFOLD_FRAMEWORK_VERSIONS.nuxt;
2340
- dependencies.vue = SCAFFOLD_NUXT_DEPENDENCY_VERSIONS.vue;
2341
- dependencies["vue-router"] = SCAFFOLD_NUXT_DEPENDENCY_VERSIONS["vue-router"];
2342
- dependencies["@holo-js/adapter-nuxt"] = SCAFFOLD_FRAMEWORK_ADAPTER_VERSIONS.nuxt;
2343
- devDependencies["vue-tsc"] = SCAFFOLD_NUXT_DEPENDENCY_VERSIONS["vue-tsc"];
2344
- }
2345
- if (options.framework === "next") {
2346
- dependencies.next = SCAFFOLD_FRAMEWORK_VERSIONS.next;
2347
- dependencies.react = SCAFFOLD_NEXT_REACT_VERSIONS.react;
2348
- dependencies["react-dom"] = SCAFFOLD_NEXT_REACT_VERSIONS["react-dom"];
2349
- dependencies["@holo-js/adapter-next"] = SCAFFOLD_FRAMEWORK_ADAPTER_VERSIONS.next;
2350
- devDependencies["@types/react"] = SCAFFOLD_NEXT_REACT_VERSIONS["@types/react"];
2351
- devDependencies["@types/react-dom"] = SCAFFOLD_NEXT_REACT_VERSIONS["@types/react-dom"];
2352
- }
2353
- if (options.framework === "sveltekit") {
2354
- dependencies["@holo-js/adapter-sveltekit"] = SCAFFOLD_FRAMEWORK_ADAPTER_VERSIONS.sveltekit;
2355
- dependencies["@sveltejs/adapter-node"] = SCAFFOLD_SVELTEKIT_DEPENDENCY_VERSIONS["@sveltejs/adapter-node"];
2356
- dependencies["@sveltejs/kit"] = SCAFFOLD_FRAMEWORK_VERSIONS.sveltekit;
2357
- dependencies["@sveltejs/vite-plugin-svelte"] = SCAFFOLD_SVELTEKIT_DEPENDENCY_VERSIONS["@sveltejs/vite-plugin-svelte"];
2358
- dependencies.svelte = SCAFFOLD_SVELTEKIT_DEPENDENCY_VERSIONS.svelte;
2359
- dependencies.vite = SCAFFOLD_SVELTEKIT_DEPENDENCY_VERSIONS.vite;
2360
- devDependencies["svelte-check"] = SCAFFOLD_SVELTEKIT_DEPENDENCY_VERSIONS["svelte-check"];
2361
- }
2362
2237
  if (optionalPackages.includes("storage")) {
2363
- dependencies["@holo-js/storage"] = SCAFFOLD_FRAMEWORK_RUNTIME_VERSIONS[options.framework]["@holo-js/storage"];
2238
+ dependencies["@holo-js/storage"] = getFrameworkRuntimeDependencyVersion(options.framework, "@holo-js/storage");
2364
2239
  }
2365
2240
  if (optionalPackages.includes("events")) {
2366
2241
  dependencies["@holo-js/events"] = `^${HOLO_PACKAGE_VERSION}`;
@@ -2392,12 +2267,8 @@ function renderScaffoldPackageJson(options) {
2392
2267
  if (optionalPackages.includes("broadcast") || optionalPackages.includes("realtime")) {
2393
2268
  dependencies["@holo-js/broadcast"] = `^${HOLO_PACKAGE_VERSION}`;
2394
2269
  dependencies["@holo-js/flux"] = `^${HOLO_PACKAGE_VERSION}`;
2395
- if (options.framework === "next") {
2396
- dependencies["@holo-js/flux-react"] = `^${HOLO_PACKAGE_VERSION}`;
2397
- } else if (options.framework === "nuxt") {
2398
- dependencies["@holo-js/flux-vue"] = `^${HOLO_PACKAGE_VERSION}`;
2399
- } else if (options.framework === "sveltekit") {
2400
- dependencies["@holo-js/flux-svelte"] = `^${HOLO_PACKAGE_VERSION}`;
2270
+ for (const packageName2 of getFrameworkBroadcastPackages(options.framework)) {
2271
+ dependencies[packageName2] = `^${HOLO_PACKAGE_VERSION}`;
2401
2272
  }
2402
2273
  }
2403
2274
  if (optionalPackages.includes("realtime")) {
@@ -2415,13 +2286,13 @@ function renderScaffoldPackageJson(options) {
2415
2286
  type: "module",
2416
2287
  packageManager: resolvePackageManagerVersion(options.packageManager),
2417
2288
  scripts: {
2418
- ...options.framework === "nuxt" ? { postinstall: "nuxt prepare" } : {},
2289
+ ...framework.scaffold.scripts,
2419
2290
  prepare: "holo key:generate && holo prepare",
2420
2291
  dev: "holo dev",
2421
2292
  build: "holo build",
2422
2293
  start: "holo start",
2423
- lint: options.framework === "nuxt" ? "eslint app config server shared tests *.d.ts --fix --no-warn-ignored --no-error-on-unmatched-pattern" : options.framework === "next" ? "eslint app config server tests --fix --no-warn-ignored --no-error-on-unmatched-pattern" : "eslint src config server tests --fix --no-warn-ignored --no-error-on-unmatched-pattern",
2424
- typecheck: options.framework === "nuxt" ? "nuxt typecheck" : options.framework === "next" ? "tsc -p tsconfig.json --noEmit" : "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
2294
+ lint: framework.scaffold.lintScript,
2295
+ typecheck: framework.scaffold.typecheckScript,
2425
2296
  ["config:cache"]: "holo config:cache",
2426
2297
  ["config:clear"]: "holo config:clear"
2427
2298
  },
@@ -2505,6 +2376,7 @@ async function scaffoldProject(projectRoot, options) {
2505
2376
  }
2506
2377
  await writeFile(resolve3(projectRoot, "package.json"), renderScaffoldPackageJson(options), "utf8");
2507
2378
  await writeFile(resolve3(projectRoot, ".gitignore"), renderScaffoldGitignore(), "utf8");
2379
+ await writeFile(resolve3(projectRoot, "eslint.config.mjs"), renderScaffoldEslintConfig(), "utf8");
2508
2380
  await writeFile(resolve3(projectRoot, ".env"), scaffoldEnv, "utf8");
2509
2381
  await writeFile(resolve3(projectRoot, ".env.example"), scaffoldEnvExample, "utf8");
2510
2382
  await writeFile(resolve3(projectRoot, "config/app.ts"), renderScaffoldAppConfig(options.projectName, options.framework), "utf8");
@@ -2735,10 +2607,8 @@ async function syncHostedAuthRouteFiles(projectRoot, features) {
2735
2607
  await mkdir3(dirname2(targetPath), { recursive: true });
2736
2608
  await writeTextFile(targetPath, file.contents);
2737
2609
  }
2738
- if (framework === "next") {
2739
- for (const file of renderNextManagedHostedAuthRouteFiles(features)) {
2740
- await writeTextFile(resolve4(projectRoot, file.path), file.contents);
2741
- }
2610
+ for (const file of renderManagedHostedAuthRouteFiles(framework, features)) {
2611
+ await writeTextFile(resolve4(projectRoot, file.path), file.contents);
2742
2612
  }
2743
2613
  }
2744
2614
  async function syncAuthRouteFiles(projectRoot) {
@@ -3092,7 +2962,7 @@ async function installMediaIntoProject(projectRoot) {
3092
2962
  if (!mediaConfigPath) {
3093
2963
  await writeTextFile(resolve4(projectRoot, "config/media.ts"), renderMediaConfig());
3094
2964
  }
3095
- const { createMediaTableMigration } = await import("./media-migrations-IWCSCKSA.mjs");
2965
+ const { createMediaTableMigration } = await import("./media-migrations-LGI7R7AR.mjs");
3096
2966
  const migrationFilePath = await createMediaTableMigration(projectRoot, {
3097
2967
  skipIfExists: true
3098
2968
  });
@@ -3179,8 +3049,9 @@ async function installBroadcastIntoProject(projectRoot) {
3179
3049
  const broadcastConfigPath = await resolveFirstExistingPath(projectRoot, BROADCAST_CONFIG_FILE_NAMES);
3180
3050
  const authConfigPath = await resolveFirstExistingPath(projectRoot, AUTH_CONFIG_FILE_NAMES);
3181
3051
  const { dependencies, devDependencies } = await readPackageJsonDependencyState(projectRoot);
3182
- const framework = detectProjectFrameworkFromPackageJson(dependencies, devDependencies);
3183
- const canCreateBroadcastAuthRoute = framework === "next" || framework === "nuxt" || framework === "sveltekit";
3052
+ const framework = await detectProjectFrameworkDescriptor(projectRoot, dependencies, devDependencies);
3053
+ const frameworkId = framework && isSupportedFrameworkId(framework.id) ? framework.id : void 0;
3054
+ const canCreateBroadcastAuthRoute = frameworkDescriptorSupportsManagedBroadcastAuthRoute(framework);
3184
3055
  const broadcastRoot = resolve4(projectRoot, "server/broadcast");
3185
3056
  const channelsRoot = resolve4(projectRoot, "server/channels");
3186
3057
  const broadcastDirectoryExists = await pathExists(broadcastRoot);
@@ -3206,24 +3077,17 @@ async function installBroadcastIntoProject(projectRoot) {
3206
3077
  const nextEnvExample = upsertEnvContents(await readTextFile(envExamplePath), broadcastEnvFiles.example);
3207
3078
  const dependencyResult = await upsertBroadcastPackageDependencies(projectRoot);
3208
3079
  let createdFrameworkSetup = false;
3209
- if (framework === "next") {
3210
- const holoHelperPath = resolve4(projectRoot, ".holo-js/generated/next/holo.ts");
3211
- const broadcastConfigRoutePath = resolve4(projectRoot, "app/broadcasting/config/route.ts");
3212
- const generatedBroadcastConfigRoutePath = resolve4(projectRoot, ".holo-js/generated/next/broadcast-config-route.ts");
3213
- if (!await pathExists(holoHelperPath)) {
3214
- await writeTextFile(holoHelperPath, renderNextHoloHelper());
3215
- createdFrameworkSetup = true;
3216
- }
3217
- if (!await pathExists(broadcastConfigRoutePath)) {
3218
- await writeTextFile(broadcastConfigRoutePath, renderNextBroadcastConfigRoute());
3219
- createdFrameworkSetup = true;
3220
- }
3221
- await writeTextFile(generatedBroadcastConfigRoutePath, renderNextGeneratedBroadcastConfigRoute());
3222
- } else if (framework === "sveltekit") {
3223
- const holoHelperPath = resolve4(projectRoot, ".holo-js/generated/sveltekit/holo.ts");
3224
- if (!await pathExists(holoHelperPath)) {
3225
- await writeTextFile(holoHelperPath, renderSvelteHoloHelper());
3226
- createdFrameworkSetup = true;
3080
+ if (frameworkId) {
3081
+ for (const file of renderBroadcastInstallFrameworkFiles(frameworkId)) {
3082
+ const filePath = resolve4(projectRoot, file.path);
3083
+ const generated = file.path.startsWith(".holo-js/generated/");
3084
+ if (!await pathExists(filePath)) {
3085
+ createdFrameworkSetup = true;
3086
+ }
3087
+ if (!generated && await pathExists(filePath)) {
3088
+ continue;
3089
+ }
3090
+ await writeTextFile(filePath, file.contents);
3227
3091
  }
3228
3092
  }
3229
3093
  const broadcastAuthSupport = await syncBroadcastAuthSupportAfterAuthInstall(projectRoot);