jac-client 0.2.3__py3-none-any.whl → 0.2.5__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 (202) hide show
  1. jac_client/examples/all-in-one/assets/workers/worker.py +5 -0
  2. jac_client/examples/all-in-one/src/app.jac +841 -0
  3. jac_client/examples/all-in-one/{button.jac → src/button.jac} +1 -1
  4. jac_client/examples/all-in-one/{components → src/components}/button.jac +1 -1
  5. jac_client/examples/asset-serving/css-with-image/{app.jac → src/app.jac} +2 -2
  6. jac_client/examples/asset-serving/image-asset/{app.jac → src/app.jac} +2 -2
  7. jac_client/examples/asset-serving/import-alias/{app.jac → src/app.jac} +3 -3
  8. jac_client/examples/basic/{app.jac → src/app.jac} +2 -2
  9. jac_client/examples/basic-auth/src/app.jac +377 -0
  10. jac_client/examples/basic-auth-with-router/{app.jac → src/app.jac} +18 -18
  11. jac_client/examples/basic-full-stack/{app.jac → src/app.jac} +175 -130
  12. jac_client/examples/css-styling/js-styling/{app.jac → src/app.jac} +6 -6
  13. jac_client/examples/css-styling/material-ui/{app.jac → src/app.jac} +5 -5
  14. jac_client/examples/css-styling/pure-css/{app.jac → src/app.jac} +6 -6
  15. jac_client/examples/css-styling/sass-example/{app.jac → src/app.jac} +6 -6
  16. jac_client/examples/css-styling/styled-components/{app.jac → src/app.jac} +5 -5
  17. jac_client/examples/css-styling/tailwind-example/{app.jac → src/app.jac} +6 -6
  18. jac_client/examples/full-stack-with-auth/{app.jac → src/app.jac} +37 -37
  19. jac_client/examples/little-x/{app.jac → src/app.jac} +27 -32
  20. jac_client/examples/little-x/src/submit-button.jac +16 -0
  21. jac_client/examples/nested-folders/nested-advance/{ButtonRoot.jac → src/ButtonRoot.jac} +1 -1
  22. jac_client/examples/nested-folders/nested-advance/{app.jac → src/app.jac} +1 -1
  23. jac_client/examples/nested-folders/nested-advance/{level1 → src/level1}/ButtonSecondL.jac +1 -1
  24. jac_client/examples/nested-folders/nested-advance/{level1 → src/level1}/Card.jac +1 -1
  25. jac_client/examples/nested-folders/nested-advance/{level1 → src/level1}/level2/ButtonThirdL.jac +1 -1
  26. jac_client/examples/nested-folders/nested-basic/{app.jac → src/app.jac} +2 -2
  27. jac_client/examples/nested-folders/nested-basic/{button.jac → src/button.jac} +1 -1
  28. jac_client/examples/nested-folders/nested-basic/{components → src/components}/button.jac +1 -1
  29. jac_client/examples/ts-support/src/app.jac +35 -0
  30. jac_client/examples/with-router/{app.jac → src/app.jac} +11 -11
  31. jac_client/plugin/cli.jac +547 -0
  32. jac_client/plugin/client.jac +52 -0
  33. jac_client/plugin/client_runtime.cl.jac +38 -0
  34. jac_client/plugin/impl/client.impl.jac +134 -0
  35. jac_client/plugin/impl/client_runtime.impl.jac +177 -0
  36. jac_client/plugin/impl/vite_client_bundle.impl.jac +72 -0
  37. jac_client/plugin/plugin_config.jac +195 -0
  38. jac_client/plugin/src/__init__.jac +20 -0
  39. jac_client/plugin/src/asset_processor.jac +33 -0
  40. jac_client/plugin/src/babel_processor.jac +18 -0
  41. jac_client/plugin/src/compiler.jac +66 -0
  42. jac_client/plugin/src/config_loader.jac +32 -0
  43. jac_client/plugin/src/impl/asset_processor.impl.jac +127 -0
  44. jac_client/plugin/src/impl/babel_processor.impl.jac +84 -0
  45. jac_client/plugin/src/impl/compiler.impl.jac +251 -0
  46. jac_client/plugin/src/impl/config_loader.impl.jac +119 -0
  47. jac_client/plugin/src/impl/import_processor.impl.jac +33 -0
  48. jac_client/plugin/src/impl/jac_to_js.impl.jac +41 -0
  49. jac_client/plugin/src/impl/package_installer.impl.jac +105 -0
  50. jac_client/plugin/src/impl/vite_bundler.impl.jac +513 -0
  51. jac_client/plugin/src/import_processor.jac +19 -0
  52. jac_client/plugin/src/jac_to_js.jac +35 -0
  53. jac_client/plugin/src/package_installer.jac +26 -0
  54. jac_client/plugin/src/vite_bundler.jac +36 -0
  55. jac_client/plugin/vite_client_bundle.jac +31 -0
  56. jac_client/tests/conftest.py +281 -0
  57. jac_client/tests/fixtures/basic-app/app.jac +2 -2
  58. jac_client/tests/fixtures/cl_file/app.cl.jac +2 -2
  59. jac_client/tests/fixtures/client_app_with_antd/app.jac +1 -1
  60. jac_client/tests/fixtures/js_import/app.jac +5 -5
  61. jac_client/tests/fixtures/spawn_test/app.jac +7 -7
  62. jac_client/tests/fixtures/with-ts/app.jac +35 -0
  63. jac_client/tests/test_cli.py +755 -0
  64. jac_client/tests/test_it.py +347 -67
  65. {jac_client-0.2.3.dist-info → jac_client-0.2.5.dist-info}/METADATA +28 -30
  66. jac_client-0.2.5.dist-info/RECORD +74 -0
  67. {jac_client-0.2.3.dist-info → jac_client-0.2.5.dist-info}/WHEEL +2 -1
  68. jac_client-0.2.5.dist-info/entry_points.txt +4 -0
  69. jac_client-0.2.5.dist-info/top_level.txt +1 -0
  70. jac_client/docs/README.md +0 -689
  71. jac_client/docs/advanced-state.md +0 -1265
  72. jac_client/docs/asset-serving/intro.md +0 -209
  73. jac_client/docs/assets/pipe_line-v2.svg +0 -32
  74. jac_client/docs/assets/pipe_line.png +0 -0
  75. jac_client/docs/file-system/app.jac.md +0 -121
  76. jac_client/docs/file-system/backend-frontend.md +0 -217
  77. jac_client/docs/file-system/intro.md +0 -72
  78. jac_client/docs/file-system/nested-imports.md +0 -348
  79. jac_client/docs/guide-example/intro.md +0 -115
  80. jac_client/docs/guide-example/step-01-setup.md +0 -270
  81. jac_client/docs/guide-example/step-02-components.md +0 -416
  82. jac_client/docs/guide-example/step-03-styling.md +0 -478
  83. jac_client/docs/guide-example/step-04-todo-ui.md +0 -477
  84. jac_client/docs/guide-example/step-05-local-state.md +0 -530
  85. jac_client/docs/guide-example/step-06-events.md +0 -749
  86. jac_client/docs/guide-example/step-07-effects.md +0 -468
  87. jac_client/docs/guide-example/step-08-walkers.md +0 -534
  88. jac_client/docs/guide-example/step-09-authentication.md +0 -586
  89. jac_client/docs/guide-example/step-10-routing.md +0 -539
  90. jac_client/docs/guide-example/step-11-final.md +0 -963
  91. jac_client/docs/imports.md +0 -1141
  92. jac_client/docs/lifecycle-hooks.md +0 -773
  93. jac_client/docs/routing.md +0 -659
  94. jac_client/docs/styling/intro.md +0 -249
  95. jac_client/docs/styling/js-styling.md +0 -367
  96. jac_client/docs/styling/material-ui.md +0 -341
  97. jac_client/docs/styling/pure-css.md +0 -299
  98. jac_client/docs/styling/sass.md +0 -403
  99. jac_client/docs/styling/styled-components.md +0 -395
  100. jac_client/docs/styling/tailwind.md +0 -298
  101. jac_client/examples/all-in-one/.babelrc +0 -9
  102. jac_client/examples/all-in-one/README.md +0 -16
  103. jac_client/examples/all-in-one/app.jac +0 -426
  104. jac_client/examples/all-in-one/assets/burger.png +0 -0
  105. jac_client/examples/all-in-one/package.json +0 -29
  106. jac_client/examples/all-in-one/styles.css +0 -26
  107. jac_client/examples/all-in-one/vite.config.js +0 -28
  108. jac_client/examples/asset-serving/css-with-image/.babelrc +0 -9
  109. jac_client/examples/asset-serving/css-with-image/README.md +0 -91
  110. jac_client/examples/asset-serving/css-with-image/assets/burger.png +0 -0
  111. jac_client/examples/asset-serving/css-with-image/package.json +0 -28
  112. jac_client/examples/asset-serving/css-with-image/styles.css +0 -26
  113. jac_client/examples/asset-serving/css-with-image/vite.config.js +0 -28
  114. jac_client/examples/asset-serving/image-asset/.babelrc +0 -9
  115. jac_client/examples/asset-serving/image-asset/README.md +0 -119
  116. jac_client/examples/asset-serving/image-asset/assets/burger.png +0 -0
  117. jac_client/examples/asset-serving/image-asset/package.json +0 -28
  118. jac_client/examples/asset-serving/image-asset/styles.css +0 -26
  119. jac_client/examples/asset-serving/image-asset/vite.config.js +0 -28
  120. jac_client/examples/asset-serving/import-alias/.babelrc +0 -9
  121. jac_client/examples/asset-serving/import-alias/README.md +0 -83
  122. jac_client/examples/asset-serving/import-alias/assets/burger.png +0 -0
  123. jac_client/examples/asset-serving/import-alias/package.json +0 -28
  124. jac_client/examples/asset-serving/import-alias/vite.config.js +0 -28
  125. jac_client/examples/basic/.babelrc +0 -9
  126. jac_client/examples/basic/README.md +0 -16
  127. jac_client/examples/basic/package.json +0 -27
  128. jac_client/examples/basic/vite.config.js +0 -27
  129. jac_client/examples/basic-auth/.babelrc +0 -9
  130. jac_client/examples/basic-auth/README.md +0 -16
  131. jac_client/examples/basic-auth/app.jac +0 -308
  132. jac_client/examples/basic-auth/package.json +0 -27
  133. jac_client/examples/basic-auth/vite.config.js +0 -27
  134. jac_client/examples/basic-auth-with-router/.babelrc +0 -9
  135. jac_client/examples/basic-auth-with-router/README.md +0 -60
  136. jac_client/examples/basic-auth-with-router/package.json +0 -28
  137. jac_client/examples/basic-auth-with-router/vite.config.js +0 -27
  138. jac_client/examples/basic-full-stack/.babelrc +0 -9
  139. jac_client/examples/basic-full-stack/README.md +0 -18
  140. jac_client/examples/basic-full-stack/package.json +0 -28
  141. jac_client/examples/basic-full-stack/vite.config.js +0 -27
  142. jac_client/examples/css-styling/js-styling/.babelrc +0 -9
  143. jac_client/examples/css-styling/js-styling/README.md +0 -183
  144. jac_client/examples/css-styling/js-styling/package.json +0 -28
  145. jac_client/examples/css-styling/js-styling/styles.js +0 -100
  146. jac_client/examples/css-styling/js-styling/vite.config.js +0 -27
  147. jac_client/examples/css-styling/material-ui/.babelrc +0 -9
  148. jac_client/examples/css-styling/material-ui/README.md +0 -16
  149. jac_client/examples/css-styling/material-ui/package.json +0 -32
  150. jac_client/examples/css-styling/material-ui/vite.config.js +0 -27
  151. jac_client/examples/css-styling/pure-css/.babelrc +0 -9
  152. jac_client/examples/css-styling/pure-css/README.md +0 -16
  153. jac_client/examples/css-styling/pure-css/package.json +0 -28
  154. jac_client/examples/css-styling/pure-css/styles.css +0 -111
  155. jac_client/examples/css-styling/pure-css/vite.config.js +0 -27
  156. jac_client/examples/css-styling/sass-example/.babelrc +0 -9
  157. jac_client/examples/css-styling/sass-example/README.md +0 -16
  158. jac_client/examples/css-styling/sass-example/package.json +0 -29
  159. jac_client/examples/css-styling/sass-example/styles.scss +0 -153
  160. jac_client/examples/css-styling/sass-example/vite.config.js +0 -27
  161. jac_client/examples/css-styling/styled-components/.babelrc +0 -9
  162. jac_client/examples/css-styling/styled-components/README.md +0 -16
  163. jac_client/examples/css-styling/styled-components/package.json +0 -29
  164. jac_client/examples/css-styling/styled-components/styled.js +0 -90
  165. jac_client/examples/css-styling/styled-components/vite.config.js +0 -27
  166. jac_client/examples/css-styling/tailwind-example/.babelrc +0 -9
  167. jac_client/examples/css-styling/tailwind-example/README.md +0 -16
  168. jac_client/examples/css-styling/tailwind-example/global.css +0 -1
  169. jac_client/examples/css-styling/tailwind-example/package.json +0 -30
  170. jac_client/examples/css-styling/tailwind-example/vite.config.js +0 -29
  171. jac_client/examples/full-stack-with-auth/.babelrc +0 -9
  172. jac_client/examples/full-stack-with-auth/README.md +0 -16
  173. jac_client/examples/full-stack-with-auth/package.json +0 -28
  174. jac_client/examples/full-stack-with-auth/vite.config.js +0 -29
  175. jac_client/examples/little-x/package.json +0 -23
  176. jac_client/examples/little-x/submit-button.jac +0 -8
  177. jac_client/examples/nested-folders/nested-advance/.babelrc +0 -9
  178. jac_client/examples/nested-folders/nested-advance/README.md +0 -77
  179. jac_client/examples/nested-folders/nested-advance/package.json +0 -29
  180. jac_client/examples/nested-folders/nested-advance/vite.config.js +0 -28
  181. jac_client/examples/nested-folders/nested-basic/.babelrc +0 -9
  182. jac_client/examples/nested-folders/nested-basic/README.md +0 -183
  183. jac_client/examples/nested-folders/nested-basic/app.js +0 -7
  184. jac_client/examples/nested-folders/nested-basic/package.json +0 -28
  185. jac_client/examples/nested-folders/nested-basic/vite.config.js +0 -27
  186. jac_client/examples/with-router/.babelrc +0 -9
  187. jac_client/examples/with-router/README.md +0 -17
  188. jac_client/examples/with-router/package.json +0 -28
  189. jac_client/examples/with-router/vite.config.js +0 -27
  190. jac_client/plugin/cli.py +0 -244
  191. jac_client/plugin/client.py +0 -152
  192. jac_client/plugin/client_runtime.jac +0 -234
  193. jac_client/plugin/vite_client_bundle.py +0 -503
  194. jac_client/tests/fixtures/js_import/utils.js +0 -21
  195. jac_client/tests/fixtures/package-lock.json +0 -329
  196. jac_client/tests/fixtures/package.json +0 -11
  197. jac_client/tests/test_asset_examples.py +0 -322
  198. jac_client/tests/test_cl.py +0 -530
  199. jac_client/tests/test_create_jac_app.py +0 -131
  200. jac_client/tests/test_nested_file.py +0 -374
  201. jac_client-0.2.3.dist-info/RECORD +0 -171
  202. jac_client-0.2.3.dist-info/entry_points.txt +0 -4
