@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/dist/live.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How many message ids a subscription remembers.
|
|
3
|
+
*
|
|
4
|
+
* Unbounded, a long-lived tab on a busy conversation keeps every id it has
|
|
5
|
+
* ever seen. The cap is far above any realistic poll window, and the oldest
|
|
6
|
+
* are dropped first — a message older than the last thousand cannot appear as
|
|
7
|
+
* "new" in a later poll of the most recent page.
|
|
8
|
+
*/
|
|
9
|
+
const MAX_REMEMBERED = 1_000;
|
|
10
|
+
/**
|
|
11
|
+
* The messages in `batch` that `seen` has not yet been told about, oldest
|
|
12
|
+
* first, with `seen` updated.
|
|
13
|
+
*
|
|
14
|
+
* Ordered by `createdAt` rather than by the order the server returned: a list
|
|
15
|
+
* endpoint is free to answer newest-first, and a consumer appending in
|
|
16
|
+
* receive order would render the conversation upside down.
|
|
17
|
+
*
|
|
18
|
+
* Deliberately NOT the widget's `mergePolled`. That one reconciles optimistic
|
|
19
|
+
* `local-*` rows against their server copies, which only matters to a UI that
|
|
20
|
+
* renders a message before the server has one. A headless consumer owns that
|
|
21
|
+
* decision themselves; all they need from us is "what is new".
|
|
22
|
+
*/
|
|
23
|
+
export function newMessagesSince(seen, batch) {
|
|
24
|
+
const fresh = [];
|
|
25
|
+
for (const message of batch) {
|
|
26
|
+
const id = message?.id;
|
|
27
|
+
if (typeof id !== 'string' || id.length === 0) {
|
|
28
|
+
// A row we cannot key is a row we would emit again on every poll.
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (seen.has(id)) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
seen.add(id);
|
|
35
|
+
fresh.push(message);
|
|
36
|
+
}
|
|
37
|
+
fresh.sort((a, b) => String(a.createdAt).localeCompare(String(b.createdAt)));
|
|
38
|
+
if (seen.size > MAX_REMEMBERED) {
|
|
39
|
+
// Insertion-ordered, so the first entries are the oldest.
|
|
40
|
+
const excess = seen.size - MAX_REMEMBERED;
|
|
41
|
+
let dropped = 0;
|
|
42
|
+
for (const id of seen) {
|
|
43
|
+
if (dropped >= excess) {
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
seen.delete(id);
|
|
47
|
+
dropped += 1;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return fresh;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* How long a "typing" indicator survives without another `typing.start`.
|
|
54
|
+
*
|
|
55
|
+
* ── Why the SDK owns this timeout and not the consumer ──────────────────
|
|
56
|
+
*
|
|
57
|
+
* `typing.stop` is best-effort. The dashboard emits one after 5s of idle
|
|
58
|
+
* keystrokes and on send, and its hook emits one on unmount — but an agent
|
|
59
|
+
* who closes the laptop mid-sentence, loses their network, or whose tab is
|
|
60
|
+
* killed sends nothing at all. A consumer rendering the raw start/stop pair
|
|
61
|
+
* gets an indicator that says "Sarah is typing…" forever, which is the exact
|
|
62
|
+
* shape of bug this codebase keeps finding: it appears to work.
|
|
63
|
+
*
|
|
64
|
+
* Leaving it to the consumer means every consumer writes this same timer, and
|
|
65
|
+
* the ones who do not ship the stuck indicator. 3,500ms is the widget's own
|
|
66
|
+
* window (`use-conversation-realtime.tsx`), so a custom UI built on the SDK
|
|
67
|
+
* behaves like the widget rather than subtly differently.
|
|
68
|
+
*/
|
|
69
|
+
export const TYPING_STOP_AFTER_MS = 3_500;
|
|
70
|
+
/**
|
|
71
|
+
* Turn a stream of `typing.start` / `typing.stop` events into the single
|
|
72
|
+
* boolean a UI actually renders.
|
|
73
|
+
*
|
|
74
|
+
* Edge-triggered: `onChange` fires only when the answer changes, so a
|
|
75
|
+
* keystroke every 300ms does not re-render the consumer's component ten times
|
|
76
|
+
* a second. Exported for its own test — the timer behaviour is the part worth
|
|
77
|
+
* pinning, and it is invisible from the outside.
|
|
78
|
+
*/
|
|
79
|
+
export function createTypingTracker(opts) {
|
|
80
|
+
const stopAfterMs = opts.stopAfterMs ?? TYPING_STOP_AFTER_MS;
|
|
81
|
+
let timer = null;
|
|
82
|
+
let active = null;
|
|
83
|
+
const clear = () => {
|
|
84
|
+
if (timer !== null) {
|
|
85
|
+
clearTimeout(timer);
|
|
86
|
+
timer = null;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const settle = (actor, isTyping) => {
|
|
90
|
+
if (isTyping === (active !== null)) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
active = isTyping ? actor : null;
|
|
94
|
+
opts.onChange({ ...actor, isTyping });
|
|
95
|
+
};
|
|
96
|
+
return {
|
|
97
|
+
start(actor) {
|
|
98
|
+
settle(actor, true);
|
|
99
|
+
clear();
|
|
100
|
+
timer = setTimeout(() => {
|
|
101
|
+
timer = null;
|
|
102
|
+
settle(actor, false);
|
|
103
|
+
}, stopAfterMs);
|
|
104
|
+
},
|
|
105
|
+
stop(actor) {
|
|
106
|
+
clear();
|
|
107
|
+
// The ACTIVE actor is preferred over the one passed in, so the
|
|
108
|
+
// `isTyping: false` signal names whoever the consumer was told about —
|
|
109
|
+
// not an empty placeholder from a `message.created` envelope.
|
|
110
|
+
const subject = active ?? actor;
|
|
111
|
+
if (subject === undefined || subject === null) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
settle(subject, false);
|
|
115
|
+
},
|
|
116
|
+
dispose() {
|
|
117
|
+
// No `onChange` on dispose: the subscription is going away and the
|
|
118
|
+
// consumer is tearing their UI down with it. Firing a last event into a
|
|
119
|
+
// component that has unmounted is how a wrapper earns a React warning.
|
|
120
|
+
clear();
|
|
121
|
+
active = null;
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* The actor a `typing.*` envelope is about, or null if it is not one we show.
|
|
127
|
+
*
|
|
128
|
+
* Two exclusions, both load-bearing:
|
|
129
|
+
*
|
|
130
|
+
* - `kind: 'viewing'`. The agent dashboard publishes room presence and
|
|
131
|
+
* collaborative-cursor frames AS `typing.start` (see `viewing.cursor` in
|
|
132
|
+
* `apps/realtime/src/gateway.ts`), ~10 per second while an agent moves
|
|
133
|
+
* their mouse. Rendering those as typing would make the indicator flicker
|
|
134
|
+
* whenever an agent so much as looked at the conversation.
|
|
135
|
+
* - anything that is not an agent or a bot. The gateway's visitor allowlist
|
|
136
|
+
* already forwards only agent typing, so this is the second of two checks
|
|
137
|
+
* rather than the only one — but a visitor must never be shown their OWN
|
|
138
|
+
* typing as the agent's, and the day the allowlist widens is not the day
|
|
139
|
+
* to discover that.
|
|
140
|
+
*/
|
|
141
|
+
export function typingActorOf(payload) {
|
|
142
|
+
if (typeof payload !== 'object' || payload === null) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
const p = payload;
|
|
146
|
+
if (p.kind === 'viewing') {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
if (p.actorType !== 'agent' && p.actorType !== 'bot') {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
actorType: p.actorType,
|
|
154
|
+
actorId: typeof p.actorId === 'string' ? p.actorId : '',
|
|
155
|
+
...(typeof p.displayName === 'string' ? { displayName: p.displayName } : {}),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=live.js.map
|
package/dist/live.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live.js","sourceRoot":"","sources":["../src/live.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public types for the headless SDK.
|
|
3
|
+
*
|
|
4
|
+
* Declared here rather than imported from `@livechat/shared`: this bundle
|
|
5
|
+
* ships to a customer's website and importing from the shared package drags
|
|
6
|
+
* zod in with it — measured at ~11KB gzipped when it happened to the widget.
|
|
7
|
+
* The shapes are the API's response bodies, which are a published contract.
|
|
8
|
+
*/
|
|
9
|
+
/** One message as the visitor endpoints return it. */
|
|
10
|
+
export interface HeadlessMessage {
|
|
11
|
+
readonly id: string;
|
|
12
|
+
readonly body: string;
|
|
13
|
+
readonly authorType: 'contact' | 'agent' | 'bot' | 'system';
|
|
14
|
+
readonly createdAt: string;
|
|
15
|
+
/** Rich blocks, when the message carries them. Opaque here — render or ignore. */
|
|
16
|
+
readonly blocks?: unknown;
|
|
17
|
+
/** A Tier 2/3 interactive step. Mutually exclusive with `blocks`. */
|
|
18
|
+
readonly canvas?: unknown;
|
|
19
|
+
readonly attachments?: ReadonlyArray<{
|
|
20
|
+
readonly id: string;
|
|
21
|
+
readonly filename: string;
|
|
22
|
+
readonly mimeType: string;
|
|
23
|
+
readonly url: string;
|
|
24
|
+
}>;
|
|
25
|
+
}
|
|
26
|
+
/** One thread in the visitor's own list. */
|
|
27
|
+
export interface HeadlessConversation {
|
|
28
|
+
readonly id: string;
|
|
29
|
+
readonly status?: string;
|
|
30
|
+
readonly lastMessageAt?: string;
|
|
31
|
+
readonly subject?: string | null;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* "The agent is typing", as the consumer should render it.
|
|
35
|
+
*
|
|
36
|
+
* `isTyping` rather than two callbacks, because a UI holds one boolean and
|
|
37
|
+
* the two-callback shape makes the consumer own the state machine — including
|
|
38
|
+
* the part they cannot know about (see `TYPING_STOP_AFTER_MS`).
|
|
39
|
+
*/
|
|
40
|
+
export interface TypingSignal {
|
|
41
|
+
/** Show the indicator, or hide it. */
|
|
42
|
+
readonly isTyping: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Who. `'agent'` in every case the server currently forwards — a visitor
|
|
45
|
+
* never receives their own typing, and agent-presence cursors are filtered
|
|
46
|
+
* out on both sides.
|
|
47
|
+
*/
|
|
48
|
+
readonly actorType: 'agent' | 'bot';
|
|
49
|
+
readonly actorId: string;
|
|
50
|
+
/** The agent's display name, when the dashboard sent one. */
|
|
51
|
+
readonly displayName?: string;
|
|
52
|
+
}
|
|
53
|
+
/** What `subscribe()` reports. */
|
|
54
|
+
export interface SubscribeHandlers {
|
|
55
|
+
/** A message the consumer has not been given before. */
|
|
56
|
+
readonly onMessage?: (message: HeadlessMessage) => void;
|
|
57
|
+
/**
|
|
58
|
+
* The agent started or stopped typing.
|
|
59
|
+
*
|
|
60
|
+
* **PUSH ONLY.** Typing is a socket event with no HTTP route, so a polling
|
|
61
|
+
* consumer never receives this — not rarely, never. There is nothing to
|
|
62
|
+
* poll and nothing to warn about at subscribe time either, because a
|
|
63
|
+
* consumer who passes `onTyping` without `io` has asked for something the
|
|
64
|
+
* transport cannot carry: `subscribe` says so once, in the console, rather
|
|
65
|
+
* than leaving them to wonder why an agent who is visibly typing in the
|
|
66
|
+
* dashboard produces nothing. (A 6-second poll would be a useless indicator
|
|
67
|
+
* even if a route existed — the dashboard stops sending after 5s of idle
|
|
68
|
+
* keystrokes, so a poll could easily see neither edge.)
|
|
69
|
+
*
|
|
70
|
+
* Called with `isTyping: false` either when the agent's `typing.stop`
|
|
71
|
+
* arrives OR after `TYPING_STOP_AFTER_MS` with no further start — see that
|
|
72
|
+
* constant for why the timeout is not the consumer's problem to solve.
|
|
73
|
+
*/
|
|
74
|
+
readonly onTyping?: (signal: TypingSignal) => void;
|
|
75
|
+
/**
|
|
76
|
+
* A poll or socket failed. Called rather than thrown: `subscribe` is
|
|
77
|
+
* long-lived, and a rejected promise nobody is awaiting becomes an
|
|
78
|
+
* unhandled rejection on the customer's page.
|
|
79
|
+
*/
|
|
80
|
+
readonly onError?: (error: unknown) => void;
|
|
81
|
+
}
|
|
82
|
+
export interface SubscribeOptions {
|
|
83
|
+
/** Poll interval. Ignored when `io` is supplied. Floored at 2s. */
|
|
84
|
+
readonly intervalMs?: number;
|
|
85
|
+
/**
|
|
86
|
+
* Your own `socket.io-client` factory, for push instead of polling:
|
|
87
|
+
*
|
|
88
|
+
* import { io } from 'socket.io-client';
|
|
89
|
+
* chatly.subscribe(id, handlers, { io });
|
|
90
|
+
*
|
|
91
|
+
* The SDK does not depend on it, so a consumer who does not want the bytes
|
|
92
|
+
* does not ship them.
|
|
93
|
+
*/
|
|
94
|
+
readonly io?: SocketIoFactory;
|
|
95
|
+
}
|
|
96
|
+
/** The shape of `socket.io-client`'s default export that the SDK uses. */
|
|
97
|
+
export type SocketIoFactory = (url: string, opts: Record<string, unknown>) => {
|
|
98
|
+
on: (event: string, handler: (payload: unknown) => void) => void;
|
|
99
|
+
emit: (event: string, payload: unknown) => void;
|
|
100
|
+
disconnect: () => void;
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* What `subscribe()` returns.
|
|
104
|
+
*
|
|
105
|
+
* Callable, so `const stop = subscribe(...); stop()` keeps working — it was
|
|
106
|
+
* documented and shipped as a plain unsubscribe function, and changing that
|
|
107
|
+
* shape hours later would break the first consumers for no gain. The extras
|
|
108
|
+
* hang off it.
|
|
109
|
+
*
|
|
110
|
+
* ── Why RECEIVING typing is not here ────────────────────────────────────
|
|
111
|
+
*
|
|
112
|
+
* A typing indicator needs both directions, and they land in different
|
|
113
|
+
* places. SENDING is an imperative call the consumer makes at a moment of
|
|
114
|
+
* their choosing (a keystroke), so it has to hang off the handle — there is
|
|
115
|
+
* nowhere else to put it. RECEIVING is an event, and every other event this
|
|
116
|
+
* SDK reports arrives through `SubscribeHandlers` (`onMessage`, `onError`).
|
|
117
|
+
*
|
|
118
|
+
* The three alternatives were:
|
|
119
|
+
*
|
|
120
|
+
* 1. **`onTyping` in the handlers.** Chosen. Zero change to the return
|
|
121
|
+
* type, so no existing caller can break, and it is the shape a consumer
|
|
122
|
+
* already knows from `onMessage`.
|
|
123
|
+
* 2. **An emitter on the handle** (`sub.onTyping(fn)`). A second
|
|
124
|
+
* subscription idiom in one SDK, with its own unsubscribe to get wrong,
|
|
125
|
+
* for one event.
|
|
126
|
+
* 3. **Returning an object instead of a function.** The breaking change the
|
|
127
|
+
* note above rejects, and it buys nothing: `setTyping` already proved the
|
|
128
|
+
* callable-plus-properties shape carries whatever we need.
|
|
129
|
+
*/
|
|
130
|
+
export type Subscription = (() => void) & {
|
|
131
|
+
/**
|
|
132
|
+
* Tell the agent this visitor is typing.
|
|
133
|
+
*
|
|
134
|
+
* Only the PUSH path can carry this: typing is a socket event
|
|
135
|
+
* (`apps/realtime/src/gateway.ts` listens for `typing.start`) and there is
|
|
136
|
+
* no HTTP route for it. On the polling path it warns once rather than
|
|
137
|
+
* silently doing nothing — a no-op that looks like it worked is how an
|
|
138
|
+
* integrator spends an hour on their own code.
|
|
139
|
+
*/
|
|
140
|
+
setTyping: (isTyping: boolean) => void;
|
|
141
|
+
};
|
|
142
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,sDAAsD;AACtD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,SAAS,GAAG,OAAO,GAAG,KAAK,GAAG,QAAQ,CAAC;IAC5D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,kFAAkF;IAClF,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,qEAAqE;IACrE,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,aAAa,CAAC;QACnC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;CACJ;AAED,4CAA4C;AAC5C,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,sCAAsC;IACtC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,GAAG,KAAK,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,6DAA6D;IAC7D,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,kCAAkC;AAClC,MAAM,WAAW,iBAAiB;IAChC,wDAAwD;IACxD,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IACxD;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,CAAC;IACnD;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC7C;AAED,MAAM,WAAW,gBAAgB;IAC/B,mEAAmE;IACnE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,CAAC,EAAE,eAAe,CAAC;CAC/B;AAED,0EAA0E;AAC1E,MAAM,MAAM,eAAe,GAAG,CAC5B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC1B;IACH,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,KAAK,IAAI,CAAC;IACjE,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAChD,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG;IACxC;;;;;;;;OAQG;IACH,SAAS,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;CACxC,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public types for the headless SDK.
|
|
3
|
+
*
|
|
4
|
+
* Declared here rather than imported from `@livechat/shared`: this bundle
|
|
5
|
+
* ships to a customer's website and importing from the shared package drags
|
|
6
|
+
* zod in with it — measured at ~11KB gzipped when it happened to the widget.
|
|
7
|
+
* The shapes are the API's response bodies, which are a published contract.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,62 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chatlychat/sdk-js",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Browser SDK for the LiveChat platform — identify visitors, fire events, control the widget.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://github.com/livechat/platform/tree/main/packages/sdk-js",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/livechat/platform.git",
|
|
10
|
+
"directory": "packages/sdk-js"
|
|
11
|
+
},
|
|
12
|
+
"bugs": "https://github.com/livechat/platform/issues",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"livechat",
|
|
15
|
+
"chat",
|
|
16
|
+
"messaging",
|
|
17
|
+
"support",
|
|
18
|
+
"widget",
|
|
19
|
+
"sdk"
|
|
20
|
+
],
|
|
21
|
+
"author": "LiveChat Platform Engineering",
|
|
22
|
+
"type": "module",
|
|
23
|
+
"main": "./dist/index.js",
|
|
24
|
+
"module": "./dist/index.js",
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"import": "./dist/index.js",
|
|
30
|
+
"default": "./dist/index.js"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist",
|
|
35
|
+
"!dist/**/*.spec.*",
|
|
36
|
+
"README.md",
|
|
37
|
+
"LICENSE",
|
|
38
|
+
"CHANGELOG.md"
|
|
39
|
+
],
|
|
40
|
+
"sideEffects": false,
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsc -p tsconfig.json",
|
|
43
|
+
"prepublishOnly": "pnpm build",
|
|
44
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
45
|
+
"lint": "eslint src --max-warnings=0",
|
|
46
|
+
"test": "vitest run"
|
|
47
|
+
},
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public",
|
|
50
|
+
"registry": "https://registry.npmjs.org/",
|
|
51
|
+
"provenance": true
|
|
52
|
+
},
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=18"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@livechat/config": "workspace:*",
|
|
58
|
+
"jsdom": "^30.0.1",
|
|
59
|
+
"typescript": "catalog:",
|
|
60
|
+
"vitest": "catalog:"
|
|
61
|
+
}
|
|
62
|
+
}
|