@chatlychat/sdk-js 0.0.0-stage → 0.1.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 +21 -0
- package/LICENSE +21 -0
- package/README.md +81 -2
- package/dist/index.d.ts +175 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +501 -0
- package/dist/index.js.map +1 -0
- package/dist/live.d.ts +99 -0
- package/dist/live.d.ts.map +1 -0
- package/dist/live.js +158 -0
- package/dist/live.js.map +1 -0
- package/dist/types.d.ts +142 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/package.json +60 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# @chatlychat/sdk-js — changelog
|
|
2
|
+
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
- `subscribe` now reports INBOUND typing through `handlers.onTyping` — the
|
|
6
|
+
send half (`setTyping`) shipped first and there was no way to show the
|
|
7
|
+
visitor that the agent was typing. Push-only, like `setTyping`: typing is a
|
|
8
|
+
socket event with no HTTP route, so a polling subscription warns once rather
|
|
9
|
+
than never firing in silence.
|
|
10
|
+
- `onTyping` is edge-triggered and self-clearing (`TYPING_STOP_AFTER_MS`,
|
|
11
|
+
3.5s — the widget's own window), because `typing.stop` is best-effort and an
|
|
12
|
+
agent who closes their laptop mid-sentence never sends one.
|
|
13
|
+
- `identify()` now remembers the contact id it was given, so `setTyping` names
|
|
14
|
+
the right contact on a returning browser instead of `'unknown'`.
|
|
15
|
+
|
|
16
|
+
## 0.1.0 — 2026-05-25
|
|
17
|
+
|
|
18
|
+
- Initial public release.
|
|
19
|
+
- `Chatly` class: `identify`, `track`, `open`, `close`, `toggle`, `send`, `on`,
|
|
20
|
+
`destroy`.
|
|
21
|
+
- TypeScript types ship with the package; no `@types/*` package needed.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Chatly Engineering
|
|
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/README.md
CHANGED
|
@@ -1,3 +1,82 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @chatlychat/sdk-js
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Browser SDK for the Chatly platform: control the in-page widget, identify
|
|
4
|
+
visitors, fire CDP events, and — headlessly — list conversations, send
|
|
5
|
+
messages and subscribe to replies without rendering our UI at all.
|
|
6
|
+
|
|
7
|
+
> **Not published to npm yet.** The install line below will 404 today. The
|
|
8
|
+
> widget-control half of this surface is already available with no package:
|
|
9
|
+
> load the widget snippet and call the methods on `window.Chatly`. The
|
|
10
|
+
> headless half (`listConversations`, `listMessages`, `send`, `uploadFile`,
|
|
11
|
+
> `subscribe`, `rate`, `emailTranscript`) has **no** global and needs this
|
|
12
|
+
> package or a direct call to the documented REST endpoints.
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @chatlychat/sdk-js
|
|
16
|
+
# or
|
|
17
|
+
pnpm add @chatlychat/sdk-js
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick start
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { Chatly } from '@chatlychat/sdk-js';
|
|
24
|
+
|
|
25
|
+
// The constructor is PRIVATE. `init` is the only way in.
|
|
26
|
+
const chatly = Chatly.init({ publicId: 'ch_web_0192…' });
|
|
27
|
+
|
|
28
|
+
await chatly.identify({ externalId: 'user_42', name: 'Ada', userHash: '…' });
|
|
29
|
+
const { conversationId } = await chatly.startConversation('Hello');
|
|
30
|
+
await chatly.send(conversationId, 'and one more thing');
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## `Chatly.init(options)`
|
|
34
|
+
|
|
35
|
+
| Option | Type | Default | Notes |
|
|
36
|
+
| ------------- | --------- | ---------------------------- | ------------------------------------------------------------------------- |
|
|
37
|
+
| `publicId` | `string` | — | The web channel's public id, from Dashboard → Channels. |
|
|
38
|
+
| `apiUrl` | `string?` | `https://api.chatlychat.com` | Set only if you self-host. |
|
|
39
|
+
| `realtimeUrl` | `string?` | reported by the server | Socket.IO host for `subscribe()`. Only for a host the server cannot know. |
|
|
40
|
+
|
|
41
|
+
## Methods
|
|
42
|
+
|
|
43
|
+
Widget control — these mirror `window.Chatly` and need the widget on the page:
|
|
44
|
+
|
|
45
|
+
- `open()` / `close()`
|
|
46
|
+
|
|
47
|
+
Visitor identity and analytics:
|
|
48
|
+
|
|
49
|
+
- `identify(input)` → `{ contactId }`. Pass `userHash` to make the identity
|
|
50
|
+
**verified**; without it the visitor is unverified and tools that require a
|
|
51
|
+
proven identity will refuse.
|
|
52
|
+
- `track(name, properties?)`
|
|
53
|
+
|
|
54
|
+
Headless conversation surface — no widget required:
|
|
55
|
+
|
|
56
|
+
- `startConversation(body, attachments?)` → `{ conversationId }`
|
|
57
|
+
- `send(conversationId, body, attachments?)`
|
|
58
|
+
- `listConversations(limit = 20)`
|
|
59
|
+
- `listMessages(conversationId, limit = 50)`
|
|
60
|
+
- `subscribe(conversationId, handlers, options?)` → `Subscription`. Uses the
|
|
61
|
+
push socket when it can and falls back to polling, so it keeps working
|
|
62
|
+
where a WebSocket cannot be opened.
|
|
63
|
+
- `uploadFile(file)` → `VisitorAttachment`, to pass to `send` or
|
|
64
|
+
`startConversation`
|
|
65
|
+
- `rate(conversationId, score, comment?)`
|
|
66
|
+
- `emailTranscript(conversationId, email)`
|
|
67
|
+
|
|
68
|
+
## Signed page context
|
|
69
|
+
|
|
70
|
+
`setContext` is **not** on this SDK — it is on the widget's own global. See
|
|
71
|
+
the [web channel guide](https://chatlychat.com/guides/channel-web) for the
|
|
72
|
+
call and [identity verification](https://chatlychat.com/docs/identity-verification)
|
|
73
|
+
for how to mint the signed `contextToken`.
|
|
74
|
+
|
|
75
|
+
## This README used to document an API that did not exist
|
|
76
|
+
|
|
77
|
+
For the record, because it may have been copied: it described
|
|
78
|
+
`new Chatly({ channelPublicId, baseUrl, widgetSelector, locale })`, plus
|
|
79
|
+
`toggle()`, `on()`, `destroy()` and `send(body)`. **None of those exist.** The
|
|
80
|
+
constructor is private, the option names are `publicId` / `apiUrl` /
|
|
81
|
+
`realtimeUrl`, and `send` takes a conversation id first. Corrected
|
|
82
|
+
2026-10-12 against `src/index.ts`.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser SDK. Pairs with the widget loader to give product code a way to
|
|
3
|
+
* identify visitors, fire CDP events, and control the widget.
|
|
4
|
+
*
|
|
5
|
+
* import { Chatly } from '@chatlychat/sdk-js';
|
|
6
|
+
* const lc = Chatly.init({ publicId: 'acme-web', apiUrl: 'https://api.acme.com' });
|
|
7
|
+
* await lc.identify({ email: 'a@b.com', name: 'Alice' });
|
|
8
|
+
* await lc.track('signup_completed', { plan: 'pro' });
|
|
9
|
+
* lc.open();
|
|
10
|
+
*/
|
|
11
|
+
import type { HeadlessConversation, HeadlessMessage, SubscribeHandlers, SubscribeOptions, Subscription } from './types.js';
|
|
12
|
+
export type { HeadlessConversation, HeadlessMessage, SubscribeHandlers, SubscribeOptions, SocketIoFactory, Subscription, TypingSignal, } from './types.js';
|
|
13
|
+
export { TYPING_STOP_AFTER_MS } from './live.js';
|
|
14
|
+
export interface SdkOptions {
|
|
15
|
+
publicId: string;
|
|
16
|
+
apiUrl?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Socket.IO host, for the push path of `subscribe()`.
|
|
19
|
+
*
|
|
20
|
+
* Normally unnecessary: `/v1/widget/init` reports the right one and the SDK
|
|
21
|
+
* remembers it. Set this only for a deployment whose realtime host the
|
|
22
|
+
* server cannot know — the same escape hatch the widget's embed has.
|
|
23
|
+
*/
|
|
24
|
+
realtimeUrl?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface IdentifyInput {
|
|
27
|
+
/**
|
|
28
|
+
* Your own id for this person. Optional — see `identify` — but it is the
|
|
29
|
+
* only field identity verification can bind, so a channel with verification
|
|
30
|
+
* enabled needs this plus `userHash` to consider the visitor proven.
|
|
31
|
+
*/
|
|
32
|
+
externalId?: string;
|
|
33
|
+
email?: string;
|
|
34
|
+
phone?: string;
|
|
35
|
+
name?: string;
|
|
36
|
+
/**
|
|
37
|
+
* `HMAC-SHA256(<your channel's IDV secret>, externalId)`, computed by YOUR
|
|
38
|
+
* SERVER. Never compute it in the browser — the secret would be in your
|
|
39
|
+
* page source. Required when the channel has identity verification enabled
|
|
40
|
+
* and you are claiming an `externalId`; ignored when it does not.
|
|
41
|
+
*/
|
|
42
|
+
userHash?: string;
|
|
43
|
+
attributes?: Record<string, unknown>;
|
|
44
|
+
}
|
|
45
|
+
export interface TrackInput {
|
|
46
|
+
name: string;
|
|
47
|
+
properties?: Record<string, unknown>;
|
|
48
|
+
}
|
|
49
|
+
declare global {
|
|
50
|
+
interface Window {
|
|
51
|
+
Chatly?: {
|
|
52
|
+
open?: () => void;
|
|
53
|
+
close?: () => void;
|
|
54
|
+
destroy?: () => void;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* An uploaded file, as returned by `uploadFile` and accepted by `send`.
|
|
60
|
+
*
|
|
61
|
+
* Declared locally rather than imported from `@livechat/shared`: this bundle
|
|
62
|
+
* ships to a customer's website, and importing from the shared package drags
|
|
63
|
+
* zod into it — measured at ~11KB gzipped when it happened to the widget.
|
|
64
|
+
*/
|
|
65
|
+
export interface VisitorAttachment {
|
|
66
|
+
readonly id: string;
|
|
67
|
+
readonly filename: string;
|
|
68
|
+
readonly mimeType: string;
|
|
69
|
+
readonly sizeBytes: number;
|
|
70
|
+
readonly url: string;
|
|
71
|
+
}
|
|
72
|
+
export declare class Chatly {
|
|
73
|
+
private readonly opts;
|
|
74
|
+
private readonly base;
|
|
75
|
+
private visitorToken;
|
|
76
|
+
/**
|
|
77
|
+
* The realtime host `/v1/widget/init` reported, remembered for `subscribe`.
|
|
78
|
+
*
|
|
79
|
+
* `/v1/widget/realtime/token` returns `{ token, expiresAt }` and NO url —
|
|
80
|
+
* the first version of `subscribe` read a `url` off it and silently fell
|
|
81
|
+
* back to the API host, which is not where the socket server is.
|
|
82
|
+
*/
|
|
83
|
+
private realtimeUrl;
|
|
84
|
+
/**
|
|
85
|
+
* This visitor's contact id, remembered for the typing event — the realtime
|
|
86
|
+
* gateway's payload requires an `actorId` and the visitor's is their contact.
|
|
87
|
+
*/
|
|
88
|
+
private contactId;
|
|
89
|
+
static init(opts: SdkOptions): Chatly;
|
|
90
|
+
private constructor();
|
|
91
|
+
open(): void;
|
|
92
|
+
close(): void;
|
|
93
|
+
/**
|
|
94
|
+
* Attach a known identity to this visitor.
|
|
95
|
+
*
|
|
96
|
+
* Re-initialises the session with an `identity` payload rather than calling
|
|
97
|
+
* a dedicated endpoint. There has never been a `/v1/widget/identify` route —
|
|
98
|
+
* this method has 404'd since it was written, as have the Kotlin and Swift
|
|
99
|
+
* equivalents. Identity is accepted by `init`, which is also where the
|
|
100
|
+
* `userHash` check for verified identity lives, so routing through it means
|
|
101
|
+
* identification and verification cannot drift apart.
|
|
102
|
+
*
|
|
103
|
+
* `identify({ email })` with no `externalId` — the exact call this file's
|
|
104
|
+
* own header comment demonstrates — used to be rejected by the server with
|
|
105
|
+
* a 400, because `widgetInitSchema` required `externalId`. It no longer is;
|
|
106
|
+
* an email-only identity attaches a reply address to whoever this browser
|
|
107
|
+
* already is. It cannot be *verified*, though: `userHash` binds the external
|
|
108
|
+
* id and there is nothing to bind without one.
|
|
109
|
+
*
|
|
110
|
+
* No longer mints an anonymous session first. That cost a round trip, and
|
|
111
|
+
* worse, it was pointless: the token the server returns HERE is the
|
|
112
|
+
* identified one, and it is stored below. Before, the SDK kept the
|
|
113
|
+
* anonymous token it had just fetched, so every later `track` or `send`
|
|
114
|
+
* spoke for the anonymous visitor and the identification was quietly lost.
|
|
115
|
+
*/
|
|
116
|
+
identify(input: IdentifyInput): Promise<{
|
|
117
|
+
contactId: string;
|
|
118
|
+
}>;
|
|
119
|
+
/**
|
|
120
|
+
* Upload a file as this visitor and return the attachment record.
|
|
121
|
+
*
|
|
122
|
+
* The two-step presign + direct PUT is deliberate: the file never passes
|
|
123
|
+
* through the API, which would mean proxying it in memory only to write it
|
|
124
|
+
* to object storage anyway.
|
|
125
|
+
*/
|
|
126
|
+
uploadFile(file: File): Promise<VisitorAttachment>;
|
|
127
|
+
/** Send a message, optionally with attachments from `uploadFile`. */
|
|
128
|
+
send(conversationId: string, body: string, attachments?: VisitorAttachment[]): Promise<void>;
|
|
129
|
+
/**
|
|
130
|
+
* This visitor's own conversations, most recent first.
|
|
131
|
+
*
|
|
132
|
+
* Scoped by the visitor token, so it is exactly the threads this browser is
|
|
133
|
+
* entitled to and never anyone else's.
|
|
134
|
+
*/
|
|
135
|
+
listConversations(limit?: number): Promise<HeadlessConversation[]>;
|
|
136
|
+
/** The messages of one conversation, oldest first. */
|
|
137
|
+
listMessages(conversationId: string, limit?: number): Promise<HeadlessMessage[]>;
|
|
138
|
+
/**
|
|
139
|
+
* Open a NEW conversation with a first message.
|
|
140
|
+
*
|
|
141
|
+
* `send` replies to one that exists and requires a `conversationId`; this is
|
|
142
|
+
* the other endpoint. Getting them the wrong way round is a 400 complaining
|
|
143
|
+
* about a missing `conversationId`, which is how the repo's own E2E spec was
|
|
144
|
+
* written and why it could never pass.
|
|
145
|
+
*/
|
|
146
|
+
startConversation(body: string, attachments?: VisitorAttachment[]): Promise<{
|
|
147
|
+
conversationId: string;
|
|
148
|
+
}>;
|
|
149
|
+
/**
|
|
150
|
+
* Call `onMessage` for every message this subscription has not already
|
|
151
|
+
* given you. Returns the unsubscribe function.
|
|
152
|
+
*
|
|
153
|
+
* **Polling by default**, because the alternative is making every consumer
|
|
154
|
+
* ship `socket.io-client` whether they want push or not. Pass your own
|
|
155
|
+
* factory for push:
|
|
156
|
+
*
|
|
157
|
+
* import { io } from 'socket.io-client';
|
|
158
|
+
* const stop = chatly.subscribe(id, { onMessage }, { io });
|
|
159
|
+
*
|
|
160
|
+
* Errors go to `onError`, never a rejected promise: this is long-lived, and
|
|
161
|
+
* a rejection nobody awaits is an unhandled rejection on the customer's own
|
|
162
|
+
* page.
|
|
163
|
+
*/
|
|
164
|
+
subscribe(conversationId: string, handlers: SubscribeHandlers, options?: SubscribeOptions): Subscription;
|
|
165
|
+
/** Submit a post-chat satisfaction score (1-5, or 0-10 for NPS). */
|
|
166
|
+
rate(conversationId: string, score: number, comment?: string): Promise<void>;
|
|
167
|
+
/** Email this visitor a transcript of their conversation. */
|
|
168
|
+
emailTranscript(conversationId: string, email: string): Promise<void>;
|
|
169
|
+
track(name: string, properties?: Record<string, unknown>): Promise<void>;
|
|
170
|
+
private setVisitorToken;
|
|
171
|
+
private ensureVisitorToken;
|
|
172
|
+
private request;
|
|
173
|
+
}
|
|
174
|
+
export default Chatly;
|
|
175
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|