jac-client 0.2.7__tar.gz → 0.2.8__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 (102) hide show
  1. {jac_client-0.2.7 → jac_client-0.2.8}/PKG-INFO +2 -2
  2. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/cli.jac +5 -0
  3. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/client.jac +8 -15
  4. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/client_runtime.cl.jac +14 -14
  5. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/impl/client.impl.jac +11 -14
  6. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/impl/client_runtime.impl.jac +27 -9
  7. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/src/impl/compiler.impl.jac +2 -4
  8. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/src/impl/vite_bundler.impl.jac +152 -3
  9. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/src/vite_bundler.jac +8 -1
  10. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/tests/test_cli.py +6 -4
  11. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/tests/test_it.py +7 -3
  12. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client.egg-info/PKG-INFO +2 -2
  13. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client.egg-info/SOURCES.txt +26 -26
  14. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client.egg-info/requires.txt +1 -1
  15. {jac_client-0.2.7 → jac_client-0.2.8}/pyproject.toml +2 -2
  16. {jac_client-0.2.7 → jac_client-0.2.8}/README.md +0 -0
  17. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/app.jac +0 -0
  18. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/all-in-one/assets/workers/worker.py +0 -0
  19. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/button.jac +0 -0
  20. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/components/CategoryFilter.jac +0 -0
  21. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/components/Header.jac +0 -0
  22. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/components/ProfitOverview.jac +0 -0
  23. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/components/Summary.jac +0 -0
  24. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/components/TransactionForm.jac +0 -0
  25. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/components/TransactionItem.jac +0 -0
  26. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/components/TransactionList.jac +0 -0
  27. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/components/button.jac +0 -0
  28. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/components/navigation.jac +0 -0
  29. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/constants/categories.jac +0 -0
  30. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/constants/clients.jac +0 -0
  31. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/context/BudgetContext.jac +0 -0
  32. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/hooks/useBudget.jac +0 -0
  33. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/hooks/useLocalStorage.jac +0 -0
  34. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/pages/BudgetPlanner.cl.jac +0 -0
  35. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/pages/BudgetPlanner.jac +0 -0
  36. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/pages/FeaturesTest.cl.jac +0 -0
  37. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/pages/FeaturesTest.jac +0 -0
  38. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/pages/LandingPage.jac +0 -0
  39. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/pages/loginPage.jac +0 -0
  40. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/pages/nestedDemo.jac +0 -0
  41. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/pages/notFound.jac +0 -0
  42. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/pages/signupPage.jac +0 -0
  43. {jac_client-0.2.7/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/utils/formatters.jac +0 -0
  44. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/asset-serving/css-with-image/src/app.jac +0 -0
  45. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/asset-serving/image-asset/src/app.jac +0 -0
  46. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/asset-serving/import-alias/src/app.jac +0 -0
  47. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/basic/src/app.jac +0 -0
  48. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/basic-auth/src/app.jac +0 -0
  49. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/basic-auth-with-router/src/app.jac +0 -0
  50. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/basic-full-stack/src/app.jac +0 -0
  51. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/css-styling/js-styling/src/app.jac +0 -0
  52. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/css-styling/material-ui/src/app.jac +0 -0
  53. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/css-styling/pure-css/src/app.jac +0 -0
  54. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/css-styling/sass-example/src/app.jac +0 -0
  55. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/css-styling/styled-components/src/app.jac +0 -0
  56. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/css-styling/tailwind-example/src/app.jac +0 -0
  57. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/full-stack-with-auth/src/app.jac +0 -0
  58. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/little-x/src/app.jac +0 -0
  59. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/little-x/src/submit-button.jac +0 -0
  60. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/nested-folders/nested-advance/src/ButtonRoot.jac +0 -0
  61. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/nested-folders/nested-advance/src/app.jac +0 -0
  62. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/nested-folders/nested-advance/src/level1/ButtonSecondL.jac +0 -0
  63. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/nested-folders/nested-advance/src/level1/Card.jac +0 -0
  64. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/nested-folders/nested-advance/src/level1/level2/ButtonThirdL.jac +0 -0
  65. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/nested-folders/nested-basic/src/app.jac +0 -0
  66. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/nested-folders/nested-basic/src/button.jac +0 -0
  67. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/nested-folders/nested-basic/src/components/button.jac +0 -0
  68. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/ts-support/src/app.jac +0 -0
  69. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/examples/with-router/src/app.jac +0 -0
  70. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/impl/vite_client_bundle.impl.jac +0 -0
  71. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/plugin_config.jac +0 -0
  72. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/src/__init__.jac +0 -0
  73. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/src/asset_processor.jac +0 -0
  74. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/src/babel_processor.jac +0 -0
  75. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/src/compiler.jac +0 -0
  76. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/src/config_loader.jac +0 -0
  77. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/src/impl/asset_processor.impl.jac +0 -0
  78. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/src/impl/babel_processor.impl.jac +0 -0
  79. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/src/impl/config_loader.impl.jac +0 -0
  80. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/src/impl/import_processor.impl.jac +0 -0
  81. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/src/impl/jac_to_js.impl.jac +0 -0
  82. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/src/impl/package_installer.impl.jac +0 -0
  83. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/src/import_processor.jac +0 -0
  84. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/src/jac_to_js.jac +0 -0
  85. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/src/package_installer.jac +0 -0
  86. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/plugin/vite_client_bundle.jac +0 -0
  87. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/tests/__init__.py +0 -0
  88. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/tests/conftest.py +0 -0
  89. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/tests/fixtures/basic-app/app.jac +0 -0
  90. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/tests/fixtures/cl_file/app.cl.jac +0 -0
  91. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/tests/fixtures/cl_file/app.jac +0 -0
  92. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/tests/fixtures/client_app_with_antd/app.jac +0 -0
  93. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/tests/fixtures/js_import/app.jac +0 -0
  94. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/tests/fixtures/relative_import/app.jac +0 -0
  95. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/tests/fixtures/relative_import/button.jac +0 -0
  96. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/tests/fixtures/spawn_test/app.jac +0 -0
  97. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/tests/fixtures/test_fragments_spread/app.jac +0 -0
  98. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client/tests/fixtures/with-ts/app.jac +0 -0
  99. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client.egg-info/dependency_links.txt +0 -0
  100. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client.egg-info/entry_points.txt +0 -0
  101. {jac_client-0.2.7 → jac_client-0.2.8}/jac_client.egg-info/top_level.txt +0 -0
  102. {jac_client-0.2.7 → jac_client-0.2.8}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jac-client
3
- Version: 0.2.7
3
+ Version: 0.2.8
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.7
14
+ Requires-Dist: jaclang==0.9.8
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"
@@ -151,12 +151,17 @@ version = "1.0.0"
151
151
  description = "Jac client application: {project_name}"
152
152
  entry-point = "main.jac"
153
153
 
154
+ [dependencies]
155
+
154
156
  [dependencies.npm]
155
157
  "jac-client-node" = "1.0.3"
156
158
 
157
159
  [dependencies.npm.dev]
158
160
  "@jac-client/dev-deps" = "1.0.0"
159
161
 
162
+ [dev-dependencies]
163
+ watchdog = ">=3.0.0"
164
+
160
165
  [serve]
161
166
  base_route_app = "app"
162
167
 
@@ -18,16 +18,6 @@ glob JsonValue: TypeAlias = None | str | int | float | bool | list['JsonValue']
18
18
  ],
