@sales-bot-llm/sdk 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/biome.json +36 -0
- package/docs/superpowers/plans/2026-05-08-sales-bot-sdk-plan.md +258 -0
- package/docs/superpowers/plans/2026-05-11-w3-sales-tool-polish-plan.md +476 -0
- package/docs/superpowers/specs/2026-05-08-sales-bot-sdk-design.md +587 -0
- package/example/.env.example +5 -0
- package/example/README.md +90 -0
- package/example/index.html +12 -0
- package/example/package.json +27 -0
- package/example/public/vanilla.global.js +345 -0
- package/example/src/App.tsx +50 -0
- package/example/src/main.tsx +16 -0
- package/example/src/routes/HookDemo.tsx +174 -0
- package/example/src/routes/VanillaDemo.tsx +67 -0
- package/example/src/routes/WidgetDemo.tsx +55 -0
- package/example/src/styles.css +18 -0
- package/example/tsconfig.json +19 -0
- package/example/tsconfig.tsbuildinfo +1 -0
- package/example/vite.config.ts +4 -0
- package/package.json +106 -0
- package/pnpm-workspace.yaml +3 -0
- package/src/core/client.ts +245 -0
- package/src/core/conversation.ts +34 -0
- package/src/core/index.ts +6 -0
- package/src/core/sse-parser.ts +87 -0
- package/src/core/storage.ts +72 -0
- package/src/core/transport.ts +271 -0
- package/src/core/types.ts +314 -0
- package/src/core/visitor.ts +21 -0
- package/src/react/index.ts +2 -0
- package/src/react/use-sales-bot.tsx +182 -0
- package/src/vanilla/index.ts +38 -0
- package/src/vue/index.ts +2 -0
- package/src/vue/use-sales-bot.ts +152 -0
- package/src/widget/index.ts +3 -0
- package/src/widget/markdown.ts +69 -0
- package/src/widget/styles.ts +350 -0
- package/src/widget/widget.ts +442 -0
- package/tests/contract/wire-format.test.ts +158 -0
- package/tests/core/client.test.ts +292 -0
- package/tests/core/conversation.test.ts +41 -0
- package/tests/core/sse-parser.test.ts +142 -0
- package/tests/core/storage.test.ts +78 -0
- package/tests/core/transport.test.ts +204 -0
- package/tests/core/visitor.test.ts +42 -0
- package/tests/react/use-sales-bot.test.tsx +188 -0
- package/tests/sales-tool-discriminator.test.ts +45 -0
- package/tests/setup.ts +3 -0
- package/tests/vanilla/vanilla.test.ts +37 -0
- package/tests/vue/use-sales-bot.test.ts +163 -0
- package/tests/widget/markdown.test.ts +113 -0
- package/tests/widget/widget.test.ts +388 -0
- package/tsconfig.json +28 -0
- package/tsup.config.ts +38 -0
- package/vitest.config.ts +26 -0
package/biome.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
|
|
3
|
+
"vcs": {
|
|
4
|
+
"enabled": true,
|
|
5
|
+
"clientKind": "git",
|
|
6
|
+
"useIgnoreFile": true
|
|
7
|
+
},
|
|
8
|
+
"formatter": {
|
|
9
|
+
"enabled": true,
|
|
10
|
+
"indentStyle": "space",
|
|
11
|
+
"indentWidth": 2,
|
|
12
|
+
"lineWidth": 100
|
|
13
|
+
},
|
|
14
|
+
"linter": {
|
|
15
|
+
"enabled": true,
|
|
16
|
+
"rules": {
|
|
17
|
+
"recommended": true,
|
|
18
|
+
"complexity": {
|
|
19
|
+
"noForEach": "off"
|
|
20
|
+
},
|
|
21
|
+
"suspicious": {
|
|
22
|
+
"noExplicitAny": "warn"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"javascript": {
|
|
27
|
+
"formatter": {
|
|
28
|
+
"quoteStyle": "single",
|
|
29
|
+
"trailingCommas": "all",
|
|
30
|
+
"semicolons": "always"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"files": {
|
|
34
|
+
"ignore": ["dist/**", "node_modules/**", "coverage/**"]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# Sales Bot SDK — Implementation Plan
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-05-08
|
|
4
|
+
**Status:** Active
|
|
5
|
+
**Author:** Claude (autonomous)
|
|
6
|
+
|
|
7
|
+
Each phase is TDD: write the failing test(s) first, implement to make them pass, commit.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Phase 0 — Bootstrap (package.json, tsconfig, tooling)
|
|
12
|
+
|
|
13
|
+
### Tasks
|
|
14
|
+
- [ ] 0.1 Create `package.json` with name `@sales-bot/sdk`, TypeScript, tsup, vitest, biome, React/Vue as peerDeps
|
|
15
|
+
- [ ] 0.2 Create `tsconfig.json` — strict mode, ESNext, bundler module resolution
|
|
16
|
+
- [ ] 0.3 Create `tsup.config.ts` — ESM+CJS for core/react/vue/widget; IIFE for vanilla
|
|
17
|
+
- [ ] 0.4 Create `vitest.config.ts` — happy-dom environment, coverage
|
|
18
|
+
- [ ] 0.5 Create `biome.json` — formatting + lint rules
|
|
19
|
+
- [ ] 0.6 Install dependencies
|
|
20
|
+
|
|
21
|
+
**Commit:** `chore: bootstrap package — tsup, vitest, biome, tsconfig`
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Phase 1 — Core types
|
|
26
|
+
|
|
27
|
+
### Tasks
|
|
28
|
+
- [ ] 1.1 Write `tests/contract/wire-format.test.ts` — imports types, asserts shape assignability
|
|
29
|
+
- [ ] 1.2 Create `src/core/types.ts` — verbatim event interfaces from backend, `SalesBotEvent` union, `SalesBotErrorCode`, `IdentifyInput`, `AskOptions`, `PostTurnInput`, `StorageAdapter`, `Unsubscribe`
|
|
30
|
+
- [ ] 1.3 Make contract test pass (compile-time + runtime shape assertions)
|
|
31
|
+
|
|
32
|
+
**Commit:** `feat(core): wire-format types + contract tests`
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Phase 2 — SSE parser
|
|
37
|
+
|
|
38
|
+
### TDD steps
|
|
39
|
+
1. Write `tests/core/sse-parser.test.ts`:
|
|
40
|
+
- parse single `turn_started` frame
|
|
41
|
+
- parse multiple frames in one chunk
|
|
42
|
+
- parse frames split across chunk boundaries
|
|
43
|
+
- parse `error` frame
|
|
44
|
+
- handle malformed frame → `SalesBotError({ code: 'parse_error' })`
|
|
45
|
+
- handle empty stream
|
|
46
|
+
2. Implement `src/core/sse-parser.ts`
|
|
47
|
+
3. All tests pass
|
|
48
|
+
|
|
49
|
+
**Commit:** `feat(core): SSE parser with boundary-spanning chunk handling`
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Phase 3 — Storage adapters
|
|
54
|
+
|
|
55
|
+
### TDD steps
|
|
56
|
+
1. Write `tests/core/storage.test.ts`:
|
|
57
|
+
- `LocalStorageAdapter` get/set/remove (happy-dom has localStorage)
|
|
58
|
+
- `MemoryStorageAdapter` get/set/remove
|
|
59
|
+
- `MemoryStorageAdapter` isolation between instances
|
|
60
|
+
2. Implement `src/core/storage.ts`
|
|
61
|
+
3. All tests pass
|
|
62
|
+
|
|
63
|
+
**Commit:** `feat(core): LocalStorageAdapter + MemoryStorageAdapter`
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Phase 4 — Visitor token
|
|
68
|
+
|
|
69
|
+
### TDD steps
|
|
70
|
+
1. Write `tests/core/visitor.test.ts`:
|
|
71
|
+
- generates UUID on first call
|
|
72
|
+
- returns same UUID on subsequent calls (same storage)
|
|
73
|
+
- namespaces key by embedKey
|
|
74
|
+
- uses injected storage adapter
|
|
75
|
+
2. Implement `src/core/visitor.ts`
|
|
76
|
+
3. All tests pass
|
|
77
|
+
|
|
78
|
+
**Commit:** `feat(core): visitor token generation + persistence`
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Phase 5 — SalesBotError
|
|
83
|
+
|
|
84
|
+
### Tasks
|
|
85
|
+
- [ ] 5.1 Add `SalesBotError` class to `src/core/types.ts`
|
|
86
|
+
- [ ] 5.2 Write test asserting it extends `Error`, has `.code`, `.retryable`, `.details`
|
|
87
|
+
- [ ] 5.3 Make test pass
|
|
88
|
+
|
|
89
|
+
**Commit:** `feat(core): SalesBotError class`
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Phase 6 — HTTP transport
|
|
94
|
+
|
|
95
|
+
### TDD steps
|
|
96
|
+
1. Write `tests/core/transport.test.ts`:
|
|
97
|
+
- sets `Authorization: Bearer <embedKey>` header
|
|
98
|
+
- sets `Idempotency-Key` header
|
|
99
|
+
- sets `Accept: text/event-stream`
|
|
100
|
+
- sets `Content-Type: application/json`
|
|
101
|
+
- sends correct JSON body
|
|
102
|
+
- returns `ReadableStream` on 200
|
|
103
|
+
- maps 401 → `SalesBotError({ code: 'invalid_embed_key' })` when body has that code
|
|
104
|
+
- maps 402 → `out_of_credits`
|
|
105
|
+
- maps 429 → `rate_limited`
|
|
106
|
+
- maps 500 → `internal`
|
|
107
|
+
- maps fetch throw → `network_error`
|
|
108
|
+
- `getResumeStream` calls `GET /api/chat/turns/:turnId/stream`
|
|
109
|
+
- merges `customHeaders`
|
|
110
|
+
2. Implement `src/core/transport.ts`
|
|
111
|
+
3. All tests pass
|
|
112
|
+
|
|
113
|
+
**Commit:** `feat(core): fetch-based HTTP transport with error mapping`
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Phase 7 — SalesBotClient class
|
|
118
|
+
|
|
119
|
+
### TDD steps
|
|
120
|
+
1. Write `tests/core/client.test.ts`:
|
|
121
|
+
- constructor stores embedKey, creates storage, generates visitor token
|
|
122
|
+
- `identify()` stores traits for next ask
|
|
123
|
+
- `ask()` calls postTurn with correct body (visitorToken, message, identify, conversationId)
|
|
124
|
+
- `ask()` yields events from the SSE stream
|
|
125
|
+
- `ask()` emits events on the event bus simultaneously
|
|
126
|
+
- `ask()` auto-updates conversationId from `turn_started`
|
|
127
|
+
- `resume(turnId)` calls getResumeStream
|
|
128
|
+
- `on()` returns unsubscribe function that actually unsubscribes
|
|
129
|
+
- `getVisitorToken()` returns stable UUID
|
|
130
|
+
- `getConversationId()` / `setConversationId()`
|
|
131
|
+
2. Implement `src/core/client.ts`
|
|
132
|
+
3. Implement `src/core/index.ts` re-exports
|
|
133
|
+
4. All tests pass
|
|
134
|
+
|
|
135
|
+
**Commit:** `feat(core): SalesBotClient with ask/identify/resume/on API`
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Phase 8 — React adapter
|
|
140
|
+
|
|
141
|
+
### TDD steps
|
|
142
|
+
1. Write `tests/react/use-sales-bot.test.tsx`:
|
|
143
|
+
- `renderHook(() => useSalesBot({ embedKey }))` returns stable shape
|
|
144
|
+
- `ask()` appends user message to `messages`
|
|
145
|
+
- `isStreaming` becomes true during ask, false after done
|
|
146
|
+
- `messages` accumulates assistant deltas
|
|
147
|
+
- `error` is set on SalesBotError
|
|
148
|
+
- `reset()` clears messages and conversationId
|
|
149
|
+
- client is not re-created on re-render
|
|
150
|
+
2. Implement `src/react/use-sales-bot.tsx`
|
|
151
|
+
3. Implement `src/react/index.ts`
|
|
152
|
+
4. All tests pass
|
|
153
|
+
|
|
154
|
+
**Commit:** `feat(react): useSalesBot hook`
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Phase 9 — Vue adapter
|
|
159
|
+
|
|
160
|
+
### TDD steps
|
|
161
|
+
1. Write `tests/vue/use-sales-bot.test.ts`:
|
|
162
|
+
- composable returns reactive refs
|
|
163
|
+
- `ask()` updates `messages` ref
|
|
164
|
+
- `isStreaming` ref transitions correctly
|
|
165
|
+
- `error` ref set on failure
|
|
166
|
+
- `reset()` clears state
|
|
167
|
+
- handlers unsubscribed on unmount
|
|
168
|
+
2. Implement `src/vue/use-sales-bot.ts`
|
|
169
|
+
3. Implement `src/vue/index.ts`
|
|
170
|
+
4. All tests pass
|
|
171
|
+
|
|
172
|
+
**Commit:** `feat(vue): useSalesBot composable`
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Phase 10 — Widget UI
|
|
177
|
+
|
|
178
|
+
### Tasks
|
|
179
|
+
- [ ] 10.1 Write `tests/widget/widget.test.ts`:
|
|
180
|
+
- `createWidget(opts)` appends `<sales-bot-widget>` to body
|
|
181
|
+
- shadow root contains launcher button and panel
|
|
182
|
+
- clicking launcher opens/closes panel
|
|
183
|
+
- `destroy()` removes element from DOM
|
|
184
|
+
- basic message rendering in shadow DOM
|
|
185
|
+
- [ ] 10.2 Implement `src/widget/styles.ts` — CSS string for shadow root
|
|
186
|
+
- [ ] 10.3 Implement `src/widget/widget.ts` — shadow DOM, message rendering, event wiring
|
|
187
|
+
- [ ] 10.4 Implement `src/widget/index.ts`
|
|
188
|
+
- [ ] 10.5 All tests pass
|
|
189
|
+
|
|
190
|
+
**Commit:** `feat(widget): shadow-DOM floating chat widget`
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Phase 11 — Vanilla / IIFE bundle entry
|
|
195
|
+
|
|
196
|
+
### Tasks
|
|
197
|
+
- [ ] 11.1 Implement `src/vanilla/index.ts` — `window.SalesBot = { init, widget }`
|
|
198
|
+
- [ ] 11.2 Write a smoke test asserting `init()` returns a `SalesBotClient`
|
|
199
|
+
- [ ] 11.3 All tests pass
|
|
200
|
+
|
|
201
|
+
**Commit:** `feat(vanilla): IIFE entry with window.SalesBot`
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Phase 12 — Build pipeline
|
|
206
|
+
|
|
207
|
+
### Tasks
|
|
208
|
+
- [ ] 12.1 Finalize `tsup.config.ts` with all entry points
|
|
209
|
+
- [ ] 12.2 Finalize `package.json` exports map
|
|
210
|
+
- [ ] 12.3 Run `pnpm build` and verify `dist/` contains expected files
|
|
211
|
+
- [ ] 12.4 Spot-check each bundle imports cleanly
|
|
212
|
+
|
|
213
|
+
**Commit:** `build: finalize tsup config + exports map`
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Phase 13 — size-limit
|
|
218
|
+
|
|
219
|
+
### Tasks
|
|
220
|
+
- [ ] 13.1 Add `size-limit` config to `package.json`
|
|
221
|
+
- [ ] 13.2 Run `size-limit` and verify budgets pass (core <8KB, react/vue <12KB, widget <25KB, vanilla <20KB)
|
|
222
|
+
|
|
223
|
+
**Commit:** `ci: add size-limit bundle budget checks`
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Phase 14 — Final review + cleanup
|
|
228
|
+
|
|
229
|
+
### Tasks
|
|
230
|
+
- [ ] 14.1 Run full test suite — all pass
|
|
231
|
+
- [ ] 14.2 Run biome check — no errors
|
|
232
|
+
- [ ] 14.3 Verify builds produce correct output
|
|
233
|
+
- [ ] 14.4 Review public API surface for consistency
|
|
234
|
+
|
|
235
|
+
**Commit:** `chore: final cleanup and verification`
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Dependency matrix
|
|
240
|
+
|
|
241
|
+
| Package | Role | Dev/Peer/Prod |
|
|
242
|
+
|---|---|---|
|
|
243
|
+
| `typescript` | Language | dev |
|
|
244
|
+
| `tsup` | Bundler | dev |
|
|
245
|
+
| `vitest` | Test runner | dev |
|
|
246
|
+
| `happy-dom` | DOM env | dev |
|
|
247
|
+
| `@testing-library/react` | React test utils | dev |
|
|
248
|
+
| `@testing-library/user-event` | User interaction | dev |
|
|
249
|
+
| `@vue/test-utils` | Vue test utils | dev |
|
|
250
|
+
| `@vitejs/plugin-react` | React support in vitest | dev |
|
|
251
|
+
| `biome` | Lint + format | dev |
|
|
252
|
+
| `size-limit` | Bundle budget | dev |
|
|
253
|
+
| `@size-limit/preset-small-lib` | size-limit preset | dev |
|
|
254
|
+
| `react` | React framework | peerDep |
|
|
255
|
+
| `react-dom` | React DOM | peerDep |
|
|
256
|
+
| `vue` | Vue framework | peerDep |
|
|
257
|
+
|
|
258
|
+
**Zero runtime dependencies.** All helpers (SSE parser, markdown renderer, storage) are hand-rolled and tree-shakeable.
|