jac-client 0.2.11__tar.gz → 0.2.12__tar.gz

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 (120) hide show
  1. {jac_client-0.2.11 → jac_client-0.2.12}/PKG-INFO +2 -2
  2. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/impl/vite_bundler.impl.jac +35 -19
  3. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/utils/__init__.jac +1 -0
  4. jac_client-0.2.12/jac_client/plugin/utils/client_deps.jac +14 -0
  5. jac_client-0.2.12/jac_client/plugin/utils/impl/client_deps.impl.jac +73 -0
  6. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/templates/client.jacpack +0 -4
  7. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/templates/fullstack.jacpack +0 -4
  8. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/tests/test_cli.py +68 -0
  9. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client.egg-info/PKG-INFO +2 -2
  10. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client.egg-info/SOURCES.txt +2 -0
  11. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client.egg-info/requires.txt +1 -1
  12. {jac_client-0.2.11 → jac_client-0.2.12}/pyproject.toml +2 -2
  13. {jac_client-0.2.11 → jac_client-0.2.12}/README.md +0 -0
  14. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/assets/workers/worker.py +0 -0
  15. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/button.jac +0 -0
  16. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/components/CategoryFilter.jac +0 -0
  17. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/components/Header.jac +0 -0
  18. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/components/ProfitOverview.jac +0 -0
  19. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/components/Summary.jac +0 -0
  20. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/components/TransactionForm.jac +0 -0
  21. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/components/TransactionItem.jac +0 -0
  22. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/components/TransactionList.jac +0 -0
  23. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/components/button.jac +0 -0
  24. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/components/navigation.jac +0 -0
  25. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/constants/categories.jac +0 -0
  26. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/constants/clients.jac +0 -0
  27. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/context/BudgetContext.jac +0 -0
  28. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/hooks/useBudget.jac +0 -0
  29. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/hooks/useLocalStorage.jac +0 -0
  30. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/main.jac +0 -0
  31. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/pages/BudgetPlanner.jac +0 -0
  32. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/pages/FeaturesTest.jac +0 -0
  33. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/pages/LandingPage.jac +0 -0
  34. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/pages/budget_planner_ui.cl.jac +0 -0
  35. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/pages/features_test_ui.cl.jac +0 -0
  36. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/pages/loginPage.jac +0 -0
  37. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/pages/nestedDemo.jac +0 -0
  38. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/pages/notFound.jac +0 -0
  39. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/pages/signupPage.jac +0 -0
  40. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/all-in-one/utils/formatters.jac +0 -0
  41. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/asset-serving/css-with-image/main.jac +0 -0
  42. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/asset-serving/image-asset/main.jac +0 -0
  43. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/asset-serving/import-alias/main.jac +0 -0
  44. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/basic/main.jac +0 -0
  45. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/basic-auth/main.jac +0 -0
  46. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/basic-auth-with-router/main.jac +0 -0
  47. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/basic-full-stack/main.jac +0 -0
  48. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/css-styling/js-styling/main.jac +0 -0
  49. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/css-styling/material-ui/main.jac +0 -0
  50. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/css-styling/pure-css/main.jac +0 -0
  51. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/css-styling/sass-example/main.jac +0 -0
  52. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/css-styling/styled-components/main.jac +0 -0
  53. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/css-styling/tailwind-example/main.jac +0 -0
  54. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/full-stack-with-auth/main.jac +0 -0
  55. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/little-x/main.jac +0 -0
  56. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/little-x/src/submit-button.jac +0 -0
  57. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/nested-folders/nested-advance/main.jac +0 -0
  58. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/nested-folders/nested-advance/src/ButtonRoot.jac +0 -0
  59. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/nested-folders/nested-advance/src/level1/ButtonSecondL.jac +0 -0
  60. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/nested-folders/nested-advance/src/level1/Card.jac +0 -0
  61. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/nested-folders/nested-advance/src/level1/level2/ButtonThirdL.jac +0 -0
  62. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/nested-folders/nested-basic/main.jac +0 -0
  63. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/nested-folders/nested-basic/src/button.jac +0 -0
  64. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/nested-folders/nested-basic/src/components/button.jac +0 -0
  65. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/ts-support/main.jac +0 -0
  66. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/examples/with-router/main.jac +0 -0
  67. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/cli.jac +0 -0
  68. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/client.jac +0 -0
  69. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/client_runtime.cl.jac +0 -0
  70. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/impl/client.impl.jac +0 -0
  71. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/impl/client_runtime.impl.jac +0 -0
  72. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/impl/vite_client_bundle.impl.jac +0 -0
  73. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/plugin_config.jac +0 -0
  74. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/__init__.jac +0 -0
  75. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/asset_processor.jac +0 -0
  76. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/compiler.jac +0 -0
  77. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/config_loader.jac +0 -0
  78. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/desktop_config.jac +0 -0
  79. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/impl/asset_processor.impl.jac +0 -0
  80. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/impl/compiler.impl.jac +0 -0
  81. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/impl/config_loader.impl.jac +0 -0
  82. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/impl/desktop_config.impl.jac +0 -0
  83. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/impl/import_processor.impl.jac +0 -0
  84. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/impl/jac_to_js.impl.jac +0 -0
  85. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/impl/package_installer.impl.jac +0 -0
  86. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/import_processor.jac +0 -0
  87. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/jac_to_js.jac +0 -0
  88. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/package_installer.jac +0 -0
  89. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/targets/desktop/sidecar/main.py +0 -0
  90. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/targets/desktop_target.jac +0 -0
  91. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/targets/impl/desktop_target.impl.jac +0 -0
  92. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/targets/impl/registry.impl.jac +0 -0
  93. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/targets/impl/web_target.impl.jac +0 -0
  94. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/targets/register.jac +0 -0
  95. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/targets/registry.jac +0 -0
  96. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/targets/web_target.jac +0 -0
  97. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/src/vite_bundler.jac +0 -0
  98. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/utils/bun_installer.jac +0 -0
  99. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/utils/impl/bun_installer.impl.jac +0 -0
  100. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/plugin/vite_client_bundle.jac +0 -0
  101. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/tests/__init__.py +0 -0
  102. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/tests/conftest.py +0 -0
  103. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/tests/fixtures/basic-app/app.jac +0 -0
  104. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/tests/fixtures/cl_file/app.cl.jac +0 -0
  105. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/tests/fixtures/cl_file/app.jac +0 -0
  106. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/tests/fixtures/client_app_with_antd/app.jac +0 -0
  107. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/tests/fixtures/js_import/app.jac +0 -0
  108. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/tests/fixtures/relative_import/app.jac +0 -0
  109. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/tests/fixtures/relative_import/button.jac +0 -0
  110. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/tests/fixtures/spawn_test/app.jac +0 -0
  111. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/tests/fixtures/test_fragments_spread/app.jac +0 -0
  112. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/tests/fixtures/with-ts/app.jac +0 -0
  113. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/tests/test_e2e.py +0 -0
  114. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/tests/test_helpers.py +0 -0
  115. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/tests/test_it.py +0 -0
  116. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client/tests/test_it_desktop.py +0 -0
  117. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client.egg-info/dependency_links.txt +0 -0
  118. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client.egg-info/entry_points.txt +0 -0
  119. {jac_client-0.2.11 → jac_client-0.2.12}/jac_client.egg-info/top_level.txt +0 -0
  120. {jac_client-0.2.11 → jac_client-0.2.12}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jac-client
