@bloonio/chat-angular 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.
@@ -1,311 +0,0 @@
1
- /**
2
- * BloonioChatService — signals-based reactive state container.
3
- *
4
- * Mirrors the Preact widget's `Widget.tsx` state machine but uses Angular
5
- * signals so templates auto-track the slots they read. Public surface:
6
- *
7
- * readonly bootstrap = signal<WidgetBootstrapConfig | null>(null);
8
- * readonly session = signal<CreateVisitorSessionResponse | null>(null);
9
- * readonly messages = signal<ChatMessage[]>([]);
10
- * readonly botTyping = signal(false);
11
- * readonly open = signal(false);
12
- * readonly connecting= signal(false);
13
- * readonly unreadCount = computed(...);
14
- *
15
- * async open(): Promise<void>
16
- * close(): void
17
- * async toggle(): Promise<void>
18
- * sendMessage(text: string): void
19
- *
20
- * SSR-safe: every transport call (fetch, WebSocket) is gated behind a
21
- * platform check via `afterNextRender()` so server pre-rendering doesn't
22
- * try to open sockets.
23
- */
24
- import { afterNextRender, computed, DestroyRef, inject, Injectable, signal, } from '@angular/core';
25
- import { isPlatformBrowser } from '@angular/common';
26
- import { PLATFORM_ID } from '@angular/core';
27
- import { firstValueFrom, isObservable } from 'rxjs';
28
- import { ChatClient, WSClient, } from '@bloonio/chat-client-core';
29
- import { injectBloonioChatConfig } from './bloonio-chat.token';
30
- import * as i0 from "@angular/core";
31
- export class BloonioChatService {
32
- config = injectBloonioChatConfig();
33
- platformId = inject(PLATFORM_ID);
34
- destroyRef = inject(DestroyRef);
35
- /** True when running in the browser (vs. server pre-render). */
36
- isBrowser = isPlatformBrowser(this.platformId);
37
- /** Bootstrap config — populated by the first `loadBootstrap()` call. */
38
- bootstrap = signal(null);
39
- /** Visitor session (id + JWT + expires_at) — set lazily on first open. */
40
- session = signal(null);
41
- /** Message log, oldest → newest. */
42
- messages = signal([]);
43
- /** True between bot's typing(start) and typing(stop) frames. */
44
- botTyping = signal(false);
45
- /** Panel visibility — drives Launcher / Panel rendering. */
46
- open = signal(false);
47
- /** True while `ensureSession()` is in flight (initial WS handshake). */
48
- connecting = signal(false);
49
- /** Set when the WS handshake fails permanently (e.g. tenant suspended). */
50
- fatalError = signal(null);
51
- /** Number of bot/agent messages received while the panel was closed.
52
- * Resets to 0 the moment the panel opens. */
53
- _seenCount = signal(0);
54
- unreadCount = computed(() => {
55
- if (this.open())
56
- return 0;
57
- const total = this.messages().filter((m) => m.from === 'bot' || m.from === 'agent').length;
58
- return Math.max(0, total - this._seenCount());
59
- });
60
- client = null;
61
- ws = null;
62
- bootstrapPromise = null;
63
- sessionPromise = null;
64
- constructor() {
65
- // SSR safety: schedule the initial bootstrap fetch on first browser render.
66
- afterNextRender(() => {
67
- this.loadBootstrap();
68
- });
69
- this.destroyRef.onDestroy(() => {
70
- this.ws?.close();
71
- this.ws = null;
72
- });
73
- }
74
- // ── Public methods ─────────────────────────────────────────────────────
75
- /** Toggle panel visibility. First open also opens the WS session. */
76
- async toggle() {
77
- const next = !this.open();
78
- this.open.set(next);
79
- if (next) {
80
- this._seenCount.set(this.messages().filter((m) => m.from === 'bot' || m.from === 'agent').length);
81
- await this.ensureSession();
82
- }
83
- }
84
- /** Force the panel open. */
85
- async openPanel() {
86
- if (this.open())
87
- return;
88
- await this.toggle();
89
- }
90
- /** Force the panel closed. Keeps the WS open so reopening is instant. */
91
- closePanel() {
92
- this.open.set(false);
93
- }
94
- /** Send a visitor message. No-op if the WS isn't connected. */
95
- sendMessage(content) {
96
- const trimmed = content.trim();
97
- if (!trimmed || !this.ws)
98
- return;
99
- const clientMsgId = `c_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
100
- this.messages.update((prev) => [
101
- ...prev,
102
- {
103
- id: clientMsgId,
104
- client_msg_id: clientMsgId,
105
- from: 'visitor',
106
- content: trimmed,
107
- pending: true,
108
- },
109
- ]);
110
- this.ws.send({ type: 'msg', client_msg_id: clientMsgId, content: trimmed });
111
- }
112
- // ── Internals ──────────────────────────────────────────────────────────
113
- async loadBootstrap() {
114
- if (!this.isBrowser)
115
- return null;
116
- if (this.bootstrap())
117
- return this.bootstrap();
118
- if (this.bootstrapPromise)
119
- return this.bootstrapPromise;
120
- this.bootstrapPromise = (async () => {
121
- try {
122
- const client = this.getClient();
123
- const cfg = await client.fetchWidgetConfig({
124
- tenantId: this.config.tenantId,
125
- widgetPublicKey: this.config.publicKey,
126
- origin: this.resolvedOrigin(),
127
- });
128
- this.bootstrap.set(cfg);
129
- return cfg;
130
- }
131
- catch (err) {
132
- const msg = err instanceof Error ? err.message : 'unknown error';
133
- this.fatalError.set(`Bootstrap failed: ${msg}`);
134
- return null;
135
- }
136
- })();
137
- return this.bootstrapPromise;
138
- }
139
- async ensureSession() {
140
- if (!this.isBrowser)
141
- return null;
142
- if (this.session())
143
- return this.session();
144
- if (this.sessionPromise)
145
- return this.sessionPromise;
146
- this.connecting.set(true);
147
- this.sessionPromise = (async () => {
148
- try {
149
- // Make sure bootstrap is resolved first — the visibility/online
150
- // flags it carries influence whether we connect at all.
151
- await this.loadBootstrap();
152
- const client = this.getClient();
153
- const session = await client.createVisitorSession({
154
- tenantId: this.config.tenantId,
155
- widgetPublicKey: this.config.publicKey,
156
- origin: this.resolvedOrigin(),
157
- locale: this.config.locale ?? 'fr',
158
- metadata: this.config.metadata ?? {},
159
- });
160
- this.session.set(session);
161
- this.openWebSocket(session);
162
- // Optional: identify the visitor server-side if the consumer wired
163
- // a token provider.
164
- this.tryIdentify(session).catch(() => undefined);
165
- return session;
166
- }
167
- catch (err) {
168
- const msg = err instanceof Error ? err.message : 'unknown error';
169
- this.fatalError.set(`Session failed: ${msg}`);
170
- return null;
171
- }
172
- finally {
173
- this.connecting.set(false);
174
- }
175
- })();
176
- return this.sessionPromise;
177
- }
178
- openWebSocket(session) {
179
- if (this.ws)
180
- return;
181
- const ws = new WSClient({
182
- baseUrl: this.config.baseUrl,
183
- visitorToken: session.visitor_token,
184
- heartbeatIntervalMs: 30_000,
185
- }, {
186
- onWelcome: () => undefined,
187
- onMessage: (frame) => {
188
- this.messages.update((prev) => [
189
- ...prev,
190
- { id: frame.id, from: frame.from, content: frame.content },
191
- ]);
192
- },
193
- onAck: (frame) => {
194
- this.messages.update((prev) => prev.map((m) => m.client_msg_id === frame.client_msg_id
195
- ? { ...m, id: frame.server_msg_id, pending: false }
196
- : m));
197
- },
198
- onTyping: (frame) => {
199
- if (frame.from === 'bot' || frame.from === 'agent') {
200
- this.botTyping.set(frame.state === 'start');
201
- }
202
- },
203
- onError: (frame) => {
204
- this.messages.update((prev) => [
205
- ...prev,
206
- { id: `err_${Date.now()}`, from: 'system', content: `Error: ${frame.message}` },
207
- ]);
208
- },
209
- // Phase 10c — agent takeover visibility. Renders a system message
210
- // and clears any stale bot-typing indicator (the bot's mid-stream
211
- // turn may have been pre-empted by the operator claim).
212
- onAgentJoined: (frame) => {
213
- this.messages.update((prev) => [
214
- ...prev,
215
- {
216
- id: `sys_join_${Date.now()}`,
217
- from: 'system',
218
- content: `${frame.agent_display_name} has joined the chat.`,
219
- },
220
- ]);
221
- this.botTyping.set(false);
222
- },
223
- onAgentLeft: () => {
224
- this.messages.update((prev) => [
225
- ...prev,
226
- {
227
- id: `sys_left_${Date.now()}`,
228
- from: 'system',
229
- content: 'The agent has left the chat.',
230
- },
231
- ]);
232
- this.botTyping.set(false);
233
- },
234
- // Phase 10f — chat_api opened a support ticket.
235
- onTicketCreated: (frame) => {
236
- const sla = frame.sla_hours === 1
237
- ? 'within 1h'
238
- : frame.sla_hours <= 24
239
- ? `within ${frame.sla_hours}h`
240
- : `within ${Math.round(frame.sla_hours / 24)}d`;
241
- this.messages.update((prev) => [
242
- ...prev,
243
- {
244
- id: `sys_ticket_${frame.ticket_id}`,
245
- from: 'system',
246
- content: `🎫 Support ticket #${frame.ticket_number} created — ` +
247
- `${frame.category} · ${frame.priority}. ` +
248
- `We'll follow up ${sla}.`,
249
- },
250
- ]);
251
- },
252
- });
253
- this.ws = ws;
254
- ws.connect();
255
- }
256
- async tryIdentify(session) {
257
- const provider = this.config.visitorTokenProvider;
258
- if (!provider)
259
- return;
260
- let raw;
261
- const result = provider();
262
- if (typeof result === 'string') {
263
- raw = result;
264
- }
265
- else if (isObservable(result)) {
266
- raw = await firstValueFrom(result);
267
- }
268
- else {
269
- raw = await result;
270
- }
271
- if (!raw)
272
- return;
273
- // Caller's token is `userId:signature` (colon-delimited). Falling back
274
- // to plain user_id when no colon is present is too easy to misuse —
275
- // require explicit signature to avoid identity forgery footguns.
276
- const sep = raw.indexOf(':');
277
- if (sep < 0) {
278
- this.fatalError.set('visitorTokenProvider returned a value without "userId:signature" — refusing to identify.');
279
- return;
280
- }
281
- const userId = raw.slice(0, sep);
282
- const userSignature = raw.slice(sep + 1);
283
- await this.getClient().identifyVisitor({
284
- visitorToken: session.visitor_token,
285
- userId,
286
- userSignature,
287
- });
288
- }
289
- getClient() {
290
- if (!this.client) {
291
- this.client = new ChatClient({ baseUrl: this.config.baseUrl });
292
- }
293
- return this.client;
294
- }
295
- resolvedOrigin() {
296
- if (this.config.origin)
297
- return this.config.origin;
298
- if (this.isBrowser && typeof window !== 'undefined') {
299
- return window.location.origin;
300
- }
301
- // SSR-safe fallback; the relay validates origins server-side anyway.
302
- return '';
303
- }
304
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BloonioChatService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
305
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BloonioChatService, providedIn: 'root' });
306
- }
307
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BloonioChatService, decorators: [{
308
- type: Injectable,
309
- args: [{ providedIn: 'root' }]
310
- }], ctorParameters: () => [] });
311
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmxvb25pby1jaGF0LnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL2Jsb29uaW8tY2hhdC5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBc0JHO0FBRUgsT0FBTyxFQUNMLGVBQWUsRUFDZixRQUFRLEVBQ1IsVUFBVSxFQUNWLE1BQU0sRUFDTixVQUFVLEVBQ1YsTUFBTSxHQUVQLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ3BELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDNUMsT0FBTyxFQUFFLGNBQWMsRUFBRSxZQUFZLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFFcEQsT0FBTyxFQUNMLFVBQVUsRUFDVixRQUFRLEdBSVQsTUFBTSwyQkFBMkIsQ0FBQztBQUVuQyxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQzs7QUFXL0QsTUFBTSxPQUFPLGtCQUFrQjtJQUNaLE1BQU0sR0FBRyx1QkFBdUIsRUFBRSxDQUFDO0lBQ25DLFVBQVUsR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDakMsVUFBVSxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUVqRCxnRUFBZ0U7SUFDL0MsU0FBUyxHQUFHLGlCQUFpQixDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUVoRSx3RUFBd0U7SUFDL0QsU0FBUyxHQUFHLE1BQU0sQ0FBK0IsSUFBSSxDQUFDLENBQUM7SUFDaEUsMEVBQTBFO0lBQ2pFLE9BQU8sR0FBRyxNQUFNLENBQXNDLElBQUksQ0FBQyxDQUFDO0lBQ3JFLG9DQUFvQztJQUMzQixRQUFRLEdBQUcsTUFBTSxDQUFnQixFQUFFLENBQUMsQ0FBQztJQUM5QyxnRUFBZ0U7SUFDdkQsU0FBUyxHQUFHLE1BQU0s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QU0sS0FBSyxXQUFXLEVBQUUsQ0FBQztZQUNwRCxPQUFPLE1BQU0sQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDO1FBQ2hDLENBQUM7UUFDRCxxRUFBcUU7UUFDckUsT0FBTyxFQUFFLENBQUM7SUFDWixDQUFDO3dHQXRTVSxrQkFBa0I7NEdBQWxCLGtCQUFrQixjQURMLE1BQU07OzRGQUNuQixrQkFBa0I7a0JBRDlCLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBCbG9vbmlvQ2hhdFNlcnZpY2Ug4oCUIHNpZ25hbHMtYmFzZWQgcmVhY3RpdmUgc3RhdGUgY29udGFpbmVyLlxuICpcbiAqIE1pcnJvcnMgdGhlIFByZWFjdCB3aWRnZXQncyBgV2lkZ2V0LnRzeGAgc3RhdGUgbWFjaGluZSBidXQgdXNlcyBBbmd1bGFyXG4gKiBzaWduYWxzIHNvIHRlbXBsYXRlcyBhdXRvLXRyYWNrIHRoZSBzbG90cyB0aGV5IHJlYWQuIFB1YmxpYyBzdXJmYWNlOlxuICpcbiAqICAgcmVhZG9ubHkgYm9vdHN0cmFwID0gc2lnbmFsPFdpZGdldEJvb3RzdHJhcENvbmZpZyB8IG51bGw+KG51bGwpO1xuICogICByZWFkb25seSBzZXNzaW9uICAgPSBzaWduYWw8Q3JlYXRlVmlzaXRvclNlc3Npb25SZXNwb25zZSB8IG51bGw+KG51bGwpO1xuICogICByZWFkb25seSBtZXNzYWdlcyAgPSBzaWduYWw8Q2hhdE1lc3NhZ2VbXT4oW10pO1xuICogICByZWFkb25seSBib3RUeXBpbmcgPSBzaWduYWwoZmFsc2UpO1xuICogICByZWFkb25seSBvcGVuICAgICAgPSBzaWduYWwoZmFsc2UpO1xuICogICByZWFkb25seSBjb25uZWN0aW5nPSBzaWduYWwoZmFsc2UpO1xuICogICByZWFkb25seSB1bnJlYWRDb3VudCA9IGNvbXB1dGVkKC4uLik7XG4gKlxuICogICBhc3luYyBvcGVuKCk6IFByb21pc2U8dm9pZD5cbiAqICAgY2xvc2UoKTogdm9pZFxuICogICBhc3luYyB0b2dnbGUoKTogUHJvbWlzZTx2b2lkPlxuICogICBzZW5kTWVzc2FnZSh0ZXh0OiBzdHJpbmcpOiB2b2lkXG4gKlxuICogU1NSLXNhZmU6IGV2ZXJ5IHRyYW5zcG9ydCBjYWxsIChmZXRjaCwgV2ViU29ja2V0KSBpcyBnYXRlZCBiZWhpbmQgYVxuICogcGxhdGZvcm0gY2hlY2sgdmlhIGBhZnRlck5leHRSZW5kZXIoKWAgc28gc2VydmVyIHByZS1yZW5kZXJpbmcgZG9lc24ndFxuICogdHJ5IHRvIG9wZW4gc29ja2V0cy5cbiAqL1xuXG5pbXBvcnQge1xuICBhZnRlck5leHRSZW5kZXIsXG4gIGNvbXB1dGVkLFxuICBEZXN0cm95UmVmLFxuICBpbmplY3QsXG4gIEluamVjdGFibGUsXG4gIHNpZ25hbCxcbiAgdHlwZSBTaWduYWwsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgaXNQbGF0Zm9ybUJyb3dzZXIgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgUExBVEZPUk1fSUQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IGZpcnN0VmFsdWVGcm9tLCBpc09ic2VydmFibGUgfSBmcm9tICdyeGpzJztcblxuaW1wb3J0IHtcbiAgQ2hhdENsaWVudCxcbiAgV1NDbGllbnQsXG4gIHR5cGUgQ3JlYXRlVmlzaXRvclNlc3Npb25SZXNwb25zZSxcbiAgdHlwZSBTZXJ2ZXJNc2dGcmFtZSxcbiAgdHlwZSBXaWRnZXRCb290c3RyYXBDb25maWcsXG59IGZyb20gJ0BibG9vbmlvL2NoYXQtY2xpZW50LWNvcmUnO1xuXG5pbXBvcnQgeyBpbmplY3RCbG9vbmlvQ2hhdENvbmZpZyB9IGZyb20gJy4vYmxvb25pby1jaGF0LnRva2VuJztcblxuZXhwb3J0IGludGVyZmFjZSBDaGF0TWVzc2FnZSB7XG4gIGlkOiBzdHJpbmc7XG4gIGZyb206ICd2aXNpdG9yJyB8ICdib3QnIHwgJ2FnZW50JyB8ICdzeXN0ZW0nO1xuICBjb250ZW50OiBzdHJpbmc7XG4gIHBlbmRpbmc/OiBib29sZWFuO1xuICBjbGllbnRfbXNnX2lkPzogc3RyaW5nO1xufVxuXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxuZXhwb3J0IGNsYXNzIEJsb29uaW9DaGF0U2VydmljZSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgY29uZmlnID0gaW5qZWN0Qmxvb25pb0NoYXRDb25maWcoKTtcbiAgcHJpdmF0ZSByZWFkb25seSBwbGF0Zm9ybUlkID0gaW5qZWN0KFBMQVRGT1JNX0lEKTtcbiAgcHJpdmF0ZSByZWFkb25seSBkZXN0cm95UmVmID0gaW5qZWN0KERlc3Ryb3lSZWYpO1xuXG4gIC8qKiBUcnVlIHdoZW4gcnVubmluZyBpbiB0aGUgYnJvd3NlciAodnMuIHNlcnZlciBwcmUtcmVuZGVyKS4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBpc0Jyb3dzZXIgPSBpc1BsYXRmb3JtQnJvd3Nlcih0aGlzLnBsYXRmb3JtSWQpO1xuXG4gIC8qKiBCb290c3RyYXAgY29uZmlnIOKAlCBwb3B1bGF0ZWQgYnkgdGhlIGZpcnN0IGBsb2FkQm9vdHN0cmFwKClgIGNhbGwuICovXG4gIHJlYWRvbmx5IGJvb3RzdHJhcCA9IHNpZ25hbDxXaWRnZXRCb290c3RyYXBDb25maWcgfCBudWxsPihudWxsKTtcbiAgLyoqIFZpc2l0b3Igc2Vzc2lvbiAoaWQgKyBKV1QgKyBleHBpcmVzX2F0KSDigJQgc2V0IGxhemlseSBvbiBmaXJzdCBvcGVuLiAqL1xuICByZWFkb25seSBzZXNzaW9uID0gc2lnbmFsPENyZWF0ZVZpc2l0b3JTZXNzaW9uUmVzcG9uc2UgfCBudWxsPihudWxsKTtcbiAgLyoqIE1lc3NhZ2UgbG9nLCBvbGRlc3Qg4oaSIG5ld2VzdC4gKi9cbiAgcmVhZG9ubHkgbWVzc2FnZXMgPSBzaWduYWw8Q2hhdE1lc3NhZ2VbXT4oW10pO1xuICAvKiogVHJ1ZSBiZXR3ZWVuIGJvdCdzIHR5cGluZyhzdGFydCkgYW5kIHR5cGluZyhzdG9wKSBmcmFtZXMuICovXG4gIHJlYWRvbmx5IGJvdFR5cGluZyA9IHNpZ25hbChmYWxzZSk7XG4gIC8qKiBQYW5lbCB2aXNpYmlsaXR5IOKAlCBkcml2ZXMgTGF1bmNoZXIgLyBQYW5lbCByZW5kZXJpbmcuICovXG4gIHJlYWRvbmx5IG9wZW4gPSBzaWduYWwoZmFsc2UpO1xuICAvKiogVHJ1ZSB3aGlsZSBgZW5zdXJlU2Vzc2lvbigpYCBpcyBpbiBmbGlnaHQgKGluaXRpYWwgV1MgaGFuZHNoYWtlKS4gKi9cbiAgcmVhZG9ubHkgY29ubmVjdGluZyA9IHNpZ25hbChmYWxzZSk7XG4gIC8qKiBTZXQgd2hlbiB0aGUgV1MgaGFuZHNoYWtlIGZhaWxzIHBlcm1hbmVudGx5IChlLmcuIHRlbmFudCBzdXNwZW5kZWQpLiAqL1xuICByZWFkb25seSBmYXRhbEVycm9yID0gc2lnbmFsPHN0cmluZyB8IG51bGw+KG51bGwpO1xuXG4gIC8qKiBOdW1iZXIgb2YgYm90L2FnZW50IG1lc3NhZ2VzIHJlY2VpdmVkIHdoaWxlIHRoZSBwYW5lbCB3YXMgY2xvc2VkLlxuICAgKiAgUmVzZXRzIHRvIDAgdGhlIG1vbWVudCB0aGUgcGFuZWwgb3BlbnMuICovXG4gIHByaXZhdGUgcmVhZG9ubHkgX3NlZW5Db3VudCA9IHNpZ25hbCgwKTtcbiAgcmVhZG9ubHkgdW5yZWFkQ291bnQ6IFNpZ25hbDxudW1iZXI+ID0gY29tcHV0ZWQoKCkgPT4ge1xuICAgIGlmICh0aGlzLm9wZW4oKSkgcmV0dXJuIDA7XG4gICAgY29uc3QgdG90YWwgPSB0aGlzLm1lc3NhZ2VzKCkuZmlsdGVyKFxuICAgICAgKG0pID0+IG0uZnJvbSA9PT0gJ2JvdCcgfHwgbS5mcm9tID09PSAnYWdlbnQnLFxuICAgICkubGVuZ3RoO1xuICAgIHJldHVybiBNYXRoLm1heCgwLCB0b3RhbCAtIHRoaXMuX3NlZW5Db3VudCgpKTtcbiAgfSk7XG5cbiAgcHJpdmF0ZSBjbGllbnQ6IENoYXRDbGllbnQgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSB3czogV1NDbGllbnQgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBib290c3RyYXBQcm9taXNlOiBQcm9taXNlPFdpZGdldEJvb3RzdHJhcENvbmZpZyB8IG51bGw+IHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgc2Vzc2lvblByb21pc2U6IFByb21pc2U8Q3JlYXRlVmlzaXRvclNlc3Npb25SZXNwb25zZSB8IG51bGw+IHwgbnVsbCA9IG51bGw7XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgLy8gU1NSIHNhZmV0eTogc2NoZWR1bGUgdGhlIGluaXRpYWwgYm9vdHN0cmFwIGZldGNoIG9uIGZpcnN0IGJyb3dzZXIgcmVuZGVyLlxuICAgIGFmdGVyTmV4dFJlbmRlcigoKSA9PiB7XG4gICAgICB0aGlzLmxvYWRCb290c3RyYXAoKTtcbiAgICB9KTtcblxuICAgIHRoaXMuZGVzdHJveVJlZi5vbkRlc3Ryb3koKCkgPT4ge1xuICAgICAgdGhpcy53cz8uY2xvc2UoKTtcbiAgICAgIHRoaXMud3MgPSBudWxsO1xuICAgIH0pO1xuICB9XG5cbiAgLy8g4pSA4pSAIFB1YmxpYyBtZXRob2RzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIC8qKiBUb2dnbGUgcGFuZWwgdmlzaWJpbGl0eS4gRmlyc3Qgb3BlbiBhbHNvIG9wZW5zIHRoZSBXUyBzZXNzaW9uLiAqL1xuICBhc3luYyB0b2dnbGUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgbmV4dCA9ICF0aGlzLm9wZW4oKTtcbiAgICB0aGlzLm9wZW4uc2V0KG5leHQpO1xuICAgIGlmIChuZXh0KSB7XG4gICAgICB0aGlzLl9zZWVuQ291bnQuc2V0KFxuICAgICAgICB0aGlzLm1lc3NhZ2VzKCkuZmlsdGVyKChtKSA9PiBtLmZyb20gPT09ICdib3QnIHx8IG0uZnJvbSA9PT0gJ2FnZW50JykubGVuZ3RoLFxuICAgICAgKTtcbiAgICAgIGF3YWl0IHRoaXMuZW5zdXJlU2Vzc2lvbigpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBGb3JjZSB0aGUgcGFuZWwgb3Blbi4gKi9cbiAgYXN5bmMgb3BlblBhbmVsKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLm9wZW4oKSkgcmV0dXJuO1xuICAgIGF3YWl0IHRoaXMudG9nZ2xlKCk7XG4gIH1cblxuICAvKiogRm9yY2UgdGhlIHBhbmVsIGNsb3NlZC4gS2VlcHMgdGhlIFdTIG9wZW4gc28gcmVvcGVuaW5nIGlzIGluc3RhbnQuICovXG4gIGNsb3NlUGFuZWwoKTogdm9pZCB7XG4gICAgdGhpcy5vcGVuLnNldChmYWxzZSk7XG4gIH1cblxuICAvKiogU2VuZCBhIHZpc2l0b3IgbWVzc2FnZS4gTm8tb3AgaWYgdGhlIFdTIGlzbid0IGNvbm5lY3RlZC4gKi9cbiAgc2VuZE1lc3NhZ2UoY29udGVudDogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgdHJpbW1lZCA9IGNvbnRlbnQudHJpbSgpO1xuICAgIGlmICghdHJpbW1lZCB8fCAhdGhpcy53cykgcmV0dXJuO1xuICAgIGNvbnN0IGNsaWVudE1zZ0lkID0gYGNfJHtEYXRlLm5vdygpfV8ke01hdGgucmFuZG9tKCkudG9TdHJpbmcoMzYpLnNsaWNlKDIsIDgpfWA7XG4gICAgdGhpcy5tZXNzYWdlcy51cGRhdGUoKHByZXYpID0+IFtcbiAgICAgIC4uLnByZXYsXG4gICAgICB7XG4gICAgICAgIGlkOiBjbGllbnRNc2dJZCxcbiAgICAgICAgY2xpZW50X21zZ19pZDogY2xpZW50TXNnSWQsXG4gICAgICAgIGZyb206ICd2aXNpdG9yJyxcbiAgICAgICAgY29udGVudDogdHJpbW1lZCxcbiAgICAgICAgcGVuZGluZzogdHJ1ZSxcbiAgICAgIH0sXG4gICAgXSk7XG4gICAgdGhpcy53cy5zZW5kKHsgdHlwZTogJ21zZycsIGNsaWVudF9tc2dfaWQ6IGNsaWVudE1zZ0lkLCBjb250ZW50OiB0cmltbWVkIH0pO1xuICB9XG5cbiAgLy8g4pSA4pSAIEludGVybmFscyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBwcml2YXRlIGFzeW5jIGxvYWRCb290c3RyYXAoKTogUHJvbWlzZTxXaWRnZXRCb290c3RyYXBDb25maWcgfCBudWxsPiB7XG4gICAgaWYgKCF0aGlzLmlzQnJvd3NlcikgcmV0dXJuIG51bGw7XG4gICAgaWYgKHRoaXMuYm9vdHN0cmFwKCkpIHJldHVybiB0aGlzLmJvb3RzdHJhcCgpO1xuICAgIGlmICh0aGlzLmJvb3RzdHJhcFByb21pc2UpIHJldHVybiB0aGlzLmJvb3RzdHJhcFByb21pc2U7XG5cbiAgICB0aGlzLmJvb3RzdHJhcFByb21pc2UgPSAoYXN5bmMgKCkgPT4ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgY2xpZW50ID0gdGhpcy5nZXRDbGllbnQoKTtcbiAgICAgICAgY29uc3QgY2ZnID0gYXdhaXQgY2xpZW50LmZldGNoV2lkZ2V0Q29uZmlnKHtcbiAgICAgICAgICB0ZW5hbnRJZDogdGhpcy5jb25maWcudGVuYW50SWQsXG4gICAgICAgICAgd2lkZ2V0UHVibGljS2V5OiB0aGlzLmNvbmZpZy5wdWJsaWNLZXksXG4gICAgICAgICAgb3JpZ2luOiB0aGlzLnJlc29sdmVkT3JpZ2luKCksXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLmJvb3RzdHJhcC5zZXQoY2ZnKTtcbiAgICAgICAgcmV0dXJuIGNmZztcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBjb25zdCBtc2cgPSBlcnIgaW5zdGFuY2VvZiBFcnJvciA/IGVyci5tZXNzYWdlIDogJ3Vua25vd24gZXJyb3InO1xuICAgICAgICB0aGlzLmZhdGFsRXJyb3Iuc2V0KGBCb290c3RyYXAgZmFpbGVkOiAke21zZ31gKTtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG4gICAgfSkoKTtcbiAgICByZXR1cm4gdGhpcy5ib290c3RyYXBQcm9taXNlO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBlbnN1cmVTZXNzaW9uKCk6IFByb21pc2U8Q3JlYXRlVmlzaXRvclNlc3Npb25SZXNwb25zZSB8IG51bGw+IHtcbiAgICBpZiAoIXRoaXMuaXNCcm93c2VyKSByZXR1cm4gbnVsbDtcbiAgICBpZiAodGhpcy5zZXNzaW9uKCkpIHJldHVybiB0aGlzLnNlc3Npb24oKTtcbiAgICBpZiAodGhpcy5zZXNzaW9uUHJvbWlzZSkgcmV0dXJuIHRoaXMuc2Vzc2lvblByb21pc2U7XG5cbiAgICB0aGlzLmNvbm5lY3Rpbmcuc2V0KHRydWUpO1xuICAgIHRoaXMuc2Vzc2lvblByb21pc2UgPSAoYXN5bmMgKCkgPT4ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gTWFrZSBzdXJlIGJvb3RzdHJhcCBpcyByZXNvbHZlZCBmaXJzdCDigJQgdGhlIHZpc2liaWxpdHkvb25saW5lXG4gICAgICAgIC8vIGZsYWdzIGl0IGNhcnJpZXMgaW5mbHVlbmNlIHdoZXRoZXIgd2UgY29ubmVjdCBhdCBhbGwuXG4gICAgICAgIGF3YWl0IHRoaXMubG9hZEJvb3RzdHJhcCgpO1xuXG4gICAgICAgIGNvbnN0IGNsaWVudCA9IHRoaXMuZ2V0Q2xpZW50KCk7XG4gICAgICAgIGNvbnN0IHNlc3Npb24gPSBhd2FpdCBjbGllbnQuY3JlYXRlVmlzaXRvclNlc3Npb24oe1xuICAgICAgICAgIHRlbmFudElkOiB0aGlzLmNvbmZpZy50ZW5hbnRJZCxcbiAgICAgICAgICB3aWRnZXRQdWJsaWNLZXk6IHRoaXMuY29uZmlnLnB1YmxpY0tleSxcbiAgICAgICAgICBvcmlnaW46IHRoaXMucmVzb2x2ZWRPcmlnaW4oKSxcbiAgICAgICAgICBsb2NhbGU6IHRoaXMuY29uZmlnLmxvY2FsZSA/PyAnZnInLFxuICAgICAgICAgIG1ldGFkYXRhOiB0aGlzLmNvbmZpZy5tZXRhZGF0YSA/PyB7fSxcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuc2Vzc2lvbi5zZXQoc2Vzc2lvbik7XG4gICAgICAgIHRoaXMub3BlbldlYlNvY2tldChzZXNzaW9uKTtcbiAgICAgICAgLy8gT3B0aW9uYWw6IGlkZW50aWZ5IHRoZSB2aXNpdG9yIHNlcnZlci1zaWRlIGlmIHRoZSBjb25zdW1lciB3aXJlZFxuICAgICAgICAvLyBhIHRva2VuIHByb3ZpZGVyLlxuICAgICAgICB0aGlzLnRyeUlkZW50aWZ5KHNlc3Npb24pLmNhdGNoKCgpID0+IHVuZGVmaW5lZCk7XG4gICAgICAgIHJldHVybiBzZXNzaW9uO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGNvbnN0IG1zZyA9IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiAndW5rbm93biBlcnJvcic7XG4gICAgICAgIHRoaXMuZmF0YWxFcnJvci5zZXQoYFNlc3Npb24gZmFpbGVkOiAke21zZ31gKTtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9IGZpbmFsbHkge1xuICAgICAgICB0aGlzLmNvbm5lY3Rpbmcuc2V0KGZhbHNlKTtcbiAgICAgIH1cbiAgICB9KSgpO1xuICAgIHJldHVybiB0aGlzLnNlc3Npb25Qcm9taXNlO1xuICB9XG5cbiAgcHJpdmF0ZSBvcGVuV2ViU29ja2V0KHNlc3Npb246IENyZWF0ZVZpc2l0b3JTZXNzaW9uUmVzcG9uc2UpOiB2b2lkIHtcbiAgICBpZiAodGhpcy53cykgcmV0dXJuO1xuICAgIGNvbnN0IHdzID0gbmV3IFdTQ2xpZW50KFxuICAgICAge1xuICAgICAgICBiYXNlVXJsOiB0aGlzLmNvbmZpZy5iYXNlVXJsLFxuICAgICAgICB2aXNpdG9yVG9rZW46IHNlc3Npb24udmlzaXRvcl90b2tlbixcbiAgICAgICAgaGVhcnRiZWF0SW50ZXJ2YWxNczogMzBfMDAwLFxuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgb25XZWxjb21lOiAoKSA9PiB1bmRlZmluZWQsXG4gICAgICAgIG9uTWVzc2FnZTogKGZyYW1lOiBTZXJ2ZXJNc2dGcmFtZSkgPT4ge1xuICAgICAgICAgIHRoaXMubWVzc2FnZXMudXBkYXRlKChwcmV2KSA9PiBbXG4gICAgICAgICAgICAuLi5wcmV2LFxuICAgICAgICAgICAgeyBpZDogZnJhbWUuaWQsIGZyb206IGZyYW1lLmZyb20sIGNvbnRlbnQ6IGZyYW1lLmNvbnRlbnQgfSxcbiAgICAgICAgICBdKTtcbiAgICAgICAgfSxcbiAgICAgICAgb25BY2s6IChmcmFtZSkgPT4ge1xuICAgICAgICAgIHRoaXMubWVzc2FnZXMudXBkYXRlKChwcmV2KSA9PlxuICAgICAgICAgICAgcHJldi5tYXAoKG0pID0+XG4gICAgICAgICAgICAgIG0uY2xpZW50X21zZ19pZCA9PT0gZnJhbWUuY2xpZW50X21zZ19pZFxuICAgICAgICAgICAgICAgID8geyAuLi5tLCBpZDogZnJhbWUuc2VydmVyX21zZ19pZCwgcGVuZGluZzogZmFsc2UgfVxuICAgICAgICAgICAgICAgIDogbSxcbiAgICAgICAgICAgICksXG4gICAgICAgICAgKTtcbiAgICAgICAgfSxcbiAgICAgICAgb25UeXBpbmc6IChmcmFtZSkgPT4ge1xuICAgICAgICAgIGlmIChmcmFtZS5mcm9tID09PSAnYm90JyB8fCBmcmFtZS5mcm9tID09PSAnYWdlbnQnKSB7XG4gICAgICAgICAgICB0aGlzLmJvdFR5cGluZy5zZXQoZnJhbWUuc3RhdGUgPT09ICdzdGFydCcpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgb25FcnJvcjogKGZyYW1lKSA9PiB7XG4gICAgICAgICAgdGhpcy5tZXNzYWdlcy51cGRhdGUoKHByZXYpID0+IFtcbiAgICAgICAgICAgIC4uLnByZXYsXG4gICAgICAgICAgICB7IGlkOiBgZXJyXyR7RGF0ZS5ub3coKX1gLCBmcm9tOiAnc3lzdGVtJywgY29udGVudDogYEVycm9yOiAke2ZyYW1lLm1lc3NhZ2V9YCB9LFxuICAgICAgICAgIF0pO1xuICAgICAgICB9LFxuICAgICAgICAvLyBQaGFzZSAxMGMg4oCUIGFnZW50IHRha2VvdmVyIHZpc2liaWxpdHkuIFJlbmRlcnMgYSBzeXN0ZW0gbWVzc2FnZVxuICAgICAgICAvLyBhbmQgY2xlYXJzIGFueSBzdGFsZSBib3QtdHlwaW5nIGluZGljYXRvciAodGhlIGJvdCdzIG1pZC1zdHJlYW1cbiAgICAgICAgLy8gdHVybiBtYXkgaGF2ZSBiZWVuIHByZS1lbXB0ZWQgYnkgdGhlIG9wZXJhdG9yIGNsYWltKS5cbiAgICAgICAgb25BZ2VudEpvaW5lZDogKGZyYW1lKSA9PiB7XG4gICAgICAgICAgdGhpcy5tZXNzYWdlcy51cGRhdGUoKHByZXYpID0+IFtcbiAgICAgICAgICAgIC4uLnByZXYsXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIGlkOiBgc3lzX2pvaW5fJHtEYXRlLm5vdygpfWAsXG4gICAgICAgICAgICAgIGZyb206ICdzeXN0ZW0nLFxuICAgICAgICAgICAgICBjb250ZW50OiBgJHtmcmFtZS5hZ2VudF9kaXNwbGF5X25hbWV9IGhhcyBqb2luZWQgdGhlIGNoYXQuYCxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgXSk7XG4gICAgICAgICAgdGhpcy5ib3RUeXBpbmcuc2V0KGZhbHNlKTtcbiAgICAgICAgfSxcbiAgICAgICAgb25BZ2VudExlZnQ6ICgpID0+IHtcbiAgICAgICAgICB0aGlzLm1lc3NhZ2VzLnVwZGF0ZSgocHJldikgPT4gW1xuICAgICAgICAgICAgLi4ucHJldixcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgaWQ6IGBzeXNfbGVmdF8ke0RhdGUubm93KCl9YCxcbiAgICAgICAgICAgICAgZnJvbTogJ3N5c3RlbScsXG4gICAgICAgICAgICAgIGNvbnRlbnQ6ICdUaGUgYWdlbnQgaGFzIGxlZnQgdGhlIGNoYXQuJyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgXSk7XG4gICAgICAgICAgdGhpcy5ib3RUeXBpbmcuc2V0KGZhbHNlKTtcbiAgICAgICAgfSxcbiAgICAgICAgLy8gUGhhc2UgMTBmIOKAlCBjaGF0X2FwaSBvcGVuZWQgYSBzdXBwb3J0IHRpY2tldC5cbiAgICAgICAgb25UaWNrZXRDcmVhdGVkOiAoZnJhbWUpID0+IHtcbiAgICAgICAgICBjb25zdCBzbGEgPVxuICAgICAgICAgICAgZnJhbWUuc2xhX2hvdXJzID09PSAxXG4gICAgICAgICAgICAgID8gJ3dpdGhpbiAxaCdcbiAgICAgICAgICAgICAgOiBmcmFtZS5zbGFfaG91cnMgPD0gMjRcbiAgICAgICAgICAgICAgICA/IGB3aXRoaW4gJHtmcmFtZS5zbGFfaG91cnN9aGBcbiAgICAgICAgICAgICAgICA6IGB3aXRoaW4gJHtNYXRoLnJvdW5kKGZyYW1lLnNsYV9ob3VycyAvIDI0KX1kYDtcbiAgICAgICAgICB0aGlzLm1lc3NhZ2VzLnVwZGF0ZSgocHJldikgPT4gW1xuICAgICAgICAgICAgLi4ucHJldixcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgaWQ6IGBzeXNfdGlja2V0XyR7ZnJhbWUudGlja2V0X2lkfWAsXG4gICAgICAgICAgICAgIGZyb206ICdzeXN0ZW0nLFxuICAgICAgICAgICAgICBjb250ZW50OlxuICAgICAgICAgICAgICAgIGDwn46rIFN1cHBvcnQgdGlja2V0ICMke2ZyYW1lLnRpY2tldF9udW1iZXJ9IGNyZWF0ZWQg4oCUIGAgK1xuICAgICAgICAgICAgICAgIGAke2ZyYW1lLmNhdGVnb3J5fSDCtyAke2ZyYW1lLnByaW9yaXR5fS4gYCArXG4gICAgICAgICAgICAgICAgYFdlJ2xsIGZvbGxvdyB1cCAke3NsYX0uYCxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgXSk7XG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICk7XG4gICAgdGhpcy53cyA9IHdzO1xuICAgIHdzLmNvbm5lY3QoKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgdHJ5SWRlbnRpZnkoXG4gICAgc2Vzc2lvbjogQ3JlYXRlVmlzaXRvclNlc3Npb25SZXNwb25zZSxcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgcHJvdmlkZXIgPSB0aGlzLmNvbmZpZy52aXNpdG9yVG9rZW5Qcm92aWRlcjtcbiAgICBpZiAoIXByb3ZpZGVyKSByZXR1cm47XG5cbiAgICBsZXQgcmF3OiBzdHJpbmcgfCBudWxsIHwgdW5kZWZpbmVkO1xuICAgIGNvbnN0IHJlc3VsdCA9IHByb3ZpZGVyKCk7XG4gICAgaWYgKHR5cGVvZiByZXN1bHQgPT09ICdzdHJpbmcnKSB7XG4gICAgICByYXcgPSByZXN1bHQ7XG4gICAgfSBlbHNlIGlmIChpc09ic2VydmFibGUocmVzdWx0KSkge1xuICAgICAgcmF3ID0gYXdhaXQgZmlyc3RWYWx1ZUZyb20ocmVzdWx0KTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmF3ID0gYXdhaXQgcmVzdWx0O1xuICAgIH1cbiAgICBpZiAoIXJhdykgcmV0dXJuO1xuXG4gICAgLy8gQ2FsbGVyJ3MgdG9rZW4gaXMgYHVzZXJJZDpzaWduYXR1cmVgIChjb2xvbi1kZWxpbWl0ZWQpLiBGYWxsaW5nIGJhY2tcbiAgICAvLyB0byBwbGFpbiB1c2VyX2lkIHdoZW4gbm8gY29sb24gaXMgcHJlc2VudCBpcyB0b28gZWFzeSB0byBtaXN1c2Ug4oCUXG4gICAgLy8gcmVxdWlyZSBleHBsaWNpdCBzaWduYXR1cmUgdG8gYXZvaWQgaWRlbnRpdHkgZm9yZ2VyeSBmb290Z3Vucy5cbiAgICBjb25zdCBzZXAgPSByYXcuaW5kZXhPZignOicpO1xuICAgIGlmIChzZXAgPCAwKSB7XG4gICAgICB0aGlzLmZhdGFsRXJyb3Iuc2V0KFxuICAgICAgICAndmlzaXRvclRva2VuUHJvdmlkZXIgcmV0dXJuZWQgYSB2YWx1ZSB3aXRob3V0IFwidXNlcklkOnNpZ25hdHVyZVwiIOKAlCByZWZ1c2luZyB0byBpZGVudGlmeS4nLFxuICAgICAgKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgdXNlcklkID0gcmF3LnNsaWNlKDAsIHNlcCk7XG4gICAgY29uc3QgdXNlclNpZ25hdHVyZSA9IHJhdy5zbGljZShzZXAgKyAxKTtcbiAgICBhd2FpdCB0aGlzLmdldENsaWVudCgpLmlkZW50aWZ5VmlzaXRvcih7XG4gICAgICB2aXNpdG9yVG9rZW46IHNlc3Npb24udmlzaXRvcl90b2tlbixcbiAgICAgIHVzZXJJZCxcbiAgICAgIHVzZXJTaWduYXR1cmUsXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGdldENsaWVudCgpOiBDaGF0Q2xpZW50IHtcbiAgICBpZiAoIXRoaXMuY2xpZW50KSB7XG4gICAgICB0aGlzLmNsaWVudCA9IG5ldyBDaGF0Q2xpZW50KHsgYmFzZVVybDogdGhpcy5jb25maWcuYmFzZVVybCB9KTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuY2xpZW50O1xuICB9XG5cbiAgcHJpdmF0ZSByZXNvbHZlZE9yaWdpbigpOiBzdHJpbmcge1xuICAgIGlmICh0aGlzLmNvbmZpZy5vcmlnaW4pIHJldHVybiB0aGlzLmNvbmZpZy5vcmlnaW47XG4gICAgaWYgKHRoaXMuaXNCcm93c2VyICYmIHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICByZXR1cm4gd2luZG93LmxvY2F0aW9uLm9yaWdpbjtcbiAgICB9XG4gICAgLy8gU1NSLXNhZmUgZmFsbGJhY2s7IHRoZSByZWxheSB2YWxpZGF0ZXMgb3JpZ2lucyBzZXJ2ZXItc2lkZSBhbnl3YXkuXG4gICAgcmV0dXJuICcnO1xuICB9XG59XG4iXX0=
@@ -1,46 +0,0 @@
1
- /**
2
- * Dependency-injection plumbing for the Angular chat SDK.
3
- *
4
- * Consumers wire the SDK into their app via the standard Angular pattern
5
- * documented in docs/12 §7.3:
6
- *
7
- * // app.config.ts
8
- * export const appConfig: ApplicationConfig = {
9
- * providers: [
10
- * provideBloonioChat({
11
- * tenantId: env.CHAT_TENANT_ID,
12
- * publicKey: env.CHAT_PUBLIC_KEY,
13
- * baseUrl: 'https://chat-relay.bloonio.com',
14
- * visitorTokenProvider: () => inject(HttpClient).get<{token: string}>(
15
- * '/api/chat/visitor-token'
16
- * ).pipe(map(r => r.token)),
17
- * locale: 'fr',
18
- * }),
19
- * ],
20
- * };
21
- */
22
- import { inject, InjectionToken, makeEnvironmentProviders, } from '@angular/core';
23
- export const BLOONIO_CHAT_CONFIG = new InjectionToken('BLOONIO_CHAT_CONFIG');
24
- /** Standalone-provider factory.
25
- *
26
- * Returns ``EnvironmentProviders`` so consumers can spread it into
27
- * ``app.config.ts``'s providers array. The service itself is
28
- * ``providedIn: 'root'`` so we don't need an explicit provider entry — we
29
- * only need the config token to be registered.
30
- */
31
- export function provideBloonioChat(config) {
32
- return makeEnvironmentProviders([
33
- { provide: BLOONIO_CHAT_CONFIG, useValue: config },
34
- ]);
35
- }
36
- /** Internal accessor used by the components to fail loud when the
37
- * consumer forgot ``provideBloonioChat()``. */
38
- export function injectBloonioChatConfig() {
39
- const cfg = inject(BLOONIO_CHAT_CONFIG, { optional: true });
40
- if (!cfg) {
41
- throw new Error('[bloonio-chat-angular] provideBloonioChat() was not called in your app.config.ts. ' +
42
- 'Add it to providers: [...] alongside provideRouter/provideHttpClient.');
43
- }
44
- return cfg;
45
- }
46
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmxvb25pby1jaGF0LnRva2VuLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xpYi9ibG9vbmlvLWNoYXQudG9rZW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBb0JHO0FBRUgsT0FBTyxFQUNMLE1BQU0sRUFDTixjQUFjLEVBRWQsd0JBQXdCLEdBQ3pCLE1BQU0sZUFBZSxDQUFDO0FBd0N2QixNQUFNLENBQUMsTUFBTSxtQkFBbUIsR0FBRyxJQUFJLGNBQWMsQ0FDbkQscUJBQXFCLENBQ3RCLENBQUM7QUFFRjs7Ozs7O0dBTUc7QUFDSCxNQUFNLFVBQVUsa0JBQWtCLENBQ2hDLE1BQXlCO0lBRXpCLE9BQU8sd0JBQXdCLENBQUM7UUFDOUIsRUFBRSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRTtLQUNuRCxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQ7Z0RBQ2dEO0FBQ2hELE1BQU0sVUFBVSx1QkFBdUI7SUFDckMsTUFBTSxHQUFHLEdBQUcsTUFBTSxDQUFDLG1CQUFtQixFQUFFLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFDNUQsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQ1QsTUFBTSxJQUFJLEtBQUssQ0FDYixvRkFBb0Y7WUFDcEYsdUVBQXVFLENBQ3hFLENBQUM7SUFDSixDQUFDO0lBQ0QsT0FBTyxHQUFHLENBQUM7QUFDYixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBEZXBlbmRlbmN5LWluamVjdGlvbiBwbHVtYmluZyBmb3IgdGhlIEFuZ3VsYXIgY2hhdCBTREsuXG4gKlxuICogQ29uc3VtZXJzIHdpcmUgdGhlIFNESyBpbnRvIHRoZWlyIGFwcCB2aWEgdGhlIHN0YW5kYXJkIEFuZ3VsYXIgcGF0dGVyblxuICogZG9jdW1lbnRlZCBpbiBkb2NzLzEyIMKnNy4zOlxuICpcbiAqICAgLy8gYXBwLmNvbmZpZy50c1xuICogICBleHBvcnQgY29uc3QgYXBwQ29uZmlnOiBBcHBsaWNhdGlvbkNvbmZpZyA9IHtcbiAqICAgICBwcm92aWRlcnM6IFtcbiAqICAgICAgIHByb3ZpZGVCbG9vbmlvQ2hhdCh7XG4gKiAgICAgICAgIHRlbmFudElkOiBlbnYuQ0hBVF9URU5BTlRfSUQsXG4gKiAgICAgICAgIHB1YmxpY0tleTogZW52LkNIQVRfUFVCTElDX0tFWSxcbiAqICAgICAgICAgYmFzZVVybDogJ2h0dHBzOi8vY2hhdC1yZWxheS5ibG9vbmlvLmNvbScsXG4gKiAgICAgICAgIHZpc2l0b3JUb2tlblByb3ZpZGVyOiAoKSA9PiBpbmplY3QoSHR0cENsaWVudCkuZ2V0PHt0b2tlbjogc3RyaW5nfT4oXG4gKiAgICAgICAgICAgJy9hcGkvY2hhdC92aXNpdG9yLXRva2VuJ1xuICogICAgICAgICApLnBpcGUobWFwKHIgPT4gci50b2tlbikpLFxuICogICAgICAgICBsb2NhbGU6ICdmcicsXG4gKiAgICAgICB9KSxcbiAqICAgICBdLFxuICogICB9O1xuICovXG5cbmltcG9ydCB7XG4gIGluamVjdCxcbiAgSW5qZWN0aW9uVG9rZW4sXG4gIHR5cGUgRW52aXJvbm1lbnRQcm92aWRlcnMsXG4gIG1ha2VFbnZpcm9ubWVudFByb3ZpZGVycyxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgdHlwZSB7IE9ic2VydmFibGUgfSBmcm9tICdyeGpzJztcblxuaW1wb3J0IHR5cGUgeyBBdHRhY2htZW50IH0gZnJvbSAnQGJsb29uaW8vY2hhdC1jbGllbnQtY29yZSc7XG5cbi8qKiBDYWxsZXItc3VwcGxpZWQgcmVzb2x2ZXIgZm9yIHRoZSB0ZW5hbnQtc2lnbmVkIHZpc2l0b3IgdG9rZW4uXG4gKlxuICogVHdvIGFjY2VwdGFibGUgc2hhcGVzOlxuICogICAtIFJldHVybnMgbm90aGluZyAob3IgYG51bGxgKSDihpIgU0RLIGZhbGxzIGJhY2sgdG8gYW5vbnltb3VzIG1vZGUuXG4gKiAgICAgQSBzZXNzaW9uIGlzIG1pbnRlZCB2aWEgYC9jcmVhdGUvdmlzaXRvci1zZXNzaW9uYCBhbmQgdGhlIHZpc2l0b3JcbiAqICAgICBzdGF5cyB1bmlkZW50aWZpZWQgdW50aWwgeW91IHN1cHBseSBvbmUuXG4gKiAgIC0gUmV0dXJucyBhIHN0cmluZyAvIE9ic2VydmFibGU8c3RyaW5nPiDihpIgU0RLIGNhbGxzIGAvaWRlbnRpZnkvdmlzaXRvcmBcbiAqICAgICB3aXRoIHRoaXMgc2lnbmVkIHRva2VuIHRvIGJpbmQgdGhlIGFub255bW91cyBzZXNzaW9uIHRvIGEgdGVuYW50IHVzZXIuXG4gKi9cbmV4cG9ydCB0eXBlIFZpc2l0b3JUb2tlblByb3ZpZGVyID1cbiAgfCAoKCkgPT4gc3RyaW5nIHwgbnVsbCB8IFByb21pc2U8c3RyaW5nIHwgbnVsbD4gfCBPYnNlcnZhYmxlPHN0cmluZyB8IG51bGw+KVxuICB8IHVuZGVmaW5lZDtcblxuZXhwb3J0IGludGVyZmFjZSBCbG9vbmlvQ2hhdENvbmZpZyB7XG4gIC8qKiBUZW5hbnQgVVVJRCB2NyAodGhlIGNhbm9uaWNhbCBoYW5kbGUgaXNzdWVkIGJ5IGNoYXRfcmVsYXkpLiAqL1xuICB0ZW5hbnRJZDogc3RyaW5nO1xuICAvKiogYHBrX+KApmAgd2lkZ2V0IGtleSBib3VuZCB0byB0aGUgdGVuYW50J3MgYGFsbG93ZWRfb3JpZ2luc2AuICovXG4gIHB1YmxpY0tleTogc3RyaW5nO1xuICAvKiogQmFzZSBVUkwgb2YgdGhlIGNoYXQgcmVsYXkgKGh0dHBzOi8vY2hhdC1yZWxheS5ibG9vbmlvLmNvbSBvciBsb2NhbCkuICovXG4gIGJhc2VVcmw6IHN0cmluZztcbiAgLyoqIFZpc2l0b3ItaWRlbnRpZmljYXRpb24gcmVzb2x2ZXIuIFNlZSB7QGxpbmsgVmlzaXRvclRva2VuUHJvdmlkZXJ9LiAqL1xuICB2aXNpdG9yVG9rZW5Qcm92aWRlcj86IFZpc2l0b3JUb2tlblByb3ZpZGVyO1xuICAvKiogRGVmYXVsdCBsb2NhbGUgZm9yIG5ldyBjb252ZXJzYXRpb25zLiAqL1xuICBsb2NhbGU/OiBzdHJpbmc7XG4gIC8qKiBGcmVlLWZvcm0gbWV0YWRhdGEgYXR0YWNoZWQgdG8gZXZlcnkgdmlzaXRvciBzZXNzaW9uLiAqL1xuICBtZXRhZGF0YT86IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICAvKiogT3B0aW9uYWwgb3ZlcnJpZGUgb2YgYHdpbmRvdy5sb2NhdGlvbi5vcmlnaW5gICh0ZXN0cyAvIFNTUikuICovXG4gIG9yaWdpbj86IHN0cmluZztcbiAgLyoqXG4gICAqIFByZS1mZXRjaGVkIGF0dGFjaG1lbnRzIHRvIGF0dGFjaCB0byB0aGUgZmlyc3Qgb3V0Ym91bmQgbWVzc2FnZS5cbiAgICogUmVzZXJ2ZWQgZm9yIHBoYXNlIDExOyBrZXB0IG9uIHRoZSBpbnRlcmZhY2UgZm9yIGZvcndhcmQgY29tcGF0LlxuICAgKi9cbiAgYXR0YWNobWVudHM/OiBBdHRhY2htZW50W107XG59XG5cbmV4cG9ydCBjb25zdCBCTE9PTklPX0NIQVRfQ09ORklHID0gbmV3IEluamVjdGlvblRva2VuPEJsb29uaW9DaGF0Q29uZmlnPihcbiAgJ0JMT09OSU9fQ0hBVF9DT05GSUcnLFxuKTtcblxuLyoqIFN0YW5kYWxvbmUtcHJvdmlkZXIgZmFjdG9yeS5cbiAqXG4gKiBSZXR1cm5zIGBgRW52aXJvbm1lbnRQcm92aWRlcnNgYCBzbyBjb25zdW1lcnMgY2FuIHNwcmVhZCBpdCBpbnRvXG4gKiBgYGFwcC5jb25maWcudHNgYCdzIHByb3ZpZGVycyBhcnJheS4gVGhlIHNlcnZpY2UgaXRzZWxmIGlzXG4gKiBgYHByb3ZpZGVkSW46ICdyb290J2BgIHNvIHdlIGRvbid0IG5lZWQgYW4gZXhwbGljaXQgcHJvdmlkZXIgZW50cnkg4oCUIHdlXG4gKiBvbmx5IG5lZWQgdGhlIGNvbmZpZyB0b2tlbiB0byBiZSByZWdpc3RlcmVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcHJvdmlkZUJsb29uaW9DaGF0KFxuICBjb25maWc6IEJsb29uaW9DaGF0Q29uZmlnLFxuKTogRW52aXJvbm1lbnRQcm92aWRlcnMge1xuICByZXR1cm4gbWFrZUVudmlyb25tZW50UHJvdmlkZXJzKFtcbiAgICB7IHByb3ZpZGU6IEJMT09OSU9fQ0hBVF9DT05GSUcsIHVzZVZhbHVlOiBjb25maWcgfSxcbiAgXSk7XG59XG5cbi8qKiBJbnRlcm5hbCBhY2Nlc3NvciB1c2VkIGJ5IHRoZSBjb21wb25lbnRzIHRvIGZhaWwgbG91ZCB3aGVuIHRoZVxuICogIGNvbnN1bWVyIGZvcmdvdCBgYHByb3ZpZGVCbG9vbmlvQ2hhdCgpYGAuICovXG5leHBvcnQgZnVuY3Rpb24gaW5qZWN0Qmxvb25pb0NoYXRDb25maWcoKTogQmxvb25pb0NoYXRDb25maWcge1xuICBjb25zdCBjZmcgPSBpbmplY3QoQkxPT05JT19DSEFUX0NPTkZJRywgeyBvcHRpb25hbDogdHJ1ZSB9KTtcbiAgaWYgKCFjZmcpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAnW2Jsb29uaW8tY2hhdC1hbmd1bGFyXSBwcm92aWRlQmxvb25pb0NoYXQoKSB3YXMgbm90IGNhbGxlZCBpbiB5b3VyIGFwcC5jb25maWcudHMuICcgK1xuICAgICAgJ0FkZCBpdCB0byBwcm92aWRlcnM6IFsuLi5dIGFsb25nc2lkZSBwcm92aWRlUm91dGVyL3Byb3ZpZGVIdHRwQ2xpZW50LicsXG4gICAgKTtcbiAgfVxuICByZXR1cm4gY2ZnO1xufVxuIl19
@@ -1,91 +0,0 @@
1
- /**
2
- * Visitor input bar — multi-line textarea + send button. Enter sends,
3
- * Shift+Enter inserts a newline. Emits `send` with the trimmed content
4
- * once it's non-empty.
5
- */
6
- import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, signal, } from '@angular/core';
7
- import * as i0 from "@angular/core";
8
- export class InputBarComponent {
9
- disabled = false;
10
- send = new EventEmitter();
11
- value = signal('');
12
- canSend() {
13
- return !this.disabled && this.value().trim().length > 0;
14
- }
15
- onInput(e) {
16
- this.value.set(e.target.value);
17
- }
18
- onKey(e) {
19
- if (e.key === 'Enter' && !e.shiftKey) {
20
- e.preventDefault();
21
- this.submit();
22
- }
23
- }
24
- submit() {
25
- if (!this.canSend())
26
- return;
27
- const trimmed = this.value().trim();
28
- this.send.emit(trimmed);
29
- this.value.set('');
30
- }
31
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: InputBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
32
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: InputBarComponent, isStandalone: true, selector: "bloonio-chat-input-bar", inputs: { disabled: "disabled" }, outputs: { send: "send" }, ngImport: i0, template: `
33
- <div class="bch-input">
34
- <textarea
35
- rows="1"
36
- placeholder="Enter your message..."
37
- [disabled]="disabled"
38
- [value]="value()"
39
- (input)="onInput($event)"
40
- (keydown)="onKey($event)"
41
- ></textarea>
42
- <button
43
- type="button"
44
- class="bch-input-send"
45
- aria-label="Send"
46
- [disabled]="!canSend()"
47
- (click)="submit()"
48
- >
49
- <svg viewBox="0 0 24 24" fill="currentColor">
50
- <path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" />
51
- </svg>
52
- </button>
53
- </div>
54
- `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
55
- }
56
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: InputBarComponent, decorators: [{
57
- type: Component,
58
- args: [{
59
- selector: 'bloonio-chat-input-bar',
60
- standalone: true,
61
- changeDetection: ChangeDetectionStrategy.OnPush,
62
- template: `
63
- <div class="bch-input">
64
- <textarea
65
- rows="1"
66
- placeholder="Enter your message..."
67
- [disabled]="disabled"
68
- [value]="value()"
69
- (input)="onInput($event)"
70
- (keydown)="onKey($event)"
71
- ></textarea>
72
- <button
73
- type="button"
74
- class="bch-input-send"
75
- aria-label="Send"
76
- [disabled]="!canSend()"
77
- (click)="submit()"
78
- >
79
- <svg viewBox="0 0 24 24" fill="currentColor">
80
- <path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" />
81
- </svg>
82
- </button>
83
- </div>
84
- `,
85
- }]
86
- }], propDecorators: { disabled: [{
87
- type: Input
88
- }], send: [{
89
- type: Output
90
- }] } });
91
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5wdXQtYmFyLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvY29tcG9uZW50cy9pbnB1dC1iYXIuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7O0dBSUc7QUFDSCxPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLFNBQVMsRUFDVCxZQUFZLEVBQ1osS0FBSyxFQUNMLE1BQU0sRUFDTixNQUFNLEdBQ1AsTUFBTSxlQUFlLENBQUM7O0FBOEJ2QixNQUFNLE9BQU8saUJBQWlCO0lBQ25CLFFBQVEsR0FBRyxLQUFLLENBQUM7SUFDaEIsSUFBSSxHQUFHLElBQUksWUFBWSxFQUFVLENBQUM7SUFFekIsS0FBSyxHQUFHLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUU1QixPQUFPO1FBQ2YsT0FBTyxDQUFDLElBQUksQ0FBQyxRQUFRLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7SUFDMUQsQ0FBQztJQUVELE9BQU8sQ0FBQyxDQUFRO1FBQ2QsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUUsQ0FBQyxDQUFDLE1BQThCLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDMUQsQ0FBQztJQUVELEtBQUssQ0FBQyxDQUFnQjtRQUNwQixJQUFJLENBQUMsQ0FBQyxHQUFHLEtBQUssT0FBTyxJQUFJLENBQUMsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ3JDLENBQUMsQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUNuQixJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDaEIsQ0FBQztJQUNILENBQUM7SUFFRCxNQUFNO1FBQ0osSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUU7WUFBRSxPQUFPO1FBQzVCLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNwQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN4QixJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNyQixDQUFDO3dHQTFCVSxpQkFBaUI7NEZBQWpCLGlCQUFpQiwrSUF4QmxCOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBc0JUOzs0RkFFVSxpQkFBaUI7a0JBNUI3QixTQUFTO21CQUFDO29CQUNULFFBQVEsRUFBRSx3QkFBd0I7b0JBQ2xDLFVBQVUsRUFBRSxJQUFJO29CQUNoQixlQUFlLEVBQUUsdUJBQXVCLENBQUMsTUFBTTtvQkFDL0MsUUFBUSxFQUFFOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBc0JUO2lCQUNGOzhCQUVVLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0ksSUFBSTtzQkFBYixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBWaXNpdG9yIGlucHV0IGJhciDigJQgbXVsdGktbGluZSB0ZXh0YXJlYSArIHNlbmQgYnV0dG9uLiBFbnRlciBzZW5kcyxcbiAqIFNoaWZ0K0VudGVyIGluc2VydHMgYSBuZXdsaW5lLiBFbWl0cyBgc2VuZGAgd2l0aCB0aGUgdHJpbW1lZCBjb250ZW50XG4gKiBvbmNlIGl0J3Mgbm9uLWVtcHR5LlxuICovXG5pbXBvcnQge1xuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgQ29tcG9uZW50LFxuICBFdmVudEVtaXR0ZXIsXG4gIElucHV0LFxuICBPdXRwdXQsXG4gIHNpZ25hbCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2Jsb29uaW8tY2hhdC1pbnB1dC1iYXInLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbiAgdGVtcGxhdGU6IGBcbiAgICA8ZGl2IGNsYXNzPVwiYmNoLWlucHV0XCI+XG4gICAgICA8dGV4dGFyZWFcbiAgICAgICAgcm93cz1cIjFcIlxuICAgICAgICBwbGFjZWhvbGRlcj1cIkVudGVyIHlvdXIgbWVzc2FnZS4uLlwiXG4gICAgICAgIFtkaXNhYmxlZF09XCJkaXNhYmxlZFwiXG4gICAgICAgIFt2YWx1ZV09XCJ2YWx1ZSgpXCJcbiAgICAgICAgKGlucHV0KT1cIm9uSW5wdXQoJGV2ZW50KVwiXG4gICAgICAgIChrZXlkb3duKT1cIm9uS2V5KCRldmVudClcIlxuICAgICAgPjwvdGV4dGFyZWE+XG4gICAgICA8YnV0dG9uXG4gICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICBjbGFzcz1cImJjaC1pbnB1dC1zZW5kXCJcbiAgICAgICAgYXJpYS1sYWJlbD1cIlNlbmRcIlxuICAgICAgICBbZGlzYWJsZWRdPVwiIWNhblNlbmQoKVwiXG4gICAgICAgIChjbGljayk9XCJzdWJtaXQoKVwiXG4gICAgICA+XG4gICAgICAgIDxzdmcgdmlld0JveD1cIjAgMCAyNCAyNFwiIGZpbGw9XCJjdXJyZW50Q29sb3JcIj5cbiAgICAgICAgICA8cGF0aCBkPVwiTTIuMDEgMjFMMjMgMTIgMi4wMSAzIDIgMTBsMTUgMi0xNSAyelwiIC8+XG4gICAgICAgIDwvc3ZnPlxuICAgICAgPC9idXR0b24+XG4gICAgPC9kaXY+XG4gIGAsXG59KVxuZXhwb3J0IGNsYXNzIElucHV0QmFyQ29tcG9uZW50IHtcbiAgQElucHV0KCkgZGlzYWJsZWQgPSBmYWxzZTtcbiAgQE91dHB1dCgpIHNlbmQgPSBuZXcgRXZlbnRFbWl0dGVyPHN0cmluZz4oKTtcblxuICBwcm90ZWN0ZWQgcmVhZG9ubHkgdmFsdWUgPSBzaWduYWwoJycpO1xuXG4gIHByb3RlY3RlZCBjYW5TZW5kKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAhdGhpcy5kaXNhYmxlZCAmJiB0aGlzLnZhbHVlKCkudHJpbSgpLmxlbmd0aCA+IDA7XG4gIH1cblxuICBvbklucHV0KGU6IEV2ZW50KTogdm9pZCB7XG4gICAgdGhpcy52YWx1ZS5zZXQoKGUudGFyZ2V0IGFzIEhUTUxUZXh0QXJlYUVsZW1lbnQpLnZhbHVlKTtcbiAgfVxuXG4gIG9uS2V5KGU6IEtleWJvYXJkRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoZS5rZXkgPT09ICdFbnRlcicgJiYgIWUuc2hpZnRLZXkpIHtcbiAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgIHRoaXMuc3VibWl0KCk7XG4gICAgfVxuICB9XG5cbiAgc3VibWl0KCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5jYW5TZW5kKCkpIHJldHVybjtcbiAgICBjb25zdCB0cmltbWVkID0gdGhpcy52YWx1ZSgpLnRyaW0oKTtcbiAgICB0aGlzLnNlbmQuZW1pdCh0cmltbWVkKTtcbiAgICB0aGlzLnZhbHVlLnNldCgnJyk7XG4gIH1cbn1cbiJdfQ==
@@ -1,81 +0,0 @@
1
- /**
2
- * Floating launcher — circular chat bubble with optional label.
3
- * Wraps the `BloonioChatService` so consumers just drop
4
- * `<bloonio-chat-launcher />` somewhere and the SDK handles state.
5
- */
6
- import { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core';
7
- import { BloonioChatService } from '../bloonio-chat.service';
8
- import * as i0 from "@angular/core";
9
- export class BloonioChatLauncherComponent {
10
- chat = inject(BloonioChatService);
11
- position = computed(() => this.chat.bootstrap()?.widget_position ?? 'right');
12
- /** Tint the bubble with the tenant's brand colour (falls back to the
13
- * stylesheet default until bootstrap config loads). */
14
- themeStyle = computed(() => {
15
- const color = this.chat.bootstrap()?.branding_primary_color;
16
- return color ? `--bch-primary: ${color}` : '';
17
- });
18
- label = computed(() => {
19
- const b = this.chat.bootstrap();
20
- return b?.button_label_enabled ? b.button_label_text : null;
21
- });
22
- ariaLabel = computed(() => {
23
- const unread = this.chat.unreadCount();
24
- return unread > 0
25
- ? `Open chat (${unread} unread)`
26
- : 'Open chat';
27
- });
28
- onToggle() {
29
- void this.chat.toggle();
30
- }
31
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BloonioChatLauncherComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
32
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: BloonioChatLauncherComponent, isStandalone: true, selector: "bloonio-chat-launcher", ngImport: i0, template: `
33
- <div class="bch-root" [attr.data-position]="position()" [style]="themeStyle()">
34
- <button
35
- type="button"
36
- class="bch-launcher"
37
- [attr.aria-label]="ariaLabel()"
38
- (click)="onToggle()"
39
- >
40
- @if (label()) {
41
- <span class="bch-launcher-label">{{ label() }}</span>
42
- }
43
- <span class="bch-launcher-bubble">
44
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor"
45
- stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
46
- <path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" />
47
- </svg>
48
- </span>
49
- </button>
50
- </div>
51
- `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
52
- }
53
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BloonioChatLauncherComponent, decorators: [{
54
- type: Component,
55
- args: [{
56
- selector: 'bloonio-chat-launcher',
57
- standalone: true,
58
- changeDetection: ChangeDetectionStrategy.OnPush,
59
- template: `
60
- <div class="bch-root" [attr.data-position]="position()" [style]="themeStyle()">
61
- <button
62
- type="button"
63
- class="bch-launcher"
64
- [attr.aria-label]="ariaLabel()"
65
- (click)="onToggle()"
66
- >
67
- @if (label()) {
68
- <span class="bch-launcher-label">{{ label() }}</span>
69
- }
70
- <span class="bch-launcher-bubble">
71
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor"
72
- stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
73
- <path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" />
74
- </svg>
75
- </span>
76
- </button>
77
- </div>
78
- `,
79
- }]
80
- }] });
81
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGF1bmNoZXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9jb21wb25lbnRzL2xhdW5jaGVyLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7OztHQUlHO0FBQ0gsT0FBTyxFQUFFLHVCQUF1QixFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRXJGLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHlCQUF5QixDQUFDOztBQTJCN0QsTUFBTSxPQUFPLDRCQUE0QjtJQUNwQixJQUFJLEdBQUcsTUFBTSxDQUFDLGtCQUFrQixDQUFDLENBQUM7SUFFbEMsUUFBUSxHQUFHLFFBQVEsQ0FDcEMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsRUFBRSxlQUFlLElBQUksT0FBTyxDQUN4RCxDQUFDO0lBRUY7NERBQ3dEO0lBQ3JDLFVBQVUsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFO1FBQzVDLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLEVBQUUsc0JBQXNCLENBQUM7UUFDNUQsT0FBTyxLQUFLLENBQUMsQ0FBQyxDQUFDLGtCQUFrQixLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0lBQ2hELENBQUMsQ0FBQyxDQUFDO0lBRWdCLEtBQUssR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFO1FBQ3ZDLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDaEMsT0FBTyxDQUFDLEVBQUUsb0JBQW9CLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO0lBQzlELENBQUMsQ0FBQyxDQUFDO0lBRWdCLFNBQVMsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFO1FBQzNDLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDdkMsT0FBTyxNQUFNLEdBQUcsQ0FBQztZQUNmLENBQUMsQ0FBQyxjQUFjLE1BQU0sVUFBVTtZQUNoQyxDQUFDLENBQUMsV0FBVyxDQUFDO0lBQ2xCLENBQUMsQ0FBQyxDQUFDO0lBRUgsUUFBUTtRQUNOLEtBQUssSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztJQUMxQixDQUFDO3dHQTVCVSw0QkFBNEI7NEZBQTVCLDRCQUE0QixpRkFyQjdCOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBbUJUOzs0RkFFVSw0QkFBNEI7a0JBekJ4QyxTQUFTO21CQUFDO29CQUNULFFBQVEsRUFBRSx1QkFBdUI7b0JBQ2pDLFVBQVUsRUFBRSxJQUFJO29CQUNoQixlQUFlLEVBQUUsdUJBQXVCLENBQUMsTUFBTTtvQkFDL0MsUUFBUSxFQUFFOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBbUJUO2lCQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBGbG9hdGluZyBsYXVuY2hlciDigJQgY2lyY3VsYXIgY2hhdCBidWJibGUgd2l0aCBvcHRpb25hbCBsYWJlbC5cbiAqIFdyYXBzIHRoZSBgQmxvb25pb0NoYXRTZXJ2aWNlYCBzbyBjb25zdW1lcnMganVzdCBkcm9wXG4gKiBgPGJsb29uaW8tY2hhdC1sYXVuY2hlciAvPmAgc29tZXdoZXJlIGFuZCB0aGUgU0RLIGhhbmRsZXMgc3RhdGUuXG4gKi9cbmltcG9ydCB7IENoYW5nZURldGVjdGlvblN0cmF0ZWd5LCBDb21wb25lbnQsIGNvbXB1dGVkLCBpbmplY3QgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcblxuaW1wb3J0IHsgQmxvb25pb0NoYXRTZXJ2aWNlIH0gZnJvbSAnLi4vYmxvb25pby1jaGF0LnNlcnZpY2UnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdibG9vbmlvLWNoYXQtbGF1bmNoZXInLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbiAgdGVtcGxhdGU6IGBcbiAgICA8ZGl2IGNsYXNzPVwiYmNoLXJvb3RcIiBbYXR0ci5kYXRhLXBvc2l0aW9uXT1cInBvc2l0aW9uKClcIiBbc3R5bGVdPVwidGhlbWVTdHlsZSgpXCI+XG4gICAgICA8YnV0dG9uXG4gICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICBjbGFzcz1cImJjaC1sYXVuY2hlclwiXG4gICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiYXJpYUxhYmVsKClcIlxuICAgICAgICAoY2xpY2spPVwib25Ub2dnbGUoKVwiXG4gICAgICA+XG4gICAgICAgIEBpZiAobGFiZWwoKSkge1xuICAgICAgICAgIDxzcGFuIGNsYXNzPVwiYmNoLWxhdW5jaGVyLWxhYmVsXCI+e3sgbGFiZWwoKSB9fTwvc3Bhbj5cbiAgICAgICAgfVxuICAgICAgICA8c3BhbiBjbGFzcz1cImJjaC1sYXVuY2hlci1idWJibGVcIj5cbiAgICAgICAgICA8c3ZnIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiBmaWxsPVwibm9uZVwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiXG4gICAgICAgICAgICAgICBzdHJva2Utd2lkdGg9XCIyLjJcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIj5cbiAgICAgICAgICAgIDxwYXRoIGQ9XCJNMjEgMTEuNWE4LjM4IDguMzggMCAwIDEtLjkgMy44IDguNSA4LjUgMCAwIDEtNy42IDQuNyA4LjM4IDguMzggMCAwIDEtMy44LS45TDMgMjFsMS45LTUuN2E4LjM4IDguMzggMCAwIDEtLjktMy44IDguNSA4LjUgMCAwIDEgNC43LTcuNiA4LjM4IDguMzggMCAwIDEgMy44LS45aC41YTguNDggOC40OCAwIDAgMSA4IDh2LjV6XCIgLz5cbiAgICAgICAgICA8L3N2Zz5cbiAgICAgICAgPC9zcGFuPlxuICAgICAgPC9idXR0b24+XG4gICAgPC9kaXY+XG4gIGAsXG59KVxuZXhwb3J0IGNsYXNzIEJsb29uaW9DaGF0TGF1bmNoZXJDb21wb25lbnQge1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgY2hhdCA9IGluamVjdChCbG9vbmlvQ2hhdFNlcnZpY2UpO1xuXG4gIHByb3RlY3RlZCByZWFkb25seSBwb3NpdGlvbiA9IGNvbXB1dGVkKFxuICAgICgpID0+IHRoaXMuY2hhdC5ib290c3RyYXAoKT8ud2lkZ2V0X3Bvc2l0aW9uID8/ICdyaWdodCcsXG4gICk7XG5cbiAgLyoqIFRpbnQgdGhlIGJ1YmJsZSB3aXRoIHRoZSB0ZW5hbnQncyBicmFuZCBjb2xvdXIgKGZhbGxzIGJhY2sgdG8gdGhlXG4gICAqICBzdHlsZXNoZWV0IGRlZmF1bHQgdW50aWwgYm9vdHN0cmFwIGNvbmZpZyBsb2FkcykuICovXG4gIHByb3RlY3RlZCByZWFkb25seSB0aGVtZVN0eWxlID0gY29tcHV0ZWQoKCkgPT4ge1xuICAgIGNvbnN0IGNvbG9yID0gdGhpcy5jaGF0LmJvb3RzdHJhcCgpPy5icmFuZGluZ19wcmltYXJ5X2NvbG9yO1xuICAgIHJldHVybiBjb2xvciA/IGAtLWJjaC1wcmltYXJ5OiAke2NvbG9yfWAgOiAnJztcbiAgfSk7XG5cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGxhYmVsID0gY29tcHV0ZWQoKCkgPT4ge1xuICAgIGNvbnN0IGIgPSB0aGlzLmNoYXQuYm9vdHN0cmFwKCk7XG4gICAgcmV0dXJuIGI/LmJ1dHRvbl9sYWJlbF9lbmFibGVkID8gYi5idXR0b25fbGFiZWxfdGV4dCA6IG51bGw7XG4gIH0pO1xuXG4gIHByb3RlY3RlZCByZWFkb25seSBhcmlhTGFiZWwgPSBjb21wdXRlZCgoKSA9PiB7XG4gICAgY29uc3QgdW5yZWFkID0gdGhpcy5jaGF0LnVucmVhZENvdW50KCk7XG4gICAgcmV0dXJuIHVucmVhZCA+IDBcbiAgICAgID8gYE9wZW4gY2hhdCAoJHt1bnJlYWR9IHVucmVhZClgXG4gICAgICA6ICdPcGVuIGNoYXQnO1xuICB9KTtcblxuICBvblRvZ2dsZSgpOiB2b2lkIHtcbiAgICB2b2lkIHRoaXMuY2hhdC50b2dnbGUoKTtcbiAgfVxufVxuIl19