19
19
  StatusCode: TypeAlias = Literal[(200, 201, 400, 401, 404, 503)];
20
20
 
21
- """Jac Client Module Introspector."""
22
- class JacClientModuleIntrospector(ModuleIntrospector) {
23
- def render_page(
24
- self: JacClientModuleIntrospector,
25
- function_name: str,
26
- args: dict[(str, Any)],
27
- username: str
28
- ) -> dict[str, Any];
29
- }
30
-
31
21
  """Jac Client."""
32
22
  class JacClient {
33
23
  @hookimpl
@@ -38,15 +28,18 @@ class JacClient {
38
28
  module: types.ModuleType, force: bool = False
39
29
  ) -> ClientBundle;
40
30
 
41
- @hookimpl
42
- static def get_module_introspector(
43
- module_name: str, base_path: (str | None)
44
- ) -> ModuleIntrospector;
45
-
46
31
  @hookimpl
47
32
  static def send_static_file(
48
33
  handler: BaseHTTPRequestHandler,
49
34
  file_path: Path,
50
35
  content_type: (str | None) = None
51
36
  ) -> None;
37
+
38
+ @hookimpl
39
+ static def render_page(
40
+ introspector: ModuleIntrospector,
41
+ function_name: str,
42
+ args: dict[(str, Any)],
43
+ username: str
44
+ ) -> dict[str, Any];
52
45
  }
