@greendrake/vue-api 0.2.0 → 0.4.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.
package/README.md CHANGED
@@ -18,10 +18,10 @@ One module declares the typed method map, builds the transport and exports the c
18
18
  // src/api.ts
19
19
  import { HttpTransport } from '@greendrake/rpc'
20
20
  import { ApiClient } from '@greendrake/vue-api'
21
- import type { Host, ListResult, PageArgs, Vlan } from './types'
21
+ import type { Host, HostQuery, ListResult, Vlan } from './types'
22
22
 
23
23
  export interface Methods {
24
- 'host.list': (query: PageArgs) => ListResult<Host>
24
+ 'host.list': (query: HostQuery) => ListResult<Host>
25
25
  'host.get': (id: number) => Host
26
26
  'host.update': (record: { id: number } & Partial<Host>) => Host
27
27
  'host.delete': (args: { id: number }) => void
@@ -131,9 +131,11 @@ Retry re-runs the same call (the button reads "Trying..." until the retried atte
131
131
  Boot wiring, `configureApiUX({ errorSink?, goHome?, connectionSource? })`:
132
132
 
133
133
  - `errorSink: ErrorSink` — `(error, context?) => void`; receives `other`-kind failures and abnormal WebSocket closes (`WebSocketClosedError.isAbnormal`) for reporting. Nothing is reported without one.
134
- - `goHome` — the not-found toast's home action; default `location.assign('/')`. `@greendrake/vue-app` sets it to `router.push('/')`. `getGoHome()` returns the configured function for modules that navigate home outside a component.
134
+ - `goHome` — the not-found toast's home action; default `location.assign('/')`. `getGoHome()` returns the configured function for modules that navigate home outside a component.
135
135
  - `connectionSource: ConnectionSource` — `{ readonly connected: boolean; onConnectionChange(listener) }`, read once when `useConnectivity` first materialises, so configure it before the store is first used. `@greendrake/rpc`'s `WsTransport` satisfies it as-is.
136
136
 
137
+ `apiUXHooks` is `{ onRouter(router), onBootError(error) }`, for an app bootstrap that offers those two hooks: `onRouter` sets `goHome` to `router.push('/')` the moment the router exists, and `onBootError` shows a failed boot through `useExceptionState().fail`. The router is typed structurally (`{ push(to: string): unknown }`), so this package takes no router dependency.
138
+
137
139
  ### Offline parking
138
140
 
139
141
  A non-silent call that fails with a `NetworkError` while `useConnectivity().offline` is true is parked instead of toasted, provided re-issuing it cannot double-apply: it carries no nonce (a cacheable read), or the transport rejected it before writing it (`WebSocketClosedError` with `inFlight === false`). A parked call releases its global loading slot — a scoped `pending` ref stays on, so the submitting control stays disabled — waits on `whenOnline()`, and re-runs once per reconnection. A nonce-carrying request that was on the wire when the socket went may have executed server-side with only its response lost, so it keeps the toast and the decision stays with the user.
@@ -180,8 +182,8 @@ The mechanism — relevance, `apply` versus `resync`, the reconnect re-read, coa
180
182
  - Its failure neither interrupts nor vanishes. A `NotFoundError` is dropped (the entity went away while the socket was down; the next navigation says so), a `NetworkError` is dropped (the socket went again mid-read, and the binding's own reconnect rule re-reads when it returns), and anything else goes to the `errorSink` configured through `configureApiUX` — reported, never toasted.
181
183
  - It must read past a response cache the missed pushes would have invalidated: invalidate the entries the read would hit, then read, so the stale entry is repaired rather than stepped around.
182
184
 
183
- `backgroundCall` also serves a table's loader, which is where a panel's re-read actually calls the API — see `@greendrake/ui-data`'s loader contract:
185
+ `backgroundCall` also serves any loader told whether anybody asked for its load — a table re-reading after a push, say, which is where a panel's re-read actually calls the API:
184
186
 
185
187
  ```ts
186
- const loader = listLoader((args, background) => api.call('admin.thread.list', [args], backgroundCall(background)))
188
+ const load = (args: ListArgs, background: boolean) => api.call('admin.thread.list', [args], backgroundCall(background))
187
189
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@greendrake/vue-api",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Vue binding of @greendrake/rpc: loading-state wiring, response cache, error-UX pipeline, silent calls, live bindings to server push",
5
5
  "license": "MIT",
6
6
  "author": "Eugene Greendrake <eugene@greendrake.nz>",
@@ -34,17 +34,17 @@
34
34
  },
35
35
  "prettier": "@greendrake/dev-config/prettier",
36
36
  "dependencies": {
37
- "@greendrake/rpc": "0.2.0",
38
- "@greendrake/ui": "0.2.0",
39
- "@greendrake/util": "0.2.0",
40
- "@greendrake/vue-kit": "0.2.0"
37
+ "@greendrake/rpc": "0.4.0",
38
+ "@greendrake/ui": "0.4.0",
39
+ "@greendrake/util": "0.4.0",
40
+ "@greendrake/vue-kit": "0.4.0"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "pinia": "^3.0.4",
44
44
  "vue": "^3.5.34"
45
45
  },
46
46
  "devDependencies": {
47
- "@greendrake/dev-config": "0.2.0",
47
+ "@greendrake/dev-config": "0.4.0",
48
48
  "pinia": "^3.0.4",
49
49
  "typescript": "6.0.3",
50
50
  "vue": "^3.5.34",
@@ -0,0 +1,24 @@
1
+ import { useExceptionState } from './exceptionState'
2
+ import { configureApiUX } from './uxConfig'
3
+
4
+ // The error-UX pipeline's half of an app's boot, for a bootstrap that offers
5
+ // these two hooks. The router is typed by the one method used, so this package
6
+ // takes no vue-router dependency.
7
+ export const apiUXHooks = {
8
+ // The not-found toast's "To the home page" navigates through the app's
9
+ // router. Wired where the router is created rather than in an app's
10
+ // main.ts, so non-component modules (stores) can navigate home via
11
+ // getGoHome() without importing the app module — an import back-edge that
12
+ // would put main.ts inside a circular import and break HMR.
13
+ onRouter: (router: { push(to: string): unknown }): void => {
14
+ configureApiUX({
15
+ goHome: () => {
16
+ void router.push('/')
17
+ }
18
+ })
19
+ },
20
+ // A failed boot surfaces through the same toast as any other failure.
21
+ onBootError: (error: Error): void => {
22
+ useExceptionState().fail(error)
23
+ }
24
+ }
package/src/main.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { ApiClient, UnacceptableResultError, type ApiClientOptions, type CallOptions } from './ApiClient'
2
2
  export { useExceptionState, classifyException, type ExceptionKind, type FailOptions } from './exceptionState'
3
3
  export { configureApiUX, getGoHome, type ConnectionSource, type ErrorSink } from './uxConfig'
4
+ export { apiUXHooks } from './apiUXHooks'
4
5
  export { useConnectivity } from './connectivity'
5
6
  export { retryWhenOnline } from './retryWhenOnline'
6
7
  export { backgroundCall, bindLive, useLive } from './live'
package/src/uxConfig.ts CHANGED
@@ -22,7 +22,7 @@ interface ApiUXConfig {
22
22
  // reporting — e.g. the visit subsystem's error channel.
23
23
  errorSink?: ErrorSink
24
24
  // Drives the not-found toast's "To the home page" action; typically
25
- // router.push('/'). @greendrake/vue-app wires this automatically.
25
+ // router.push('/'). apiUXHooks.onRouter wires it to the app's router.
26
26
  goHome?: () => void
27
27
  // Read once, when useConnectivity is first instantiated.
28
28
  connectionSource?: ConnectionSource