3
- Version: 0.2.11
3
+ Version: 0.2.12
4
4
  Summary: Build full-stack web applications with Jac - one language for frontend and backend.
5
5
  Author-email: Jason Mars <jason@mars.ninja>
6
6
  Maintainer-email: Jason Mars <jason@mars.ninja>
@@ -11,7 +11,7 @@ Project-URL: Documentation, https://jac-lang.org
11
11
  Keywords: jac,jaclang,jaseci,frontend,full-stack,web-development
12
12
  Requires-Python: >=3.12
13
13
  Description-Content-Type: text/markdown
14
- Requires-Dist: jaclang>=0.9.11
14
+ Requires-Dist: jaclang>=0.9.12
15
15
  Provides-Extra: dev
16
16
  Requires-Dist: python-dotenv==1.0.1; extra == "dev"
17
17
  Requires-Dist: pytest==8.3.5; extra == "dev"
@@ -426,22 +426,29 @@ impl ViteBundler.build(self: ViteBundler, entry_file: Optional[Path] = None) ->
426
426
  import sys;
427
427
  import time;
428
428
  import shutil;
429
- import from jac_client.plugin.utils { ensure_bun_available }
429
+ import from jac_client.plugin.utils { ensure_bun_available, ensure_client_deps }
430
430
  # Ensure bun is available before proceeding
