jac-client 0.2.7__py3-none-any.whl → 0.2.9__py3-none-any.whl

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 (72) hide show
  1. jac_client/examples/all-in-one/{src/app.jac → main.jac} +5 -5
  2. jac_client/examples/all-in-one/{src/pages → pages}/BudgetPlanner.jac +8 -1
  3. jac_client/examples/all-in-one/{src/pages → pages}/FeaturesTest.jac +16 -1
  4. jac_client/examples/all-in-one/{src/pages/FeaturesTest.cl.jac → pages/features_test_ui.cl.jac} +11 -0
  5. jac_client/examples/all-in-one/{src/pages → pages}/nestedDemo.jac +1 -1
  6. jac_client/examples/all-in-one/{src/pages → pages}/notFound.jac +2 -7
  7. jac_client/plugin/cli.jac +162 -430
  8. jac_client/plugin/client.jac +30 -12
  9. jac_client/plugin/client_runtime.cl.jac +19 -15
  10. jac_client/plugin/impl/client.impl.jac +107 -69
  11. jac_client/plugin/impl/client_runtime.impl.jac +181 -9
  12. jac_client/plugin/plugin_config.jac +243 -15
  13. jac_client/plugin/src/config_loader.jac +1 -0
  14. jac_client/plugin/src/impl/compiler.impl.jac +2 -4
  15. jac_client/plugin/src/impl/config_loader.impl.jac +8 -0
  16. jac_client/plugin/src/impl/vite_bundler.impl.jac +241 -11
  17. jac_client/plugin/src/vite_bundler.jac +14 -1
  18. jac_client/plugin/utils/__init__.jac +1 -0
  19. jac_client/plugin/utils/impl/node_installer.impl.jac +249 -0
  20. jac_client/plugin/utils/node_installer.jac +41 -0
  21. jac_client/templates/client.jacpack +72 -0
  22. jac_client/templates/fullstack.jacpack +61 -0
  23. jac_client/tests/conftest.py +48 -7
  24. jac_client/tests/test_cli.py +189 -73
  25. jac_client/tests/test_e2e.py +232 -0
  26. jac_client/tests/test_helpers.py +65 -0
  27. jac_client/tests/test_it.py +97 -137
  28. {jac_client-0.2.7.dist-info → jac_client-0.2.9.dist-info}/METADATA +4 -4
  29. jac_client-0.2.9.dist-info/RECORD +104 -0
  30. {jac_client-0.2.7.dist-info → jac_client-0.2.9.dist-info}/WHEEL +1 -1
  31. jac_client-0.2.7.dist-info/RECORD +0 -97
  32. /jac_client/examples/all-in-one/{src/button.jac → button.jac} +0 -0
  33. /jac_client/examples/all-in-one/{src/components → components}/CategoryFilter.jac +0 -0
  34. /jac_client/examples/all-in-one/{src/components → components}/Header.jac +0 -0
  35. /jac_client/examples/all-in-one/{src/components → components}/ProfitOverview.jac +0 -0
  36. /jac_client/examples/all-in-one/{src/components → components}/Summary.jac +0 -0
  37. /jac_client/examples/all-in-one/{src/components → components}/TransactionForm.jac +0 -0
  38. /jac_client/examples/all-in-one/{src/components → components}/TransactionItem.jac +0 -0
  39. /jac_client/examples/all-in-one/{src/components → components}/TransactionList.jac +0 -0
  40. /jac_client/examples/all-in-one/{src/components → components}/button.jac +0 -0
  41. /jac_client/examples/all-in-one/{src/components → components}/navigation.jac +0 -0
  42. /jac_client/examples/all-in-one/{src/constants → constants}/categories.jac +0 -0
  43. /jac_client/examples/all-in-one/{src/constants → constants}/clients.jac +0 -0
  44. /jac_client/examples/all-in-one/{src/context → context}/BudgetContext.jac +0 -0
  45. /jac_client/examples/all-in-one/{src/hooks → hooks}/useBudget.jac +0 -0
  46. /jac_client/examples/all-in-one/{src/hooks → hooks}/useLocalStorage.jac +0 -0
  47. /jac_client/examples/all-in-one/{src/pages → pages}/LandingPage.jac +0 -0
  48. /jac_client/examples/all-in-one/{src/pages/BudgetPlanner.cl.jac → pages/budget_planner_ui.cl.jac} +0 -0
  49. /jac_client/examples/all-in-one/{src/pages → pages}/loginPage.jac +0 -0
  50. /jac_client/examples/all-in-one/{src/pages → pages}/signupPage.jac +0 -0
  51. /jac_client/examples/all-in-one/{src/utils → utils}/formatters.jac +0 -0
  52. /jac_client/examples/asset-serving/css-with-image/{src/app.jac → main.jac} +0 -0
  53. /jac_client/examples/asset-serving/image-asset/{src/app.jac → main.jac} +0 -0
  54. /jac_client/examples/asset-serving/import-alias/{src/app.jac → main.jac} +0 -0
  55. /jac_client/examples/basic/{src/app.jac → main.jac} +0 -0
  56. /jac_client/examples/basic-auth/{src/app.jac → main.jac} +0 -0
  57. /jac_client/examples/basic-auth-with-router/{src/app.jac → main.jac} +0 -0
  58. /jac_client/examples/basic-full-stack/{src/app.jac → main.jac} +0 -0
  59. /jac_client/examples/css-styling/js-styling/{src/app.jac → main.jac} +0 -0
  60. /jac_client/examples/css-styling/material-ui/{src/app.jac → main.jac} +0 -0
  61. /jac_client/examples/css-styling/pure-css/{src/app.jac → main.jac} +0 -0
  62. /jac_client/examples/css-styling/sass-example/{src/app.jac → main.jac} +0 -0
  63. /jac_client/examples/css-styling/styled-components/{src/app.jac → main.jac} +0 -0
  64. /jac_client/examples/css-styling/tailwind-example/{src/app.jac → main.jac} +0 -0
  65. /jac_client/examples/full-stack-with-auth/{src/app.jac → main.jac} +0 -0
  66. /jac_client/examples/little-x/{src/app.jac → main.jac} +0 -0
  67. /jac_client/examples/nested-folders/nested-advance/{src/app.jac → main.jac} +0 -0
  68. /jac_client/examples/nested-folders/nested-basic/{src/app.jac → main.jac} +0 -0
  69. /jac_client/examples/ts-support/{src/app.jac → main.jac} +0 -0
  70. /jac_client/examples/with-router/{src/app.jac → main.jac} +0 -0
  71. {jac_client-0.2.7.dist-info → jac_client-0.2.9.dist-info}/entry_points.txt +0 -0
  72. {jac_client-0.2.7.dist-info → jac_client-0.2.9.dist-info}/top_level.txt +0 -0
