@holo-js/cli 0.1.7 → 0.1.8

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.
@@ -342,22 +342,6 @@ function renderNuxtConfig() {
342
342
  ""
343
343
  ].join("\n");
344
344
  }
345
- function renderNuxtHealthRoute() {
346
- return [
347
- "export default defineEventHandler(async () => {",
348
- " const app = await holo.getApp()",
349
- "",
350
- " return {",
351
- " ok: true,",
352
- " app: app.config.app.name,",
353
- " env: app.config.app.env,",
354
- " models: app.registry?.models.length ?? 0,",
355
- " commands: app.registry?.commands.length ?? 0,",
356
- " }",
357
- "})",
358
- ""
359
- ].join("\n");
360
- }
361
345
  function renderNuxtCurrentAuthRoute() {
362
346
  return [
363
347
  "import auth, { check, isAuthError, provider, user } from '@holo-js/auth'",
@@ -535,30 +519,13 @@ function renderNextRouteBridge(modulePath, methods) {
535
519
  }
536
520
  function renderNextHoloHelper() {
537
521
  return [
538
- "import { createNextHoloHelpers } from '@holo-js/adapter-next'",
539
- "",
540
- "export const holo = createNextHoloHelpers()",
541
- ""
542
- ].join("\n");
543
- }
544
- function renderNextHealthRoute() {
545
- return renderNextRouteBridge("../../../../.holo-js/generated/next/health-route", ["GET"]);
546
- }
547
- function renderNextGeneratedHealthRoute() {
548
- return [
549
- "import { holo } from '../../../server/holo'",
522
+ "import { dirname, resolve } from 'node:path'",
523
+ "import { fileURLToPath } from 'node:url'",
524
+ "import { createNextHoloHelpers } from '@holo-js/adapter-next/runtime'",
550
525
  "",
551
- "export async function GET() {",
552
- " const app = await holo.getApp()",
526
+ "const projectRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../..')",
553
527
  "",
554
- " return Response.json({",
555
- " ok: true,",
556
- " app: app.config.app.name,",
557
- " env: app.config.app.env,",
558
- " models: app.registry?.models.length ?? 0,",
559
- " commands: app.registry?.commands.length ?? 0,",
560
- " })",
561
- "}",
528
+ "export const holo = createNextHoloHelpers({ projectRoot })",
562
529
  ""
563
530
  ].join("\n");
564
531
  }
@@ -568,7 +535,7 @@ function renderNextCurrentAuthRoute() {
568
535
  function renderNextGeneratedCurrentAuthRoute() {
569
536
  return [
570
537
  "import auth, { check, isAuthError, provider, user } from '@holo-js/auth'",
571
- "import { holo } from '../../../server/holo'",
538
+ "import { holo } from './holo'",
572
539
  "",
573
540
  "export async function GET(request: Request) {",
574
541
  " await holo.getApp()",
@@ -605,7 +572,7 @@ function renderNextHostedAuthLoginRoute(spec) {
605
572
  function renderNextGeneratedHostedAuthLoginRoute(spec) {
606
573
  return [
607
574
  `import { ${spec.loginFunction} } from '${spec.packageName}'`,
608
- "import { holo } from '../../../server/holo'",
575
+ "import { holo } from './holo'",
609
576
  "",
610
577
  "export async function GET(request: Request) {",
611
578
  " await holo.getApp()",
@@ -621,7 +588,7 @@ function renderNextHostedAuthRegisterRoute(spec) {
621
588
  function renderNextGeneratedHostedAuthRegisterRoute(spec) {
622
589
  return [
623
590
  `import { ${spec.registerFunction} } from '${spec.packageName}'`,
624
- "import { holo } from '../../../server/holo'",
591
+ "import { holo } from './holo'",
625
592
  "",
626
593
  "export async function GET(request: Request) {",
627
594
  " await holo.getApp()",
@@ -637,7 +604,7 @@ function renderNextHostedAuthCallbackRoute(spec) {
637
604
  function renderNextGeneratedHostedAuthCallbackRoute(spec) {
638
605
  return [
639
606
  `import { ${spec.callbackFunction} } from '${spec.packageName}'`,
640
- "import { holo } from '../../../server/holo'",
607
+ "import { holo } from './holo'",
641
608
  "",
642
609
  "export async function GET(request: Request) {",
643
610
  " await holo.getApp()",
@@ -659,7 +626,7 @@ function renderNextGeneratedHostedAuthLogoutRoute(spec) {
659
626
  return [
660
627
  "import { provider } from '@holo-js/auth'",
661
628
  `import { ${spec.logoutFunction} } from '${spec.packageName}'`,
662
- "import { holo } from '../../../server/holo'",
629
+ "import { holo } from './holo'",
663
630
  "",
664
631
  "export async function POST(request: Request) {",
665
632
  " await holo.getApp()",
@@ -700,7 +667,7 @@ function renderNextStorageRoute() {
700
667
  function renderNextGeneratedStorageRoute() {
701
668
  return [
702
669
  "import { createPublicStorageResponse } from '@holo-js/storage'",
703
- "import { holo } from '../../../server/holo'",
670
+ "import { holo } from './holo'",
704
671
  "",
705
672
  "export async function GET(request: Request) {",
706
673
  " const app = await holo.getApp()",
@@ -715,7 +682,7 @@ function renderNextBroadcastAuthRoute() {
715
682
  function renderNextGeneratedBroadcastAuthRoute() {
716
683
  return [
717
684
  "import { renderBroadcastAuthResponse } from '@holo-js/broadcast/auth'",
718
- "import { holo } from '../../../server/holo'",
685
+ "import { holo } from './holo'",
719
686
  "",
720
687
  "export async function POST(request: Request) {",
721
688
  " const app = await holo.getApp()",
@@ -736,7 +703,7 @@ function renderNextGeneratedBroadcastAuthRoute() {
736
703
  }
737
704
  function renderNextManagedRouteFiles(options = {}) {
738
705
  return [
739
- { path: ".holo-js/generated/next/health-route.ts", contents: renderNextGeneratedHealthRoute() },
706
+ { path: ".holo-js/generated/next/holo.ts", contents: renderNextHoloHelper() },
740
707
  ...options.authEnabled ? [{ path: ".holo-js/generated/next/auth-user-route.ts", contents: renderNextGeneratedCurrentAuthRoute() }] : [],
741
708
  ...options.storageEnabled ? [{ path: ".holo-js/generated/next/storage-route.ts", contents: renderNextGeneratedStorageRoute() }] : [],
742
709
  ...options.broadcastAuthEnabled ? [{ path: ".holo-js/generated/next/broadcast-auth-route.ts", contents: renderNextGeneratedBroadcastAuthRoute() }] : []
@@ -746,6 +713,7 @@ function renderNextManagedHostedAuthRouteFiles(features) {
746
713
  return getRequestedHostedAuthProviders(features).flatMap((provider) => {
747
714
  const spec = HOSTED_AUTH_PROVIDERS[provider];
748
715
  return [
716
+ { path: ".holo-js/generated/next/holo.ts", contents: renderNextHoloHelper() },
749
717
  { path: `.holo-js/generated/next/auth-${provider}-login-route.ts`, contents: renderNextGeneratedHostedAuthLoginRoute(spec) },
750
718
  { path: `.holo-js/generated/next/auth-${provider}-register-route.ts`, contents: renderNextGeneratedHostedAuthRegisterRoute(spec) },
751
719
  { path: `.holo-js/generated/next/auth-${provider}-callback-route.ts`, contents: renderNextGeneratedHostedAuthCallbackRoute(spec) },
@@ -753,6 +721,11 @@ function renderNextManagedHostedAuthRouteFiles(features) {
753
721
  ];
754
722
  });
755
723
  }
724
+ function renderSvelteManagedRuntimeFiles() {
725
+ return [
726
+ { path: ".holo-js/generated/sveltekit/holo.ts", contents: renderSvelteHoloHelper() }
727
+ ];
728
+ }
756
729
  function renderSvelteConfig() {
757
730
  return [
758
731
  "import adapter from '@sveltejs/adapter-node'",
@@ -896,108 +869,61 @@ function renderSveltePage(projectName) {
896
869
  }
897
870
  function renderSvelteHoloHelper() {
898
871
  return [
872
+ "import { dirname, resolve } from 'node:path'",
873
+ "import { fileURLToPath } from 'node:url'",
899
874
  "import { createSvelteKitHoloHelpers } from '@holo-js/adapter-sveltekit'",
900
875
  "",
901
- "export const holo = createSvelteKitHoloHelpers()",
902
- ""
903
- ].join("\n");
904
- }
905
- function renderSvelteHealthRoute() {
906
- return [
907
- "import { json } from '@sveltejs/kit'",
908
- "import { holo } from '$lib/server/holo'",
909
- "",
910
- "export async function GET() {",
911
- " const app = await holo.getApp()",
876
+ "const projectRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../..')",
912
877
  "",
913
- " return json({",
914
- " ok: true,",
915
- " app: app.config.app.name,",
916
- " env: app.config.app.env,",
917
- " models: app.registry?.models.length ?? 0,",
918
- " commands: app.registry?.commands.length ?? 0,",
919
- " })",
920
- "}",
921
- ""
922
- ].join("\n");
923
- }
924
- function renderSvelteCurrentAuthRoute() {
925
- return [
926
- "import { json } from '@sveltejs/kit'",
927
- "import auth, { check, isAuthError, provider, user } from '@holo-js/auth'",
928
- "",
929
- "export async function GET({ url }: { url: URL }) {",
930
- " const guard = url.searchParams.get('guard') ?? undefined",
931
- " try {",
932
- " const guardAuth = guard ? auth.guard(guard) : undefined",
933
- "",
934
- " return json({",
935
- " authenticated: guardAuth ? await guardAuth.check() : await check(),",
936
- " guard: guard ?? 'web',",
937
- " provider: guardAuth ? await guardAuth.provider() : await provider(),",
938
- " user: guardAuth ? await guardAuth.user() : await user(),",
939
- " })",
940
- " } catch (error) {",
941
- " if (isAuthError(error) && error.code === 'guard_not_configured') {",
942
- " return json({",
943
- " authenticated: false,",
944
- " guard: guard ?? 'web',",
945
- " provider: null,",
946
- " user: null,",
947
- " }, { status: 400 })",
948
- " }",
949
- "",
950
- " throw error",
951
- " }",
952
- "}",
878
+ "export const holo = createSvelteKitHoloHelpers({ projectRoot })",
953
879
  ""
954
880
  ].join("\n");
955
881
  }
956
882
  function renderSvelteHostedAuthLoginRoute(spec) {
957
883
  return [
958
884
  `import { ${spec.loginFunction} } from '${spec.packageName}'`,
959
- "import type { RequestHandler } from './$types'",
885
+ "import type { RequestEvent } from '@sveltejs/kit'",
960
886
  "",
961
- "export const GET = (async (event) => {",
887
+ "export async function GET(event: RequestEvent) {",
962
888
  ` return await ${spec.loginFunction}(event)`,
963
- "}) satisfies RequestHandler",
889
+ "}",
964
890
  ""
965
891
  ].join("\n");
966
892
  }
967
893
  function renderSvelteHostedAuthRegisterRoute(spec) {
968
894
  return [
969
895
  `import { ${spec.registerFunction} } from '${spec.packageName}'`,
970
- "import type { RequestHandler } from './$types'",
896
+ "import type { RequestEvent } from '@sveltejs/kit'",
971
897
  "",
972
- "export const GET = (async (event) => {",
898
+ "export async function GET(event: RequestEvent) {",
973
899
  ` return await ${spec.registerFunction}(event)`,
974
- "}) satisfies RequestHandler",
900
+ "}",
975
901
  ""
976
902
  ].join("\n");
977
903
  }
978
904
  function renderSvelteHostedAuthCallbackRoute(spec) {
979
905
  return [
980
- "import { redirect, type RequestHandler } from '@sveltejs/kit'",
906
+ "import { redirect, type RequestEvent } from '@sveltejs/kit'",
981
907
  `import { ${spec.callbackFunction} } from '${spec.packageName}'`,
982
908
  "",
983
- "export const GET = (async (event) => {",
909
+ "export async function GET(event: RequestEvent) {",
984
910
  ` const { error } = await ${spec.callbackFunction}(event)`,
985
911
  " if (error) {",
986
912
  " throw redirect(303, `/login?error=${encodeURIComponent(error.code)}`)",
987
913
  " }",
988
914
  "",
989
915
  " throw redirect(303, '/')",
990
- "}) satisfies RequestHandler",
916
+ "}",
991
917
  ""
992
918
  ].join("\n");
993
919
  }
994
920
  function renderSvelteHostedAuthLogoutRoute(spec) {
995
921
  return [
996
- "import { redirect, type RequestHandler } from '@sveltejs/kit'",
922
+ "import { redirect, type RequestEvent } from '@sveltejs/kit'",
997
923
  "import { provider } from '@holo-js/auth'",
998
924
  `import { ${spec.logoutFunction} } from '${spec.packageName}'`,
999
925
  "",
1000
- "export const POST = (async (event) => {",
926
+ "export async function POST(event: RequestEvent) {",
1001
927
  " let currentProvider: string | null",
1002
928
  " try {",
1003
929
  " currentProvider = await provider()",
@@ -1015,7 +941,7 @@ function renderSvelteHostedAuthLogoutRoute(spec) {
1015
941
  " }",
1016
942
  "",
1017
943
  " throw redirect(303, data.url)",
1018
- "}) satisfies RequestHandler",
944
+ "}",
1019
945
  ""
1020
946
  ].join("\n");
1021
947
  }
@@ -1025,7 +951,8 @@ function renderSvelteHostedAuthRouteFiles(provider) {
1025
951
  { path: `src/routes/api/auth/${provider}/login/+server.ts`, contents: renderSvelteHostedAuthLoginRoute(spec) },
1026
952
  { path: `src/routes/api/auth/${provider}/register/+server.ts`, contents: renderSvelteHostedAuthRegisterRoute(spec) },
1027
953
  { path: `src/routes/api/auth/${provider}/callback/+server.ts`, contents: renderSvelteHostedAuthCallbackRoute(spec) },
1028
- { path: `src/routes/api/auth/${provider}/logout/+server.ts`, contents: renderSvelteHostedAuthLogoutRoute(spec) }
954
+ { path: `src/routes/api/auth/${provider}/logout/+server.ts`, contents: renderSvelteHostedAuthLogoutRoute(spec) },
955
+ ...renderSvelteManagedRuntimeFiles()
1029
956
  ];
1030
957
  }
1031
958
  function renderAuthProviderRouteFiles(framework, features) {
@@ -1043,6 +970,7 @@ function renderAuthRouteFiles(framework) {
1043
970
  if (framework === "next") {
1044
971
  return [
1045
972
  { path: "app/api/auth/user/route.ts", contents: renderNextCurrentAuthRoute() },
973
+ { path: ".holo-js/generated/next/holo.ts", contents: renderNextHoloHelper() },
1046
974
  { path: ".holo-js/generated/next/auth-user-route.ts", contents: renderNextGeneratedCurrentAuthRoute() }
1047
975
  ];
1048
976
  }
@@ -1052,21 +980,9 @@ function renderAuthRouteFiles(framework) {
1052
980
  ];
1053
981
  }
1054
982
  return [
1055
- { path: "src/routes/api/auth/user/+server.ts", contents: renderSvelteCurrentAuthRoute() }
983
+ ...renderSvelteManagedRuntimeFiles()
1056
984
  ];
1057
985
  }
1058
- function renderSvelteStorageRoute() {
1059
- return [
1060
- "import { holo } from '$lib/server/holo'",
1061
- "import { createPublicStorageResponse } from '@holo-js/storage'",
1062
- "",
1063
- "export async function GET({ request }: { request: Request }) {",
1064
- " const app = await holo.getApp()",
1065
- " return createPublicStorageResponse(app.projectRoot, app.config.storage, request)",
1066
- "}",
1067
- ""
1068
- ].join("\n");
1069
- }
1070
986
  function renderFrameworkFiles(options) {
1071
987
  const optionalPackages = normalizeScaffoldOptionalPackages(options.optionalPackages);
1072
988
  const storageEnabled = optionalPackages.includes("storage");
@@ -1075,7 +991,6 @@ function renderFrameworkFiles(options) {
1075
991
  return [
1076
992
  { path: "app/app.vue", contents: renderNuxtAppVue(options.projectName) },
1077
993
  { path: "nuxt.config.ts", contents: renderNuxtConfig() },
1078
- { path: "server/api/holo/health.get.ts", contents: renderNuxtHealthRoute() },
1079
994
  { path: "shared/.gitkeep", contents: "" },
1080
995
  ...authEnabled ? renderAuthRouteFiles("nuxt") : []
1081
996
  ];
@@ -1086,10 +1001,8 @@ function renderFrameworkFiles(options) {
1086
1001
  { path: "next-env.d.ts", contents: renderNextEnvDts() },
1087
1002
  { path: "app/layout.tsx", contents: renderNextLayout(options.projectName) },
1088
1003
  { path: "app/page.tsx", contents: renderNextPage(options.projectName) },
1089
- { path: "app/api/holo/health/route.ts", contents: renderNextHealthRoute() },
1090
1004
  ...authEnabled ? [{ path: "app/api/auth/user/route.ts", contents: renderNextCurrentAuthRoute() }] : [],
1091
1005
  ...storageEnabled ? [{ path: "app/storage/[[...path]]/route.ts", contents: renderNextStorageRoute() }] : [],
1092
- { path: "server/holo.ts", contents: renderNextHoloHelper() },
1093
1006
  ...renderNextManagedRouteFiles({ authEnabled, storageEnabled })
1094
1007
  ];
1095
1008
  }
@@ -1100,10 +1013,8 @@ function renderFrameworkFiles(options) {
1100
1013
  { path: "src/hooks.server.ts", contents: renderSvelteServerUserHooks() },
1101
1014
  { path: "src/app.html", contents: renderSvelteAppHtml() },
1102
1015
  { path: "src/routes/+page.svelte", contents: renderSveltePage(options.projectName) },
1103
- { path: "src/routes/api/holo/health/+server.ts", contents: renderSvelteHealthRoute() },
1104
1016
  ...authEnabled ? renderAuthRouteFiles("sveltekit") : [],
1105
- ...storageEnabled ? [{ path: "src/routes/storage/[...path]/+server.ts", contents: renderSvelteStorageRoute() }] : [],
1106
- { path: "src/lib/server/holo.ts", contents: renderSvelteHoloHelper() }
1017
+ ...renderSvelteManagedRuntimeFiles()
1107
1018
  ];
1108
1019
  }
1109
1020
  function renderFrameworkRunner(options) {
@@ -1401,13 +1312,13 @@ function renderFrameworkRunner(options) {
1401
1312
 
1402
1313
  // src/project/registry.ts
1403
1314
  import { constants as fsConstants } from "fs";
1404
- import { access, mkdir as mkdir2, readFile as readFile2, readdir, writeFile as writeFile2 } from "fs/promises";
1315
+ import { access, mkdir as mkdir2, readFile as readFile2, readdir as readdir2, writeFile as writeFile2 } from "fs/promises";
1405
1316
  import { dirname as dirname3, extname, join, resolve as resolve3 } from "path";
1406
1317
  import { loadConfigDirectory } from "@holo-js/config";
1407
1318
  import { DEFAULT_HOLO_PROJECT_PATHS, renderGeneratedSchemaRuntimeModule } from "@holo-js/db";
1408
1319
 
1409
1320
  // src/project/registry-svelte.ts
1410
- import { mkdir, readFile, unlink, writeFile } from "fs/promises";
1321
+ import { mkdir, readdir, readFile, rm, writeFile } from "fs/promises";
1411
1322
  import { dirname as dirname2, resolve as resolve2 } from "path";
1412
1323
  function renderManagedSvelteHooksModule() {
1413
1324
  return [
@@ -1454,22 +1365,151 @@ function renderManagedSvelteHooksModule() {
1454
1365
  ""
1455
1366
  ].join("\n");
1456
1367
  }
1457
- function renderManagedSvelteServerHooksModule() {
1458
- return [
1368
+ function renderManagedSvelteServerHooksModule(features) {
1369
+ const imports = [
1459
1370
  "// Generated by holo prepare. Do not edit.",
1460
1371
  "",
1461
- "import { error as svelteKitError, type Handle, type HandleFetch, type HandleServerError } from '@sveltejs/kit'",
1372
+ "import { error as svelteKitError, type Handle, type HandleFetch, type HandleServerError, type RequestEvent } from '@sveltejs/kit'",
1462
1373
  "import { adapterSvelteKitInternals, runWithSvelteKitRequestEvent } from '@holo-js/adapter-sveltekit'",
1463
1374
  "import { sequence } from '@sveltejs/kit/hooks'",
1464
- "import { holo } from '$lib/server/holo'",
1375
+ ...features.authEnabled ? ["import auth, { check, isAuthError, provider, user } from '@holo-js/auth'"] : [],
1376
+ ...features.broadcastEnabled ? ["import { renderBroadcastAuthResponse } from '@holo-js/broadcast/auth'"] : [],
1377
+ ...features.storageEnabled ? ["import { createPublicStorageResponse } from '@holo-js/storage'"] : [],
1378
+ ...features.clerkEnabled ? ["import { completeClerkAuth, loginWithClerk, logoutWithClerk, registerWithClerk } from '@holo-js/auth-clerk'"] : [],
1379
+ ...features.workosEnabled ? ["import { completeWorkosAuth, loginWithWorkos, logoutWithWorkos, registerWithWorkos } from '@holo-js/auth-workos'"] : [],
1380
+ "import { holo } from './sveltekit/holo'",
1465
1381
  "import * as userHooks from '../../src/hooks.server'",
1466
- "",
1382
+ ""
1383
+ ];
1384
+ const routeHandlers = [
1385
+ ...features.authEnabled ? ["handleHoloCurrentAuthRoute"] : [],
1386
+ ...features.storageEnabled ? ["handleHoloStorageRoute"] : [],
1387
+ ...features.broadcastEnabled ? ["handleHoloBroadcastAuthRoute"] : [],
1388
+ ...features.clerkEnabled ? [
1389
+ "handleHoloClerkLoginRoute",
1390
+ "handleHoloClerkRegisterRoute",
1391
+ "handleHoloClerkCallbackRoute",
1392
+ "handleHoloClerkLogoutRoute"
1393
+ ] : [],
1394
+ ...features.workosEnabled ? [
1395
+ "handleHoloWorkosLoginRoute",
1396
+ "handleHoloWorkosRegisterRoute",
1397
+ "handleHoloWorkosCallbackRoute",
1398
+ "handleHoloWorkosLogoutRoute"
1399
+ ] : []
1400
+ ];
1401
+ return [
1402
+ ...imports,
1467
1403
  "const serverHooks = userHooks as {",
1468
1404
  " handle?: Handle",
1469
1405
  " handleError?: HandleServerError",
1470
1406
  " handleFetch?: HandleFetch",
1471
1407
  "}",
1472
1408
  "",
1409
+ "type HoloApp = Awaited<ReturnType<typeof holo.getApp>>",
1410
+ "type HoloRouteHandler = (event: RequestEvent, app: HoloApp) => Promise<Response | undefined>",
1411
+ "",
1412
+ "function isRoute(event: RequestEvent, method: string, paths: readonly string[]): boolean {",
1413
+ " return event.request.method.toUpperCase() === method && paths.includes(event.url.pathname)",
1414
+ "}",
1415
+ "",
1416
+ "function redirectResponse(event: RequestEvent, location: string): Response {",
1417
+ " return Response.redirect(new URL(location, event.url), 303)",
1418
+ "}",
1419
+ "",
1420
+ "function normalizeRoutePrefix(value: string | undefined, fallback: string): string {",
1421
+ " const raw = value?.trim() ?? fallback",
1422
+ " if (!raw || raw === '/') {",
1423
+ " return fallback",
1424
+ " }",
1425
+ "",
1426
+ " return `/${raw.replace(/^\\/+|\\/+$/g, '')}`",
1427
+ "}",
1428
+ "",
1429
+ "function pathMatchesPrefix(pathname: string, prefix: string): boolean {",
1430
+ " return pathname === prefix || pathname.startsWith(`${prefix}/`)",
1431
+ "}",
1432
+ "",
1433
+ ...features.authEnabled ? [
1434
+ "async function handleHoloCurrentAuthRoute(event: RequestEvent): Promise<Response | undefined> {",
1435
+ " if (!isRoute(event, 'GET', ['/api/auth/user'])) {",
1436
+ " return undefined",
1437
+ " }",
1438
+ "",
1439
+ " const guard = event.url.searchParams.get('guard') ?? undefined",
1440
+ " try {",
1441
+ " const guardAuth = guard ? auth.guard(guard) : undefined",
1442
+ "",
1443
+ " return Response.json({",
1444
+ " authenticated: guardAuth ? await guardAuth.check() : await check(),",
1445
+ " guard: guard ?? 'web',",
1446
+ " provider: guardAuth ? await guardAuth.provider() : await provider(),",
1447
+ " user: guardAuth ? await guardAuth.user() : await user(),",
1448
+ " })",
1449
+ " } catch (error) {",
1450
+ " if (isAuthError(error) && error.code === 'guard_not_configured') {",
1451
+ " return Response.json({",
1452
+ " authenticated: false,",
1453
+ " guard: guard ?? 'web',",
1454
+ " provider: null,",
1455
+ " user: null,",
1456
+ " }, { status: 400 })",
1457
+ " }",
1458
+ "",
1459
+ " throw error",
1460
+ " }",
1461
+ "}",
1462
+ ""
1463
+ ] : [],
1464
+ ...features.storageEnabled ? [
1465
+ "async function handleHoloStorageRoute(event: RequestEvent, app: HoloApp): Promise<Response | undefined> {",
1466
+ " if (event.request.method.toUpperCase() !== 'GET') {",
1467
+ " return undefined",
1468
+ " }",
1469
+ "",
1470
+ " const prefix = normalizeRoutePrefix(app.config.storage.routePrefix, '/storage')",
1471
+ " if (!pathMatchesPrefix(event.url.pathname, prefix)) {",
1472
+ " return undefined",
1473
+ " }",
1474
+ "",
1475
+ " return createPublicStorageResponse(app.projectRoot, app.config.storage, event.request)",
1476
+ "}",
1477
+ ""
1478
+ ] : [],
1479
+ ...features.broadcastEnabled ? [
1480
+ "async function handleHoloBroadcastAuthRoute(event: RequestEvent, app: HoloApp): Promise<Response | undefined> {",
1481
+ " if (!isRoute(event, 'POST', ['/broadcasting/auth'])) {",
1482
+ " return undefined",
1483
+ " }",
1484
+ "",
1485
+ " const auth = await holo.getAuth()",
1486
+ " return await renderBroadcastAuthResponse(event.request, {",
1487
+ " resolveUser: async () => await auth?.user(),",
1488
+ " channelAuth: {",
1489
+ " registry: {",
1490
+ " projectRoot: app.projectRoot,",
1491
+ " channels: app.registry?.channels ?? [],",
1492
+ " },",
1493
+ " },",
1494
+ " })",
1495
+ "}",
1496
+ ""
1497
+ ] : [],
1498
+ ...features.clerkEnabled ? renderSvelteHostedAuthHookRoutes("clerk", "Clerk") : [],
1499
+ ...features.workosEnabled ? renderSvelteHostedAuthHookRoutes("workos", "Workos") : [],
1500
+ `const holoRouteHandlers: readonly HoloRouteHandler[] = [${routeHandlers.join(", ")}]`,
1501
+ "",
1502
+ "async function handleHoloRoute(event: RequestEvent, app: HoloApp): Promise<Response | undefined> {",
1503
+ " for (const handler of holoRouteHandlers) {",
1504
+ " const response = await handler(event, app)",
1505
+ " if (response) {",
1506
+ " return response",
1507
+ " }",
1508
+ " }",
1509
+ "",
1510
+ " return undefined",
1511
+ "}",
1512
+ "",
1473
1513
  "function isHoloAuthorizationHttpError(cause: unknown): cause is Error & { readonly decision: { readonly status: 403 | 404 } } {",
1474
1514
  " if (!(cause instanceof Error) || cause.name !== 'AuthorizationError') {",
1475
1515
  " return false",
@@ -1484,9 +1524,14 @@ function renderManagedSvelteServerHooksModule() {
1484
1524
  "}",
1485
1525
  "",
1486
1526
  "const holoHandle: Handle = ({ event, resolve }) => runWithSvelteKitRequestEvent(event, async () => {",
1487
- " await holo.getApp()",
1527
+ " const app = await holo.getApp()",
1488
1528
  "",
1489
1529
  " try {",
1530
+ " const holoRouteResponse = await handleHoloRoute(event, app)",
1531
+ " if (holoRouteResponse) {",
1532
+ " return holoRouteResponse",
1533
+ " }",
1534
+ "",
1490
1535
  " const response = await resolve(event)",
1491
1536
  " return await adapterSvelteKitInternals.mapValidationActionResponse(event, response)",
1492
1537
  " } catch (cause) {",
@@ -1531,6 +1576,63 @@ function renderManagedSvelteServerHooksModule() {
1531
1576
  ""
1532
1577
  ].join("\n");
1533
1578
  }
1579
+ function renderSvelteHostedAuthHookRoutes(providerName, functionSuffix) {
1580
+ return [
1581
+ `async function handleHolo${functionSuffix}LoginRoute(event: RequestEvent): Promise<Response | undefined> {`,
1582
+ ` if (!isRoute(event, 'GET', ['/api/auth/${providerName}/login'])) {`,
1583
+ " return undefined",
1584
+ " }",
1585
+ "",
1586
+ ` return await loginWith${functionSuffix}(event)`,
1587
+ "}",
1588
+ "",
1589
+ `async function handleHolo${functionSuffix}RegisterRoute(event: RequestEvent): Promise<Response | undefined> {`,
1590
+ ` if (!isRoute(event, 'GET', ['/api/auth/${providerName}/register'])) {`,
1591
+ " return undefined",
1592
+ " }",
1593
+ "",
1594
+ ` return await registerWith${functionSuffix}(event)`,
1595
+ "}",
1596
+ "",
1597
+ `async function handleHolo${functionSuffix}CallbackRoute(event: RequestEvent): Promise<Response | undefined> {`,
1598
+ ` if (!isRoute(event, 'GET', ['/api/auth/${providerName}/callback'])) {`,
1599
+ " return undefined",
1600
+ " }",
1601
+ "",
1602
+ ` const { error } = await complete${functionSuffix}Auth(event)`,
1603
+ " if (error) {",
1604
+ " return redirectResponse(event, `/login?error=${encodeURIComponent(error.code)}`)",
1605
+ " }",
1606
+ "",
1607
+ " return redirectResponse(event, '/')",
1608
+ "}",
1609
+ "",
1610
+ `async function handleHolo${functionSuffix}LogoutRoute(event: RequestEvent): Promise<Response | undefined> {`,
1611
+ ` if (!isRoute(event, 'POST', ['/api/auth/${providerName}/logout'])) {`,
1612
+ " return undefined",
1613
+ " }",
1614
+ "",
1615
+ " let currentProvider: string | null",
1616
+ " try {",
1617
+ " currentProvider = await provider()",
1618
+ " } catch {",
1619
+ " return redirectResponse(event, '/')",
1620
+ " }",
1621
+ "",
1622
+ ` if (currentProvider !== '${providerName}') {`,
1623
+ " return redirectResponse(event, '/')",
1624
+ " }",
1625
+ "",
1626
+ ` const { data, error } = await logoutWith${functionSuffix}(event)`,
1627
+ " if (error) {",
1628
+ " return Response.json({ data, error }, { status: error.status })",
1629
+ " }",
1630
+ "",
1631
+ " return redirectResponse(event, data.url)",
1632
+ "}",
1633
+ ""
1634
+ ];
1635
+ }
1534
1636
  function renderSvelteDefaultHooksModule() {
1535
1637
  return [
1536
1638
  "export {}",
@@ -1594,10 +1696,7 @@ async function readFileIfPresent(path) {
1594
1696
  }
1595
1697
  }
1596
1698
  async function unlinkIfPresent(path) {
1597
- try {
1598
- await unlink(path);
1599
- } catch {
1600
- }
1699
+ await rm(path, { force: true });
1601
1700
  }
1602
1701
  async function pathExists(path) {
1603
1702
  return await readFileIfPresent(path) !== void 0;
@@ -1682,7 +1781,7 @@ async function writeFileIfChanged(path, contents) {
1682
1781
  await mkdir(dirname2(path), { recursive: true });
1683
1782
  await writeFile(path, contents, "utf8");
1684
1783
  }
1685
- async function ensureSvelteManagedHooks(projectRoot) {
1784
+ async function ensureSvelteManagedHooks(projectRoot, features) {
1686
1785
  const hooksPath = resolve2(projectRoot, "src/hooks.ts");
1687
1786
  const hooksServerPath = resolve2(projectRoot, "src/hooks.server.ts");
1688
1787
  const generatedHooksPath = resolve2(projectRoot, GENERATED_SVELTE_HOOKS_PATH);
@@ -1716,9 +1815,52 @@ async function ensureSvelteManagedHooks(projectRoot) {
1716
1815
  await writeFileIfChanged(hooksServerPath, renderSvelteDefaultServerHooksModule());
1717
1816
  }
1718
1817
  await writeFileIfChanged(generatedHooksPath, renderManagedSvelteHooksModule());
1719
- await writeFileIfChanged(generatedServerHooksPath, renderManagedSvelteServerHooksModule());
1818
+ await writeFileIfChanged(generatedServerHooksPath, renderManagedSvelteServerHooksModule(features));
1720
1819
  await ensureSvelteConfigHooksOverride(projectRoot);
1721
1820
  }
1821
+ async function removeLegacyManagedHoloHelper(path, managedContents) {
1822
+ const contents = await readFileIfPresent(path);
1823
+ const trimmedContents = contents?.trim();
1824
+ const trimmedManagedContents = managedContents.trim();
1825
+ const isLegacyManagedHelper = trimmedContents === [
1826
+ "import { createNextHoloHelpers } from '@holo-js/adapter-next'",
1827
+ "",
1828
+ "export const holo = createNextHoloHelpers()"
1829
+ ].join("\n") || trimmedContents === [
1830
+ "import { createSvelteKitHoloHelpers } from '@holo-js/adapter-sveltekit'",
1831
+ "",
1832
+ "export const holo = createSvelteKitHoloHelpers()"
1833
+ ].join("\n");
1834
+ if (trimmedContents === trimmedManagedContents || isLegacyManagedHelper) {
1835
+ await unlinkIfPresent(path);
1836
+ }
1837
+ }
1838
+ async function removeLegacyManagedRoute(path, markerGroups) {
1839
+ const contents = await readFileIfPresent(path);
1840
+ if (contents && markerGroups.some((markers) => markers.every((marker) => contents.includes(marker)))) {
1841
+ await unlinkIfPresent(path);
1842
+ }
1843
+ }
1844
+ async function directoryContainsText(path, pattern) {
1845
+ const entries = await readdir(path, { withFileTypes: true }).catch(() => []);
1846
+ for (const entry of entries) {
1847
+ const entryPath = resolve2(path, entry.name);
1848
+ if (entry.isDirectory()) {
1849
+ if (await directoryContainsText(entryPath, pattern)) {
1850
+ return true;
1851
+ }
1852
+ continue;
1853
+ }
1854
+ if (!entry.isFile() || !/\.[cm]?[jt]s$/.test(entry.name)) {
1855
+ continue;
1856
+ }
1857
+ const contents = await readFileIfPresent(entryPath);
1858
+ if (contents?.includes(pattern)) {
1859
+ return true;
1860
+ }
1861
+ }
1862
+ return false;
1863
+ }
1722
1864
  async function ensureNextManagedRoutes(projectRoot) {
1723
1865
  const authEnabled = await pathExists(resolve2(projectRoot, "app/api/auth/user/route.ts"));
1724
1866
  const storageEnabled = await pathExists(resolve2(projectRoot, "app/storage/[[...path]]/route.ts"));
@@ -1739,6 +1881,79 @@ async function ensureNextManagedRoutes(projectRoot) {
1739
1881
  for (const file of files) {
1740
1882
  await writeFileIfChanged(resolve2(projectRoot, file.path), file.contents);
1741
1883
  }
1884
+ await removeLegacyManagedHoloHelper(resolve2(projectRoot, "server/holo.ts"), renderNextHoloHelper());
1885
+ }
1886
+ function isRecord2(value) {
1887
+ return !!value && typeof value === "object" && !Array.isArray(value);
1888
+ }
1889
+ async function readProjectDependencies(projectRoot) {
1890
+ const contents = await readFileIfPresent(resolve2(projectRoot, "package.json"));
1891
+ if (!contents) {
1892
+ return /* @__PURE__ */ new Set();
1893
+ }
1894
+ const manifest = JSON.parse(contents);
1895
+ if (!isRecord2(manifest)) {
1896
+ return /* @__PURE__ */ new Set();
1897
+ }
1898
+ const dependencies = isRecord2(manifest.dependencies) ? Object.keys(manifest.dependencies) : [];
1899
+ const devDependencies = isRecord2(manifest.devDependencies) ? Object.keys(manifest.devDependencies) : [];
1900
+ return /* @__PURE__ */ new Set([...dependencies, ...devDependencies]);
1901
+ }
1902
+ async function resolveSvelteManagedFeatures(projectRoot) {
1903
+ const dependencies = await readProjectDependencies(projectRoot);
1904
+ return {
1905
+ authEnabled: dependencies.has("@holo-js/auth"),
1906
+ broadcastEnabled: dependencies.has("@holo-js/broadcast"),
1907
+ storageEnabled: dependencies.has("@holo-js/storage"),
1908
+ clerkEnabled: dependencies.has("@holo-js/auth-clerk"),
1909
+ workosEnabled: dependencies.has("@holo-js/auth-workos")
1910
+ };
1911
+ }
1912
+ async function ensureSvelteManagedRuntime(projectRoot) {
1913
+ const files = renderSvelteManagedRuntimeFiles();
1914
+ for (const file of files) {
1915
+ await writeFileIfChanged(resolve2(projectRoot, file.path), file.contents);
1916
+ }
1917
+ }
1918
+ async function ensureSvelteManagedRoutes(projectRoot) {
1919
+ await removeLegacyManagedRoute(
1920
+ resolve2(projectRoot, "src/routes/api/holo/health/+server.ts"),
1921
+ [
1922
+ ["app.registry?.models.length ?? 0", "app.registry?.commands.length ?? 0"],
1923
+ [".holo-js/generated/sveltekit/health-route"]
1924
+ ]
1925
+ );
1926
+ await removeLegacyManagedRoute(
1927
+ resolve2(projectRoot, "src/routes/api/holo/+server.ts"),
1928
+ [
1929
+ ["app.registry?.models.length ?? 0", "app.registry?.commands.length ?? 0"],
1930
+ [".holo-js/generated/sveltekit/health-route"]
1931
+ ]
1932
+ );
1933
+ await removeLegacyManagedRoute(
1934
+ resolve2(projectRoot, "src/routes/api/auth/user/+server.ts"),
1935
+ [
1936
+ ["authenticated:", "guard:", "provider:", "user:"],
1937
+ [".holo-js/generated/sveltekit/auth-user-route"]
1938
+ ]
1939
+ );
1940
+ await removeLegacyManagedRoute(
1941
+ resolve2(projectRoot, "src/routes/storage/[...path]/+server.ts"),
1942
+ [
1943
+ ["createPublicStorageResponse", "app.config.storage"],
1944
+ [".holo-js/generated/sveltekit/storage-route"]
1945
+ ]
1946
+ );
1947
+ await removeLegacyManagedRoute(
1948
+ resolve2(projectRoot, "src/routes/broadcasting/auth/+server.ts"),
1949
+ [
1950
+ ["renderBroadcastAuthResponse", "channelAuth"],
1951
+ [".holo-js/generated/sveltekit/broadcast-auth-route"]
1952
+ ]
1953
+ );
1954
+ if (!await directoryContainsText(resolve2(projectRoot, "src"), "$lib/server/holo")) {
1955
+ await removeLegacyManagedHoloHelper(resolve2(projectRoot, "src/lib/server/holo.ts"), renderSvelteHoloHelper());
1956
+ }
1742
1957
  }
1743
1958
  async function syncManagedFrameworkArtifacts(projectRoot) {
1744
1959
  let manifest;
@@ -1749,7 +1964,10 @@ async function syncManagedFrameworkArtifacts(projectRoot) {
1749
1964
  return;
1750
1965
  }
1751
1966
  if (manifest.framework === "sveltekit") {
1752
- await ensureSvelteManagedHooks(projectRoot);
1967
+ const features = await resolveSvelteManagedFeatures(projectRoot);
1968
+ await ensureSvelteManagedRuntime(projectRoot);
1969
+ await ensureSvelteManagedHooks(projectRoot, features);
1970
+ await ensureSvelteManagedRoutes(projectRoot);
1753
1971
  }
1754
1972
  if (manifest.framework === "next") {
1755
1973
  await ensureNextManagedRoutes(projectRoot);
@@ -2292,7 +2510,7 @@ function getConfigExtensionPriority(fileName) {
2292
2510
  }
2293
2511
  async function collectProjectConfigEntries(projectRoot) {
2294
2512
  const configDir = resolve3(projectRoot, "config");
2295
- const entries = await readdir(configDir, { withFileTypes: true }).catch(() => []);
2513
+ const entries = await readdir2(configDir, { withFileTypes: true }).catch(() => []);
2296
2514
  const selectedByName = /* @__PURE__ */ new Map();
2297
2515
  for (const entry of entries) {
2298
2516
  if (!entry.isFile()) {