@@ -14,10 +14,10 @@ import from 'react-router-dom' {
14
14
  useParams as reactRouterUseParams
15
15
  }
16
16
 
17
- def : pub __jacJsx(tag: any, props: dict = {}, children: any = []) -> any;
17
+ def:pub __jacJsx(tag: any, props: dict = {}, children: any = []) -> any;
18
18
 
19
19
  # React hooks re-exported for auto-injection by `has` variables
20
- glob : pub useState = reactUseState,
20
+ glob:pub useState = reactUseState,
21
21
  Router = ReactRouterHashRouter,
22
22
  Routes = ReactRouterRoutes,
23
23
  Route = ReactRouterRoute,
@@ -27,16 +27,16 @@ glob : pub useState = reactUseState,
27
27
  useLocation = reactRouterUseLocation,
28
28
  useParams = reactRouterUseParams;
29
29
 
30
- def : pub useRouter -> dict;
31
- def : pub navigate(path: str) -> None;
32
- async def : pub __jacSpawn(left: str, right: str = "", fields: dict = {}) -> any;
33
- def : pub jacSpawn(left: str, right: str = "", fields: dict = {}) -> any;
34
- async def : pub __jacCallFunction(function_name: str, args: dict = {}) -> any;
35
- async def : pub jacSignup(username: str, password: str) -> dict;
36
- async def : pub jacLogin(username: str, password: str) -> bool;
37
- def : pub jacLogout -> None;
38
- def : pub jacIsLoggedIn -> bool;
39
- def : pub __getLocalStorage(key: str) -> str;
40
- def : pub __setLocalStorage(key: str, value: str) -> None;
41
- def : pub __removeLocalStorage(key: str) -> None;
30
+ def:pub useRouter -> dict;
31
+ def:pub navigate(path: str) -> None;
32
+ async def:pub __jacSpawn(left: str, right: str = "", fields: dict = {}) -> any;
33
+ def:pub jacSpawn(left: str, right: str = "", fields: dict = {}) -> any;
34
+ async def:pub __jacCallFunction(function_name: str, args: dict = {}) -> any;
35
+ async def:pub jacSignup(username: str, password: str) -> dict;
36
+ async def:pub jacLogin(username: str, password: str) -> bool;
37
+ def:pub jacLogout -> None;
38
+ def:pub jacIsLoggedIn -> bool;
39
+ def:pub __getLocalStorage(key: str) -> str;
40
+ def:pub __setLocalStorage(key: str, value: str) -> None;
41
+ def:pub __removeLocalStorage(key: str) -> None;
42
42
  # React Router components
@@ -30,13 +30,6 @@ impl JacClient.send_static_file(
30
30
  }
31
31
  }
32
32
 
33
- """Get a module introspector for the supplied module."""
34
- impl JacClient.get_module_introspector(
35
- module_name: str, base_path: (str | None)
36
- ) -> ModuleIntrospector {
37
- return JacClientModuleIntrospector(module_name, base_path);
38
- }
39
-
40
33
  """Build a client bundle for the supplied module."""