@@ -6,87 +6,21 @@ import gc
6
6
  import json
7
7
  import os
8
8
  import shutil
9
- import socket
10
- import sys
11
9
  import tempfile
12
10
  import time
13
11
  from http.client import RemoteDisconnected
14
- from pathlib import Path
15
12
  from subprocess import PIPE, Popen, run
16
13
  from urllib.error import HTTPError, URLError
17
14
  from urllib.request import Request, urlopen
18
15
 
19
16
  import pytest
20
17
 
21
- from jaclang.pycore.runtime import JacRuntime as Jac
22
-
23
-
24
- def _get_jac_command() -> list[str]:
25
- """Get the jac command with proper path handling."""
26
- jac_path = shutil.which("jac")
27
- if jac_path:
28
- return [jac_path]
29
- return [sys.executable, "-m", "jaclang"]
30
-
31
-
32
- def _get_env_with_npm() -> dict[str, str]:
33
- """Get environment dict with npm in PATH."""
34
- env = os.environ.copy()
35
- npm_path = shutil.which("npm")
36
- if npm_path:
37
- npm_dir = str(Path(npm_path).parent)
38
- current_path = env.get("PATH", "")
39
- if npm_dir not in current_path:
40
- env["PATH"] = f"{npm_dir}:{current_path}"
41
- # Also check common nvm locations
42
- nvm_dir = os.environ.get("NVM_DIR", os.path.expanduser("~/.nvm"))
43
- nvm_node_bin = Path(nvm_dir) / "versions" / "node"
44
- if nvm_node_bin.exists():
45
- for version_dir in nvm_node_bin.iterdir():
46
- bin_dir = version_dir / "bin"
47
- if bin_dir.exists() and (bin_dir / "npm").exists():
48
- current_path = env.get("PATH", "")
49
- if str(bin_dir) not in current_path:
50
- env["PATH"] = f"{bin_dir}:{current_path}"
51
- break
52
- return env
53
-
54
-
55
- @pytest.fixture(autouse=True)
56
- def reset_jac_machine():
57
- """Reset Jac machine before and after each test."""
58
- Jac.reset_machine()
59
- yield
60
- Jac.reset_machine()
61
-
62
-
63
- def _wait_for_port(
64
- host: str,
65
- port: int,
66
- timeout: float = 60.0,
67
- poll_interval: float = 0.5,
68
- ) -> None:
69
- """Block until a TCP port is accepting connections or timeout.
70
-
71
- Raises:
72
- TimeoutError: if the port is not accepting connections within timeout.
73
- """
74
- deadline = time.time() + timeout
75
- last_err: Exception | None = None
76
-
77
- while time.time() < deadline:
78
- with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
79
- sock.settimeout(poll_interval)
80
- try:
81
- sock.connect((host, port))
82
- return
83
- except OSError as exc: # Connection refused / timeout
84
- last_err = exc
85
- time.sleep(poll_interval)
86
-
87
- raise TimeoutError(
88
- f"Timed out waiting for {host}:{port} to become available. Last error: {last_err}"
89
- )
18
+ from .test_helpers import (
19
+ get_env_with_npm,
20
+ get_free_port,
21
+ get_jac_command,
22
+ wait_for_port,
23
+ )
90
24
 
91
25
 