431
431
  if not ensure_bun_available() {
432
432
  raise ClientBundleError('Bun is required. Install manually: https://bun.sh') from None ;
433
433
  }
434
- self.output_dir.mkdir(parents=True, exist_ok=True);
435
- generated_package_json = self._get_client_dir() / 'configs' / 'package.json';
436
- if not generated_package_json.exists() {
437
- self.create_package_json();
438
- } else {
439
- # Ensure tsconfig.json exists even if package.json already exists
440
- self.create_tsconfig();
434
+ # Ensure client npm deps are configured; prompt to install defaults if missing
435
+ if not ensure_client_deps(self.config_loader) {
436
+ raise ClientBundleError(
437
+ 'Client dependencies not configured. Add [dependencies.npm] to jac.toml '
438
+ 'or create a project with: jac create --use client'
439
+ ) from None ;
441
440
  }
441
+ self.output_dir.mkdir(parents=True, exist_ok=True);
442
+ # Always regenerate package.json to pick up any dependency changes
443
+ self.create_package_json();
442
444
  try {
443
445
  build_dir = self._get_client_dir();
444
446
  node_modules = build_dir / 'node_modules';
447
+ # Reinstall if node_modules is missing or stale (e.g. empty from a prior failed install)
448
+ vite_bin = node_modules / '.bin' / 'vite';
449
+ if node_modules.exists() and not vite_bin.exists() {
450
+ shutil.rmtree(node_modules);
451
+ }
445
452
  if not node_modules.exists() {
446
453
  # Temporarily copy package.json to client build dir for bun install
447
454
  build_package_json = build_dir / 'package.json';
@@ -455,15 +462,17 @@ impl ViteBundler.build(self: ViteBundler, entry_file: Optional[Path] = None) ->
455
462
  print("\n ⏳ Installing dependencies...\n", flush=True);
456
463
  start_time = time.time();
457
464
  result = subprocess.run(
458
- ['bun', 'install'], cwd=build_dir, check=False, text=True
465
+ ['bun', 'install'],
466
+ cwd=build_dir,
467
+ check=False,
468
+ text=True,
469
+ capture_output=True
459
470
  );
460
471
  elapsed = time.time() - start_time;
461
472
  if result.returncode != 0 {
462
- print(
463
- f"\n ✖ bun install failed after {elapsed:.1f}s",
464
- file=sys.stderr
465
- );
466
- raise ClientBundleError("Failed to install dependencies") ;
473
+ error_output = result.stderr or result.stdout;
474
+ error_msg = f"Dependency installation failed after {elapsed:.1f}s\n\n{error_output}\nCommand: bun install";
475
+ raise ClientBundleError(error_msg) from None ;
467
476
  }
468
477
  print(f"\n ✔ Dependencies installed ({elapsed:.1f}s)", flush=True);
469
478
  } except FileNotFoundError {
@@ -500,13 +509,16 @@ impl ViteBundler.build(self: ViteBundler, entry_file: Optional[Path] = None) ->
500
509
  # Run vite from client build directory so it can find node_modules
501
510
  print("\n ⏳ Building client bundle...\n", flush=True);
502
511
  start_time = time.time();
503
- result = subprocess.run(command, cwd=build_dir, check=False, text=True);
512
+ result = subprocess.run(
513
+ command, cwd=build_dir, check=False, text=True, capture_output=True
514
+ );
504
515
  elapsed = time.time() - start_time;
505
516
  if result.returncode != 0 {
506
- print(f"\n ✖ Vite build failed after {elapsed:.1f}s", file=sys.stderr);
507
- raise ClientBundleError(
508
- f"Vite build failed (see output above)\nCommand: {' '.join(command)}"
509
- ) from None ;
517
+ error_output = result.stderr or result.stdout;
518
+ error_msg = f"Vite build failed after {elapsed:.1f}s\n\n{error_output}\nCommand: {' '.join(
519
+ command
520
+ )}";
521
+ raise ClientBundleError(error_msg) from None ;
510
522
  }
511
523
  print(f"\n ✔ Client bundle built ({elapsed:.1f}s)", flush=True);
512
524
  } finally {
@@ -615,6 +627,10 @@ export default defineConfig({{
615
627
  target: "http://localhost:{api_port}",
616
628
  changeOrigin: true,
617
629
  }},
630
+ "/static": {{
631
+ target: "http://localhost:{api_port}",
632
+ changeOrigin: true,
633
+ }},
618
634
  }},
