@zerotal/arch 1.7.0

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 (160) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/LICENSE +21 -0
  3. package/README.md +67 -0
  4. package/api-surface.md +283 -0
  5. package/docs/about.md +676 -0
  6. package/docs/admin/actions.md +183 -0
  7. package/docs/admin/auth.md +89 -0
  8. package/docs/admin/dashboard.md +155 -0
  9. package/docs/admin/extending-ui.md +229 -0
  10. package/docs/admin/extending.md +205 -0
  11. package/docs/admin/forms.md +155 -0
  12. package/docs/admin/index.md +144 -0
  13. package/docs/admin/operations.md +224 -0
  14. package/docs/admin/references.md +174 -0
  15. package/docs/admin/resources.md +132 -0
  16. package/docs/admin/structure.md +158 -0
  17. package/docs/admin/tables.md +185 -0
  18. package/docs/admin/testing.md +138 -0
  19. package/docs/ai.md +373 -0
  20. package/docs/application.md +435 -0
  21. package/docs/arch.md +263 -0
  22. package/docs/assets.md +755 -0
  23. package/docs/audit.md +367 -0
  24. package/docs/authentication.md +1000 -0
  25. package/docs/authorization.md +529 -0
  26. package/docs/broadcasting/channels.md +170 -0
  27. package/docs/broadcasting/client.md +108 -0
  28. package/docs/broadcasting/events.md +190 -0
  29. package/docs/broadcasting/index.md +163 -0
  30. package/docs/broadcasting/references.md +84 -0
  31. package/docs/broadcasting/testing.md +132 -0
  32. package/docs/cache.md +387 -0
  33. package/docs/carbon.md +830 -0
  34. package/docs/changelog.md +465 -0
  35. package/docs/client/auth.md +113 -0
  36. package/docs/client/errors.md +139 -0
  37. package/docs/client/files.md +118 -0
  38. package/docs/client/index.md +128 -0
  39. package/docs/client/references.md +58 -0
  40. package/docs/client/requests.md +131 -0
  41. package/docs/client/resilience.md +141 -0
  42. package/docs/client/testing.md +146 -0
  43. package/docs/commands.md +450 -0
  44. package/docs/components.md +2427 -0
  45. package/docs/config-system.md +258 -0
  46. package/docs/container.md +596 -0
  47. package/docs/context.md +579 -0
  48. package/docs/contributing.md +164 -0
  49. package/docs/controllers.md +354 -0
  50. package/docs/conventions.md +466 -0
  51. package/docs/cookies.md +101 -0
  52. package/docs/csrf.md +206 -0
  53. package/docs/database.md +476 -0
  54. package/docs/deployment.md +434 -0
  55. package/docs/devtools.md +1013 -0
  56. package/docs/email-verification.md +320 -0
  57. package/docs/encryption.md +380 -0
  58. package/docs/errors.md +317 -0
  59. package/docs/events.md +420 -0
  60. package/docs/flow/components.md +846 -0
  61. package/docs/flow/decorators.md +458 -0
  62. package/docs/flow/events.md +420 -0
  63. package/docs/flow/forms.md +551 -0
  64. package/docs/flow/index.md +568 -0
  65. package/docs/flow/layouts.md +793 -0
  66. package/docs/flow/lifecycle.md +336 -0
  67. package/docs/flow/pagination.md +402 -0
  68. package/docs/flow/performance.md +262 -0
  69. package/docs/flow/references.md +317 -0
  70. package/docs/flow/routing.md +550 -0
  71. package/docs/flow/testing.md +447 -0
  72. package/docs/getting-started.md +286 -0
  73. package/docs/health.md +269 -0
  74. package/docs/helpers.md +423 -0
  75. package/docs/i18n.md +414 -0
  76. package/docs/index.md +65 -0
  77. package/docs/inertia/build.md +95 -0
  78. package/docs/inertia/devtools.md +197 -0
  79. package/docs/inertia/index.md +267 -0
  80. package/docs/inertia/middleware.md +81 -0
  81. package/docs/inertia/props.md +507 -0
  82. package/docs/inertia/references.md +144 -0
  83. package/docs/inertia/rendering.md +189 -0
  84. package/docs/inertia/ssr.md +102 -0
  85. package/docs/inspirations.md +257 -0
  86. package/docs/lifecycle.md +331 -0
  87. package/docs/lock.md +454 -0
  88. package/docs/logger.md +517 -0
  89. package/docs/media.md +582 -0
  90. package/docs/middleware.md +509 -0
  91. package/docs/migrations.md +529 -0
  92. package/docs/monitor.md +377 -0
  93. package/docs/notifications.md +848 -0
  94. package/docs/orm/casts.md +365 -0
  95. package/docs/orm/factories.md +231 -0
  96. package/docs/orm/index.md +663 -0
  97. package/docs/orm/lifecycle.md +421 -0
  98. package/docs/orm/queries.md +692 -0
  99. package/docs/orm/relationships.md +440 -0
  100. package/docs/orm/serialization.md +251 -0
  101. package/docs/package-development.md +536 -0
  102. package/docs/pagination.md +340 -0
  103. package/docs/password-reset.md +335 -0
  104. package/docs/providers.md +447 -0
  105. package/docs/query-builder.md +465 -0
  106. package/docs/queue.md +549 -0
  107. package/docs/rate-limiting.md +253 -0
  108. package/docs/responses.md +336 -0
  109. package/docs/roles-and-2fa.md +418 -0
  110. package/docs/routing.md +1008 -0
  111. package/docs/scaffolding.md +335 -0
  112. package/docs/scheduler.md +533 -0
  113. package/docs/seeding.md +229 -0
  114. package/docs/session.md +451 -0
  115. package/docs/social.md +524 -0
  116. package/docs/storage.md +622 -0
  117. package/docs/structure.md +230 -0
  118. package/docs/support-policy.md +114 -0
  119. package/docs/telemetry.md +505 -0
  120. package/docs/tenancy.md +608 -0
  121. package/docs/testing/browser.md +153 -0
  122. package/docs/testing/console.md +130 -0
  123. package/docs/testing/database.md +238 -0
  124. package/docs/testing/flow-browser.md +216 -0
  125. package/docs/testing/http.md +441 -0
  126. package/docs/testing/index.md +240 -0
  127. package/docs/testing/mocking.md +410 -0
  128. package/docs/upgrade.md +192 -0
  129. package/docs/validator.md +549 -0
  130. package/docs/view.md +453 -0
  131. package/package.json +60 -0
  132. package/src/bin/mcp.ts +73 -0
  133. package/src/config.ts +63 -0
  134. package/src/errors.ts +27 -0
  135. package/src/index.ts +56 -0
  136. package/src/install/ArchInstallCommand.ts +189 -0
  137. package/src/install/detect.ts +98 -0
  138. package/src/install/guidelines.ts +290 -0
  139. package/src/install/markers.ts +77 -0
  140. package/src/install/mcpConfig.ts +81 -0
  141. package/src/mcp/index.ts +27 -0
  142. package/src/mcp/jsonrpc.ts +133 -0
  143. package/src/mcp/server.ts +307 -0
  144. package/src/mcp/stdio.ts +111 -0
  145. package/src/mcp/types.ts +146 -0
  146. package/src/probe/ArchProbeCommand.ts +48 -0
  147. package/src/probe/sentinel.ts +13 -0
  148. package/src/probe/topics.ts +291 -0
  149. package/src/provider/ArchProvider.ts +101 -0
  150. package/src/tools/_probe.ts +164 -0
  151. package/src/tools/apiSurface.ts +241 -0
  152. package/src/tools/appInfo.ts +88 -0
  153. package/src/tools/baselines.ts +210 -0
  154. package/src/tools/context.ts +37 -0
  155. package/src/tools/doctor.ts +93 -0
  156. package/src/tools/index.ts +50 -0
  157. package/src/tools/logs.ts +265 -0
  158. package/src/tools/routes.ts +133 -0
  159. package/src/tools/schema.ts +119 -0
  160. package/src/tools/searchDocs.ts +345 -0
