@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 +7 -5
- package/package.json +6 -6
- package/src/apiUXHooks.ts +24 -0
- package/src/main.ts +1 -0
- package/src/uxConfig.ts +1 -1
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,
|
|
21
|
+
import type { Host, HostQuery, ListResult, Vlan } from './types'
|
|
22
22
|
|
|
23
23
|
export interface Methods {
|
|
24
|
-
'host.list': (query:
|
|
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('/')`.
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
38
|
-
"@greendrake/ui": "0.
|
|
39
|
-
"@greendrake/util": "0.
|
|
40
|
-
"@greendrake/vue-kit": "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.
|
|
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('/').
|
|
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
|