@owlmeans/socket 0.1.18-rc.1 → 0.1.18-rc.11
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 +2 -2
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/socket/SKILL.md +92 -13
- package/package.json +4 -4
- package/build/.gitkeep +0 -0
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ Shared WebSocket connection types and message protocol for OwlMeans real-time co
|
|
|
12
12
|
## Installation
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
bun add @owlmeans/socket
|
|
15
|
+
bun add @owlmeans/socket@^0.1.18-rc.8
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
## Usage
|
|
@@ -91,7 +91,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
91
91
|
your project's skill store (`.agents/skills/`):
|
|
92
92
|
|
|
93
93
|
```sh
|
|
94
|
-
npx @owlmeans/agent-skills
|
|
94
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.14
|
|
95
95
|
```
|
|
96
96
|
|
|
97
97
|
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/socket",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-
|
|
4
|
+
"version": "0.1.18-rc.11",
|
|
5
|
+
"generatedAt": "2026-09-10T23:12:07.511Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: socket
|
|
3
|
-
description: How to use @owlmeans/socket —
|
|
3
|
+
description: How to use @owlmeans/socket — the transport-agnostic Connection model shared by client-socket and server-socket, its message types (call/request/event/auth/system), the type guards, and the socket error classes. Auto-invoked when importing socket types, message constants or the connection model.
|
|
4
4
|
user-invocable: false
|
|
5
5
|
---
|
|
6
6
|
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
@@ -8,29 +8,108 @@ user-invocable: false
|
|
|
8
8
|
# @owlmeans/socket
|
|
9
9
|
|
|
10
10
|
**Layer:** Core
|
|
11
|
-
**Install:** `"@owlmeans/socket": "^0.1.18-rc.
|
|
11
|
+
**Install:** `"@owlmeans/socket": "^0.1.18-rc.11"` in `dependencies`
|
|
12
|
+
|
|
13
|
+
Contracts and one implementation-free connection model. It knows nothing about WebSockets: the
|
|
14
|
+
browser side is `@owlmeans/client-socket`, the Fastify side `@owlmeans/server-socket`, and each
|
|
15
|
+
supplies the members the model leaves abstract — `send`, `close`, `authenticate` and `prepare` —
|
|
16
|
+
that make it concrete. Both halves of an application therefore speak the same frames.
|
|
12
17
|
|
|
13
18
|
## Key Exports
|
|
14
19
|
|
|
15
20
|
| Export | Description |
|
|
16
21
|
|--------|-------------|
|
|
17
|
-
| `
|
|
18
|
-
| `
|
|
19
|
-
|
|
|
20
|
-
|
|
|
21
|
-
|
|
|
22
|
+
| `createBasicConnection()` | The connection model — everything below the wire. A carrier assigns `send` / `close` / `authenticate` / `prepare` and feeds bytes to `receive` |
|
|
23
|
+
| `Connection` | What a handler is handed: the messaging verbs, `stage`, `getListeners` |
|
|
24
|
+
| `Message<T>` | The frame — `{ type, payload, id?, sender?, recipient?, dt?, rawData? }` |
|
|
25
|
+
| `CallMessage<T>` / `EventMessage<T>` / `AuthMessage<T>` | The three frames that add a field: `method` + `timeout`, `event`, `stage` |
|
|
26
|
+
| `MessageType` | `Call` `Result` `Error` `Request` `Response` `Event` `Message` `Auth` `System` |
|
|
27
|
+
| `isMessage` / `isEventMessage` / `isCallMessage` / `isAuthMessage` | Type guards — `isMessage(msg, true)` excludes system frames, `isEventMessage(msg, true)` keeps only them |
|
|
28
|
+
| `ConnectionListener` / `CallHendler` / `RequestHandler` / `CallResolver` | The callback shapes |
|
|
29
|
+
| `SocketError` and subclasses | `SocketInitializationError`, `SocketConnectionError`, `SocketUnauthorized`, `SocketUnsupported`, `SocketTimeout`, `SocketMessageError`, `SocketMessageMalformed` — all registered with `ResilientError` |
|
|
30
|
+
| `CALL_TIMEOUT` | 60 000 ms, the fallback when neither the message nor `connection.defaultCallTimeout` says |
|
|
31
|
+
|
|
32
|
+
## The four ways to say something
|
|
22
33
|
|
|
23
|
-
|
|
34
|
+
Pick by who is expected to answer and how often — they are separate registries, and a handler
|
|
35
|
+
bound to one never sees the others.
|
|
36
|
+
|
|
37
|
+
| Verb | Answered by | Shape |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| `notify(event, payload)` | `observe(event, handler)` | Fire-and-forget, fanned out to every observer of that event name |
|
|
40
|
+
| `call(method, ...args)` | `perform(method, handler)` | One RPC, resolved with the handler's return value or rejected with its error |
|
|
41
|
+
| `request(payload, observer?)` | `acknowledge(handler)`, answered with `reply(id, payload)` | An open question — acknowledgers run in turn until one takes it |
|
|
42
|
+
| `enqueue(payload, id?)` | `consume(filter?)` | A mailbox the far side drains on its own schedule; `enqueued()` is its depth |
|
|
24
43
|
|
|
25
44
|
```typescript
|
|
26
|
-
import
|
|
45
|
+
import { MessageType } from '@owlmeans/socket'
|
|
46
|
+
import type { Connection, EventMessage } from '@owlmeans/socket'
|
|
47
|
+
|
|
48
|
+
connection.observe<Progress>('job-event', async message => render(message.payload))
|
|
49
|
+
await connection.notify('job-event', { id, progress: 0.5 })
|
|
50
|
+
|
|
51
|
+
connection.perform<Report, [string]>('report', async id => await build(id))
|
|
52
|
+
const report = await connection.call<Report, [string]>('report', id)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
A `call` carries an id and a timeout, and the model arms the timer on both sides: the caller
|
|
56
|
+
rejects with `SocketTimeout` when the answer does not arrive, and the performer stops sending one
|
|
57
|
+
once it has elapsed. `timeout: 0` disables it. A performer that throws is answered with a
|
|
58
|
+
`MessageType.Error` frame carrying the marshalled error, so the caller's `call` rejects with the
|
|
59
|
+
original class rather than with a string.
|
|
60
|
+
|
|
61
|
+
## Frames a listener sees
|
|
27
62
|
|
|
28
|
-
|
|
63
|
+
`listen(listener)` receives EVERY inbound frame after the model has routed it — the escape hatch
|
|
64
|
+
for what the verbs above do not cover. It also receives the frames a carrier synthesises, which is
|
|
65
|
+
how a handler learns the connection is gone:
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
connection.listen(async message => {
|
|
69
|
+
if (typeof message !== 'object') {
|
|
70
|
+
return
|
|
71
|
+
}
|
|
72
|
+
const msg = message as EventMessage<void>
|
|
73
|
+
if (msg.type === MessageType.System && msg.event === 'close') {
|
|
74
|
+
await cleanUp()
|
|
75
|
+
}
|
|
76
|
+
})
|
|
29
77
|
```
|
|
30
78
|
|
|
31
|
-
|
|
79
|
+
Both carriers emit exactly that frame — `MessageType.System`, `event: 'close'`, payload
|
|
80
|
+
`{ code }` — when the socket closes. Nothing else reports a disconnect, so any subscription a
|
|
81
|
+
handler opened is released there.
|
|
82
|
+
|
|
83
|
+
## What the model expects of a carrier
|
|
84
|
+
|
|
85
|
+
- `receive(raw)` takes the raw string. It only parses text that starts with `{` or `[`; anything
|
|
86
|
+
else is dropped without reaching a listener. The carriers' own heartbeat IS JSON
|
|
87
|
+
(`{ type: 'ping' }`), so it is parsed: it matches no `MessageType` and routes nowhere, yet it
|
|
88
|
+
still reaches every `listen` listener — a listener has to recognise the frames it wants.
|
|
89
|
+
- A frame with no `type` is read as `MessageType.Message` and a frame with no `payload` is treated
|
|
90
|
+
as its own payload, so a plain JSON body from a foreign client still arrives as a message.
|
|
91
|
+
- `prepare(message, isRequest?)` is the carrier's hook for stamping a frame — timestamps,
|
|
92
|
+
`sender` / `recipient`. It runs on every outbound frame and on every inbound one.
|
|
93
|
+
- `send`, `close` and `authenticate` throw `SyntaxError` until a carrier assigns them, so one that
|
|
94
|
+
forgets a member fails loudly rather than dropping frames. `prepare` is the exception: it is
|
|
95
|
+
optional on the interface and simply absent until assigned, and the model calls it defensively —
|
|
96
|
+
a carrier that omits it stamps nothing.
|
|
97
|
+
|
|
98
|
+
## Authentication
|
|
99
|
+
|
|
100
|
+
`auth(stage, payload)` sends an `AuthMessage` and waits. The far side's `authenticate` answers with
|
|
101
|
+
the next stage and its payload, or throws — a rejection travels back as an `AuthMessage` with a
|
|
102
|
+
null stage and is rebuilt by the initiator. `connection.stage` holds the current
|
|
103
|
+
`AuthenticationStage` throughout. Only the server carrier implements a real sequence; see the
|
|
104
|
+
`server-socket` skill.
|
|
32
105
|
|
|
33
106
|
## Depends On
|
|
34
107
|
|
|
35
|
-
- `@owlmeans/error`,
|
|
36
|
-
- `@owlmeans/
|
|
108
|
+
- `@owlmeans/error` — `ResilientError`, which every socket error registers with
|
|
109
|
+
- `@owlmeans/auth` — `AuthenticationStage`, the vocabulary the auth frames carry
|
|
110
|
+
- `@owlmeans/basic-ids` — `uuid` for call and request ids
|
|
111
|
+
|
|
112
|
+
## Related
|
|
113
|
+
|
|
114
|
+
- `client-socket` — the browser carrier and `useWs`
|
|
115
|
+
- `server-socket` — the Fastify carrier, guard enforcement and `handleConnection`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/socket",
|
|
3
|
-
"version": "0.1.18-rc.
|
|
3
|
+
"version": "0.1.18-rc.11",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@owlmeans/auth": "^0.1.18-rc.
|
|
25
|
-
"@owlmeans/basic-ids": "^0.1.18-rc.
|
|
26
|
-
"@owlmeans/error": "^0.1.18-rc.
|
|
24
|
+
"@owlmeans/auth": "^0.1.18-rc.11",
|
|
25
|
+
"@owlmeans/basic-ids": "^0.1.18-rc.11",
|
|
26
|
+
"@owlmeans/error": "^0.1.18-rc.10"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@owlmeans/dep-config": "workspace:*",
|
package/build/.gitkeep
DELETED
|
File without changes
|