@stapel/chat-react 0.1.0 → 0.2.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/CHANGELOG.md +49 -0
- package/LICENSE +21 -0
- package/dist/flows/freshness.js +2 -2
- package/dist/model/runtime.d.ts +1 -1
- package/llms.txt +1 -1
- package/manifest.json +1 -1
- package/nav-manifest.json +1 -1
- package/package.json +13 -13
- package/src/analytics/generated/events.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1 +1,50 @@
|
|
|
1
1
|
# @stapel/chat-react
|
|
2
|
+
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- ca35e19: New pair: `@stapel/chat-react` — the React half of `stapel-chat`, wiring both
|
|
8
|
+
of its transports behind one seam.
|
|
9
|
+
|
|
10
|
+
The storefront spec ruled polling-only for chat v1, and it was right about the
|
|
11
|
+
fleet it surveyed: the resumable consumer existed but `stapel_chat.routing`
|
|
12
|
+
exported nothing, so no host could mount it. stapel-chat 0.2.2 ships that mount
|
|
13
|
+
(`ws/chat/<uuid:conversation_id>`). So this pair carries **two transports and
|
|
14
|
+
one seam** — `useChatFreshness(streamKey, mapToQueryKeys, { fallbackRefetchInterval })`,
|
|
15
|
+
deliberately the signature the realtime substrate reserves for
|
|
16
|
+
`useSignalInvalidate`:
|
|
17
|
+
|
|
18
|
+
- a typed client for the module's own protocol — `hello{last_seq}` → `welcome`
|
|
19
|
+
→ replay → `replay_done` → live frames, seq-deduped on both ends, resume from
|
|
20
|
+
the cursor the STORE holds (not the one the socket opened with), `error{resync}`
|
|
21
|
+
forwarded verbatim, close codes 4401/4403 treated as answers rather than
|
|
22
|
+
faults (no reconnect), everything else reconnected with jittered backoff;
|
|
23
|
+
- polling by `seq`, visibility-aware, with exponential backoff on consecutive
|
|
24
|
+
failures — used whenever the socket is not carrying the stream, and for the
|
|
25
|
+
inbox, which has no socket at all (the module fans out per thread).
|
|
26
|
+
|
|
27
|
+
Both ends do the same thing with what they learn: refetch the thread query,
|
|
28
|
+
whose query function advances the window BY SEQ
|
|
29
|
+
(`?direction=prev&anchor=<tip>`). The screens are written once and the tests
|
|
30
|
+
run against both transports. Writes never go over the socket: the `send` frame
|
|
31
|
+
is typed (a mirror must be complete) and never emitted, because its refusals
|
|
32
|
+
carry socket-local codes with no i18n key and no remediation, while
|
|
33
|
+
`POST …/messages` answers with the persisted row and a real error envelope.
|
|
34
|
+
|
|
35
|
+
Surface: `<ConversationList>` (server-computed unread counts, as a LoadState so
|
|
36
|
+
a badge cannot read "0" during an outage), `<ConversationThread>` (a contiguous
|
|
37
|
+
seq-ordered window — a hole is re-read, never stitched — with backfill and an
|
|
38
|
+
automatic, monotonic read marker), `<MessageComposer>` (code-point length
|
|
39
|
+
counting, so an emoji is one character on both sides of the wire), and
|
|
40
|
+
`<StartDirectChat>` — "message the seller", get-or-create over the module's own
|
|
41
|
+
participant-pair idempotency. An opt-in antd skin at `@stapel/chat-react/default`
|
|
42
|
+
and a member-surface nav entry.
|
|
43
|
+
|
|
44
|
+
Two contract facts recorded rather than papered over:
|
|
45
|
+
`CreateConversationRequest.scope_key` is ignored by the server, so a direct
|
|
46
|
+
thread cannot be scoped to a listing and the pair exposes no argument that
|
|
47
|
+
pretends otherwise; and stapel-chat ships no `translations/` directory, so the
|
|
48
|
+
pair authors ru/es for the twelve error keys the module owns (the
|
|
49
|
+
stapel-forms/stapel_attributes precedent) while the cross-cutting keys come from
|
|
50
|
+
stapel-core's catalogue.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Stapel contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/flows/freshness.js
CHANGED
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
*
|
|
5
5
|
* ── What changed since the spec ─────────────────────────────────────────────
|
|
6
6
|
*
|
|
7
|
-
*
|
|
7
|
+
* The storefront spec §3.6 ruled polling-by-seq for chat v1,
|
|
8
8
|
* and it was right about the fleet it surveyed: stapel-chat had the resumable
|
|
9
9
|
* consumer but `routing.py` exported nothing, so no host could mount it.
|
|
10
10
|
* stapel-chat 0.2.2 ships that mount (`ws/chat/<uuid:conversation_id>`) and
|
|
11
|
-
* the
|
|
11
|
+
* the client fleet runs it. So the pair carries BOTH transports and picks at
|
|
12
12
|
* runtime — a deployment without sockets (WSGI, no channel layer, a
|
|
13
13
|
* misconfigured proxy) is not a broken chat, it is a chat that refreshes on a
|
|
14
14
|
* timer.
|
package/dist/model/runtime.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ import type { ChatReconnectOptions, ChatWebSocketFactory } from "../realtime/cha
|
|
|
10
10
|
export interface ChatRealtimeOptions {
|
|
11
11
|
/**
|
|
12
12
|
* Where this deployment mounts `stapel_chat.routing.websocket_urlpatterns`,
|
|
13
|
-
* e.g. `wss://
|
|
13
|
+
* e.g. `wss://shop.example/ws/chat/`. Omit to derive it from `baseUrl`
|
|
14
14
|
* (the canonical `/ws/chat/` at the API's own origin). Pass `null` to turn
|
|
15
15
|
* the socket transport OFF explicitly — a host that knows its backend runs
|
|
16
16
|
* under WSGI says so here instead of letting every tab fail a handshake
|
package/llms.txt
CHANGED
package/manifest.json
CHANGED
package/nav-manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stapel/chat-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Headless React pair for stapel-chat: typed API client, TanStack Query hooks, a seq-ordered thread store, and ONE transport seam behind which the module's own resumable WebSocket protocol (hello/welcome/replay/replay_done/message/error) and seq-anchored polling are interchangeable — the UI never knows which is live. Conversation list with unread badges, thread replay + live tail, REST send, direct-thread idempotency for \"message the seller\", monotonic read markers. Zero visual opinion in the main entry; an opt-in /default subpath ships the antd skin.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -47,13 +47,6 @@
|
|
|
47
47
|
"nav-manifest.json",
|
|
48
48
|
"llms.txt"
|
|
49
49
|
],
|
|
50
|
-
"scripts": {
|
|
51
|
-
"build": "tsc -p tsconfig.json",
|
|
52
|
-
"test": "tsc -p tsconfig.demo.json && vitest run --exclude test/prodBundlePurity.test.ts",
|
|
53
|
-
"test:pack": "vitest run test/prodBundlePurity.test.ts",
|
|
54
|
-
"lint": "eslint .",
|
|
55
|
-
"size": "size-limit"
|
|
56
|
-
},
|
|
57
50
|
"size-limit": [
|
|
58
51
|
{
|
|
59
52
|
"name": "index — headless pair (client + hooks + thread store + transport seam)",
|
|
@@ -89,9 +82,6 @@
|
|
|
89
82
|
},
|
|
90
83
|
"devDependencies": {
|
|
91
84
|
"@size-limit/preset-small-lib": "^11.2.0",
|
|
92
|
-
"@stapel/core": "workspace:^",
|
|
93
|
-
"@stapel/showcase": "workspace:^",
|
|
94
|
-
"@stapel/tokens": "workspace:^",
|
|
95
85
|
"@tanstack/react-query": "^5.81.0",
|
|
96
86
|
"@testing-library/react": "^16.3.0",
|
|
97
87
|
"@types/react": "^19.1.0",
|
|
@@ -103,12 +93,22 @@
|
|
|
103
93
|
"react-dom": "^19.1.0",
|
|
104
94
|
"size-limit": "^11.2.0",
|
|
105
95
|
"typescript": "^5.8.3",
|
|
106
|
-
"vitest": "^3.2.4"
|
|
96
|
+
"vitest": "^3.2.4",
|
|
97
|
+
"@stapel/core": "^0.15.0",
|
|
98
|
+
"@stapel/showcase": "^0.2.0",
|
|
99
|
+
"@stapel/tokens": "^0.5.0"
|
|
107
100
|
},
|
|
108
101
|
"engines": {
|
|
109
102
|
"node": ">=22"
|
|
110
103
|
},
|
|
111
104
|
"publishConfig": {
|
|
112
105
|
"access": "public"
|
|
106
|
+
},
|
|
107
|
+
"scripts": {
|
|
108
|
+
"build": "tsc -p tsconfig.json",
|
|
109
|
+
"test": "tsc -p tsconfig.demo.json && vitest run --exclude test/prodBundlePurity.test.ts",
|
|
110
|
+
"test:pack": "vitest run test/prodBundlePurity.test.ts",
|
|
111
|
+
"lint": "eslint .",
|
|
112
|
+
"size": "size-limit"
|
|
113
113
|
}
|
|
114
|
-
}
|
|
114
|
+
}
|