@@ -0,0 +1,317 @@
1
+ ---
2
+ title: Flow Reference
3
+ description: Every decorator, prop, directive, and client global in one table.
4
+ ---
5
+
6
+ # References
7
+
8
+ Quick reference for all Flow JSX props, client expressions, and decorator combinations.
9
+
10
+ ## Commands
11
+
12
+ `@zerotal/flow` ships one generator:
13
+
14
+ | Command | What it does |
15
+ | -------------------------- | -------------------------------------------------------------------------------- |
16
+ | `bun zt make:flow Counter` | Create a Flow page or child component (`--child`, `--crud`, `--layout`, `--dir`) |
17
+
18
+ ## JSX props reference
19
+
20
+ Write these as ordinary JSX attributes. The right-hand column shows what each compiles to, for when you're inspecting rendered HTML.
21
+
22
+ ### Event binding
23
+
24
+ | You write | Behaviour | Compiles to |
25
+ | -------------------------- | ----------------------------------------------- | ------------------------------ |
26
+ | `onClick={this.method}` | Server action on click (round-trip) | `flow:click="method"` |
27
+ | `onClick={() => this.x++}` | Client expression, no round-trip | `flow:click="() => $flow.x++"` |
28
+ | `onSubmit={this.method}` | Server action on submit (auto-prevents default) | `flow:submit="method"` |
29
+ | `onChange={this.method}` | Server action on change | `flow:change="method"` |
30
+ | `onInput={this.method}` | Server action on input | `flow:input="method"` |
31
+ | `onKeydown={this.method}` | Server action on keydown | `flow:keydown="method"` |
32
+
33
+ ### Two-way binding
34
+
35
+ | You write | Behaviour | Compiles to |
36
+ | ------------------------- | ------------------------------------------------- | ------------------------- |
37
+ | `value={this.x}` | Two-way bind (`@expose`) or read-only (`@locked`) | `flow:model="x"` |
38
+ | `checked={this.x}` | Two-way checkbox bind | `flow:model="x"` |
39
+ | `value={this.x} live` | Sync to server on each keystroke | `flow:model.live="x"` |
40
+ | `value={this.x} blur` | Sync to server on blur | `flow:model.blur="x"` |
41
+ | `value={this.form.field}` | Nested form field binding | `flow:model="form.field"` |
42
+
43
+ ### Validation
44
+
45
+ | You write | Behaviour | Compiles to |
46
+ | --------------------------- | --------------------------------- | -------------------- |
47
+ | `error={this.errors.field}` | Reactive first validation message | `flow:error="field"` |
48
+
49
+ ### Reactive attributes
50
+
51
+ | You write | Behaviour | Compiles to |
52
+ | ---------------------------- | ------------------------------------------ | --------------- |
53
+ | `className={cond ? a : b}` | Reactive class, updates without round-trip | `:class="…"` |
54
+ | `class={cond ? a : b}` | Same as `className` | `:class="…"` |
55
+ | `style={{ color: this.x }}` | Reactive inline style | `:style="…"` |
56
+ | `href={"/posts/" + this.id}` | Reactive attribute | `:href="…"` |
57
+ | `disabled={this.saving}` | Reactive boolean attribute | `:disabled="…"` |
58
+
59
+ ### Loading states
60
+
61
+ Visual loading indicators (`showOnLoading`, `hideOnLoading`, `loadingClass`) wait out a short delay (~200ms) so a fast action never flashes them; `loadingAttr` is applied immediately (double-click guard).
62
+
63
+ | You write | Behaviour | Compiles to |
64
+ | ---------------------------- | --------------------------------------------------------------- | ------------------------------- |
65
+ | `loadingAttr="disabled"` | Sets `disabled` immediately while an action is in flight | `flow:loading.attr.disabled` |
66
+ | `showOnLoading` | Shows element while an action is in flight (after the delay) | `flow:loading` |
67
+ | `hideOnLoading` | Hides element while an action is in flight (after the delay) | `flow:loading.remove` |
68
+ | `loadingClass="opacity-50"` | Adds class while loading (after the delay) | `flow:loading.class.opacity-50` |
69
+ | `loadingTarget="save"` | Scope the loading state to specific action(s) (comma-separated) | `flow:target` |
70
+ | `loadingTargetExcept="poll"` | Scope loading to every action **except** these | `flow:target.except` |
71
+ | `showOnDirty` | Shows element when local state differs from server snapshot | `flow:dirty` |
72
+ | `hideOnDirty` | Hides element when local state is dirty | `flow:dirty.remove` |
73
+ | `showOnError` | Shows element after an action fails (optimistic failed state) | `flow:failed` |
74
+ | `hideOnError` | Hides element after an action fails | `flow:failed.remove` |
75
+
76
+ ### Visibility and control
77
+
78
+ | You write | Behaviour | Compiles to |
79
+ | ------------------------- | ----------------------------------------------- | ------------------ |
80
+ | `show={this.flag}` | Reactive show/hide off a boolean prop | `flow:show="flag"` |
81
+ | `confirm="Are you sure?"` | Browser confirm gate before the action fires | `flow:confirm` |
82
+ | `cloak` | Hidden until Alpine initialises (prevents FOUC) | `x-cloak` |
83
+
84
+ ### Navigation props
85
+
86
+ | You write | Behaviour | Compiles to |
87
+ | ----------------- | --------------------------------------------------------- | ----------------------------------- |
88
+ | `navigate` | SPA navigation to `href`, layout stays mounted | `flow:navigate` |
89
+ | `navigate hover` | Prefetch page on hover (~60ms debounce) | `flow:navigate flow:navigate.hover` |
90
+ | `current={false}` | Disable automatic `data-current` attribute | — |
91
+ | `exact` | `data-current` only on an exact URL match (not sub-pages) | `flow:current.exact` |
92
+
93
+ ### Polling
94
+
95
+ | You write | Behaviour | Compiles to |
96
+ | ------------------------------------------- | --------------------------------------------- | ----------- |
97
+ | `poll={{ every: "5s", action: this.tick }}` | Call action on an interval | `flow:poll` |
98
+ | `poll={{ every: "30s" }}` | Re-render on an interval (no specific action) | `flow:poll` |
99
+
100
+ ### Streaming props
101
+
102
+ | You write | Behaviour | Compiles to |
103
+ | -------------- | ------------------------------------------------ | ------------------- |
104
+ | `stream="ref"` | Target element for `this.stream("ref", content)` | `flow:stream="ref"` |
105
+
106
+ ### Intersection and visibility
107
+
108
+ | You write | Behaviour | Compiles to |
109
+ | --------------------------- | ------------------------------------------------ | ---------------- |
110
+ | `onIntersect={this.method}` | Call action when the element enters the viewport | `flow:intersect` |
111
+
112
+ ### Offline states
113
+
114
+ The client keeps a live WebSocket; when it drops (and while it reconnects with exponential back-off), Flow flips `body[data-flow-connection]` to `offline` and the props below react. Actions taken while offline are queued and replayed in order on reconnect, so the UI keeps working through a blip.
115
+
116
+ | You write | Behaviour | Compiles to |
117
+ | --------------------------- | --------------------------------------------- | --------------------- |
118
+ | `showOnOffline` | Show the element while the connection is down | `flow:offline` |
119
+ | `hideOnOffline` | Hide the element while the connection is down | `flow:offline.remove` |
120
+ | `offlineClass="opacity-50"` | Add a class while offline | `flow:offline.class` |
121
+ | `offlineAttr="disabled"` | Set an attribute while offline | `flow:offline.attr` |
122
+
123
+ #### Recovering from a drop mid-action
124
+
125
+ If the connection drops while an action is in flight, the client cannot tell whether it ran. The server is stateless per frame, so a completed action has already committed its database write — while the browser is still holding the state from before it. Guessing either way is wrong: replaying risks doing the work twice, discarding loses it.
126
+
127
+ So Flow re-derives instead. Any component left mid-action is refreshed from the server on reconnect (`onMount()` runs again and a fresh patch comes back), which lands on the truth whether the action ran or not. The same applies when an acknowledgement simply times out.
128
+
129
+ The refresh is announced first, so you can say something rather than have the UI change under the user:
130
+
131
+ ```ts
132
+ document.addEventListener("flow:desync", (e) => {
133
+ const { components } = (e as CustomEvent<{ components: string[] }>).detail;
134
+ toast(`Reconnected — refreshing ${components.length} component(s).`);
135
+ });
136
+ ```
137
+
138
+ ### Transitions
139
+
140
+ | You write | Behaviour | Compiles to |
141
+ | ------------ | ----------------------------------------------------------- | ----------------- |
142
+ | `transition` | Fade/slide the element in when the morph adds it to the DOM | `flow:transition` |
143
+
144
+ Tune the duration with the `--flow-transition-duration` CSS variable (default `200ms`).
145
+
146
+ ### Drag-and-drop reordering
147
+
148
+ Mark a container with `onSort` (the reorder action) and each child with `sortItem` (its stable key). Dragging a child calls the action as `reorder(key, newIndex)` on drop.
149
+
150
+ | You write | Behaviour | Compiles to |
151
+ | ----------------------- | -------------------------------------------------------- | ------------------ |
152
+ | `onSort={this.reorder}` | Reorder action on the container — `(key, index)` | `flow:sort` |
153
+ | `sortItem="id"` | Stable key of a draggable child | `flow:sort:item` |
154
+ | `sortHandle` | Restrict the drag grip to this element | `flow:sort:handle` |
155
+ | `sortIgnore` | Exclude this child from dragging/reordering | `flow:sort:ignore` |
156
+ | `sortGroup="tasks"` | Allow dragging between containers sharing the group name | `flow:sort:group` |
157
+
158
+ ```tsx
159
+ @expose async reorder(key: string, index: number) {
160
+ const moved = this.items.find((i) => String(i.id) === key);
161
+ if (!moved) return;
162
+ this.items = this.items.filter((i) => i !== moved);
163
+ this.items.splice(index, 0, moved);
164
+ await this.persistOrder();
165
+ }
166
+
167
+ override async render() {
168
+ return (
169
+ <ul onSort={this.reorder}>
170
+ {this.items.map((it) => (
171
+ <li key={String(it.id)} sortItem={String(it.id)}>{it.name}</li>
172
+ ))}
173
+ </ul>
174
+ );
175
+ }
176
+ ```
177
+
178
+ > A dynamic `sortItem={String(it.id)}` inside a `.map()` renders through the standard runtime (not the AOT fast path) — the drag behaviour is identical either way.
179
+
180
+ ### DOM utilities
181
+
182
+ | You write | Behaviour | Compiles to |
183
+ | ----------------- | ------------------------------------------------------------ | --------------- |
184
+ | `teleport="body"` | Move the element to a CSS selector target (modals, tooltips) | `flow:teleport` |
185
+ | `ref="name"` | Name this element as `$refs.name` for `this.client()` calls | `x-ref` |
186
+
187
+ ### Alpine plugins
188
+
189
+ | You write | Behaviour | Compiles to |
190
+ | ------------------------ | ----------------------------------------- | ------------ |
191
+ | `mask="(999) 999-9999"` | Format an input as the user types | `x-mask` |
192
+ | `trap="$flow.open"` | Trap focus while the expression is truthy | `x-trap` |
193
+ | `collapse` | Animate `x-show` with a height transition | `x-collapse` |
194
+ | `anchor="$refs.trigger"` | Float relative to another element | `x-anchor` |
195
+
196
+ ### Escape hatch
197
+
198
+ | You write | Behaviour |
199
+ | ---------------------------------------- | ------------------------------------------------------------ |
200
+ | `x-text="$flow.count"` | Raw Alpine attribute using live client state via `$flow` |
201
+ | `x-show="$flow.open && $flow.count > 0"` | Raw Alpine expression |
202
+ | `flow:click="increment"` | Hand-written Flow directive (accepted but not needed in JSX) |
203
+
204
+ ## Client expressions
205
+
206
+ Inside a client expression — `onClick={() => this.X(...)}` — `this.` resolves to the live client runtime (no server round-trip to start it). You write the **same names as on the server** — no `$`-prefixed syntax, and it all type-checks.
207
+
208
+ ### State manipulation
209
+
210
+ | Expression | Behaviour |
211
+ | ------------------------ | -------------------------------------------------------------------------------------------- |
212
+ | `this.count++` | Write to an `@expose` prop — updates the DOM instantly, then syncs so `render()` reflects it |
213
+ | `this.open = true` | Set any `@expose` prop; `@locked` props are read-only |
214
+ | `this.filter = "active"` | Works with any primitive value |
215
+
216
+ A write syncs to the server after the expression finishes, unless the same expression also calls a server action (that action's round-trip already carries it) or the value ends back where it started. Client-only UI state belongs in [`this.store()`](#global-client-store), which never round-trips.
217
+
218
+ ### Querying state
219
+
220
+ | Expression | Behaviour |
221
+ | ------------------- | ------------------------------------ |
222
+ | `this.count > 10` | Read any `@expose` or `@locked` prop |
223
+ | `this.user.name` | Nested property access |
224
+ | `this.posts.length` | Array methods and properties |
225
+
226
+ ### Navigation props and lifecycle
227
+
228
+ | Expression | Behaviour |
229
+ | --------------------------------------- | --------------------------------------------------------------------------------------- |
230
+ | `this.refresh()` | Request a fresh server render of this component |
231
+ | `this.currentUrl({ query, hash })` | Build a URL from the current one with merged query params (no navigation) — client-only |
232
+ | `this.navigateCurrent({ query, hash })` | Build that URL and SPA-navigate to it — client-only |
233
+
234
+ `currentUrl()` / `navigateCurrent()` merge query params onto the current URL: listed params are added/updated, unlisted ones preserved, and a `null`/`undefined`/`""` value removes a param. Use `currentUrl()` in a binding (`href={this.currentUrl({ query: { page: this.page + 1 } })}`) and `navigateCurrent()` in a handler (`onChange={(e) => this.navigateCurrent({ query: { status: e.target.value || null } })}`). Both are client-only — they throw if called from server code. See [Query-aware navigation](/docs/flow/routing#query-aware-navigation).
235
+
236
+ ### Event dispatch
237
+
238
+ | Expression | Behaviour |
239
+ | ------------------------------------------------- | ------------------------------------------- |
240
+ | `this.dispatch("event", data)` | Dispatch to every component on the page |
241
+ | `this.dispatchTo("ComponentName", "event", data)` | Dispatch only to a specific component class |
242
+ | `this.dispatchSelf("event", data)` | Dispatch only to this component |
243
+
244
+ ### Parent interaction
245
+
246
+ | Expression | Behaviour |
247
+ | --------------------------- | -------------------------------------------------- |
248
+ | `$flow.parent.method(args)` | Invoke an action on the nearest ancestor component |
249
+ | `$flow.parent.prop` | Read an exposed property of the parent |
250
+
251
+ ### Global client store
252
+
253
+ | Expression | Behaviour |
254
+ | ------------------------- | --------------------------------------------------------------- |
255
+ | `$flow.store.ui.dark` | Read a value from the global client store (reactive) |
256
+ | `$flow.store.ui.dark = …` | Write it — every component reading it re-renders, no round-trip |
257
+
258
+ `$flow.store` is app-wide UI state that shouldn't round-trip to the server — side-panel visibility, colour scheme, notification drawer, etc. Declare its shape with `defineStore(...)` at app start and type it by augmenting `FlowStore` (see [The global client store](/docs/flow#the-global-client-store)):
259
+
260
+ ```tsx
261
+ <button onClick={() => ($flow.store.ui.sidebarOpen = true)}>Open sidebar</button>
262
+ <aside show={$flow.store.ui.sidebarOpen}>Sidebar content</aside>
263
+ ```
264
+
265
+ ## Decorator quick reference
266
+
267
+ | Decorator | On | Effect |
268
+ | ------------------------------------ | -------- | -------------------------------------------------------------- |
269
+ | `@expose` | property | Synced to client; client can mutate via `value=` or expression |
270
+ | `@expose` | method | Callable from browser via WebSocket |
271
+ | `@locked` | property | Synced to client for display; client cannot change it |
272
+ | `@validate((rule) => rule.…)` | property | Auto-validated by `this.validate()`; live on `flow:model.live` |
273
+ | `@url` | property | Synced to URL query string (`?prop=value`) |
274
+ | `@url({ as: "p", history: "push" })` | property | Custom param name; push history entry |
275
+ | `@session` | property | Persisted in HTTP session across page loads |
276
+ | `@computed` | getter | Derived from state; memoized per render pass; not in snapshot |
277
+ | `@transient` | property | Excluded from snapshot; reset on every round-trip |
278
+ | `@renderless` | method | Runs server-side but skips re-render |
279
+ | `@on("event")` | method | Listens for cross-component events (auto-exposed) |
280
+ | `@reactive` | property | Child prop the parent can re-push on change |
281
+ | `@modelable` | property | Two-way child prop (parent↔child sync) |
282
+
283
+ ## Lifecycle hook quick reference
284
+
285
+ | Hook | `GET` (initial) | `WebSocket` (subsequent) |
286
+ | ----------------------- | --------------- | ------------------------------- |
287
+ | `onBoot()` | ✓ | ✓ |
288
+ | `onMount()` | ✓ | only if `this.refresh()` called |
289
+ | `onHydrate()` | — | ✓ |
290
+ | `onUpdating(prop, val)` | — | ✓ (per client write) |
291
+ | `onUpdated(prop, val)` | — | ✓ (per client write) |
292
+ | `action()` | — | ✓ |
293
+ | `onUpdate()` | — | ✓ |
294
+ | `onRendering()` | ✓ | ✓ |
295
+ | `render()` | ✓ | ✓ |
296
+ | `onRendered(html)` | ✓ | ✓ |
297
+ | `onDehydrate()` | ✓ | ✓ |
298
+ | `onError(error)` | — | ✓ (on throw) |
299
+
300
+ ## FlowTest assertion reference
301
+
302
+ | Method | Asserts |
303
+ | ------------------------------- | -------------------------------------------- |
304
+ | `t.assertSee(text)` | Rendered HTML contains `text` |
305
+ | `t.assertDontSee(text)` | Rendered HTML does NOT contain `text` |
306
+ | `t.assertHasErrors(field)` | Validation error exists for `field` |
307
+ | `t.assertHasErrors(field, msg)` | Error for `field` contains `msg` |
308
+ | `t.assertNoErrors()` | No validation errors |
309
+ | `t.assertRedirectedTo(url)` | Last action redirected to `url` |
310
+ | `t.assertNotRedirected()` | Last action did not redirect |
311
+ | `t.assertFlashed(level?, msg?)` | Flash notification was emitted |
312
+ | `t.assertDispatched(event)` | Cross-component event was dispatched |
313
+ | `t.page()` | The component instance |
314
+ | `t.html()` | Rendered HTML string |
315
+ | `t.errors()` | Error bag: `Record<string, string[]>` |
316
+ | `t.effects()` | Drained effects (flashes, redirects, events) |
317
+ | `t.snapshot()` | Serialised snapshot |