619
635
  }},
620
636
  resolve: {{
@@ -1,3 +1,4 @@
1
1
  """Utility modules for jac-client plugin."""
2
2
 
3
3
  import from .bun_installer { ensure_bun_available, prompt_install_bun }
4
+ import from .client_deps { ensure_client_deps }
@@ -0,0 +1,14 @@
1
+ """Client dependency checker utility for jac-client.
2
+
3
+ Provides a function to check if required npm dependencies are configured
4
+ and prompt the user to install defaults if missing.
5
+ """
6
+
7
+ """Check if client npm dependencies are configured, prompt to install if missing.
8
+
9
+ Takes a JacClientConfig instance, checks if dependencies and devDependencies
10
+ are both empty, and if so prompts the user to install default jac-client deps.
11
+
12
+ Returns True if deps are configured (or were just installed), False if user declined.
13
+ """
14
+ def ensure_client_deps(config_loader: object) -> bool;
@@ -0,0 +1,73 @@
1
+ """Implementation of client dependency checker utility."""
2
+
3
+ """Check if client npm dependencies are configured, prompt to install if missing."""
4
+ impl ensure_client_deps(config_loader: object) -> bool {
5
+ package_config = config_loader.get_package_config();
6
+ dependencies = package_config.get('dependencies', {});
7
+ dev_dependencies = package_config.get('devDependencies', {});
8
+ # If either deps or devDeps has entries, assume configured
9
+ if dependencies or dev_dependencies {
10
+ return True;
11
+ }
12
+ # No deps configured — prompt the user
13
+ return prompt_install_client_deps(config_loader);
14
+ }
15
+
16
+ """Prompt user to install default jac-client npm dependencies."""
17
+ def prompt_install_client_deps(config_loader: object) -> bool {
18
+ import sys;
19
+ print("\n ⚠ Client dependencies are not configured.", file=sys.stderr);
20
+ print(
21
+ " jac-client requires npm packages (react, vite, etc.) to build client pages.",
22
+ file=sys.stderr
23
+ );
24
+ print(" These will be added to your jac.toml file.\n", file=sys.stderr);
25
+ try {
26
+ response = input(" Install default client dependencies now? [Y/n]: ").strip().lower();
27
+ } except (EOFError, KeyboardInterrupt) {
28
+ print("", file=sys.stderr);
29
+ return False;
30
+ }
31
+ if response and response not in ('y', 'yes', '') {
32
+ print(
33
+ "\n To configure manually, add [dependencies.npm] to your jac.toml.",
34
+ file=sys.stderr
35
+ );
36
+ print(
37
+ " Or create a new project with: jac create --use client\n",
38
+ file=sys.stderr
39
+ );
40
+ return False;
41
+ }
42
+ # Default runtime dependencies
43
+ default_deps: dict[str, str] = {
44
+ 'react': '^18.2.0',
45
+ 'react-dom': '^18.2.0',
46
+ 'react-router-dom': '^6.22.0',
47
+ 'react-error-boundary': '^5.0.0'
48
+ };
49
+ # Default build infrastructure dependencies
50
+ default_dev_deps: dict[str, str] = {
51
+ 'vite': '^6.4.1',
52
+ '@vitejs/plugin-react': '^4.2.1',
53
+ 'typescript': '^5.3.3',
54
+ '@types/react': '^18.2.0',
55
+ '@types/react-dom': '^18.2.0'
56
+ };
57
+ print("\n ⏳ Adding default client dependencies to jac.toml...", flush=True);
58
+ try {
59
+ for (name, version) in default_deps.items() {
60
+ config_loader.add_dependency(name, version, is_dev=False);
61
+ }
62
+ for (name, version) in default_dev_deps.items() {
63
+ config_loader.add_dependency(name, version, is_dev=True);
64
+ }
65
+ config_loader.save();
66
+ config_loader.invalidate();
67
+ print(" ✔ Default client dependencies added to jac.toml\n", flush=True);
68
+ return True;
69
+ } except Exception as e {
70
+ print(f" ✖ Failed to add dependencies: {e}", file=sys.stderr);
71
+ return False;
72
+ }
73
+ }
@@ -33,10 +33,6 @@
33
33
  "assets",
34
34
  ".jac/client"
35
35
  ],
36
- "gitignore_entries": [
37
- "# Ignore all build artifacts in .jac directory",
38
- "*"
39
- ],
40
36
  "root_gitignore_entries": [
41
37
  "# Jac project",
42
38
  "packages/",
@@ -36,10 +36,6 @@
36
36
  ".jac",
37
37
  "assets"
38
38
  ],
39
- "gitignore_entries": [
40
- "# Ignore all build artifacts in .jac directory",
41
- "*"
42
- ],
43
39
  "root_gitignore_entries": [
44
40
  "# Jac build artifacts",
45
41
  ".jac/",
@@ -1,9 +1,11 @@
1
1
  """Test create-jac-app command."""
2
2
 
3
+ import contextlib
3
4
  import os
4
5
  import tempfile
5
6
  import tomllib
6
7
  from subprocess import PIPE, Popen, run
8
+ from unittest.mock import patch
7
9
 
8
10
 
9
11
  def test_create_jac_app() -> None:
@@ -920,3 +922,69 @@ def test_create_cl_and_run_no_root_files() -> None:
920
922
 
921
923
  finally:
922
924
  os.chdir(original_cwd)
925
+
926
+
927
+ def test_vite_build_prompts_for_missing_client_deps() -> None:
928
+ """Test that ViteBundler.build() prompts to install deps when jac.toml is missing.
929
+
930
+ Exercises the same code path as `jac start` → server.start() → ensure_bundle()
931
+ → ViteBundler.build(), which checks for npm deps before building.
932
+ """
933
+ import json
934
+ from pathlib import Path
935
+
936
+ from jac_client.plugin.src.vite_bundler import ViteBundler
937
+
938
+ with tempfile.TemporaryDirectory() as temp_dir:
939
+ project_dir = Path(temp_dir)
940
+ config_file = project_dir / "jac.toml"
941
+
942
+ # No jac.toml — ViteBundler.build() should prompt via ensure_client_deps
943
+ bundler = ViteBundler(project_dir)
944
+
945
+ # Mock input to accept, and mock bun/vite so we don't need real installs.
946
+ # We only care that ensure_client_deps wrote jac.toml before reaching bun.
947
+ with (
948
+ patch("builtins.input", return_value="Y"),
949
+ patch(
950
+ "jac_client.plugin.utils.bun_installer.ensure_bun_available",
951
+ return_value=True,
952
+ ),
953
+ patch("subprocess.run") as mock_subprocess,
954
+ ):
955
+ # bun install returns success, vite build returns failure
956
+ # (we don't have real vite — that's fine, we're testing the dep prompt)
957
+ mock_subprocess.side_effect = [
958
+ type("Result", (), {"returncode": 0})(), # bun install
959
+ type("Result", (), {"returncode": 1})(), # vite build
960
+ ]
961
+ with contextlib.suppress(Exception):
962
+ bundler.build() # vite build failure is expected
963
+
964
+ # The key assertion: jac.toml was created with default client deps
965
+ assert config_file.exists(), (
966
+ "jac.toml should have been created after accepting the prompt"
967
+ )
968
+
969
+ with open(config_file, "rb") as f:
970
+ data = tomllib.load(f)
971
+
972
+ npm_deps = data.get("dependencies", {}).get("npm", {})
973
+ assert "react" in npm_deps, "react should be in dependencies.npm"
974
+ assert "react-dom" in npm_deps, "react-dom should be in dependencies.npm"
975
+
976
+ npm_dev = npm_deps.get("dev", {})
977
+ assert "vite" in npm_dev, "vite should be in dev dependencies"
978
+ assert "@vitejs/plugin-react" in npm_dev, (
979
+ "@vitejs/plugin-react should be in dev deps"
980
+ )
981
+
982
+ # Verify the generated package.json also picked up the deps
983
+ package_json = project_dir / ".jac" / "client" / "configs" / "package.json"
984
+ assert package_json.exists(), "package.json should have been generated"
985
+
986
+ with open(package_json) as f:
987
+ pkg = json.load(f)
988
+
989
+ assert pkg["dependencies"].get("react"), "package.json should have react"
990
+ assert pkg["devDependencies"].get("vite"), "package.json should have vite"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jac-client
3
- Version: 0.2.11
3
+ Version: 0.2.12
4
4
  Summary: Build full-stack web applications with Jac - one language for frontend and backend.
5
5
  Author-email: Jason Mars <jason@mars.ninja>
6
6
  Maintainer-email: Jason Mars <jason@mars.ninja>
@@ -11,7 +11,7 @@ Project-URL: Documentation, https://jac-lang.org
11
11
  Keywords: jac,jaclang,jaseci,frontend,full-stack,web-development
12
12
  Requires-Python: >=3.12
13
13
  Description-Content-Type: text/markdown
14
- Requires-Dist: jaclang>=0.9.11
14
+ Requires-Dist: jaclang>=0.9.12
15
15
  Provides-Extra: dev
16
16
  Requires-Dist: python-dotenv==1.0.1; extra == "dev"
17
17
  Requires-Dist: pytest==8.3.5; extra == "dev"
@@ -94,7 +94,9 @@ jac_client/plugin/src/targets/impl/registry.impl.jac
94
94
  jac_client/plugin/src/targets/impl/web_target.impl.jac
95
95
  jac_client/plugin/utils/__init__.jac
96
96
  jac_client/plugin/utils/bun_installer.jac
97
+ jac_client/plugin/utils/client_deps.jac
97
98
  jac_client/plugin/utils/impl/bun_installer.impl.jac
99
+ jac_client/plugin/utils/impl/client_deps.impl.jac
98
100
  jac_client/templates/client.jacpack
99
101
  jac_client/templates/fullstack.jacpack
100
102
  jac_client/tests/__init__.py
@@ -1,4 +1,4 @@
1
- jaclang>=0.9.11
1
+ jaclang>=0.9.12
2
2
 
3
3
  [dev]
4
4
  python-dotenv==1.0.1
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "jac-client"
3
- version = "0.2.11"
3
+ version = "0.2.12"
4
4
  description = "Build full-stack web applications with Jac - one language for frontend and backend."
5
5
  authors = [{name = "Jason Mars", email = "jason@mars.ninja"}]
6
6
  maintainers = [{name = "Jason Mars", email = "jason@mars.ninja"}]
@@ -16,7 +16,7 @@ keywords = [
16
16
  ]
17
17
  requires-python = ">=3.12"
18
18
  dependencies = [
19
- "jaclang>=0.9.11",
19
+ "jaclang>=0.9.12",
20
20
  ]
21
21
 
22
22
  [project.urls]
File without changes
File without changes