jac-client 0.2.3__py3-none-any.whl → 0.2.8__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 (224) hide show
  1. jac_client/examples/all-in-one/app.jac +494 -347
  2. jac_client/examples/all-in-one/assets/workers/worker.py +5 -0
  3. jac_client/examples/all-in-one/button.jac +1 -1
  4. jac_client/examples/all-in-one/components/CategoryFilter.jac +35 -0
  5. jac_client/examples/all-in-one/components/Header.jac +13 -0
  6. jac_client/examples/all-in-one/components/ProfitOverview.jac +50 -0
  7. jac_client/examples/all-in-one/components/Summary.jac +53 -0
  8. jac_client/examples/all-in-one/components/TransactionForm.jac +158 -0
  9. jac_client/examples/all-in-one/components/TransactionItem.jac +55 -0
  10. jac_client/examples/all-in-one/components/TransactionList.jac +37 -0
  11. jac_client/examples/all-in-one/components/button.jac +1 -1
  12. jac_client/examples/all-in-one/components/navigation.jac +132 -0
  13. jac_client/examples/all-in-one/constants/categories.jac +37 -0
  14. jac_client/examples/all-in-one/constants/clients.jac +13 -0
  15. jac_client/examples/all-in-one/context/BudgetContext.jac +28 -0
  16. jac_client/examples/all-in-one/hooks/useBudget.jac +116 -0
  17. jac_client/examples/all-in-one/hooks/useLocalStorage.jac +36 -0
  18. jac_client/examples/all-in-one/pages/BudgetPlanner.cl.jac +70 -0
  19. jac_client/examples/all-in-one/pages/BudgetPlanner.jac +126 -0
  20. jac_client/examples/all-in-one/pages/FeaturesTest.cl.jac +552 -0
  21. jac_client/examples/all-in-one/pages/FeaturesTest.jac +126 -0
  22. jac_client/examples/all-in-one/pages/LandingPage.jac +101 -0
  23. jac_client/examples/all-in-one/pages/loginPage.jac +132 -0
  24. jac_client/examples/all-in-one/pages/nestedDemo.jac +61 -0
  25. jac_client/examples/all-in-one/pages/notFound.jac +24 -0
  26. jac_client/examples/all-in-one/pages/signupPage.jac +133 -0
  27. jac_client/examples/all-in-one/utils/formatters.jac +52 -0
  28. jac_client/examples/asset-serving/css-with-image/{app.jac → src/app.jac} +4 -4
  29. jac_client/examples/asset-serving/image-asset/{app.jac → src/app.jac} +4 -4
  30. jac_client/examples/asset-serving/import-alias/{app.jac → src/app.jac} +5 -5
  31. jac_client/examples/basic/{app.jac → src/app.jac} +4 -4
  32. jac_client/examples/basic-auth/src/app.jac +371 -0
  33. jac_client/examples/basic-auth-with-router/{app.jac → src/app.jac} +28 -28
  34. jac_client/examples/basic-full-stack/{app.jac → src/app.jac} +166 -127
  35. jac_client/examples/css-styling/js-styling/{app.jac → src/app.jac} +7 -7
  36. jac_client/examples/css-styling/material-ui/{app.jac → src/app.jac} +6 -6
  37. jac_client/examples/css-styling/pure-css/{app.jac → src/app.jac} +7 -7
  38. jac_client/examples/css-styling/sass-example/{app.jac → src/app.jac} +7 -7
  39. jac_client/examples/css-styling/styled-components/{app.jac → src/app.jac} +6 -6
  40. jac_client/examples/css-styling/tailwind-example/{app.jac → src/app.jac} +7 -7
  41. jac_client/examples/full-stack-with-auth/{app.jac → src/app.jac} +47 -47
  42. jac_client/examples/little-x/{app.jac → src/app.jac} +27 -32
  43. jac_client/examples/little-x/src/submit-button.jac +16 -0
  44. jac_client/examples/nested-folders/nested-advance/{ButtonRoot.jac → src/ButtonRoot.jac} +1 -1
  45. jac_client/examples/nested-folders/nested-advance/{app.jac → src/app.jac} +1 -1
  46. jac_client/examples/nested-folders/nested-advance/{level1 → src/level1}/ButtonSecondL.jac +1 -1
  47. jac_client/examples/nested-folders/nested-advance/{level1 → src/level1}/Card.jac +1 -1
  48. jac_client/examples/nested-folders/nested-advance/{level1 → src/level1}/level2/ButtonThirdL.jac +1 -1
  49. jac_client/examples/nested-folders/nested-basic/{app.jac → src/app.jac} +2 -2
  50. jac_client/examples/nested-folders/nested-basic/{button.jac → src/button.jac} +1 -1
  51. jac_client/examples/nested-folders/nested-basic/{components → src/components}/button.jac +1 -1
  52. jac_client/examples/ts-support/src/app.jac +35 -0
  53. jac_client/examples/with-router/{app.jac → src/app.jac} +15 -15
  54. jac_client/plugin/cli.jac +504 -0
  55. jac_client/plugin/client.jac +45 -0
  56. jac_client/plugin/client_runtime.cl.jac +42 -0
  57. jac_client/plugin/impl/client.impl.jac +193 -0
  58. jac_client/plugin/impl/client_runtime.impl.jac +195 -0
  59. jac_client/plugin/impl/vite_client_bundle.impl.jac +72 -0
  60. jac_client/plugin/plugin_config.jac +195 -0
  61. jac_client/plugin/src/__init__.jac +20 -0
  62. jac_client/plugin/src/asset_processor.jac +33 -0
  63. jac_client/plugin/src/babel_processor.jac +18 -0
  64. jac_client/plugin/src/compiler.jac +67 -0
  65. jac_client/plugin/src/config_loader.jac +32 -0
  66. jac_client/plugin/src/impl/asset_processor.impl.jac +127 -0
  67. jac_client/plugin/src/impl/babel_processor.impl.jac +89 -0
  68. jac_client/plugin/src/impl/compiler.impl.jac +288 -0
  69. jac_client/plugin/src/impl/config_loader.impl.jac +119 -0
  70. jac_client/plugin/src/impl/import_processor.impl.jac +33 -0
  71. jac_client/plugin/src/impl/jac_to_js.impl.jac +41 -0
  72. jac_client/plugin/src/impl/package_installer.impl.jac +105 -0
  73. jac_client/plugin/src/impl/vite_bundler.impl.jac +626 -0
  74. jac_client/plugin/src/import_processor.jac +19 -0
  75. jac_client/plugin/src/jac_to_js.jac +35 -0
  76. jac_client/plugin/src/package_installer.jac +26 -0
  77. jac_client/plugin/src/vite_bundler.jac +44 -0
  78. jac_client/plugin/vite_client_bundle.jac +31 -0
  79. jac_client/tests/conftest.py +283 -0
  80. jac_client/tests/fixtures/basic-app/app.jac +2 -2
  81. jac_client/tests/fixtures/cl_file/app.cl.jac +2 -2
  82. jac_client/tests/fixtures/client_app_with_antd/app.jac +1 -1
  83. jac_client/tests/fixtures/js_import/app.jac +5 -5
  84. jac_client/tests/fixtures/spawn_test/app.jac +15 -18
  85. jac_client/tests/fixtures/with-ts/app.jac +35 -0
  86. jac_client/tests/test_cli.py +811 -0
  87. jac_client/tests/test_it.py +592 -97
  88. {jac_client-0.2.3.dist-info → jac_client-0.2.8.dist-info}/METADATA +41 -34
  89. jac_client-0.2.8.dist-info/RECORD +97 -0
  90. {jac_client-0.2.3.dist-info → jac_client-0.2.8.dist-info}/WHEEL +2 -1
  91. jac_client-0.2.8.dist-info/entry_points.txt +4 -0
  92. jac_client-0.2.8.dist-info/top_level.txt +1 -0
  93. jac_client/docs/README.md +0 -689
  94. jac_client/docs/advanced-state.md +0 -1265
  95. jac_client/docs/asset-serving/intro.md +0 -209
  96. jac_client/docs/assets/pipe_line-v2.svg +0 -32
  97. jac_client/docs/assets/pipe_line.png +0 -0
  98. jac_client/docs/file-system/app.jac.md +0 -121
  99. jac_client/docs/file-system/backend-frontend.md +0 -217
  100. jac_client/docs/file-system/intro.md +0 -72
  101. jac_client/docs/file-system/nested-imports.md +0 -348
  102. jac_client/docs/guide-example/intro.md +0 -115
  103. jac_client/docs/guide-example/step-01-setup.md +0 -270
  104. jac_client/docs/guide-example/step-02-components.md +0 -416
  105. jac_client/docs/guide-example/step-03-styling.md +0 -478
  106. jac_client/docs/guide-example/step-04-todo-ui.md +0 -477
  107. jac_client/docs/guide-example/step-05-local-state.md +0 -530
  108. jac_client/docs/guide-example/step-06-events.md +0 -749
  109. jac_client/docs/guide-example/step-07-effects.md +0 -468
  110. jac_client/docs/guide-example/step-08-walkers.md +0 -534
  111. jac_client/docs/guide-example/step-09-authentication.md +0 -586
  112. jac_client/docs/guide-example/step-10-routing.md +0 -539
  113. jac_client/docs/guide-example/step-11-final.md +0 -963
  114. jac_client/docs/imports.md +0 -1141
  115. jac_client/docs/lifecycle-hooks.md +0 -773
  116. jac_client/docs/routing.md +0 -659
  117. jac_client/docs/styling/intro.md +0 -249
  118. jac_client/docs/styling/js-styling.md +0 -367
  119. jac_client/docs/styling/material-ui.md +0 -341
  120. jac_client/docs/styling/pure-css.md +0 -299
  121. jac_client/docs/styling/sass.md +0 -403
  122. jac_client/docs/styling/styled-components.md +0 -395
  123. jac_client/docs/styling/tailwind.md +0 -298
  124. jac_client/examples/all-in-one/.babelrc +0 -9
  125. jac_client/examples/all-in-one/README.md +0 -16
  126. jac_client/examples/all-in-one/assets/burger.png +0 -0
  127. jac_client/examples/all-in-one/package.json +0 -29
  128. jac_client/examples/all-in-one/styles.css +0 -26
  129. jac_client/examples/all-in-one/vite.config.js +0 -28
  130. jac_client/examples/asset-serving/css-with-image/.babelrc +0 -9
  131. jac_client/examples/asset-serving/css-with-image/README.md +0 -91
  132. jac_client/examples/asset-serving/css-with-image/assets/burger.png +0 -0
  133. jac_client/examples/asset-serving/css-with-image/package.json +0 -28
  134. jac_client/examples/asset-serving/css-with-image/styles.css +0 -26
  135. jac_client/examples/asset-serving/css-with-image/vite.config.js +0 -28
  136. jac_client/examples/asset-serving/image-asset/.babelrc +0 -9
  137. jac_client/examples/asset-serving/image-asset/README.md +0 -119
  138. jac_client/examples/asset-serving/image-asset/assets/burger.png +0 -0
  139. jac_client/examples/asset-serving/image-asset/package.json +0 -28
  140. jac_client/examples/asset-serving/image-asset/styles.css +0 -26
  141. jac_client/examples/asset-serving/image-asset/vite.config.js +0 -28
  142. jac_client/examples/asset-serving/import-alias/.babelrc +0 -9
  143. jac_client/examples/asset-serving/import-alias/README.md +0 -83
  144. jac_client/examples/asset-serving/import-alias/assets/burger.png +0 -0
  145. jac_client/examples/asset-serving/import-alias/package.json +0 -28
  146. jac_client/examples/asset-serving/import-alias/vite.config.js +0 -28
  147. jac_client/examples/basic/.babelrc +0 -9
  148. jac_client/examples/basic/README.md +0 -16
  149. jac_client/examples/basic/package.json +0 -27
  150. jac_client/examples/basic/vite.config.js +0 -27
  151. jac_client/examples/basic-auth/.babelrc +0 -9
  152. jac_client/examples/basic-auth/README.md +0 -16
  153. jac_client/examples/basic-auth/app.jac +0 -308
  154. jac_client/examples/basic-auth/package.json +0 -27
  155. jac_client/examples/basic-auth/vite.config.js +0 -27
  156. jac_client/examples/basic-auth-with-router/.babelrc +0 -9
  157. jac_client/examples/basic-auth-with-router/README.md +0 -60
  158. jac_client/examples/basic-auth-with-router/package.json +0 -28
  159. jac_client/examples/basic-auth-with-router/vite.config.js +0 -27
  160. jac_client/examples/basic-full-stack/.babelrc +0 -9
  161. jac_client/examples/basic-full-stack/README.md +0 -18
  162. jac_client/examples/basic-full-stack/package.json +0 -28
  163. jac_client/examples/basic-full-stack/vite.config.js +0 -27
  164. jac_client/examples/css-styling/js-styling/.babelrc +0 -9
  165. jac_client/examples/css-styling/js-styling/README.md +0 -183
  166. jac_client/examples/css-styling/js-styling/package.json +0 -28
  167. jac_client/examples/css-styling/js-styling/styles.js +0 -100
  168. jac_client/examples/css-styling/js-styling/vite.config.js +0 -27
  169. jac_client/examples/css-styling/material-ui/.babelrc +0 -9
  170. jac_client/examples/css-styling/material-ui/README.md +0 -16
  171. jac_client/examples/css-styling/material-ui/package.json +0 -32
  172. jac_client/examples/css-styling/material-ui/vite.config.js +0 -27
  173. jac_client/examples/css-styling/pure-css/.babelrc +0 -9
  174. jac_client/examples/css-styling/pure-css/README.md +0 -16
  175. jac_client/examples/css-styling/pure-css/package.json +0 -28
  176. jac_client/examples/css-styling/pure-css/styles.css +0 -111
  177. jac_client/examples/css-styling/pure-css/vite.config.js +0 -27
  178. jac_client/examples/css-styling/sass-example/.babelrc +0 -9
  179. jac_client/examples/css-styling/sass-example/README.md +0 -16
  180. jac_client/examples/css-styling/sass-example/package.json +0 -29
  181. jac_client/examples/css-styling/sass-example/styles.scss +0 -153
  182. jac_client/examples/css-styling/sass-example/vite.config.js +0 -27
  183. jac_client/examples/css-styling/styled-components/.babelrc +0 -9
  184. jac_client/examples/css-styling/styled-components/README.md +0 -16
  185. jac_client/examples/css-styling/styled-components/package.json +0 -29
  186. jac_client/examples/css-styling/styled-components/styled.js +0 -90
  187. jac_client/examples/css-styling/styled-components/vite.config.js +0 -27
  188. jac_client/examples/css-styling/tailwind-example/.babelrc +0 -9
  189. jac_client/examples/css-styling/tailwind-example/README.md +0 -16
  190. jac_client/examples/css-styling/tailwind-example/global.css +0 -1
  191. jac_client/examples/css-styling/tailwind-example/package.json +0 -30
  192. jac_client/examples/css-styling/tailwind-example/vite.config.js +0 -29
  193. jac_client/examples/full-stack-with-auth/.babelrc +0 -9
  194. jac_client/examples/full-stack-with-auth/README.md +0 -16
  195. jac_client/examples/full-stack-with-auth/package.json +0 -28
  196. jac_client/examples/full-stack-with-auth/vite.config.js +0 -29
  197. jac_client/examples/little-x/package.json +0 -23
  198. jac_client/examples/little-x/submit-button.jac +0 -8
  199. jac_client/examples/nested-folders/nested-advance/.babelrc +0 -9
  200. jac_client/examples/nested-folders/nested-advance/README.md +0 -77
  201. jac_client/examples/nested-folders/nested-advance/package.json +0 -29
  202. jac_client/examples/nested-folders/nested-advance/vite.config.js +0 -28
  203. jac_client/examples/nested-folders/nested-basic/.babelrc +0 -9
  204. jac_client/examples/nested-folders/nested-basic/README.md +0 -183
  205. jac_client/examples/nested-folders/nested-basic/app.js +0 -7
  206. jac_client/examples/nested-folders/nested-basic/package.json +0 -28
  207. jac_client/examples/nested-folders/nested-basic/vite.config.js +0 -27
  208. jac_client/examples/with-router/.babelrc +0 -9
  209. jac_client/examples/with-router/README.md +0 -17
  210. jac_client/examples/with-router/package.json +0 -28
  211. jac_client/examples/with-router/vite.config.js +0 -27
  212. jac_client/plugin/cli.py +0 -244
  213. jac_client/plugin/client.py +0 -152
  214. jac_client/plugin/client_runtime.jac +0 -234
  215. jac_client/plugin/vite_client_bundle.py +0 -503
  216. jac_client/tests/fixtures/js_import/utils.js +0 -21
  217. jac_client/tests/fixtures/package-lock.json +0 -329
  218. jac_client/tests/fixtures/package.json +0 -11
  219. jac_client/tests/test_asset_examples.py +0 -322
  220. jac_client/tests/test_cl.py +0 -530
  221. jac_client/tests/test_create_jac_app.py +0 -131
  222. jac_client/tests/test_nested_file.py +0 -374
  223. jac_client-0.2.3.dist-info/RECORD +0 -171
  224. jac_client-0.2.3.dist-info/entry_points.txt +0 -4