41
34
  impl JacClient.build_client_bundle(
42
35
  module: types.ModuleType, force: bool = False
@@ -92,21 +85,21 @@ impl JacClient.get_client_bundle_builder -> ViteClientBundleBuilder {
92
85
  }
93
86
 
94
87
  """Render HTML page for client function using the Vite bundle."""
95
- impl JacClientModuleIntrospector.render_page(
96
- self: JacClientModuleIntrospector,
88
+ impl JacClient.render_page(
89
+ introspector: ModuleIntrospector,
97
90
  function_name: str,
98
91
  args: dict[(str, Any)],
99
92
  username: str
100
93
  ) -> dict[str, Any] {
101
- self.load();
94
+ introspector.load();
102
95
  available_exports = (
103
- set(self._client_manifest.get('exports', []))
104
- or set(self.get_client_functions().keys())
96
+ set(introspector._client_manifest.get('exports', []))
97
+ or set(introspector.get_client_functions().keys())
105
98
  );
106
99
  if (function_name not in available_exports) {
107
100
  raise ValueError(f"Client function '{function_name}' not found") ;
108
101
  }
109
- bundle_hash = self.ensure_bundle();
102
+ bundle_hash = introspector.ensure_bundle();
110
103
  import from jaclang.project.config { find_project_root, get_config }
111
104
  # Find project root by looking for jac.toml (base_path_dir might be src/ for entry files)
112
105
  base_path_dir = Path(Jac.base_path_dir);
@@ -192,5 +185,9 @@ impl JacClientModuleIntrospector.render_page(
192
185
  head_content += f"\n {css_link}";
193
186
  }
194
187
  page = f'<!DOCTYPE html><html lang="en"><head>{head_content}</head><body><div id="root"></div><script src="/static/client.js?hash={bundle_hash}" defer></script></body></html>';
195
- return {'html': page, 'bundle_hash': bundle_hash, 'bundle_code': self._bundle.code};
188
+ return {
189
+ 'html': page,
190
+ 'bundle_hash': bundle_hash,
191
+ 'bundle_code': introspector._bundle.code
192
+ };
196
193
  }
@@ -65,9 +65,11 @@ impl __jacSpawn(left: str, right: str = "", fields: dict = {}) -> any {
65
65
  );
66
66
  if not response.ok {
67
67
  error_text = await response.json();
68
- raise Exception(f"Walker {walker} failed: {error_text}") ;
68
+ walker_name = f"{left}/{right}" if right else left;
69
+ raise Exception(f"Walker {walker_name} failed: {error_text}") ;
69
70
  }
70
- return await response.json();
71
+ payload = await response.json();
72
+ return payload["data"] if payload["data"] else {};
71
73
  }
72
74
 
73
75
  impl jacSpawn(left: str, right: str = "", fields: dict = {}) -> any {
@@ -87,12 +89,18 @@ impl __jacCallFunction(function_name: str, args: dict = {}) -> any {
87
89
  "body": JSON.stringify({"args": args})
88
90
  }
89
91
  );
90
- if not response.ok {
91
- error_text = await response.text();
92
- raise Exception(f"Function {function_name} failed: {error_text}") ;
92
+ payload = await response.json();
93
+ if not payload["ok"] {
94
+ error_msg = payload["error"] if payload["error"] else "Unknown error";
95
+ raise Exception(f"Function {function_name} failed: {error_msg}") ;
93
96
  }
94
- data = JSON.parse(await response.text());
95
- return data["result"];
97
+ result = None;
98
+ try {
99
+ if payload["data"] and payload["data"]["result"] {
100
+ result = payload["data"]["result"];
101
+ }
102
+ } except Exception { }
103
+ return result;
96
104
  }
97
105
 
98
106
  impl jacSignup(username: str, password: str) -> dict {
@@ -106,7 +114,10 @@ impl jacSignup(username: str, password: str) -> dict {
106
114
  );
107
115
  if response.ok {
108
116
  data = JSON.parse(await response.text());
109
- token = data["token"];
117
+ token = None;
118
+ if data["data"] and data["data"]["token"] {
119
+ token = data["data"]["token"];
120
+ }
110
121
  if token {
111
122
  __setLocalStorage("jac_token", token);
112
123
  return {"success": True, "token": token, "username": username};
@@ -139,7 +150,14 @@ impl jacLogin(username: str, password: str) -> bool {
139
150
  );
140
151
  if response.ok {
141
152
  data = JSON.parse(await response.text());
142
- token = data["token"];
153
+ console.log("data", data);
154
+ token = None;
155
+ try {
156
+ if data["data"] and data["data"]["token"] {
157
+ token = data["data"]["token"];
158
+ }
159
+ } except Exception { }
160
+ console.log("token", token);
143
161
  if token {
144
162
  __setLocalStorage("jac_token", token);
145
163
  return True;
@@ -7,9 +7,7 @@ impl ViteCompiler._get_client_dir(self: ViteCompiler) -> Path {
7
7
  if config is not None {
8
8
  return config.get_client_dir();
9
9
  }
10
- } except ImportError {
11
- pass;
12
- }
10
+ } except ImportError { }
13
11
  # Fallback to default
14
12
  return self.project_dir / '.jac' / 'client';
15
13
  }
@@ -51,7 +49,7 @@ impl ViteCompiler.create_entry_file(self: ViteCompiler, module_path: Path) -> No
51
49
  entry_file = self.compiled_dir / '_entry.js';
52
50
  # Derive the app module filename from the entry point (e.g., main.jac -> main.js, app.jac -> app.js)
53
51
  app_module_name = module_path.stem;
54
- entry_content = f'import React from "react";\nimport {{ createRoot }} from "react-dom/client";\nimport {{ app as App }} from "./{app_module_name}.js";\n\nconst root = createRoot(document.getElementById("root"));\nroot.render(<App />);\n';
52
+ entry_content = f'import React from "react";\nimport {{ createRoot }} from "react-dom/client";\nimport {{ app as App }} from "./{app_module_name}.js";\n\nconst root = createRoot(document.getElementById("root"));\nroot.render(React.createElement(App, null));\n';
55
53
  entry_file.write_text(entry_content, encoding='utf-8');
56
54
  }
57
55
 
@@ -7,9 +7,7 @@ impl ViteBundler._get_client_dir(self: ViteBundler) -> Path {
7
7
  if config is not None {
8
8
  return config.get_client_dir();
9
9
  }
10
- } except ImportError {
11
- pass;
12
- }
10
+ } except ImportError { }
13
11
  # Fallback to default
14
12
  return self.project_dir / '.jac' / 'client';
15
13
  }
@@ -475,3 +473,154 @@ impl ViteBundler.init(
475
473
  # Set output_dir after config_loader is initialized so _get_client_dir works
476
474
  self.output_dir = output_dir or (self._get_client_dir() / 'dist');
477
475
  }
476
+
477
+ """Create a dev-mode vite config with API proxy for HMR."""
478
+ impl ViteBundler.create_dev_vite_config(
479
+ self: ViteBundler, entry_file: Path, api_port: int = 8000
480
+ ) -> Path {
481
+ build_dir = self._get_client_dir();
482
+ build_dir.mkdir(parents=True, exist_ok=True);
483
+ configs_dir = build_dir / 'configs';
484
+ configs_dir.mkdir(exist_ok=True);
485
+ config_path = configs_dir / 'vite.dev.config.js';
486
+ # Get entry file relative path
487
+ try {
488
+ entry_relative = entry_file.relative_to(build_dir).as_posix();
489
+ } except ValueError {
490
+ entry_relative = entry_file.as_posix();
491
+ }
492
+ # Calculate paths for aliases
493
+ if entry_relative.endswith('/build/main.js') {
494
+ compiled_utils_relative = entry_relative[:-13] + '/compiled/client_runtime.js';
495
+ compiled_assets_relative = entry_relative[:-13] + '/compiled/assets';
496
+ } elif entry_relative.endswith('build/main.js') {
497
+ compiled_utils_relative = 'compiled/client_runtime.js';
498
+ compiled_assets_relative = 'compiled/assets';
499
+ } else {
500
+ compiled_utils_relative = 'compiled/client_runtime.js';
501
+ compiled_assets_relative = 'compiled/assets';
502
+ }
503
+ # Extensions for TypeScript
504
+ extensions = ['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json'];
505
+ extensions_str = ', '.join(f'"{ext}"' for ext in extensions);
506
+ # Generate dev config with proxy for API routes
507
+ config_content = f'''import {{ defineConfig }} from "vite";
508
+ import path from "path";
509
+ import {{ fileURLToPath }} from "url";
510
+ import react from "@vitejs/plugin-react";
511
+
512
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
513
+ const buildDir = path.resolve(__dirname, "..");
514
+ const projectRoot = path.resolve(__dirname, "../../..");
515
+
516
+ /**
517
+ * Vite DEV configuration for HMR mode
518
+ * Proxies API routes to Python server at localhost:{api_port}
519
+ */
520
+ export default defineConfig({{
521
+ plugins: [react()],
522
+ root: buildDir,
523
+ publicDir: false,
524
+ server: {{
525
+ watch: {{
526
+ usePolling: true,
527
+ interval: 100,
528
+ }},
529
+ proxy: {{
530
+ "/walker": {{
531
+ target: "http://localhost:{api_port}",
532
+ changeOrigin: true,
533
+ }},
534
+ "/function": {{
535
+ target: "http://localhost:{api_port}",
536
+ changeOrigin: true,
537
+ }},
538
+ "/user": {{
539
+ target: "http://localhost:{api_port}",
540
+ changeOrigin: true,
541
+ }},
542
+ "/introspect": {{
543
+ target: "http://localhost:{api_port}",
544
+ changeOrigin: true,
545
+ }},
546
+ }},
547
+ }},
548
+ resolve: {{
549
+ alias: {{
550
+ "@jac-client/utils": path.resolve(buildDir, "{compiled_utils_relative}"),
551
+ "@jac-client/assets": path.resolve(buildDir, "{compiled_assets_relative}"),
552
+ }},
553
+ extensions: [{extensions_str}],
554
+ }},
555
+ }});
556
+ ''';
557
+ config_path.write_text(config_content, encoding='utf-8');
558
+ return config_path;
559
+ }
560
+
561
+ """Start Vite dev server as a subprocess."""
562
+ impl ViteBundler.start_dev_server(self: ViteBundler, port: int = 3000) -> Any {
563
+ build_dir = self._get_client_dir();
564
+ node_modules = build_dir / 'node_modules';
565
+ # Create/update index.html for dev server (load from compiled/ for HMR)
566
+ index_html = build_dir / 'index.html';
567
+ index_content = '''<!DOCTYPE html>
568
+ <html lang="en">
569
+ <head>
570
+ <meta charset="UTF-8" />
571
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
572
+ <title>Jac App (Dev)</title>
573
+ </head>
574
+ <body>
575
+ <div id="root"></div>
576
+ <script type="module" src="/compiled/_entry.js"></script>
577
+ </body>
578
+ </html>
579
+ ''';
580
+ index_html.write_text(index_content, encoding='utf-8');
581
+ # Ensure dependencies are installed
582
+ if not node_modules.exists() {
583
+ generated_package_json = build_dir / 'configs' / 'package.json';
584
+ if not generated_package_json.exists() {
585
+ self.create_package_json();
586
+ }
587
+ # Temporarily copy package.json for npm install
588
+ build_package_json = build_dir / 'package.json';
589
+ if not build_package_json.exists() {
590
+ shutil.copy2(generated_package_json, build_package_json);
591
+ }
592
+ try {
593
+ print("[Vite] Installing dependencies...");
594
+ subprocess.run(
595
+ ['npm', 'install'],
596
+ cwd=build_dir,
597
+ check=True,
598
+ capture_output=True,
599
+ text=True
600
+ );
601
+ } except subprocess.CalledProcessError as e {
602
+ print(f"[Vite] Error installing dependencies: {e.stderr}");
603
+ raise ;
604
+ } finally {
605
+ # Clean up temp package.json
606
+ if build_package_json.exists() {
607
+ build_package_json.unlink();
608
+ }
609
+ }
610
+ }
611
+ # Find the dev config
612
+ dev_config = build_dir / 'configs' / 'vite.dev.config.js';
613
+ if not dev_config.exists() {
614
+ raise ClientBundleError(
615
+ "Dev config not found. Call create_dev_vite_config first."
616
+ ) ;
617
+ }
618
+ config_rel = dev_config.relative_to(build_dir);
619
+ print(f"[Vite] Starting dev server on port {port}...");
620
+ # Start Vite in dev mode (let output go to terminal for HMR visibility)
621
+ process = subprocess.Popen(
622
+ ['npx', 'vite', '--config', str(config_rel), '--port', str(port)],
623
+ cwd=build_dir
624
+ );
625
+ return process;
626
+ }
@@ -4,7 +4,7 @@ import json;
4
4
  import shutil;
5
5
  import subprocess;
6
6
  import from pathlib { Path }
7
- import from typing { Optional }
7
+ import from typing { Any, Optional }
8
8
  import from jaclang.runtimelib.client_bundle { ClientBundleError }
9
9
  import from .config_loader { JacClientConfig }
10
10
  """Handles Vite bundling operations."""
@@ -34,4 +34,11 @@ class ViteBundler {
34
34
  ) -> Path;
35
35
 
36
36
  def create_tsconfig(self: ViteBundler) -> Path;
37
+ """Create a dev-mode vite config with API proxy for HMR."""
38
+ def create_dev_vite_config(
39
+ self: ViteBundler, entry_file: Path, api_port: int = 8000
40
+ ) -> Path;
41
+
42
+ """Start Vite dev server as a subprocess."""
43
+ def start_dev_server(self: ViteBundler, port: int = 3000) -> Any;
37
44
  }