@@ -1,586 +0,0 @@
1
- # Step 9: Adding Authentication
2
-
3
- > ** Quick Tip:** Each step has two parts. **Part 1** shows you what to build. **Part 2** explains why it works. Want to just build? Skip all Part 2 sections!
4
-
5
- In this step, you'll add user authentication so each person has their own private todos!
6
-
7
- ---
8
-
9
- ## Part 1: Building the App
10
-
11
- ### Step 9.1: Import Authentication Functions
12
-
13
- Add these imports at the top of your `cl` block:
14
-
15
- ```jac
16
- cl import from react {useState, useEffect}
17
- cl import from "@jac-client/utils" {
18
- jacLogin,
19
- jacSignup,
20
- jacLogout,
21
- jacIsLoggedIn
22
- }
23
-
24
- cl {
25
- # ... your components
26
- }
27
- ```
28
-
29
- ### Step 9.2: Create the Login Page
30
-
31
- Add this component:
32
-
33
- ```jac
34
- def LoginPage() -> any {
35
- let [username, setUsername] = useState("");
36
- let [password, setPassword] = useState("");
37
- let [error, setError] = useState("");
38
-
39
- async def handleLogin(e: any) -> None {
40
- e.preventDefault();
41
- setError("");
42
-
43
- if not username or not password {
44
- setError("Please fill in all fields");
45
- return;
46
- }
47
-
48
- success = await jacLogin(username, password);
49
- if success {
50
- console.log("Login successful!");
51
- } else {
52
- setError("Invalid credentials");
53
- }
54
- }
55
-
56
- def handleUsernameChange(e: any) -> None {
57
- setUsername(e.target.value);
58
- }
59
-
60
- def handlePasswordChange(e: any) -> None {
61
- setPassword(e.target.value);
62
- }
63
-
64
- let errorDisplay = None;
65
- if error {
66
- errorDisplay = <div style={{
67
- "color": "#dc2626",
68
- "fontSize": "14px",
69
- "marginBottom": "10px"
70
- }}>
71
- {error}
72
- </div>;
73
- }
74
-
75
- return <div style={{
76
- "minHeight": "100vh",
77
- "display": "flex",
78
- "alignItems": "center",
79
- "justifyContent": "center",
80
- "background": "#f5f5f5"
81
- }}>
82
- <div style={{
83
- "background": "#ffffff",
84
- "padding": "30px",
85
- "borderRadius": "8px",
86
- "width": "280px",
87
- "boxShadow": "0 2px 4px rgba(0,0,0,0.1)"
88
- }}>
89
- <h2 style={{"marginBottom": "20px"}}>Login</h2>
90
- <form onSubmit={handleLogin}>
91
- <input
92
- type="text"
93
- value={username}
94
- onChange={handleUsernameChange}
95
- placeholder="Username"
96
- style={{
97
- "width": "100%",
98
- "padding": "8px",
99
- "marginBottom": "10px",
100
- "border": "1px solid #ddd",
101
- "borderRadius": "4px",
102
- "boxSizing": "border-box"
103
- }}
104
- />
105
- <input
106
- type="password"
107
- value={password}
108
- onChange={handlePasswordChange}
109
- placeholder="Password"
110
- style={{
111
- "width": "100%",
112
- "padding": "8px",
113
- "marginBottom": "10px",
114
- "border": "1px solid #ddd",
115
- "borderRadius": "4px",
116
- "boxSizing": "border-box"
117
- }}
118
- />
119
- {errorDisplay}
120
- <button
121
- type="submit"
122
- style={{
123
- "width": "100%",
124
- "padding": "8px",
125
- "background": "#3b82f6",
126
- "color": "#ffffff",
127
- "border": "none",
128
- "borderRadius": "4px",
129
- "cursor": "pointer",
130
- "fontWeight": "600"
131
- }}
132
- >
133
- Login
134
- </button>
135
- </form>
136
- <p style={{
137
- "textAlign": "center",
138
- "marginTop": "12px",
139
- "fontSize": "14px"
140
- }}>
141
- Need an account? Sign up link here
142
- </p>
143
- </div>
144
- </div>;
145
- }
146
- ```
147
-
148
- ### Step 9.3: Create the Signup Page
149
-
150
- Add this component:
151
-
152
- ```jac
153
- def SignupPage() -> any {
154
- let [username, setUsername] = useState("");
155
- let [password, setPassword] = useState("");
156
- let [error, setError] = useState("");
157
-
158
- async def handleSignup(e: any) -> None {
159
- e.preventDefault();
160
- setError("");
161
-
162
- if not username or not password {
163
- setError("Please fill in all fields");
164
- return;
165
- }
166
-
167
- result = await jacSignup(username, password);
168
- if result["success"] {
169
- console.log("Signup successful!");
170
- } else {
171
- setError(result["error"] if result["error"] else "Signup failed");
172
- }
173
- }
174
-
175
- def handleUsernameChange(e: any) -> None {
176
- setUsername(e.target.value);
177
- }
178
-
179
- def handlePasswordChange(e: any) -> None {
180
- setPassword(e.target.value);
181
- }
182
-
183
- let errorDisplay = None;
184
- if error {
185
- errorDisplay = <div style={{
186
- "color": "#dc2626",
187
- "fontSize": "14px",
188
- "marginBottom": "10px"
189
- }}>
190
- {error}
191
- </div>;
192
- }
193
-
194
- return <div style={{
195
- "minHeight": "100vh",
196
- "display": "flex",
197
- "alignItems": "center",
198
- "justifyContent": "center",
199
- "background": "#f5f5f5"
200
- }}>
201
- <div style={{
202
- "background": "#ffffff",
203
- "padding": "30px",
204
- "borderRadius": "8px",
205
- "width": "280px",
206
- "boxShadow": "0 2px 4px rgba(0,0,0,0.1)"
207
- }}>
208
- <h2 style={{"marginBottom": "20px"}}>Sign Up</h2>
209
- <form onSubmit={handleSignup}>
210
- <input
211
- type="text"
212
- value={username}
213
- onChange={handleUsernameChange}
214
- placeholder="Username"
215
- style={{
216
- "width": "100%",
217
- "padding": "8px",
218
- "marginBottom": "10px",
219
- "border": "1px solid #ddd",
220
- "borderRadius": "4px",
221
- "boxSizing": "border-box"
222
- }}
223
- />
224
- <input
225
- type="password"
226
- value={password}
227
- onChange={handlePasswordChange}
228
- placeholder="Password"
229
- style={{
230
- "width": "100%",
231
- "padding": "8px",
232
- "marginBottom": "10px",
233
- "border": "1px solid #ddd",
234
- "borderRadius": "4px",
235
- "boxSizing": "border-box"
236
- }}
237
- />
238
- {errorDisplay}
239
- <button
240
- type="submit"
241
- style={{
242
- "width": "100%",
243
- "padding": "8px",
244
- "background": "#3b82f6",
245
- "color": "#ffffff",
246
- "border": "none",
247
- "borderRadius": "4px",
248
- "cursor": "pointer",
249
- "fontWeight": "600"
250
- }}
251
- >
252
- Sign Up
253
- </button>
254
- </form>
255
- <p style={{
256
- "textAlign": "center",
257
- "marginTop": "12px",
258
- "fontSize": "14px"
259
- }}>
260
- Have an account? Login link here
261
- </p>
262
- </div>
263
- </div>;
264
- }
265
- ```
266
-
267
- ### Step 9.4: Test the Pages
268
-
269
- For now, update your `app()` function to show the login page:
270
-
271
- ```jac
272
- def app() -> any {
273
- return <LoginPage />;
274
- }
275
- ```
276
-
277
- **Try it!** You should see a login form. Try logging in (it won't work yet because we haven't created an account).
278
-
279
- Change it to show signup:
280
-
281
- ```jac
282
- def app() -> any {
283
- return <SignupPage />;
284
- }
285
- ```
286
-
287
- **Create an account!** Enter a username and password, then click "Sign Up". Check the browser console - you should see "Signup successful!"
288
-
289
- ### Step 9.5: Protect Your Todo Page
290
-
291
- Now let's make the todo page require login. Rename your current `app` function to `TodosPage`:
292
-
293
- ```jac
294
- # Rename app to TodosPage
295
- def TodosPage() -> any {
296
- # Check if user is logged in
297
- if not jacIsLoggedIn() {
298
- return <div style={{"padding": "20px"}}>
299
- <h1>Please login to view todos</h1>
300
- </div>;
301
- }
302
-
303
- # ... all your existing todo code (useState, useEffect, functions, return)
304
- }
305
- ```
306
-
307
- **What we did:**
308
- - Renamed `app` to `TodosPage`
309
- - Added a check: if not logged in, show a message
310
- - If logged in, show the todos
311
-
312
- **Try it!** You should see the "Please login" message (we'll add routing next to make this work properly).
313
-
314
- ---
315
-
316
- **⏭ Want to skip the theory?** Jump to [Step 10: Routing](./step-10-routing.md)
317
-
318
- ---
319
-
320
- ## Part 2: Understanding the Concepts
321
-
322
- ### What is Authentication?
323
-
324
- Authentication = Proving who you are
325
-
326
- **Real-world analogy:**
327
- - **ID card** - You show it to prove your identity
328
- - **Username/Password** - Same thing, but digital!
329
-
330
- ### Jac's Built-in Auth Functions
331
-
332
- ```jac
333
- # 1. Sign up a new user
334
- let result = await jacSignup(username, password);
335
-
336
- # 2. Log in an existing user
337
- let success = await jacLogin(username, password);
338
-
339
- # 3. Log out
340
- jacLogout();
341
-
342
- # 4. Check if logged in
343
- if jacIsLoggedIn() {
344
- // User is logged in
345
- }
346
- ```
347
-
348
- ### How jacSignup Works
349
-
350
- ```jac
351
- let result = await jacSignup("alice", "password123");
352
-
353
- // Returns:
354
- {
355
- "success": true, // or false if failed
356
- "error": null // or error message
357
- }
358
- ```
359
-
360
- **What happens:**
361
- 1. Jac creates a new user account
362
- 2. Hashes the password (secure!)
363
- 3. Creates a session token
364
- 4. Stores token in browser
365
- 5. Returns success/failure
366
-
367
- ### How jacLogin Works
368
-
369
- ```jac
370
- let success = await jacLogin("alice", "password123");
371
-
372
- // Returns:
373
- true // Login successful
374
- false // Login failed
375
- ```
376
-
377
- **What happens:**
378
- 1. Jac checks if user exists
379
- 2. Verifies password (securely)
380
- 3. Creates a session token
381
- 4. Stores token in browser
382
- 5. Returns true/false
383
-
384
- ### How jacLogout Works
385
-
386
- ```jac
387
- jacLogout();
388
- ```
389
-
390
- **What happens:**
391
- 1. Removes session token from browser
392
- 2. You're now logged out
393
- 3. Next API call will fail (not authenticated)
394
-
395
- ### How jacIsLoggedIn Works
396
-
397
- ```jac
398
- if jacIsLoggedIn() {
399
- // User is logged in
400
- } else {
401
- // User is NOT logged in
402
- }
403
- ```
404
-
405
- **What it checks:**
406
- 1. Is there a valid session token?
407
- 2. Has it expired?
408
- 3. Returns true/false
409
-
410
- ### Form Handling with onSubmit
411
-
412
- ```jac
413
- <form onSubmit={handleLogin}>
414
- <input type="text" />
415
- <button type="submit">Login</button>
416
- </form>
417
- ```
418
-
419
- **Key points:**
420
- - `onSubmit` fires when form is submitted
421
- - Submitting = clicking button OR pressing Enter
422
- - Always call `e.preventDefault()` to stop page reload
423
-
424
- ```jac
425
- async def handleLogin(e: any) -> None {
426
- e.preventDefault(); # Stop page reload!
427
- // Your login logic
428
- }
429
- ```
430
-
431
- ### Password Input Type
432
-
433
- ```jac
434
- <input type="password" /> # Hides characters (•••)
435
- <input type="text" /> # Shows characters (abc)
436
- ```
437
-
438
- Always use `type="password"` for passwords!
439
-
440
- ### Error Handling
441
-
442
- ```jac
443
- let [error, setError] = useState("");
444
-
445
- # Show error if exists
446
- {(<div style={{"color": "red"}}>{error}</div>) if error else None}
447
-
448
- # Set error
449
- setError("Invalid credentials");
450
-
451
- # Clear error
452
- setError("");
453
- ```
454
-
455
- ### Conditional Rendering for Auth
456
-
457
- ```jac
458
- def TodosPage() -> any {
459
- if not jacIsLoggedIn() {
460
- return <div>Please login</div>;
461
- }
462
-
463
- # User is logged in, show todos
464
- return <div>Your todos here</div>;
465
- }
466
- ```
467
-
468
- This pattern protects pages from unauthorized access!
469
-
470
- ### User Isolation
471
-
472
- **Magic happens automatically!**
473
-
474
- When you add authentication to walkers:
475
-
476
- ```jac
477
- walker read_todos {
478
- # No special code needed - Jac handles it!
479
- can read with `root entry {
480
- visit [-->(`?Todo)];
481
- }
482
- }
483
- ```
484
-
485
- Jac automatically:
486
- - Uses the logged-in user's root node
487
- - Each user sees only their own todos
488
- - No way to access other users' data
489
-
490
- ### Session Persistence
491
-
492
- Sessions persist across page refreshes!
493
-
494
- ```jac
495
- # User logs in
496
- await jacLogin("alice", "password123");
497
-
498
- # Refresh page
499
- # jacIsLoggedIn() still returns true!
500
-
501
- # Sessions last until:
502
- # 1. User logs out (jacLogout)
503
- # 2. Session expires (configurable)
504
- # 3. User clears browser data
505
- ```
506
-
507
- ---
508
-
509
- ## What You've Learned
510
-
511
- - What authentication is and why it's important
512
- - Using `jacSignup` to create accounts
513
- - Using `jacLogin` to log users in
514
- - Using `jacLogout` to log users out
515
- - Using `jacIsLoggedIn` to check auth status
516
- - Creating login and signup forms
517
- - Handling form submission
518
- - Protecting pages with auth checks
519
- - User isolation (each user sees only their data)
520
-
521
- ---
522
-
523
- ## Common Issues
524
-
525
- ### Issue: "Signup failed"
526
-
527
- **Check:**
528
- - Is the username already taken? Try a different one
529
- - Are username/password not empty?
530
- - Check browser console for errors
531
-
532
- ### Issue: Login says "Invalid credentials"
533
-
534
- **Check:**
535
- - Did you create an account first?
536
- - Is the username/password correct?
537
- - Usernames are case-sensitive!
538
-
539
- ### Issue: jacIsLoggedIn() always returns false
540
-
541
- **Check:**
542
- - Did you successfully login/signup?
543
- - Check browser console for errors
544
- - Try logging in again
545
-
546
- ### Issue: Can't create multiple accounts
547
-
548
- **Solution:** Each username can only be used once. Try different usernames:
549
- - alice, bob, carol
550
- - user1, user2, user3
551
- - test_alice, test_bob
552
-
553
- ---
554
-
555
- ## Quick Exercise
556
-
557
- Try adding a "Remember me" message:
558
-
559
- ```jac
560
- def LoginPage() -> any {
561
- let [username, setUsername] = useState("");
562
- let [password, setPassword] = useState("");
563
-
564
- # Check if already logged in
565
- if jacIsLoggedIn() {
566
- return <div style={{"padding": "20px"}}>
567
- <h2>You're already logged in!</h2>
568
- <button onClick={lambda -> None { jacLogout(); }}>
569
- Logout
570
- </button>
571
- </div>;
572
- }
573
-
574
- # ... rest of login form
575
- }
576
- ```
577
-
578
- ---
579
-
580
- ## Next Step
581
-
582
- Great! You now have authentication, but you're still showing only one page at a time.
583
-
584
- In the next step, we'll add **routing** so users can navigate between login, signup, and todos pages!
585
-
586
- **[Continue to Step 10: Routing](./step-10-routing.md)**