@owlmeans/client-socket 0.1.18-rc.21 → 0.1.18-rc.23
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 +11 -9
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/client-socket/SKILL.md +97 -44
- package/build/consts.d.ts +7 -0
- package/build/consts.d.ts.map +1 -0
- package/build/consts.js +15 -0
- package/build/consts.js.map +1 -0
- package/build/helper.d.ts +26 -2
- package/build/helper.d.ts.map +1 -1
- package/build/helper.js +94 -20
- package/build/helper.js.map +1 -1
- package/build/index.d.ts +2 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +2 -0
- package/build/index.js.map +1 -1
- package/build/status.d.ts +22 -0
- package/build/status.d.ts.map +1 -0
- package/build/status.js +94 -0
- package/build/status.js.map +1 -0
- package/build/types.d.ts +64 -0
- package/build/types.d.ts.map +1 -1
- package/build/utils/connection.d.ts +35 -2
- package/build/utils/connection.d.ts.map +1 -1
- package/build/utils/connection.js +190 -28
- package/build/utils/connection.js.map +1 -1
- package/package.json +13 -10
- package/src/consts.ts +17 -0
- package/src/helper.ts +111 -22
- package/src/index.ts +2 -0
- package/src/status.ts +108 -0
- package/src/types.ts +73 -1
- package/src/utils/connection.ts +215 -32
- package/tests/context.ts +20 -0
- package/tests/reconnect.spec.ts +150 -0
- package/tests/tsconfig.json +12 -0
- package/tsconfig.json +1 -1
package/README.md
CHANGED
|
@@ -5,14 +5,14 @@ React hook and factory for WebSocket connections via OwlMeans entrypoint routing
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
7
|
- `ws(entrypoint, request?)` — creates a `Connection` from the entrypoint's URL and opens a WebSocket
|
|
8
|
-
- `useWs(entrypoint, request?)` — React hook wrapping `ws()` with lifecycle management;
|
|
9
|
-
|
|
8
|
+
- `useWs(entrypoint, request?)` — React hook wrapping `ws()` with lifecycle management; pass a
|
|
9
|
+
protocol-bound entrypoint directly
|
|
10
10
|
- The returned `Connection` implements `@owlmeans/socket`'s `Connection` interface
|
|
11
11
|
|
|
12
12
|
## Installation
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
bun add @owlmeans/client-socket@^0.1.18-rc.
|
|
15
|
+
bun add @owlmeans/client-socket@^0.1.18-rc.22
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
## Usage
|
|
@@ -23,11 +23,11 @@ Connect to a WebSocket entrypoint and observe events:
|
|
|
23
23
|
import { useWs } from '@owlmeans/client-socket'
|
|
24
24
|
import { MessageType } from '@owlmeans/socket'
|
|
25
25
|
import { useContext } from '@owlmeans/web-client'
|
|
26
|
-
import {
|
|
26
|
+
import { appProtocols } from 'my-app-common'
|
|
27
27
|
|
|
28
28
|
function ThinkingPanel({ storyId }: { storyId: string }) {
|
|
29
29
|
const context = useContext()
|
|
30
|
-
const conn = useWs(context.entrypoint(
|
|
30
|
+
const conn = useWs(context.entrypoint(appProtocols.api.storyThinking), { params: { id: storyId } })
|
|
31
31
|
|
|
32
32
|
useEffect(() => {
|
|
33
33
|
if (!conn) return
|
|
@@ -43,9 +43,9 @@ Direct connection (non-hook):
|
|
|
43
43
|
|
|
44
44
|
```typescript
|
|
45
45
|
import { ws } from '@owlmeans/client-socket'
|
|
46
|
-
import {
|
|
46
|
+
import { appProtocols } from 'my-app-common'
|
|
47
47
|
|
|
48
|
-
const wsEntrypoint = context.entrypoint(
|
|
48
|
+
const wsEntrypoint = context.entrypoint(appProtocols.api.storyThinking)
|
|
49
49
|
const connection = await ws(wsEntrypoint, { params: { id: storyId } })
|
|
50
50
|
```
|
|
51
51
|
|
|
@@ -57,7 +57,9 @@ Builds the entrypoint's URL, opens a WebSocket, and returns a `Connection` once
|
|
|
57
57
|
|
|
58
58
|
### `useWs(entrypoint, request?): Connection | null`
|
|
59
59
|
|
|
60
|
-
React hook version of `ws()`. Returns `null` while connecting. Manages connection lifecycle (opens
|
|
60
|
+
React hook version of `ws()`. Returns `null` while connecting. Manages connection lifecycle (opens
|
|
61
|
+
on mount, closes on unmount). Alias input is reserved for a dynamic external boundary; application
|
|
62
|
+
code calls `context.entrypoint(protocol)` first.
|
|
61
63
|
|
|
62
64
|
## Related Packages
|
|
63
65
|
|
|
@@ -73,7 +75,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
73
75
|
your project's skill store (`.agents/skills/`):
|
|
74
76
|
|
|
75
77
|
```sh
|
|
76
|
-
npx @owlmeans/agent-skills@^0.1.18-rc.
|
|
78
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.21
|
|
77
79
|
```
|
|
78
80
|
|
|
79
81
|
The embedded files are version-matched to this package release. Do not edit them
|
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"package": "@owlmeans/client-socket",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-09-
|
|
4
|
+
"version": "0.1.18-rc.23",
|
|
5
|
+
"generatedAt": "2026-09-15T12:21:31.902Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: client-socket
|
|
3
|
-
description: How to use @owlmeans/client-socket — opening a WebSocket Connection to a socket entrypoint from browsers and native clients, the
|
|
3
|
+
description: How to use @owlmeans/client-socket — opening a self-restoring WebSocket Connection to a socket entrypoint from browsers and native clients, the reconnect policy and its options, the socket-status aggregator, the useWs hook and the system frames a carrier emits. Auto-invoked when importing client socket primitives or wiring a browser subscription.
|
|
4
4
|
user-invocable: false
|
|
5
5
|
---
|
|
6
6
|
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
@@ -8,20 +8,25 @@ user-invocable: false
|
|
|
8
8
|
# @owlmeans/client-socket
|
|
9
9
|
|
|
10
10
|
**Layer:** Client
|
|
11
|
-
**Install:** `"@owlmeans/client-socket": "^0.1.18-rc.
|
|
11
|
+
**Install:** `"@owlmeans/client-socket": "^0.1.18-rc.23"` in `dependencies`
|
|
12
12
|
|
|
13
13
|
The browser carrier for `@owlmeans/socket`. It supplies the four members the connection model
|
|
14
14
|
leaves abstract — `send`, `close`, `prepare`, `authenticate` — and hands back a plain `Connection`,
|
|
15
15
|
so everything a screen does with the socket is the vocabulary of that package — `observe`,
|
|
16
|
-
`notify`, `call`, `listen`.
|
|
16
|
+
`notify`, `call`, `listen`. It also restores a dropped WebSocket on its own, on the SAME
|
|
17
|
+
`Connection` model, so nothing a caller registered with `observe`/`listen` needs to be
|
|
18
|
+
re-registered after a network blip.
|
|
17
19
|
|
|
18
20
|
## Key Exports
|
|
19
21
|
|
|
20
22
|
| Export | Description |
|
|
21
23
|
|--------|-------------|
|
|
22
|
-
| `ws(entrypoint, request?)` | Open a `Connection` to a socket entrypoint. Resolves once the
|
|
23
|
-
| `useWs(
|
|
24
|
-
| `
|
|
24
|
+
| `ws(entrypoint, request?, options?)` | Open a `Connection` to a socket entrypoint. Resolves once the FIRST attempt opens; rejects with `SocketConnectionError('lost')` if the retry budget elapses first |
|
|
25
|
+
| `useWs(protocol \| alias, request?, options?)` | React hook — `Connection \| null` until it opens (or gives up); re-opens on `alias`/`AUTH_QUERY`/`params` change and closes on unmount |
|
|
26
|
+
| `connect(address, ctx, options?)` | The same machinery with no entrypoint behind it — an `address` callback returning the URL, for an adapter or a test |
|
|
27
|
+
| `appendSocketStatus(ctx, alias?)` / `useSocketStatus()` | The status aggregator — see below |
|
|
28
|
+
| `Config` / `Context` | The client config (`socket?: SocketClientSettings`) and context types this package expects |
|
|
29
|
+
| `ReconnectPolicy` / `SocketClientSettings` / `ConnectOptions` / `WsOptions` | The reconnect policy shape and where it can be set — config, or per-call `options` |
|
|
25
30
|
|
|
26
31
|
## How the address is built
|
|
27
32
|
|
|
@@ -29,16 +34,19 @@ A socket entrypoint is **addressed, not called**: `entrypointUrl` from
|
|
|
29
34
|
`@owlmeans/client-entrypoint/utils` turns the declaration plus the asking context into the `wss://`
|
|
30
35
|
URL — `:params` filled in, query appended, protocol and TLS taken from the entrypoint's address —
|
|
31
36
|
and the connection is opened on that. Nothing is hand-concatenated, so the same declaration the
|
|
32
|
-
server binds is the one the client dials.
|
|
37
|
+
server binds is the one the client dials. It is re-resolved on EVERY attempt, first one included,
|
|
38
|
+
so a `beforeConnect` hook that mutates the request's query (a refreshed token, most often) reaches
|
|
39
|
+
every reconnect too, not just the first handshake.
|
|
33
40
|
|
|
34
41
|
Authentication rides on the query, because a WebSocket handshake carries no Authorization header a
|
|
35
42
|
browser can set: the token goes under `AUTH_QUERY`, and the server derives the connection's subject
|
|
36
43
|
from it.
|
|
37
44
|
|
|
38
45
|
**Take the authenticated hook, not this one.** `@owlmeans/client-auth` exports its own `useWs` that
|
|
39
|
-
wraps this one
|
|
40
|
-
|
|
41
|
-
|
|
46
|
+
wraps this one, fills `AUTH_QUERY` from `ctx.auth().token`, and refreshes it via `beforeConnect` on
|
|
47
|
+
every reconnect — unless the request already carried its own token, in which case that caller's
|
|
48
|
+
value is left alone across reconnects too. Import `useWs` from there for anything a guard
|
|
49
|
+
protects, and from here only for an entrypoint that is open to everyone.
|
|
42
50
|
|
|
43
51
|
The in-band auth sequence is a different thing from the query token, and only half of it is here.
|
|
44
52
|
`connection.auth(stage, payload)` sends the frame and resolves on the server's reply — that is the
|
|
@@ -46,10 +54,17 @@ client-initiated exchange, and it works. This carrier's own `authenticate` is a
|
|
|
46
54
|
empty tuple, so an `Auth` frame the SERVER opens finds no stage to answer with and is dropped
|
|
47
55
|
without a reply: a browser can start an exchange, never answer one.
|
|
48
56
|
|
|
57
|
+
**A reconnect is a brand-new server-side connection.** If a server sets up subscriptions only
|
|
58
|
+
after an in-band `authenticate` frame (as this platform's own handlers do — see the `socket`
|
|
59
|
+
memory in `viable`), the carrier does NOT replay that frame by itself; it only reopens the pipe.
|
|
60
|
+
A caller that authenticates in-band must listen for `SocketSystemEvent.Reconnected` and resend it
|
|
61
|
+
— `viable`'s `sources/manager-web/src/lib/ws.ts` `useAuthWs` is the worked example.
|
|
62
|
+
|
|
49
63
|
## Usage
|
|
50
64
|
|
|
51
65
|
```typescript
|
|
52
|
-
// A guarded entrypoint: this useWs fills AUTH_QUERY from the current session
|
|
66
|
+
// A guarded entrypoint: this useWs fills AUTH_QUERY from the current session and keeps it fresh
|
|
67
|
+
// across reconnects.
|
|
53
68
|
import { useWs } from '@owlmeans/client-auth'
|
|
54
69
|
|
|
55
70
|
// An open one: this useWs sends whatever query it is given, and nothing more.
|
|
@@ -67,54 +82,92 @@ useEffect(() => {
|
|
|
67
82
|
}, [connection])
|
|
68
83
|
```
|
|
69
84
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
85
|
+
Pass the immutable socket protocol declaration in application code. A string alias is reserved
|
|
86
|
+
for an adapter whose remote declaration is unavailable to import. Both hooks re-open when the
|
|
87
|
+
protocol, `AUTH_QUERY` value, or params change — the params are compared by content, so a fresh
|
|
88
|
+
object literal each render does not re-open. Both close the connection when the component unmounts,
|
|
89
|
+
and both answer `null` until the socket is open, so every effect that touches one guards on that.
|
|
90
|
+
|
|
91
|
+
## Disconnects and reconnects
|
|
92
|
+
|
|
93
|
+
The carrier keeps the same `Connection` MODEL for the life of the hook/call and swaps only the
|
|
94
|
+
underlying `WebSocket` underneath it — every `observe`/`listen` a caller registered survives a
|
|
95
|
+
reconnect, because it was registered on the model, not on the socket.
|
|
96
|
+
|
|
97
|
+
**The retry policy** (`ReconnectPolicy`, defaults in `DEFAULT_RECONNECT_POLICY`):
|
|
98
|
+
|
|
99
|
+
| Field | Default | Meaning |
|
|
100
|
+
|---|---|---|
|
|
101
|
+
| `minDelay` | 200ms | First retry delay |
|
|
102
|
+
| `maxDelay` | 3000ms | Delay ceiling — backoff never grows past this |
|
|
103
|
+
| `factor` | 2 | Geometric growth per failed attempt |
|
|
104
|
+
| `jitter` | 0.1 | ±10% randomization on each computed delay |
|
|
105
|
+
| `budget` | 600000ms (10 min) | Total retry time before the carrier gives up |
|
|
106
|
+
| `stableAfter` | 10000ms | How long a reopened socket must stay up before the attempt count and the outage clock reset |
|
|
107
|
+
| `heartbeat` | 30000ms | Ping interval — runs even with `reconnect: false` |
|
|
108
|
+
| `pongTimeout` | 10000ms | No frame of ANY kind since the last ping past this long ⇒ the carrier force-closes the socket itself (code 4000, `SOCKET_HEARTBEAT_TIMEOUT_CODE`) — the only way a silently half-open TCP connection is noticed before the OS would, minutes later |
|
|
109
|
+
|
|
110
|
+
Set it on `ctx.cfg.socket.reconnect` (app-wide) or per call via `options.reconnect` (which wins).
|
|
111
|
+
`reconnect: false` disables retries — a drop is reported once and stays dropped, the
|
|
112
|
+
pre-reconnect-support behaviour — while the heartbeat/liveness check above still runs. Use it for
|
|
113
|
+
a stateful one-shot handshake a reconnect could never resume correctly (the wallet-tunnel rely
|
|
114
|
+
session in `client-auth` sets it for exactly this reason).
|
|
115
|
+
|
|
116
|
+
**System frames** (`SocketSystemEvent`, from `@owlmeans/socket`) reach every `connection.listen`
|
|
117
|
+
subscriber:
|
|
118
|
+
|
|
119
|
+
| Event | When |
|
|
120
|
+
|---|---|
|
|
121
|
+
| `disconnected` | The socket dropped and a retry IS scheduled — `{ code }` |
|
|
122
|
+
| `reconnecting` | Before each retry attempt — `{ attempt, delay }` |
|
|
123
|
+
| `reconnected` | A retry succeeded — `{ attempts }` |
|
|
124
|
+
| `lost` | The retry budget elapsed with no success — no payload |
|
|
125
|
+
| `close` | The connection is gone for GOOD: a client-initiated close, a terminal server code (1000/1008), `reconnect: false` and the one attempt failed, or right after `lost` |
|
|
82
126
|
|
|
83
127
|
```typescript
|
|
84
128
|
connection.listen(async message => {
|
|
85
|
-
const msg = message as EventMessage<
|
|
86
|
-
if (typeof message
|
|
87
|
-
|
|
88
|
-
|
|
129
|
+
const msg = message as EventMessage<unknown>
|
|
130
|
+
if (typeof message !== 'object' || msg.type !== 'system') return
|
|
131
|
+
if (msg.event === SocketSystemEvent.Reconnected) await resubscribe()
|
|
132
|
+
if (msg.event === SocketSystemEvent.Close) await release()
|
|
89
133
|
})
|
|
90
134
|
```
|
|
91
135
|
|
|
92
|
-
**
|
|
93
|
-
`useWs`
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
136
|
+
**The status aggregator.** `appendSocketStatus(ctx)` registers a shared service every
|
|
137
|
+
`ws()`/`useWs()` connection reports its state into; `useSocketStatus()` reads the WORST state
|
|
138
|
+
across all of them (`'online' | 'reconnecting' | 'lost'`). A connection that ends in `'lost'` is
|
|
139
|
+
NOT released from the aggregate — there is no `Connection` for the caller to close, since `ws()`
|
|
140
|
+
rejected — so the aggregate latches at `'lost'` until the page reloads. That is deliberate: it is
|
|
141
|
+
what `@owlmeans/web-panel`'s `SocketReloadDialog` reads to put up a global, blocking "reload the
|
|
142
|
+
page" prompt once every socket in the app has given up (`cfg.socket.reloadDialog`). Calling
|
|
143
|
+
`appendSocketStatus` unconditionally is cheap and safe for a host package — nothing reports into
|
|
144
|
+
it unless something calls `ws()`/`useWs()`, so an app that never does behaves exactly as before.
|
|
145
|
+
|
|
146
|
+
`useSocketStatus()` tolerates being called before the context's own `configure()`/`init()` has
|
|
147
|
+
run (it defaults to `'online'` and re-attaches once `ctx.waitForInitialized()` resolves) — a
|
|
148
|
+
component mounted as a sibling of the router, as `SocketReloadDialog` is, renders on React's
|
|
149
|
+
first commit, before the router's effect has had a chance to initialize the context.
|
|
97
150
|
|
|
98
151
|
Outbound frames are stamped with `dt` and dropped rather than queued while the socket is not
|
|
99
|
-
`OPEN`, so a `notify` issued while the socket is down is lost rather than delivered late.
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
`useWs` stays `null` with nothing reported, and an awaited `ws()` call hangs. Treat a `null` that
|
|
104
|
-
never turns into a connection as a failed handshake, and give a screen that depends on one a
|
|
105
|
-
timeout of its own.
|
|
152
|
+
`OPEN`, so a `notify` issued while the socket is down is lost rather than delivered late. Nothing
|
|
153
|
+
here replays events the SERVER sent while the socket was down either — a caller that cannot
|
|
154
|
+
tolerate a gap re-syncs its own state on `reconnected` (viable's file-watch editor re-lists files;
|
|
155
|
+
its thinking/slot socket relies on a separate periodic API push for the same reason).
|
|
106
156
|
|
|
107
157
|
## Depends On
|
|
108
158
|
|
|
109
|
-
- `@owlmeans/socket` — `createBasicConnection`, `MessageType`,
|
|
159
|
+
- `@owlmeans/socket` — `createBasicConnection`, `MessageType`, `SocketSystemEvent`,
|
|
160
|
+
`SOCKET_HEARTBEAT_TIMEOUT_CODE`, `SocketConnectionError`, the `Connection` contract
|
|
110
161
|
- `@owlmeans/client-entrypoint` — `entrypointUrl`, `provideRequest`
|
|
111
162
|
- `@owlmeans/client` — `useContext`, `useValue`; `@owlmeans/client-context` — the config type
|
|
112
|
-
- `@owlmeans/auth` — `AUTH_QUERY`
|
|
163
|
+
- `@owlmeans/auth` — `AUTH_QUERY`, `AuthenticationStage`
|
|
164
|
+
- `@owlmeans/basic-ids` — `createIdOfLength`, for the per-connection status-tracking id
|
|
113
165
|
- `react` (peer)
|
|
114
166
|
|
|
115
167
|
## Related
|
|
116
168
|
|
|
117
|
-
- `socket` — the message model every verb here belongs to
|
|
169
|
+
- `socket` — the message model every verb here belongs to, and the `SocketSystemEvent` vocabulary
|
|
118
170
|
- `server-socket` — the far side: guard enforcement, and what it stamps on a frame
|
|
119
|
-
- `client-auth` — the `useWs` that carries the token
|
|
120
|
-
subscription built on it
|
|
171
|
+
- `client-auth` — the `useWs` that carries the token and refreshes it across reconnects;
|
|
172
|
+
`client-job` — `useJobFeed`, a worked subscription built on it
|
|
173
|
+
- `web-panel` — `SocketReloadDialog`, the global blocking prompt built on `useSocketStatus()`
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ReconnectPolicy } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* 0.2s → 3s geometric backoff, retried for up to 10 minutes before the carrier gives up and
|
|
4
|
+
* reports the connection lost. See the client-socket skill's "Disconnects" section.
|
|
5
|
+
*/
|
|
6
|
+
export declare const DEFAULT_RECONNECT_POLICY: ReconnectPolicy;
|
|
7
|
+
//# sourceMappingURL=consts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD;;;GAGG;AACH,eAAO,MAAM,wBAAwB,EAAE,eAStC,CAAA"}
|
package/build/consts.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 0.2s → 3s geometric backoff, retried for up to 10 minutes before the carrier gives up and
|
|
3
|
+
* reports the connection lost. See the client-socket skill's "Disconnects" section.
|
|
4
|
+
*/
|
|
5
|
+
export const DEFAULT_RECONNECT_POLICY = {
|
|
6
|
+
minDelay: 200,
|
|
7
|
+
maxDelay: 3_000,
|
|
8
|
+
factor: 2,
|
|
9
|
+
jitter: 0.1,
|
|
10
|
+
budget: 600_000,
|
|
11
|
+
stableAfter: 10_000,
|
|
12
|
+
heartbeat: 30_000,
|
|
13
|
+
pongTimeout: 10_000,
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=consts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.js","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAoB;IACvD,QAAQ,EAAE,GAAG;IACb,QAAQ,EAAE,KAAK;IACf,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,GAAG;IACX,MAAM,EAAE,OAAO;IACf,WAAW,EAAE,MAAM;IACnB,SAAS,EAAE,MAAM;IACjB,WAAW,EAAE,MAAM;CACpB,CAAA"}
|
package/build/helper.d.ts
CHANGED
|
@@ -1,8 +1,32 @@
|
|
|
1
1
|
import type { ClientEntrypoint } from '@owlmeans/client-entrypoint';
|
|
2
2
|
import type { AbstractRequest } from '@owlmeans/entrypoint';
|
|
3
3
|
import type { Connection } from '@owlmeans/socket';
|
|
4
|
+
import type { EntrypointReference } from '@owlmeans/context';
|
|
5
|
+
import type { Context, ConnectOptions, WsOptions } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Open a socket with no declared entrypoint behind it — the primitive `ws()` builds on, and what
|
|
8
|
+
* a test drives directly against a bare WebSocket server.
|
|
9
|
+
*/
|
|
10
|
+
export declare const connect: (address: () => Promise<string> | string, ctx: Context, options?: ConnectOptions) => Promise<Connection>;
|
|
11
|
+
/**
|
|
12
|
+
* Open a socket through a declared entrypoint protocol, restoring it on its own after a network
|
|
13
|
+
* failure — see the client-socket skill's "Disconnects" section for the full policy. Resolves
|
|
14
|
+
* once the first attempt opens; rejects with `SocketConnectionError('lost')` if the retry budget
|
|
15
|
+
* elapses before that ever happens (or the single attempt fails, with `reconnect: false`).
|
|
16
|
+
*/
|
|
4
17
|
export declare const ws: (module: ClientEntrypoint<string>, request?: AbstractRequest<{
|
|
5
18
|
token?: string;
|
|
6
|
-
}
|
|
7
|
-
|
|
19
|
+
}>, options?: WsOptions) => Promise<Connection>;
|
|
20
|
+
/**
|
|
21
|
+
* Open a socket through a declared entrypoint protocol.
|
|
22
|
+
*
|
|
23
|
+
* String aliases remain an adapter input for dynamically addressed integrations, while
|
|
24
|
+
* application callers pass their immutable protocol declaration and receive its bound client
|
|
25
|
+
* entrypoint here at the transport boundary.
|
|
26
|
+
*
|
|
27
|
+
* Re-opens on its own after a network drop (see `ws()`). `null` until the first attempt opens,
|
|
28
|
+
* and again once the retry budget elapses without one ever opening — a screen that must tell
|
|
29
|
+
* those two apart reads `useSocketStatus()` (from `./status.js`) alongside this.
|
|
30
|
+
*/
|
|
31
|
+
export declare const useWs: (module: EntrypointReference | string, request?: Partial<AbstractRequest<any>>, options?: WsOptions) => Connection | null;
|
|
8
32
|
//# sourceMappingURL=helper.d.ts.map
|
package/build/helper.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AACnE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAE3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AACnE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAE3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAIlD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAC5D,OAAO,KAAK,EAAU,OAAO,EAAE,cAAc,EAA8C,SAAS,EAAE,MAAM,YAAY,CAAA;AA8DxH;;;GAGG;AACH,eAAO,MAAM,OAAO,YACT,MAAM,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,OAAO,OAAO,YAAY,cAAc,KAC9E,OAAO,CAAC,UAAU,CAGpB,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,EAAE,WACL,gBAAgB,CAAC,MAAM,CAAC,YAAY,eAAe,CAAC;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,YAAY,SAAS,KACnG,OAAO,CAAC,UAAU,CAUpB,CAAA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,KAAK,WACR,mBAAmB,GAAG,MAAM,YAAY,OAAO,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,YAAY,SAAS,KACjG,UAAU,GAAG,IAqCf,CAAA"}
|
package/build/helper.js
CHANGED
|
@@ -1,37 +1,111 @@
|
|
|
1
1
|
import { provideRequest } from '@owlmeans/client-entrypoint';
|
|
2
|
+
import { SocketConnectionError } from '@owlmeans/socket';
|
|
2
3
|
import { makeConnection } from './utils/connection.js';
|
|
3
4
|
import { assertContext } from '@owlmeans/context';
|
|
4
5
|
import { useContext, useValue } from '@owlmeans/client';
|
|
5
6
|
import { AUTH_QUERY } from '@owlmeans/auth';
|
|
6
7
|
import { entrypointUrl } from '@owlmeans/client-entrypoint/utils';
|
|
7
8
|
import { useEffect, useMemo } from 'react';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
import { createIdOfLength } from '@owlmeans/basic-ids';
|
|
10
|
+
import { DEFAULT_RECONNECT_POLICY } from './consts.js';
|
|
11
|
+
import { SOCKET_STATUS } from './status.js';
|
|
12
|
+
const resolvePolicy = (ctx, options) => {
|
|
13
|
+
const requested = options?.reconnect !== undefined ? options.reconnect : ctx.cfg.socket?.reconnect;
|
|
14
|
+
const retry = requested !== false;
|
|
15
|
+
const overrides = requested === false || requested == null ? {} : requested;
|
|
16
|
+
return { policy: { ...DEFAULT_RECONNECT_POLICY, ...overrides }, retry };
|
|
17
|
+
};
|
|
18
|
+
const openRawSocket = async (url) => {
|
|
12
19
|
const socket = new WebSocket(url);
|
|
13
|
-
return new Promise(resolve => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
}, 30_000);
|
|
20
|
-
socket.addEventListener('close', () => {
|
|
21
|
-
console.info('WebSocket connection closed, clearing heartbeat interval.');
|
|
22
|
-
clearInterval(heartbeat);
|
|
23
|
-
});
|
|
24
|
-
resolve(makeConnection(socket, ctx));
|
|
20
|
+
return await new Promise((resolve, reject) => {
|
|
21
|
+
const cleanup = () => {
|
|
22
|
+
socket.removeEventListener('open', onOpen);
|
|
23
|
+
socket.removeEventListener('error', onFail);
|
|
24
|
+
socket.removeEventListener('close', onFail);
|
|
25
25
|
};
|
|
26
|
+
const onOpen = () => { cleanup(); resolve(socket); };
|
|
27
|
+
const onFail = () => { cleanup(); reject(new SocketConnectionError('handshake')); };
|
|
28
|
+
socket.addEventListener('open', onOpen);
|
|
29
|
+
socket.addEventListener('error', onFail);
|
|
30
|
+
socket.addEventListener('close', onFail);
|
|
26
31
|
});
|
|
27
32
|
};
|
|
28
|
-
|
|
33
|
+
const establish = async (ctx, policy, retry, open) => {
|
|
34
|
+
const statusId = createIdOfLength(8);
|
|
35
|
+
const status = ctx.hasService(SOCKET_STATUS)
|
|
36
|
+
? ctx.socketStatus() : null;
|
|
37
|
+
const { connection, ready } = makeConnection({
|
|
38
|
+
policy, retry, open, onStatus: state => status?.report(statusId, state)
|
|
39
|
+
});
|
|
40
|
+
const baseClose = connection.close;
|
|
41
|
+
connection.close = async () => {
|
|
42
|
+
await baseClose();
|
|
43
|
+
status?.release(statusId);
|
|
44
|
+
};
|
|
45
|
+
// A rejection here means `finish()` already ran and reported this id's terminal state —
|
|
46
|
+
// `'lost'` in every case, since the budget-exhausted path is the only one that rejects
|
|
47
|
+
// `ready`. Deliberately NOT released: there is no `Connection` to hand back for a caller to
|
|
48
|
+
// close, so the aggregate stays `'lost'` — the whole reason `SocketReloadDialog` exists — until
|
|
49
|
+
// the page reloads. Only a connection this function actually returns can be released, and only
|
|
50
|
+
// by the caller closing it on purpose.
|
|
51
|
+
await ready;
|
|
52
|
+
return connection;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Open a socket with no declared entrypoint behind it — the primitive `ws()` builds on, and what
|
|
56
|
+
* a test drives directly against a bare WebSocket server.
|
|
57
|
+
*/
|
|
58
|
+
export const connect = async (address, ctx, options) => {
|
|
59
|
+
const { policy, retry } = resolvePolicy(ctx, options);
|
|
60
|
+
return await establish(ctx, policy, retry, async () => openRawSocket(await address()));
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Open a socket through a declared entrypoint protocol, restoring it on its own after a network
|
|
64
|
+
* failure — see the client-socket skill's "Disconnects" section for the full policy. Resolves
|
|
65
|
+
* once the first attempt opens; rejects with `SocketConnectionError('lost')` if the retry budget
|
|
66
|
+
* elapses before that ever happens (or the single attempt fails, with `reconnect: false`).
|
|
67
|
+
*/
|
|
68
|
+
export const ws = async (module, request, options) => {
|
|
69
|
+
const ctx = assertContext(module.ctx, 'client-ws');
|
|
70
|
+
request = request ?? provideRequest(module.alias, module.path());
|
|
71
|
+
const { policy, retry } = resolvePolicy(ctx, options);
|
|
72
|
+
return await establish(ctx, policy, retry, async () => {
|
|
73
|
+
await options?.beforeConnect?.(request);
|
|
74
|
+
const url = await entrypointUrl({ ref: module }, request);
|
|
75
|
+
return await openRawSocket(url);
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Open a socket through a declared entrypoint protocol.
|
|
80
|
+
*
|
|
81
|
+
* String aliases remain an adapter input for dynamically addressed integrations, while
|
|
82
|
+
* application callers pass their immutable protocol declaration and receive its bound client
|
|
83
|
+
* entrypoint here at the transport boundary.
|
|
84
|
+
*
|
|
85
|
+
* Re-opens on its own after a network drop (see `ws()`). `null` until the first attempt opens,
|
|
86
|
+
* and again once the retry budget elapses without one ever opening — a screen that must tell
|
|
87
|
+
* those two apart reads `useSocketStatus()` (from `./status.js`) alongside this.
|
|
88
|
+
*/
|
|
89
|
+
export const useWs = (module, request, options) => {
|
|
29
90
|
const ctx = useContext();
|
|
30
|
-
const mod = useMemo(() =>
|
|
31
|
-
const connection = useValue(async () => {
|
|
91
|
+
const mod = useMemo(() => ctx.entrypoint(module), [module]);
|
|
92
|
+
const connection = useValue(async (cancel) => {
|
|
32
93
|
const _request = provideRequest(mod.alias, mod.path());
|
|
33
94
|
Object.assign(_request, request);
|
|
34
|
-
|
|
95
|
+
try {
|
|
96
|
+
const conn = await ws(mod, _request, options);
|
|
97
|
+
if (cancel?.current) {
|
|
98
|
+
// The component unmounted while the handshake (or its retries) were still in flight —
|
|
99
|
+
// there is no `useEffect` cleanup coming for this value, so close it here instead of
|
|
100
|
+
// leaving a live socket and its retry timers attached to nothing.
|
|
101
|
+
void conn.close();
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
return conn;
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
35
109
|
}, [
|
|
36
110
|
mod.alias,
|
|
37
111
|
request?.query?.[AUTH_QUERY],
|
package/build/helper.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helper.js","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAE5D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"helper.js","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"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"}
|
package/build/index.d.ts
CHANGED
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,aAAa,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA"}
|
package/build/index.js
CHANGED
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,aAAa,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Config, Context, SocketConnectionState, SocketStatusService, SocketStatusServiceAppend } from './types.js';
|
|
2
|
+
export declare const SOCKET_STATUS = "socket-status";
|
|
3
|
+
/**
|
|
4
|
+
* Aggregates the coarse health of every `ws()`/`useWs()` connection an app has open into one
|
|
5
|
+
* worst-of-all state. A page with several sockets (thinking stream, file watch, notifications…)
|
|
6
|
+
* still shows one dialog, not one per socket — so the aggregate, not any single connection, is
|
|
7
|
+
* what a UI like `SocketReloadDialog` reads.
|
|
8
|
+
*/
|
|
9
|
+
export declare const createSocketStatusService: (alias?: string) => SocketStatusService;
|
|
10
|
+
/**
|
|
11
|
+
* Register the shared socket-status aggregator. Idempotent, and cheap enough for a host package
|
|
12
|
+
* (`@owlmeans/web-panel`) to call unconditionally on every context: every `ws()`/`useWs()`
|
|
13
|
+
* connection reports itself here if — and only if — the context carries this service, so an app
|
|
14
|
+
* that never calls this behaves exactly as it did before reconnect support existed.
|
|
15
|
+
*/
|
|
16
|
+
export declare const appendSocketStatus: <C extends Config = Config, T extends Context<C> = Context<C>>(ctx: T, alias?: string) => T & SocketStatusServiceAppend;
|
|
17
|
+
/**
|
|
18
|
+
* The worst state across every live `ws()`/`useWs()` connection, or `'online'` if the app never
|
|
19
|
+
* registered the status service (`appendSocketStatus`) or has not finished initializing yet.
|
|
20
|
+
*/
|
|
21
|
+
export declare const useSocketStatus: () => SocketConnectionState;
|
|
22
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,MAAM,EAAE,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,yBAAyB,EACvF,MAAM,YAAY,CAAA;AAEnB,eAAO,MAAM,aAAa,kBAAkB,CAAA;AAI5C;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,WAAW,MAAM,KAAmB,mBAyBzE,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAAI,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,OACxF,CAAC,UAAS,MAAM,KACpB,CAAC,GAAG,yBAON,CAAA;AAiBD;;;GAGG;AACH,eAAO,MAAM,eAAe,QAAO,qBA2BlC,CAAA"}
|