@@ -423,7 +423,7 @@ entry-point = "app.jac"
423
423
 
424
424
 
425
425
  def test_install_without_cl_flag() -> None:
426
- """Test add command without --cl flag should fail when no jac.toml exists."""
426
+ """Test add command without --cl flag should skip silently when no jac.toml exists."""
427
427
  with tempfile.TemporaryDirectory() as temp_dir:
428
428
  original_cwd = os.getcwd()
429
429
  try:
@@ -436,9 +436,11 @@ def test_install_without_cl_flag() -> None:
436
436
  text=True,
437
437
  )
438
438
 
439
- # Should fail with non-zero exit code because no jac.toml
440
- assert result.returncode != 0
441
- assert "No jac.toml found" in result.stderr
439
+ # Should skip silently (return 0) when no jac.toml exists
440
+ assert result.returncode == 0
441
+ # No error message should be printed
442
+ assert "No jac.toml found" not in result.stderr
443
+ assert "No jac.toml found" not in result.stdout
442
444
 
443
445
  finally:
444
446
  os.chdir(original_cwd)
@@ -240,7 +240,7 @@ def test_all_in_one_app_endpoints() -> None:
240
240
  f"STDERR:\n{jac_add_result.stderr}\n"
241
241
  )
242
242
 
243
- app_jac_path = os.path.join(project_path, "src", "app.jac")
243
+ app_jac_path = os.path.join(project_path, "app.jac")
244
244
  assert os.path.isfile(app_jac_path), "all-in-one src/app.jac file missing"