92
26
  def _wait_for_endpoint(
@@ -150,7 +84,7 @@ def _wait_for_endpoint(
150
84
  def test_all_in_one_app_endpoints() -> None:
151
85
  """Create a Jac app, copy @all-in-one into it, install packages from jac.toml, then verify endpoints."""
152
86
  print(
153
- "[DEBUG] Starting test_all_in_one_app_endpoints using jac create --cl + @all-in-one"
87
+ "[DEBUG] Starting test_all_in_one_app_endpoints using jac create --use client + @all-in-one"
154
88
  )
155
89
 
156
90
  # Resolve the path to jac_client/examples/all-in-one relative to this test file.
@@ -171,9 +105,9 @@ def test_all_in_one_app_endpoints() -> None:
171
105
  print(f"[DEBUG] Changed working directory to {temp_dir}")
172
106
 
173
107
  # 1. Create a new Jac app via CLI (requires jac + jac-client plugin installed)
174
- print(f"[DEBUG] Running 'jac create --cl {app_name}'")
108
+ print(f"[DEBUG] Running 'jac create --use client {app_name}'")
175
109
  process = Popen(
176
- ["jac", "create", "--cl", app_name],
110
+ ["jac", "create", "--use", "client", app_name],
177
111
  stdin=PIPE,
178
112
  stdout=PIPE,
179
113
  stderr=PIPE,
@@ -183,21 +117,21 @@ def test_all_in_one_app_endpoints() -> None:
183
117
  returncode = process.returncode
184
118
 
185
119
  print(
186
- "[DEBUG] 'jac create --cl' completed "
120
+ "[DEBUG] 'jac create --use client' completed "
187
121
  f"returncode={returncode}\n"
188
122
  f"STDOUT:\n{stdout}\n"
189
123
  f"STDERR:\n{stderr}\n"
190
124
  )
191
125
 
192
- # If the currently installed `jac` CLI does not support `create --cl`,
126
+ # If the currently installed `jac` CLI does not support `create --use client`,
193
127
  # fail the test instead of skipping it.
194
- if returncode != 0 and "unrecognized arguments: --cl" in stderr:
128
+ if returncode != 0 and "unrecognized arguments: --use" in stderr:
195
129
  pytest.fail(
196
- "Test failed: installed `jac` CLI does not support `create --cl`."
130
+ "Test failed: installed `jac` CLI does not support `create --use client`."
197
131
  )
198
132
 
199
133
  assert returncode == 0, (
200
- f"jac create --cl failed\nSTDOUT:\n{stdout}\nSTDERR:\n{stderr}\n"
134
+ f"jac create --use client failed\nSTDOUT:\n{stdout}\nSTDERR:\n{stderr}\n"
201
135
  )
202
136
 
203
137
  project_path = os.path.join(temp_dir, app_name)
@@ -217,17 +151,17 @@ def test_all_in_one_app_endpoints() -> None:
217
151
  else:
218
152
  shutil.copy2(src, dst)
219
153
 
220
- # 3. Install packages from jac.toml using `jac add --cl`
154
+ # 3. Install packages from jac.toml using `jac add --npm`
221
155
  # This reads packages from jac.toml, generates package.json, and runs npm install
222
- print("[DEBUG] Running 'jac add --cl' to install packages from jac.toml")
156
+ print("[DEBUG] Running 'jac add --npm' to install packages from jac.toml")
223
157
  jac_add_result = run(
224
- ["jac", "add", "--cl"],
158
+ ["jac", "add", "--npm"],
225
159
  cwd=project_path,
226
160
  capture_output=True,
227
161
  text=True,
228
162
  )
229
163
  print(
230
- "[DEBUG] 'jac add --cl' completed "
164
+ "[DEBUG] 'jac add --npm' completed "
231
165
  f"returncode={jac_add_result.returncode}\n"
232
166
  f"STDOUT (truncated to 2000 chars):\n{jac_add_result.stdout[:2000]}\n"
233
167
  f"STDERR (truncated to 2000 chars):\n{jac_add_result.stderr[:2000]}\n"
@@ -235,28 +169,36 @@ def test_all_in_one_app_endpoints() -> None:
235
169
 
236
170
  if jac_add_result.returncode != 0:
237
171
  pytest.fail(
238
- f"Test failed: jac add --cl failed or npm is not available in PATH.\n"
172
+ f"Test failed: jac add --npm failed or npm is not available in PATH.\n"
239
173
  f"STDOUT:\n{jac_add_result.stdout}\n"
240
174
  f"STDERR:\n{jac_add_result.stderr}\n"
241
175
  )
242
176
 
243
- app_jac_path = os.path.join(project_path, "src", "app.jac")
244
- assert os.path.isfile(app_jac_path), "all-in-one src/app.jac file missing"
177
+ app_jac_path = os.path.join(project_path, "main.jac")
178
+ assert os.path.isfile(app_jac_path), "all-in-one main.jac file missing"
245
179
 
246
- # 4. Start the server: `jac start src/app.jac`
180
+ # 4. Start the server: `jac start main.jac`
247
181
  # NOTE: We don't use text mode here, so `Popen` defaults to bytes.
248
182
  # Use `Popen[bytes]` in the type annotation to keep mypy happy.
249
183
  server: Popen[bytes] | None = None
184
+ # Use dynamic port allocation to avoid conflicts when running tests in parallel
185
+ server_port = get_free_port()
250
186
  try:
251
- print("[DEBUG] Starting server with 'jac start src/app.jac'")
187
+ print(
188
+ f"[DEBUG] Starting server with 'jac start main.jac -p {server_port}'"
189
+ )
252
190
  server = Popen(
253
- ["jac", "start", "src/app.jac"],
191
+ ["jac", "start", "main.jac", "-p", str(server_port)],
254
192
  cwd=project_path,
255
193
  )
256
194
  # Wait for localhost:8000 to become available
257
- print("[DEBUG] Waiting for server to be available on 127.0.0.1:8000")
258
- _wait_for_port("127.0.0.1", 8000, timeout=90.0)
259
- print("[DEBUG] Server is now accepting connections on 127.0.0.1:8000")
195
+ print(
196
+ f"[DEBUG] Waiting for server to be available on 127.0.0.1:{server_port}"
197
+ )
198
+ wait_for_port("127.0.0.1", server_port, timeout=90.0)
199
+ print(
200
+ f"[DEBUG] Server is now accepting connections on 127.0.0.1:{server_port}"
201
+ )
260
202
 
261
203
  # "/" – server up (serves client app HTML due to base_route_app="app")
262
204
  # Note: The root endpoint may return 503 while the client bundle is building.
@@ -264,7 +206,7 @@ def test_all_in_one_app_endpoints() -> None:
264
206
  try:
265
207
  print("[DEBUG] Sending GET request to root endpoint / (with retry)")
266
208
  root_bytes = _wait_for_endpoint(
267
- "http://127.0.0.1:8000",
209
+ f"http://127.0.0.1:{server_port}",
268
210
  timeout=120.0,
269
211
  poll_interval=2.0,
270
212
  request_timeout=30.0,
@@ -290,7 +232,7 @@ def test_all_in_one_app_endpoints() -> None:
290
232
  "[DEBUG] Sending GET request to /cl/app endpoint (with retry)"
291
233
  )
292
234
  page_bytes = _wait_for_endpoint(
293
- "http://127.0.0.1:8000/cl/app",
235
+ f"http://127.0.0.1:{server_port}/cl/app",
294
236
  timeout=120.0,
295
237
  poll_interval=2.0,
296
238
  request_timeout=30.0,
@@ -310,7 +252,7 @@ def test_all_in_one_app_endpoints() -> None:
310
252
  try:
311
253
  print("[DEBUG] Sending GET request to /cl/app#/nested endpoint")
312
254
  with urlopen(
313
- "http://127.0.0.1:8000/cl/app#/nested",
255
+ f"http://127.0.0.1:{server_port}/cl/app#/nested",
314
256
  timeout=200,
315
257
  ) as resp_nested:
316
258
  nested_body = resp_nested.read().decode(
@@ -336,7 +278,7 @@ def test_all_in_one_app_endpoints() -> None:
336
278
  try:
337
279
  print("[DEBUG] Sending GET request to /static/assets/burger.png")
338
280
  with urlopen(
339
- "http://127.0.0.1:8000/static/assets/burger.png",
281
+ f"http://127.0.0.1:{server_port}/static/assets/burger.png",
340
282
  timeout=20,
341
283
  ) as resp_png:
342
284
  png_bytes = resp_png.read()
@@ -362,7 +304,7 @@ def test_all_in_one_app_endpoints() -> None:
362
304
  "[DEBUG] Sending GET request to /workers/worker.js (with retry)"
363
305
  )
364
306
  worker_js_bytes = _wait_for_endpoint(
365
- "http://127.0.0.1:8000/workers/worker.js",
307
+ f"http://127.0.0.1:{server_port}/workers/worker.js",
366
308
  timeout=60.0,
367
309
  poll_interval=2.0,
368
310
  request_timeout=20.0,
@@ -384,13 +326,18 @@ def test_all_in_one_app_endpoints() -> None:
384
326
  f"Failed to GET /workers/worker.js after retries: {exc}"
385
327
  )
386
328
 
387
- # "/walker/get_server_message" – walkers are integrated and up and running
329
+ # POST /walker/get_server_message – walkers are integrated and up and running
388
330
  try:
389
- print("[DEBUG] Sending GET request to /walker/get_server_message")
390
- with urlopen(
391
- "http://127.0.0.1:8000/walker/get_server_message",
392
- timeout=20,
393
- ) as resp_walker:
331
+ print(
332
+ "[DEBUG] Sending POST request to /walker/get_server_message endpoint"
333
+ )
334
+ req = Request(
335
+ f"http://127.0.0.1:{server_port}/walker/get_server_message",
336
+ data=json.dumps({}).encode("utf-8"),
337
+ headers={"Content-Type": "application/json"},
338
+ method="POST",
339
+ )
340
+ with urlopen(req, timeout=20) as resp_walker:
394
341
  walker_body = resp_walker.read().decode(
395
342
  "utf-8", errors="ignore"
396
343
  )
@@ -400,12 +347,13 @@ def test_all_in_one_app_endpoints() -> None:
400
347
  f"Body (truncated to 500 chars):\n{walker_body[:500]}"
401
348
  )
402
349
  assert resp_walker.status == 200
403
- assert "get_server_message" in walker_body
404
- except (URLError, HTTPError) as exc:
350
+ # The walker reports "hello from a basic walker!"
351
+ assert "hello from a basic walker" in walker_body.lower()
352
+ except (URLError, HTTPError, RemoteDisconnected) as exc:
405
353
  print(
406
354
  f"[DEBUG] Error while requesting /walker/get_server_message: {exc}"
407
355
  )
408
- pytest.fail("Failed to GET /walker/get_server_message")
356
+ pytest.fail("Failed to POST /walker/get_server_message")
409
357
 
410
358
  # POST /walker/create_todo – create a Todo via walker HTTP API
411
359
  try:
@@ -416,7 +364,7 @@ def test_all_in_one_app_endpoints() -> None:
416
364
  "text": "Sample todo from all-in-one app",
417
365
  }
418
366
  req = Request(
419
- "http://127.0.0.1:8000/walker/create_todo",
367
+ f"http://127.0.0.1:{server_port}/walker/create_todo",
420
368
  data=json.dumps(payload).encode("utf-8"),
421
369
  headers={"Content-Type": "application/json"},
422
370
  method="POST",
@@ -447,7 +395,7 @@ def test_all_in_one_app_endpoints() -> None:
447
395
  "password": test_password,
448
396
  }
449
397
  req_register = Request(
450
- "http://127.0.0.1:8000/user/register",
398
+ f"http://127.0.0.1:{server_port}/user/register",
451
399
  data=json.dumps(register_payload).encode("utf-8"),
452
400
  headers={"Content-Type": "application/json"},
453
401
  method="POST",
@@ -462,7 +410,9 @@ def test_all_in_one_app_endpoints() -> None:
462
410
  f"Body (truncated to 500 chars):\n{register_body[:500]}"
463
411
  )
464
412
  assert resp_register.status == 201
465
- register_data = json.loads(register_body)
413
+ register_response = json.loads(register_body)
414
+ # Handle new TransportResponse envelope format
415
+ register_data = register_response.get("data", register_response)
466
416
  assert "username" in register_data
467
417
  assert "token" in register_data
468
418
  assert "root_id" in register_data
@@ -486,7 +436,7 @@ def test_all_in_one_app_endpoints() -> None:
486
436
  "password": test_password,
487
437
  }
488
438
  req_login = Request(
489
- "http://127.0.0.1:8000/user/login",
439
+ f"http://127.0.0.1:{server_port}/user/login",
490
440
  data=json.dumps(login_payload).encode("utf-8"),
491
441
  headers={"Content-Type": "application/json"},
492
442
  method="POST",
@@ -499,7 +449,9 @@ def test_all_in_one_app_endpoints() -> None:
499
449
  f"Body (truncated to 500 chars):\n{login_body[:500]}"
500
450
  )
501
451
  assert resp_login.status == 200
502
- login_data = json.loads(login_body)
452
+ login_response = json.loads(login_body)
453
+ # Handle new TransportResponse envelope format
454
+ login_data = login_response.get("data", login_response)
503
455
  assert "token" in login_data
504
456
  assert len(login_data["token"]) > 0
505
457
  print(
@@ -520,7 +472,7 @@ def test_all_in_one_app_endpoints() -> None:
520
472
  "password": "wrong_password",
521
473
  }
522
474
  req_invalid_login = Request(
523
- "http://127.0.0.1:8000/user/login",
475
+ f"http://127.0.0.1:{server_port}/user/login",
524
476
  data=json.dumps(invalid_login_payload).encode("utf-8"),
525
477
  headers={"Content-Type": "application/json"},
526
478
  method="POST",
@@ -607,10 +559,10 @@ def test_all_in_one_app_endpoints() -> None:
607
559
 
608
560
 
609
561
  def test_default_client_app_renders() -> None:
610
- """Test that a default `jac create --cl` app renders correctly when served.
562
+ """Test that a default `jac create --use client` app renders correctly when served.
611
563
 
612
564
  This test validates the out-of-the-box experience:
613
- 1. Creates a new client app using `jac create --cl`
565
+ 1. Creates a new client app using `jac create --use client`
614
566
  2. Installs packages
615
567
  3. Starts the server
616
568
  4. Validates that the default app renders with expected content
@@ -627,11 +579,13 @@ def test_default_client_app_renders() -> None:
627
579
  print(f"[DEBUG] Changed working directory to {temp_dir}")
628
580
 
629
581
  # 1. Create a new default Jac client app
630
- jac_cmd = _get_jac_command()
631
- env = _get_env_with_npm()
632
- print(f"[DEBUG] Running '{' '.join(jac_cmd)} create --cl {app_name}'")
582
+ jac_cmd = get_jac_command()
583
+ env = get_env_with_npm()
584
+ print(
585
+ f"[DEBUG] Running '{' '.join(jac_cmd)} create --use client {app_name}'"
586
+ )
633
587
  process = Popen(
634
- [*jac_cmd, "create", "--cl", app_name],
588
+ [*jac_cmd, "create", "--use", "client", app_name],
635
589
  stdin=PIPE,
636
590
  stdout=PIPE,
637
591
  stderr=PIPE,
@@ -642,18 +596,18 @@ def test_default_client_app_renders() -> None:
642
596
  returncode = process.returncode
643
597
 
644
598
  print(
645
- f"[DEBUG] 'jac create --cl' completed returncode={returncode}\n"
599
+ f"[DEBUG] 'jac create --use client' completed returncode={returncode}\n"
646
600
  f"STDOUT:\n{stdout}\n"
647
601
  f"STDERR:\n{stderr}\n"
648
602
  )
649
603
 
650
- if returncode != 0 and "unrecognized arguments: --cl" in stderr:
604
+ if returncode != 0 and "unrecognized arguments: --use" in stderr:
651
605
  pytest.fail(
652
- "Test failed: installed `jac` CLI does not support `create --cl`."
606
+ "Test failed: installed `jac` CLI does not support `create --use client`."
653
607
  )
654
608
 
655
609
  assert returncode == 0, (
656
- f"jac create --cl failed\nSTDOUT:\n{stdout}\nSTDERR:\n{stderr}\n"
610
+ f"jac create --use client failed\nSTDOUT:\n{stdout}\nSTDERR:\n{stderr}\n"
657
611
  )
658
612
 
659
613
  project_path = os.path.join(temp_dir, app_name)
@@ -675,46 +629,52 @@ def test_default_client_app_renders() -> None:
675
629
  jac_toml_path = os.path.join(project_path, "jac.toml")
676
630
  assert os.path.isfile(jac_toml_path), "jac.toml should exist"
677
631
 
678
- # 2. Ensure packages are installed (jac create --cl should have done this)
679
- # If node_modules doesn't exist, run jac add --cl
632
+ # 2. Ensure packages are installed (jac create --use client should have done this)
633
+ # If node_modules doesn't exist, run jac add --npm
680
634
  node_modules_path = os.path.join(
681
635
  project_path, ".jac", "client", "node_modules"
682
636
  )
683
637
  if not os.path.isdir(node_modules_path):
684
- print("[DEBUG] node_modules not found, running 'jac add --cl'")
638
+ print("[DEBUG] node_modules not found, running 'jac add --npm'")
685
639
  jac_add_result = run(
686
- [*jac_cmd, "add", "--cl"],
640
+ [*jac_cmd, "add", "--npm"],
687
641
  cwd=project_path,
688
642
  capture_output=True,
689
643
  text=True,
690
644
  env=env,
691
645
  )
692
646
  print(
693
- f"[DEBUG] 'jac add --cl' completed returncode={jac_add_result.returncode}\n"
647
+ f"[DEBUG] 'jac add --npm' completed returncode={jac_add_result.returncode}\n"
694
648
  f"STDOUT (truncated):\n{jac_add_result.stdout[:1000]}\n"
695
649
  f"STDERR (truncated):\n{jac_add_result.stderr[:1000]}\n"
696
650
  )
697
651
  if jac_add_result.returncode != 0:
698
652
  pytest.fail(
699
- f"jac add --cl failed\n"
653
+ f"jac add --npm failed\n"
700
654
  f"STDOUT:\n{jac_add_result.stdout}\n"
701
655
  f"STDERR:\n{jac_add_result.stderr}\n"
702
656
  )
703
657
 
704
658
  # 3. Start the server (now uses main.jac at project root)
705
659
  server: Popen[bytes] | None = None
660
+ # Use dynamic port allocation to avoid conflicts when running tests in parallel
661
+ server_port = get_free_port()
706
662
  try:
707
- print("[DEBUG] Starting server with 'jac start main.jac'")
663
+ print(
664
+ f"[DEBUG] Starting server with 'jac start main.jac -p {server_port}'"
665
+ )
708
666
  server = Popen(
709
- [*jac_cmd, "start", "main.jac"],
667
+ [*jac_cmd, "start", "main.jac", "-p", str(server_port)],
710
668
  cwd=project_path,
711
669
  env=env,
712
670
  )
713
671
 
714
672
  # Wait for server to be ready
715
- print("[DEBUG] Waiting for server on 127.0.0.1:8000")
716
- _wait_for_port("127.0.0.1", 8000, timeout=90.0)
717
- print("[DEBUG] Server is accepting connections")
673
+ print(f"[DEBUG] Waiting for server on 127.0.0.1:{server_port}")
674
+ wait_for_port("127.0.0.1", server_port, timeout=90.0)
675
+ print(
676
+ f"[DEBUG] Server is accepting connections on 127.0.0.1:{server_port}"
677
+ )
718
678
 
719
679
  # 4. Test root endpoint - for client-only apps, root serves the HTML app
720
680
  # Note: The root endpoint may return 503 while the client bundle is building.
@@ -722,7 +682,7 @@ def test_default_client_app_renders() -> None:
722
682
  try:
723
683
  print("[DEBUG] Testing root endpoint / (with retry)")
724
684
  root_bytes = _wait_for_endpoint(
725
- "http://127.0.0.1:8000",
685
+ f"http://127.0.0.1:{server_port}",
726
686
  timeout=120.0,
727
687
  poll_interval=2.0,
728
688
  request_timeout=30.0,
@@ -746,7 +706,7 @@ def test_default_client_app_renders() -> None:
746
706
  try:
747
707
  print("[DEBUG] Testing client app endpoint /cl/app")
748
708
  page_bytes = _wait_for_endpoint(
749
- "http://127.0.0.1:8000/cl/app",
709
+ f"http://127.0.0.1:{server_port}/cl/app",
750
710
  timeout=120.0,
751
711
  poll_interval=2.0,
752
712
  request_timeout=30.0,
@@ -782,7 +742,7 @@ def test_default_client_app_renders() -> None:
782
742
  )
783
743
  if script_match:
784
744
  js_path = script_match.group(1)
785
- js_url = f"http://127.0.0.1:8000{js_path}"
745
+ js_url = f"http://127.0.0.1:{server_port}{js_path}"
786
746
  print(f"[DEBUG] Fetching JS bundle from {js_url}")
787
747
  with urlopen(js_url, timeout=30) as resp:
788
748
  js_body = resp.read().decode("utf-8", errors="ignore")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jac-client
3
- Version: 0.2.7
3
+ Version: 0.2.9
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.9
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"
@@ -47,7 +47,7 @@ pip install jac-client
47
47
  ### Create a New App
48
48
 
49
49
  ```bash
50
- jac create --cl my-app
50
+ jac create --use client my-app
51
51
  cd my-app
52
52
  jac start src/app.jac
53
53
  ```
@@ -56,7 +56,7 @@ Visit `http://localhost:8000` to see your app! (The `app` component is served at
56
56
 
57
57
  You can also access the app at `http://localhost:8000/cl/app`.
58
58
 
59
- > **Note**: The `--cl` flag creates a client-side project with an organized folder structure. Without `--cl`, `jac create` creates a standard Jac project.
59
+ > **Note**: The `--npm` flag creates a client-side project with an organized folder structure. Without `--npm`, `jac create` creates a standard Jac project.
60
60
 
61
61
  ---
62
62
 
@@ -0,0 +1,104 @@
1
+ jac_client/examples/all-in-one/button.jac,sha256=YS_Ae3dyNAvnGh8iP_uUg1VyuzaxleEkLFEx4u959tw,126
2
+ jac_client/examples/all-in-one/main.jac,sha256=VIQU5iZLKDzD4rnicv_h2t2XNy8ra1UI-k496hPV994,16042
3
+ jac_client/examples/all-in-one/assets/workers/worker.py,sha256=erXICb1WvDKYlReUIzgZf9v0Pey6pmWDbvAm9vtGQmg,131
4
+ jac_client/examples/all-in-one/components/CategoryFilter.jac,sha256=nuyBpUmG29FHEm73eTVHOtPBJBiqjy_rF-unl5NIMno,1434
5
+ jac_client/examples/all-in-one/components/Header.jac,sha256=qN3yiq-jQvSRyeaEhsKI8oDb1MdloRNunScx0t_Exus,382
6
+ jac_client/examples/all-in-one/components/ProfitOverview.jac,sha256=YaG0XFIcaLelZ49jLc2CBAA0SS7js0asPSTuOow7tow,1986
7
+ jac_client/examples/all-in-one/components/Summary.jac,sha256=Jh956an_BDqvGp0gwZYihv7Ftqs0B_b1nMit9alctx0,2316
8
+ jac_client/examples/all-in-one/components/TransactionForm.jac,sha256=1W3r9s43FqQrUeNncX9nQZZSdizIbPufIasodrfhqTA,6152
9
+ jac_client/examples/all-in-one/components/TransactionItem.jac,sha256=we8QplGm_k-z3KAAGcpqh4xjSvSJmanRKAYU6bvNg14,1863
10
+ jac_client/examples/all-in-one/components/TransactionList.jac,sha256=CnQCqCudcwYHZGjQkca1YI6gahY_4f9TihvKHUZ0QPI,1283
11
+ jac_client/examples/all-in-one/components/button.jac,sha256=AoWR2fUXS2UEAUk1CLoRgI-u9ecA0D_SUPKvQGEORIg,124
12
+ jac_client/examples/all-in-one/components/navigation.jac,sha256=MDzdorVvymnIbE6T3MTk9w6_LB5oCkX_Qhtn5NxFy78,3738
13
+ jac_client/examples/all-in-one/constants/categories.jac,sha256=3R2xi2PSUo46_fdiGi57H2ccjN4EPh9v_GX_Ix5QfCc,986
14
+ jac_client/examples/all-in-one/constants/clients.jac,sha256=NjUOOw1iQ-4WfPC2UkEjmbJX4VcwS3TmnrKIZzCwtGE,282
15
+ jac_client/examples/all-in-one/context/BudgetContext.jac,sha256=MYeVLYijJJRRz095Q0J8Gg4bFGLCMj32NjOuh5eJKpE,865
16
+ jac_client/examples/all-in-one/hooks/useBudget.jac,sha256=FjZP6D8surhkaF5jYRV7UzZRovMU3m6LO92awN2OndA,3996
17
+ jac_client/examples/all-in-one/hooks/useLocalStorage.jac,sha256=Cj4EDiRfzOJkTBGPhUCncCo4Wvo37LIWAWcSUwmrync,1179
18
+ jac_client/examples/all-in-one/pages/BudgetPlanner.jac,sha256=b50GHNG2O7dozv2JJIzx9szVdF3eVpXFZZmGdbkg_9o,3661
19
+ jac_client/examples/all-in-one/pages/FeaturesTest.jac,sha256=mlwJ3GjKcJygn3zlBf7TelIcEJlu4yFHfnssK5jx2bI,4180
20
+ jac_client/examples/all-in-one/pages/LandingPage.jac,sha256=szbtJMwfgMSNi-p4emu9apUk_7wI-ARPV9w0lcLZ6Zw,3859
21
+ jac_client/examples/all-in-one/pages/budget_planner_ui.cl.jac,sha256=2KTdxH3IelVSEi_pKzvIse7dfY5_j7661nDWt5aVYWg,2493
22
+ jac_client/examples/all-in-one/pages/features_test_ui.cl.jac,sha256=OKNndwDox7ZnDbNmDNUupMR7NYw60NBKVbVBOV2nTnI,23316
23
+ jac_client/examples/all-in-one/pages/loginPage.jac,sha256=2IuVVZ7nizRJrNGlZdYQP3nzmJQh2uv0m7Gu1q02arA,3776
24
+ jac_client/examples/all-in-one/pages/nestedDemo.jac,sha256=wCZAM-5ZUZ28X6SnLQs8mS6Z2jC3rkSP7j5MlzOzDEk,1415
25
+ jac_client/examples/all-in-one/pages/notFound.jac,sha256=QdmqvCDBw6bmqTYIvtS7KjJhBHzGEsIwRa6vuIQIOrc,415
26
+ jac_client/examples/all-in-one/pages/signupPage.jac,sha256=a79OPuW9g3-OcKiHwrE1kCa9AiIKdfcYPyBn0hnZ3u4,3826
27
+ jac_client/examples/all-in-one/utils/formatters.jac,sha256=YN-87e4HUkHukhYzKP6g0L7K0n4do8el6cCr7Gzxf9c,1573
28
+ jac_client/examples/asset-serving/css-with-image/main.jac,sha256=2L71jgzrciLt3fdcw0FCqJ-zrdHEFeC9YGZqczk2xWQ,2805
29
+ jac_client/examples/asset-serving/image-asset/main.jac,sha256=Hi3YXI9aCTdnaIad4LZ1PSJ6guZF0saBHRCJRp-1ED0,1640
30
+ jac_client/examples/asset-serving/import-alias/main.jac,sha256=7jxIKwsUyfjs5jMFyyDxVyVsXOV6hc_16EW_vxv_jgw,3499
31
+ jac_client/examples/basic/main.jac,sha256=0Rw2xaWKvYmvf3Cq6n1cjd9n2_tbvd1dQmTgutv5r8A,509
32
+ jac_client/examples/basic-auth/main.jac,sha256=p7jWmkLrRvBb548XlxXgR-cG7L9c3CLhPsBFDZu1O3E,13972
33
+ jac_client/examples/basic-auth-with-router/main.jac,sha256=Koa_swLvoHADKHGGbSVdRiTUWYqqVnMHPqq914h8Z3I,14907
34
+ jac_client/examples/basic-full-stack/main.jac,sha256=M-v1KUtZUe553ctREe2iabirfDckemQnsAU964CL_EY,13038
35
+ jac_client/examples/css-styling/js-styling/main.jac,sha256=C9pEnt3dxD9c0nb2Hj5bx3eZYy_vxrli92W8nvud7cw,2461
36
+ jac_client/examples/css-styling/material-ui/main.jac,sha256=PAeTSRr95_ask89pE_kJ5uNLp8t6BQ_834TqAdvKLVQ,4741
37
+ jac_client/examples/css-styling/pure-css/main.jac,sha256=Xm1sXdlPN_HVIQJo8tX9bP60LLO0DDKFDMy-Zv0lUrA,2045
38
+ jac_client/examples/css-styling/sass-example/main.jac,sha256=25qlPTh-4k0dxBrXt9JZ1gYmB1v6mNvz_UCiXoLlr5c,2046
39
+ jac_client/examples/css-styling/styled-components/main.jac,sha256=yy-8Ajm6Hr1c_npXChc73SBm_KRcAl43DTYQcHCUJCk,1930
40
+ jac_client/examples/css-styling/tailwind-example/main.jac,sha256=Mis1_zCLTZLZFe9XmpIbZGjvu7xU99lx8HgdaRm03Hg,2976
41
+ jac_client/examples/full-stack-with-auth/main.jac,sha256=IccVn9iJD0Dia7BaRQo0BCA4fO9UN0lEj5y7heN7oBU,21958
42
+ jac_client/examples/little-x/main.jac,sha256=_hvNGuDjmIW3ddyNB7xOpA90sowz5XcBeLgMDVMiPq0,19151
43
+ jac_client/examples/little-x/src/submit-button.jac,sha256=zxaD7xRdpH8iDU-8lrNQaoMU_cYr-rC_ZxaVhZqTsmc,370
44
+ jac_client/examples/nested-folders/nested-advance/main.jac,sha256=XO8_sjUv4KHQ4sXBiLFUPIrgMhrbj0t7SLkAnpmERMM,800
45
+ jac_client/examples/nested-folders/nested-advance/src/ButtonRoot.jac,sha256=cflz34exdyamxZaoK4zZOpOCZIIGkhOQw3P6iZ9myi4,195
46
+ jac_client/examples/nested-folders/nested-advance/src/level1/ButtonSecondL.jac,sha256=smbct7iMQ_3W17v_5juphv0iw7kojFErgJxXekm7KAE,425
47
+ jac_client/examples/nested-folders/nested-advance/src/level1/Card.jac,sha256=4Ky5cxs8M0pBz7Ju2wTAI3H0z9qaw4LLDk4oYCKimVg,994
48
+ jac_client/examples/nested-folders/nested-advance/src/level1/level2/ButtonThirdL.jac,sha256=Y0PwJDrzp8x64Ks9IhXcsRBgjUnko-Ch10ZmRqIO4CI,603
49
+ jac_client/examples/nested-folders/nested-basic/main.jac,sha256=moz3YDZ3S9MFftcBrJHmFKYe6mpj_Hdb2kxcoX2R7GM,270
50
+ jac_client/examples/nested-folders/nested-basic/src/button.jac,sha256=WlV2pcssnGGsO-25hrcyA4PRw5o4Y5UpsUmCfBF-LrE,123
51
+ jac_client/examples/nested-folders/nested-basic/src/components/button.jac,sha256=_ErhjGJud5G32XiFL7p3N8wca-NSknvz2eNUt1fHKkE,119
52
+ jac_client/examples/ts-support/main.jac,sha256=FaI5S2cztmQ6Az836Zr008LCK1irs_UaE_2tuvdXFQk,978
53
+ jac_client/examples/with-router/main.jac,sha256=5He-ssFYXal1Q6Ihv6WhcpeWjcMJCT4UqJfMJF-8Xxw,8624
54
+ jac_client/plugin/cli.jac,sha256=q3Uu3R-Vm92KYcMmNa-4Vyd3J-ielT3KbcenprqkY-A,7818
55
+ jac_client/plugin/client.jac,sha256=WVn8IwQO2Kgr8XLDI8D4FSVj9kdewBXB3Mgi9ifCVTI,2095
56
+ jac_client/plugin/client_runtime.cl.jac,sha256=1TJww4MS4WTzP_uCTjrshGBZdReQ7e7TYHJ4geYUsdw,1868
57
+ jac_client/plugin/plugin_config.jac,sha256=PexvStd6MwJQEJaEl5gB6cNO5LbsWk_sT78sqbjxk_o,15111
58
+ jac_client/plugin/vite_client_bundle.jac,sha256=l8EY8O2sdsqhtO8I32Of01dgShRQBfMBNWXyl-y-vtY,1016
59
+ jac_client/plugin/impl/client.impl.jac,sha256=UOmY3Pzi00Cvqdze_BnoIX1QS5_QWEPDQATNp5VDh4k,8956
60
+ jac_client/plugin/impl/client_runtime.impl.jac,sha256=VGQnJOZh7dnxuPKjN-slZCCufHxmyfa0J8FkzoW3Syk,10691
61
+ jac_client/plugin/impl/vite_client_bundle.impl.jac,sha256=KXFqXSZaa08Z6CrEqebfdjo7TvdakTNJHVnGOhj4e0s,2620
62
+ jac_client/plugin/src/__init__.jac,sha256=ZyA9pRNofbdVMKKzKwMgWpqNHVF4gCq4fxVykEnU_6c,823
63
+ jac_client/plugin/src/asset_processor.jac,sha256=Qpm1a174PPJl32nH_eDZYR-6vx59V2NEWfj0knUMwXY,961
64
+ jac_client/plugin/src/babel_processor.jac,sha256=e6wgeGA4Wd1vu4di9PRik7M_Hbt6nhwq5pZaHCs5OMQ,612
65
+ jac_client/plugin/src/compiler.jac,sha256=roy_Pf8zRtb4AJnCSglWFXIfgGQUVe24WI2nB_e_eaQ,2367
66
+ jac_client/plugin/src/config_loader.jac,sha256=-UJsqmaddZZ2dOJuvqjOXBreAU-DdQccqWodGvcLzRE,1302
67
+ jac_client/plugin/src/import_processor.jac,sha256=wYg8bD5qHxpvFyXkQxNpqUIV3ei5aMoevA2bWyq9VG8,589
68
+ jac_client/plugin/src/jac_to_js.jac,sha256=U2_v95tdsbw1oMPGPY0HOhDcAsHg3uQIcGWzLmFdWyc,1115
69
+ jac_client/plugin/src/package_installer.jac,sha256=5maePqEe3xIys9Ufn54m423tAr54z-urtXc84Ki3bIY,850
70
+ jac_client/plugin/src/vite_bundler.jac,sha256=7Sx7Mmyg6VAwdzcQ9y7lGWqb_4mI82b5mEK9bff4idM,1969
71
+ jac_client/plugin/src/impl/asset_processor.impl.jac,sha256=-ljWYzKLKyAdfJybr8sjJlYSK57KzueeNvTo_WjAFAY,4256
72
+ jac_client/plugin/src/impl/babel_processor.impl.jac,sha256=Sl6YiDa6F0LkJ5YxFYAEqXsuKoNEG89CMeAEQTanR2o,3733
73
+ jac_client/plugin/src/impl/compiler.impl.jac,sha256=pq0X9XfA7KP6HqhvUp_S90mRCsKFBFggctKRhzkqQj8,11710
74
+ jac_client/plugin/src/impl/config_loader.impl.jac,sha256=pTGfdh3g-nQmUiEr6N_mVLqTKpT9-seGv7BpWFtNSxQ,4459
75
+ jac_client/plugin/src/impl/import_processor.impl.jac,sha256=BMkkZXlF-6jbC-r3tuFj8PDFvDZrbfzuhnaw8qraWIQ,1214
76
+ jac_client/plugin/src/impl/jac_to_js.impl.jac,sha256=YWu5U4Vx1fUnopln8wNPvAd17PcQTTfCUYALZerlZfo,1547
77
+ jac_client/plugin/src/impl/package_installer.impl.jac,sha256=Jb3sq9zK8HBm_GINz-9ohhhgMgD-omVjCso40UdnCo8,3887
78
+ jac_client/plugin/src/impl/vite_bundler.impl.jac,sha256=Zbkk5N2YXy-CRydIEnIHUHsjrbzmJ785i-DVCN9x378,27345
79
+ jac_client/plugin/utils/__init__.jac,sha256=LG_G_15uD8IAAwP20Koz86jpzn8MYlkL0ZottcoEGnA,45
80
+ jac_client/plugin/utils/node_installer.jac,sha256=monZ5mVhWSLi5rbxyV3250LjfwY2j4c8fxiB_uc5WIM,1356
81
+ jac_client/plugin/utils/impl/node_installer.impl.jac,sha256=gvYIFpWcLIZAMzzTHH-nAK_WZvCKsMYTN8JAiu2OumM,8775
82
+ jac_client/templates/client.jacpack,sha256=7Atks2Swszn-0Amcl7LfQWXuCw4sOoGOSArMKlKzGmI,4279
83
+ jac_client/templates/fullstack.jacpack,sha256=4__i_lIcmXjhJfVHTHd34tW78OWGdmOn9odS_SQV-9E,23206
84
+ jac_client/tests/__init__.py,sha256=HSr78dvKyvNmP7bLmAssfYItAn4puFwAe1oWnV8l7pA,36
85
+ jac_client/tests/conftest.py,sha256=T7J4MHylKuZAP-Up_xIL6_jFtRaVyiFl_2zs5c2mugU,10559
86
+ jac_client/tests/test_cli.py,sha256=N854aqp60LXv56YbLcrMTX5xlOlLjZ3qP3dVk9hhM0c,32502
87
+ jac_client/tests/test_e2e.py,sha256=MqMXiUnLl8qwsW-OQFN1GK-5hbCKKzxT2SewmVWEsow,8197
88
+ jac_client/tests/test_helpers.py,sha256=KrxarU4G-QLwN_5mxTG8VoCrIOkszSqs0xUur6o-E0w,2084
89
+ jac_client/tests/test_it.py,sha256=9lt5CpoRG5JukQAVgpgcJAEliSQocIEE8fH61dAch3M,37800
90
+ jac_client/tests/fixtures/basic-app/app.jac,sha256=sDup4PmtUm93oVOxIz874SSZfMimPv4Qn683iXm43TI,489
91
+ jac_client/tests/fixtures/cl_file/app.cl.jac,sha256=fHJvjKWLhX5uVdZl12mPwcNRgMVFrCz8oY3oMoCWeuM,1157
92
+ jac_client/tests/fixtures/cl_file/app.jac,sha256=GmuOisnyOGfDnQ_-6juBumliLDUt1t9HQtfRpJ8xuqk,277
93
+ jac_client/tests/fixtures/client_app_with_antd/app.jac,sha256=a8cNThrEuaBq6Lv7aa-K8hAzBIDHkiBHwqON1_Gq4D8,575
94
+ jac_client/tests/fixtures/js_import/app.jac,sha256=CAmAJ299KsbJ6BIdGYykBrTDAh-Df_fhOENwNxxAEbw,796
95
+ jac_client/tests/fixtures/relative_import/app.jac,sha256=Su4UVwZeXV32wnKWvrESaLPR30C-kqyKDUrZPyaw5gQ,188
96
+ jac_client/tests/fixtures/relative_import/button.jac,sha256=kCDNaHEcxMEFdezfnecyVc56cnZU_ZnqdBDOB4kCFeE,118
97
+ jac_client/tests/fixtures/spawn_test/app.jac,sha256=nhWwzuzKGQ7La4BvvHRD6hb2Nmay-hcv1osMVRJjpWU,3785
98
+ jac_client/tests/fixtures/test_fragments_spread/app.jac,sha256=CMzAz4Ydx_5eAV82-io8sJdy8_xy-mR7YOVc7FcozlU,1277
99
+ jac_client/tests/fixtures/with-ts/app.jac,sha256=jTHQX6OysUESeoHYFFqvXk4SOlcg_g5kiN460BYCNHI,977
100
+ jac_client-0.2.9.dist-info/METADATA,sha256=1AoSxeEJvir7JERxTi1I1sj2UEpUqCUW1QgNOJ_XG_I,5505
101
+ jac_client-0.2.9.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
102
+ jac_client-0.2.9.dist-info/entry_points.txt,sha256=fVrlaJKcSa2DK2hcfR6bNaQDB9mszMpZeEa6pitMdt4,154
103
+ jac_client-0.2.9.dist-info/top_level.txt,sha256=u1VEBfiqwRrZEopKraIh-Ym55qSnDZR3Q5xdw2HinhU,11
104
+ jac_client-0.2.9.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5