@@ -1,152 +0,0 @@
1
- import hashlib
2
- import html
3
- import mimetypes
4
- import types
5
- from http.server import BaseHTTPRequestHandler
6
- from pathlib import Path
7
- from typing import Any, Literal, TypeAlias
8
-
9
- from jaclang.runtimelib.client_bundle import ClientBundle
10
- from jaclang.runtimelib.runtime import (
11
- JacRuntime as Jac,
12
- )
13
- from jaclang.runtimelib.runtime import (
14
- hookimpl,
15
- )
16
- from jaclang.runtimelib.server import ModuleIntrospector
17
-
18
- from .vite_client_bundle import ViteClientBundleBuilder
19
-
20
- JsonValue: TypeAlias = (
21
- None | str | int | float | bool | list["JsonValue"] | dict[str, "JsonValue"]
22
- )
23
- StatusCode: TypeAlias = Literal[200, 201, 400, 401, 404, 503]
24
-
25
-
26
- class JacClientModuleIntrospector(ModuleIntrospector):
27
- """Jac Client Module Introspector."""
28
-
29
- def render_page(
30
- self, function_name: str, args: dict[str, Any], username: str
31
- ) -> dict[str, Any]:
32
- """Render HTML page for client function using the Vite bundle."""
33
- self.load()
34
-
35
- available_exports = set(self._client_manifest.get("exports", [])) or set(
36
- self.get_client_functions().keys()
37
- )
38
- if function_name not in available_exports:
39
- raise ValueError(f"Client function '{function_name}' not found")
40
-
41
- bundle_hash = self.ensure_bundle()
42
-
43
- # Find CSS file in dist directory
44
- base_path = Path(Jac.base_path_dir)
45
- dist_dir = base_path / "dist"
46
- css_link = ""
47
-
48
- # Try to find CSS file (main.css is the default Vite output)
49
- css_file = dist_dir / "main.css"
50
- if css_file.exists():
51
- css_hash = hashlib.sha256(css_file.read_bytes()).hexdigest()[:8]
52
- css_link = (
53
- f'<link rel="stylesheet" href="/static/main.css?hash={css_hash}"/>'
54
- )
55
-
56
- head_content = f'<meta charset="utf-8"/>\n <title>{html.escape(function_name)}</title>'
57
- if css_link:
58
- head_content += f"\n {css_link}"
59
-
60
- page = (
61
- "<!DOCTYPE html>"
62
- '<html lang="en">'
63
- "<head>"
64
- f"{head_content}"
65
- "</head>"
66
- "<body>"
67
- '<div id="root"></div>'
68
- f'<script src="/static/client.js?hash={bundle_hash}" defer></script>'
69
- "</body>"
70
- "</html>"
71
- )
72
-
73
- return {
74
- "html": page,
75
- "bundle_hash": bundle_hash,
76
- "bundle_code": self._bundle.code,
77
- }
78
-
79
-
80
- class JacClient:
81
- """Jac Client."""
82
-
83
- @staticmethod
84
- @hookimpl
85
- def get_client_bundle_builder() -> ViteClientBundleBuilder:
86
- """Get the client bundle builder instance."""
87
- base_path = Path(Jac.base_path_dir)
88
- package_json_path = base_path / "package.json"
89
- output_dir = base_path / "dist"
90
- # Use the plugin's client_runtime.jac file
91
- runtime_path = Path(__file__).with_name("client_runtime.jac")
92
- return ViteClientBundleBuilder(
93
- runtime_path=runtime_path,
94
- vite_package_json=package_json_path,
95
- vite_output_dir=output_dir,
96
- vite_minify=False,
97
- )
98
-
99
- @staticmethod
100
- @hookimpl
101
- def build_client_bundle(
102
- module: types.ModuleType,
103
- force: bool = False,
104
- ) -> ClientBundle:
105
- """Build a client bundle for the supplied module."""
106
- builder = JacClient.get_client_bundle_builder()
107
- return builder.build(module, force=force)
108
-
109
- @staticmethod
110
- @hookimpl
111
- def get_module_introspector(
112
- module_name: str, base_path: str | None
113
- ) -> ModuleIntrospector:
114
- """Get a module introspector for the supplied module."""
115
- return JacClientModuleIntrospector(module_name, base_path)
116
-
117
- @staticmethod
118
- @hookimpl
119
- def send_static_file(
120
- handler: BaseHTTPRequestHandler,
121
- file_path: Path,
122
- content_type: str | None = None,
123
- ) -> None:
124
- """Send static file response (images, fonts, etc.).
125
-
126
- Args:
127
- handler: HTTP request handler
128
- file_path: Path to the file to serve
129
- content_type: MIME type (auto-detected if None)
130
- """
131
- from jaclang.runtimelib.server import ResponseBuilder
132
-
133
- if not file_path.exists() or not file_path.is_file():
134
- ResponseBuilder.send_json(handler, 404, {"error": "File not found"})
135
- return
136
-
137
- try:
138
- file_content = file_path.read_bytes()
139
- if content_type is None:
140
- content_type, _ = mimetypes.guess_type(str(file_path))
141
- if content_type is None:
142
- content_type = "application/octet-stream"
143
-
144
- handler.send_response(200)
145
- handler.send_header("Content-Type", content_type)
146
- handler.send_header("Content-Length", str(len(file_content)))
147
- handler.send_header("Cache-Control", "public, max-age=3600")
148
- ResponseBuilder._add_cors_headers(handler)
149
- handler.end_headers()
150
- handler.wfile.write(file_content)
151
- except Exception as exc:
152
- ResponseBuilder.send_json(handler, 500, {"error": str(exc)})
@@ -1,234 +0,0 @@
1
- """Client-side runtime for Jac JSX and walker interactions."""
2
-
3
- cl import from 'react' { * as React }
4
- cl import from 'react-dom/client' { * as ReactDOM }
5
- cl import from 'react-router-dom' {
6
- HashRouter as ReactRouterHashRouter,
7
- Routes as ReactRouterRoutes,
8
- Route as ReactRouterRoute,
9
- Link as ReactRouterLink,
10
- Navigate as ReactRouterNavigate,
11
- useNavigate as reactRouterUseNavigate,
12
- useLocation as reactRouterUseLocation,
13
- useParams as reactRouterUseParams
14
- }
15
-
16
- cl {
17
- # JSX factory function - uses React.createElement
18
- def __jacJsx(tag: any, props: dict = {}, children: any = []) -> any {
19
- # Handle fragments: when tag is None/null, use React.Fragment
20
- if tag == None {
21
- tag = React.Fragment;
22
- }
23
-
24
- childrenArray = [];
25
- if children != None {
26
- if Array.isArray(children) {
27
- childrenArray = children;
28
- } else {
29
- childrenArray = [children];
30
- }
31
- }
32
-
33
- # Filter out null/undefined children
34
- reactChildren = [];
35
- for child in childrenArray {
36
- if child != None {
37
- reactChildren.push(child);
38
- }
39
- }
40
-
41
- if reactChildren.length > 0 {
42
- args = [tag, props];
43
- for child in reactChildren {
44
- args.push(child);
45
- }
46
- return React.createElement.apply(React, args);
47
- } else {
48
- return React.createElement(tag, props);
49
- }
50
- }
51
-
52
- # ============================================================================
53
- # React Router Integration (using react-router-dom v6)
54
- # ============================================================================
55
- # Direct re-exports of React Router components for seamless integration
56
- # Router uses HashRouter for hash-based routing (#/path)
57
- # See: https://reactrouter.com/6.30.1/router-components/hash-router
58
- let Router = ReactRouterHashRouter;
59
- let Routes = ReactRouterRoutes;
60
- let Route = ReactRouterRoute;
61
- let Link = ReactRouterLink;
62
- let Navigate = ReactRouterNavigate;
63
-
64
- # React Router Hooks - wrapped for Jac compatibility
65
- let useNavigate = reactRouterUseNavigate;
66
- let useLocation = reactRouterUseLocation;
67
- let useParams = reactRouterUseParams;
68
-
69
- # useRouter Hook - convenience hook that combines common router utilities
70
- def useRouter() -> dict {
71
- navigate = reactRouterUseNavigate();
72
- location = reactRouterUseLocation();
73
- params = reactRouterUseParams();
74
-
75
- return {
76
- "navigate": navigate,
77
- "location": location,
78
- "params": params,
79
- "pathname": location.pathname,
80
- "search": location.search,
81
- "hash": location.hash
82
- };
83
- }
84
-
85
- # navigate function - programmatic navigation (backward compatibility)
86
- # Note: Use useNavigate() hook inside components instead
87
- def navigate(path: str) -> None {
88
- window.location.hash = "#" + path;
89
- }
90
-
91
- # ============================================================================
92
- # Walker spawn function
93
- # ============================================================================
94
- async def __jacSpawn(left: str, right: str = "", fields: dict = {}) -> any {
95
- token = __getLocalStorage("jac_token");
96
- url = f"/walker/{left}";
97
- if right != "" {
98
- url = f"/walker/{left}/{right}";
99
- }
100
- response = await fetch(
101
- url,
102
- {
103
- "method": "POST",
104
- "accept": "application/json",
105
- "headers": {
106
- "Content-Type": "application/json",
107
- "Authorization": f"Bearer {token}" if token else ""
108
- },
109
- "body": JSON.stringify(fields)
110
- }
111
- );
112
-
113
- if not response.ok {
114
- error_text = await response.json();
115
- raise Exception(f"Walker {walker} failed: {error_text}") ;
116
- }
117
-
118
- return await response.json();
119
- }
120
-
121
- def jacSpawn(left: str, right: str = "", fields: dict = {}) -> any {
122
- return __jacSpawn(left, right, fields);
123
- }
124
-
125
- # Function call function - calls server-side functions from client
126
- async def __jacCallFunction(function_name: str, args: dict = {}) -> any {
127
- token = __getLocalStorage("jac_token");
128
-
129
- response = await fetch(
130
- f"/function/{function_name}",
131
- {
132
- "method": "POST",
133
- "headers": {
134
- "Content-Type": "application/json",
135
- "Authorization": f"Bearer {token}" if token else ""
136
- },
137
- "body": JSON.stringify({"args": args})
138
- }
139
- );
140
-
141
- if not response.ok {
142
- error_text = await response.text();
143
- raise Exception(f"Function {function_name} failed: {error_text}") ;
144
- }
145
-
146
- data = JSON.parse(await response.text());
147
- return data["result"];
148
- }
149
-
150
- # Authentication helpers
151
- async def jacSignup(username: str, password: str) -> dict {
152
- response = await fetch(
153
- "/user/create",
154
- {
155
- "method": "POST",
156
- "headers": {"Content-Type": "application/json"},
157
- "body": JSON.stringify({"username": username, "password": password})
158
- }
159
- );
160
-
161
- if response.ok {
162
- data = JSON.parse(await response.text());
163
- token = data["token"];
164
- if token {
165
- __setLocalStorage("jac_token", token);
166
- return {"success": True, "token": token, "username": username};
167
- }
168
- return {"success": False, "error": "No token received"};
169
- } else {
170
- error_text = await response.text();
171
- try {
172
- error_data = JSON.parse(error_text);
173
- return {
174
- "success": False,
175
- "error": error_data["error"]
176
- if error_data["error"] != None
177
- else "Signup failed"
178
- };
179
- } except Exception {
180
- return {"success": False, "error": error_text};
181
- }
182
- }
183
- }
184
-
185
- async def jacLogin(username: str, password: str) -> bool {
186
- response = await fetch(
187
- "/user/login",
188
- {
189
- "method": "POST",
190
- "headers": {"Content-Type": "application/json"},
191
- "body": JSON.stringify({"username": username, "password": password})
192
- }
193
- );
194
-
195
- if response.ok {
196
- data = JSON.parse(await response.text());
197
- token = data["token"];
198
- if token {
199
- __setLocalStorage("jac_token", token);
200
- return True;
201
- }
202
- }
203
- return False;
204
- }
205
-
206
- def jacLogout() -> None {
207
- __removeLocalStorage("jac_token");
208
- }
209
-
210
- def jacIsLoggedIn() -> bool {
211
- token = __getLocalStorage("jac_token");
212
- return token != None and token != "";
213
- }
214
-
215
- # Browser API shims
216
- def __getLocalStorage(key: str) -> str {
217
- storage = globalThis.localStorage;
218
- return storage.getItem(key) if storage else "";
219
- }
220
-
221
- def __setLocalStorage(key: str, value: str) -> None {
222
- storage = globalThis.localStorage;
223
- if storage {
224
- storage.setItem(key, value);
225
- }
226
- }
227
-
228
- def __removeLocalStorage(key: str) -> None {
229
- storage = globalThis.localStorage;
230
- if storage {
231
- storage.removeItem(key);
232
- }
233
- }
234
- }