245
245
 
246
246
  # 4. Start the server: `jac start src/app.jac`
@@ -462,7 +462,9 @@ def test_all_in_one_app_endpoints() -> None:
462
462
  f"Body (truncated to 500 chars):\n{register_body[:500]}"
463
463
  )
464
464
  assert resp_register.status == 201
465
- register_data = json.loads(register_body)
465
+ register_response = json.loads(register_body)
466
+ # Handle new TransportResponse envelope format
467
+ register_data = register_response.get("data", register_response)
466
468
  assert "username" in register_data
467
469
  assert "token" in register_data
468
470
  assert "root_id" in register_data
@@ -499,7 +501,9 @@ def test_all_in_one_app_endpoints() -> None:
499
501
  f"Body (truncated to 500 chars):\n{login_body[:500]}"
500
502
  )
501
503
  assert resp_login.status == 200
502
- login_data = json.loads(login_body)
504
+ login_response = json.loads(login_body)
505
+ # Handle new TransportResponse envelope format
506
+ login_data = login_response.get("data", login_response)
503
507
  assert "token" in login_data
504
508
  assert len(login_data["token"]) > 0
505
509
  print(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jac-client
3
- Version: 0.2.7
3
+ Version: 0.2.8
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.7
14
+ Requires-Dist: jaclang==0.9.8
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"
@@ -6,33 +6,33 @@ jac_client.egg-info/dependency_links.txt
6
6
  jac_client.egg-info/entry_points.txt
7
7
  jac_client.egg-info/requires.txt
8
8
  jac_client.egg-info/top_level.txt
9
+ jac_client/examples/all-in-one/app.jac
10
+ jac_client/examples/all-in-one/button.jac
9
11
  jac_client/examples/all-in-one/assets/workers/worker.py
10
- jac_client/examples/all-in-one/src/app.jac
11
- jac_client/examples/all-in-one/src/button.jac
12
- jac_client/examples/all-in-one/src/components/CategoryFilter.jac
13
- jac_client/examples/all-in-one/src/components/Header.jac
14
- jac_client/examples/all-in-one/src/components/ProfitOverview.jac
15
- jac_client/examples/all-in-one/src/components/Summary.jac
16
- jac_client/examples/all-in-one/src/components/TransactionForm.jac
17
- jac_client/examples/all-in-one/src/components/TransactionItem.jac
18
- jac_client/examples/all-in-one/src/components/TransactionList.jac
19
- jac_client/examples/all-in-one/src/components/button.jac
20
- jac_client/examples/all-in-one/src/components/navigation.jac
21
- jac_client/examples/all-in-one/src/constants/categories.jac
22
- jac_client/examples/all-in-one/src/constants/clients.jac
23
- jac_client/examples/all-in-one/src/context/BudgetContext.jac
24
- jac_client/examples/all-in-one/src/hooks/useBudget.jac
25
- jac_client/examples/all-in-one/src/hooks/useLocalStorage.jac
26
- jac_client/examples/all-in-one/src/pages/BudgetPlanner.cl.jac
27
- jac_client/examples/all-in-one/src/pages/BudgetPlanner.jac
28
- jac_client/examples/all-in-one/src/pages/FeaturesTest.cl.jac
29
- jac_client/examples/all-in-one/src/pages/FeaturesTest.jac
30
- jac_client/examples/all-in-one/src/pages/LandingPage.jac
31
- jac_client/examples/all-in-one/src/pages/loginPage.jac
32
- jac_client/examples/all-in-one/src/pages/nestedDemo.jac
33
- jac_client/examples/all-in-one/src/pages/notFound.jac
34
- jac_client/examples/all-in-one/src/pages/signupPage.jac
35
- jac_client/examples/all-in-one/src/utils/formatters.jac
12
+ jac_client/examples/all-in-one/components/CategoryFilter.jac
13
+ jac_client/examples/all-in-one/components/Header.jac
14
+ jac_client/examples/all-in-one/components/ProfitOverview.jac
15
+ jac_client/examples/all-in-one/components/Summary.jac
16
+ jac_client/examples/all-in-one/components/TransactionForm.jac
17
+ jac_client/examples/all-in-one/components/TransactionItem.jac
18
+ jac_client/examples/all-in-one/components/TransactionList.jac
19
+ jac_client/examples/all-in-one/components/button.jac
20
+ jac_client/examples/all-in-one/components/navigation.jac
21
+ jac_client/examples/all-in-one/constants/categories.jac
22
+ jac_client/examples/all-in-one/constants/clients.jac
23
+ jac_client/examples/all-in-one/context/BudgetContext.jac
24
+ jac_client/examples/all-in-one/hooks/useBudget.jac
25
+ jac_client/examples/all-in-one/hooks/useLocalStorage.jac
26
+ jac_client/examples/all-in-one/pages/BudgetPlanner.cl.jac
27
+ jac_client/examples/all-in-one/pages/BudgetPlanner.jac
28
+ jac_client/examples/all-in-one/pages/FeaturesTest.cl.jac
29
+ jac_client/examples/all-in-one/pages/FeaturesTest.jac
30
+ jac_client/examples/all-in-one/pages/LandingPage.jac
31
+ jac_client/examples/all-in-one/pages/loginPage.jac
32
+ jac_client/examples/all-in-one/pages/nestedDemo.jac
33
+ jac_client/examples/all-in-one/pages/notFound.jac
34
+ jac_client/examples/all-in-one/pages/signupPage.jac
35
+ jac_client/examples/all-in-one/utils/formatters.jac
36
36
  jac_client/examples/asset-serving/css-with-image/src/app.jac
37
37
  jac_client/examples/asset-serving/image-asset/src/app.jac
38
38
  jac_client/examples/asset-serving/import-alias/src/app.jac
@@ -1,4 +1,4 @@
1
- jaclang==0.9.7
1
+ jaclang==0.9.8
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.7"
3
+ version = "0.2.8"
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.7",
19
+ "jaclang==0.9.8",
20
20
  ]
21
21
 
22
22
  [project.urls]
File without changes
File without changes