@auxx/chat 0.0.1
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/dist/client/client/index.d.ts +24 -0
- package/dist/client/client/index.d.ts.map +1 -0
- package/dist/client/client/index.js +127 -0
- package/dist/client/shared/env.d.ts +4 -0
- package/dist/client/shared/env.d.ts.map +1 -0
- package/dist/client/shared/env.js +29 -0
- package/dist/react/client/index.d.ts +24 -0
- package/dist/react/client/index.d.ts.map +1 -0
- package/dist/react/client/index.js +127 -0
- package/dist/react/react/index.d.ts +6 -0
- package/dist/react/react/index.d.ts.map +1 -0
- package/dist/react/react/index.js +39 -0
- package/dist/react/shared/env.d.ts +4 -0
- package/dist/react/shared/env.d.ts.map +1 -0
- package/dist/react/shared/env.js +29 -0
- package/dist/server/server/index.d.ts +28 -0
- package/dist/server/server/index.d.ts.map +1 -0
- package/dist/server/server/index.js +26 -0
- package/dist/widget-bundle/auxx-chat.js +1108 -0
- package/package.json +75 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface BootOptions {
|
|
2
|
+
channelId: string;
|
|
3
|
+
userJwt?: string;
|
|
4
|
+
attributes?: Record<string, unknown>;
|
|
5
|
+
apiBase?: string;
|
|
6
|
+
widgetBase?: string;
|
|
7
|
+
theme?: 'light' | 'dark' | 'system';
|
|
8
|
+
}
|
|
9
|
+
declare global {
|
|
10
|
+
interface Window {
|
|
11
|
+
AuxxChat?: unknown;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
declare function boot(options: BootOptions): void;
|
|
15
|
+
declare function update(attributes: Record<string, unknown>): void;
|
|
16
|
+
declare function shutdown(): void;
|
|
17
|
+
declare const Auxx: {
|
|
18
|
+
boot: typeof boot;
|
|
19
|
+
update: typeof update;
|
|
20
|
+
shutdown: typeof shutdown;
|
|
21
|
+
};
|
|
22
|
+
export default Auxx;
|
|
23
|
+
export { boot, update, shutdown };
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AA0BA,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACpC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAA;CACpC;AAYD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,QAAQ,CAAC,EAAE,OAAO,CAAA;KACnB;CACF;AA0BD,iBAAS,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CA0DxC;AAED,iBAAS,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAOzD;AAED,iBAAS,QAAQ,IAAI,IAAI,CAYxB;AAED,QAAA,MAAM,IAAI;;;;CAA6B,CAAA;AAEvC,eAAe,IAAI,CAAA;AACnB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAA"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// packages/chat/src/client/index.ts
|
|
2
|
+
/**
|
|
3
|
+
* Browser bootstrap for `@auxx/chat`.
|
|
4
|
+
*
|
|
5
|
+
* Wraps the widget bundle that ships in `./widget-bundle` so customers can
|
|
6
|
+
* install via npm instead of pasting a `<script data-channel-id>` snippet:
|
|
7
|
+
*
|
|
8
|
+
* import Auxx from '@auxx/chat'
|
|
9
|
+
* Auxx.boot({ channelId: 'abc', userJwt, attributes: {...} })
|
|
10
|
+
* Auxx.update({ plan: 'pro' })
|
|
11
|
+
* Auxx.shutdown()
|
|
12
|
+
*
|
|
13
|
+
* Defaults to the hosted bundle at `app.auxx.ai/scripts/chat-widget.js`.
|
|
14
|
+
* Customers self-hosting can pass `widgetBase` (or set `AUXX_WIDGET_URL` at
|
|
15
|
+
* build time). `apiBase` is propagated to the bundle via
|
|
16
|
+
* `window.__AUXX_CONFIG__` *before* the script tag is injected, so the same
|
|
17
|
+
* override chain applies whether the bundle came from our CDN or from
|
|
18
|
+
* `node_modules`.
|
|
19
|
+
*
|
|
20
|
+
* `userJwt` is accepted here but only stored on the bootstrap state — phase 3
|
|
21
|
+
* wires it through the actual transport layer.
|
|
22
|
+
*/
|
|
23
|
+
import { API_URL, WIDGET_URL } from '../shared/env';
|
|
24
|
+
let state = null;
|
|
25
|
+
function ensureBrowser() {
|
|
26
|
+
if (typeof window === 'undefined' || typeof document === 'undefined') {
|
|
27
|
+
throw new Error('@auxx/chat: boot() can only run in a browser environment');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function pushAttributes(attributes) {
|
|
31
|
+
if (!Object.keys(attributes).length)
|
|
32
|
+
return;
|
|
33
|
+
const queue = (window.AuxxChat ??= []);
|
|
34
|
+
if (Array.isArray(queue)) {
|
|
35
|
+
queue.push(['identify', attributes]);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
const handle = queue;
|
|
39
|
+
handle.push?.(['identify', attributes]);
|
|
40
|
+
}
|
|
41
|
+
// Mirror onto __AUXX_CONFIG__ so `buildUserDataEnvelope()` can ship the
|
|
42
|
+
// non-sensitive bag alongside the JWT for phase-4 resolution.
|
|
43
|
+
const cfg = (window.__AUXX_CONFIG__ ??= {});
|
|
44
|
+
cfg.attributes = { ...(cfg.attributes ?? {}), ...attributes };
|
|
45
|
+
}
|
|
46
|
+
function boot(options) {
|
|
47
|
+
ensureBrowser();
|
|
48
|
+
if (state) {
|
|
49
|
+
// Same-channel re-boot is a soft refresh: we don't re-inject the script,
|
|
50
|
+
// but we do roll forward the userJwt (so the React wrapper's reboot-on-
|
|
51
|
+
// JWT-change effect actually rotates the token) and push any new
|
|
52
|
+
// attributes through the identify queue.
|
|
53
|
+
if (state.channelId === options.channelId) {
|
|
54
|
+
if (options.userJwt !== undefined) {
|
|
55
|
+
state.userJwt = options.userJwt;
|
|
56
|
+
const cfg = (window.__AUXX_CONFIG__ ??= {});
|
|
57
|
+
if (options.userJwt)
|
|
58
|
+
cfg.userJwt = options.userJwt;
|
|
59
|
+
else
|
|
60
|
+
delete cfg.userJwt;
|
|
61
|
+
}
|
|
62
|
+
if (options.attributes)
|
|
63
|
+
pushAttributes(options.attributes);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
shutdown();
|
|
67
|
+
}
|
|
68
|
+
const apiBase = options.apiBase ?? API_URL;
|
|
69
|
+
const widgetBase = options.widgetBase ?? WIDGET_URL;
|
|
70
|
+
window.__AUXX_CONFIG__ = {
|
|
71
|
+
...(window.__AUXX_CONFIG__ ?? {}),
|
|
72
|
+
apiBase,
|
|
73
|
+
...(options.userJwt ? { userJwt: options.userJwt } : {}),
|
|
74
|
+
};
|
|
75
|
+
if (options.attributes)
|
|
76
|
+
pushAttributes(options.attributes);
|
|
77
|
+
const next = {
|
|
78
|
+
channelId: options.channelId,
|
|
79
|
+
apiBase,
|
|
80
|
+
widgetBase,
|
|
81
|
+
userJwt: options.userJwt,
|
|
82
|
+
attributes: options.attributes,
|
|
83
|
+
};
|
|
84
|
+
// Reuse an already-loaded bundle if present.
|
|
85
|
+
const existing = document.querySelector(`script[data-auxx-chat][data-channel-id="${options.channelId}"]`);
|
|
86
|
+
if (existing) {
|
|
87
|
+
next.scriptTag = existing;
|
|
88
|
+
state = next;
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const tag = document.createElement('script');
|
|
92
|
+
tag.async = true;
|
|
93
|
+
tag.dataset.auxxChat = 'true';
|
|
94
|
+
tag.dataset.channelId = options.channelId;
|
|
95
|
+
if (options.theme)
|
|
96
|
+
tag.dataset.theme = options.theme;
|
|
97
|
+
tag.src = widgetBase;
|
|
98
|
+
document.head.appendChild(tag);
|
|
99
|
+
next.scriptTag = tag;
|
|
100
|
+
state = next;
|
|
101
|
+
}
|
|
102
|
+
function update(attributes) {
|
|
103
|
+
ensureBrowser();
|
|
104
|
+
if (!state) {
|
|
105
|
+
throw new Error('@auxx/chat: update() called before boot()');
|
|
106
|
+
}
|
|
107
|
+
state.attributes = { ...(state.attributes ?? {}), ...attributes };
|
|
108
|
+
pushAttributes(attributes);
|
|
109
|
+
}
|
|
110
|
+
function shutdown() {
|
|
111
|
+
if (typeof window === 'undefined')
|
|
112
|
+
return;
|
|
113
|
+
if (!state)
|
|
114
|
+
return;
|
|
115
|
+
state.scriptTag?.remove();
|
|
116
|
+
// The widget mounts inside a closed shadow DOM under a host element with
|
|
117
|
+
// a stable id; remove the host so a subsequent boot() starts cold.
|
|
118
|
+
document.getElementById('auxx-chat-widget-root')?.remove();
|
|
119
|
+
delete window.__AUXX_CONFIG__;
|
|
120
|
+
if (window.AuxxChat && !Array.isArray(window.AuxxChat)) {
|
|
121
|
+
delete window.AuxxChat;
|
|
122
|
+
}
|
|
123
|
+
state = null;
|
|
124
|
+
}
|
|
125
|
+
const Auxx = { boot, update, shutdown };
|
|
126
|
+
export default Auxx;
|
|
127
|
+
export { boot, update, shutdown };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../../src/shared/env.ts"],"names":[],"mappings":"AAwBA,eAAO,MAAM,OAAO,SAAuC,CAAA;AAE3D,eAAO,MAAM,OAAO,QACoE,CAAA;AAExF,eAAO,MAAM,UAAU,QAI8B,CAAA"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// packages/chat/src/shared/env.ts
|
|
2
|
+
/**
|
|
3
|
+
* Build-time / runtime defaults for the npm entry points (`client`, `server`,
|
|
4
|
+
* `react`). The widget *bundle* itself does not consult this file — it reads
|
|
5
|
+
* `window.__AUXX_CONFIG__` via `shared/runtime-config.ts` and falls back to
|
|
6
|
+
* the Vite-`define`d `__AUXX_API_BASE_URL__` constant.
|
|
7
|
+
*
|
|
8
|
+
* Override priority for hosts using the npm shims:
|
|
9
|
+
* 1. Explicit `Auxx.boot({ apiBase, widgetBase })` — runtime args win.
|
|
10
|
+
* 2. Build-time `process.env.AUXX_*` — customer bundler replaces at build.
|
|
11
|
+
* 3. Built-in defaults below, gated by `AUXX_ENV`.
|
|
12
|
+
*
|
|
13
|
+
* Mirrors `packages/sdk/src/env.ts`.
|
|
14
|
+
*/
|
|
15
|
+
function readEnv(key) {
|
|
16
|
+
if (typeof process === 'undefined' || !process.env)
|
|
17
|
+
return undefined;
|
|
18
|
+
const value = process.env[key];
|
|
19
|
+
if (!value)
|
|
20
|
+
return undefined;
|
|
21
|
+
const trimmed = value.trim();
|
|
22
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
23
|
+
}
|
|
24
|
+
export const IS_PROD = readEnv('AUXX_ENV') === 'production';
|
|
25
|
+
export const API_URL = readEnv('AUXX_API_URL') ?? (IS_PROD ? 'https://api.auxx.ai' : 'http://localhost:3007');
|
|
26
|
+
export const WIDGET_URL = readEnv('AUXX_WIDGET_URL') ??
|
|
27
|
+
(IS_PROD
|
|
28
|
+
? 'https://app.auxx.ai/scripts/chat-widget.js'
|
|
29
|
+
: 'http://localhost:3000/scripts/chat-widget.js');
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface BootOptions {
|
|
2
|
+
channelId: string;
|
|
3
|
+
userJwt?: string;
|
|
4
|
+
attributes?: Record<string, unknown>;
|
|
5
|
+
apiBase?: string;
|
|
6
|
+
widgetBase?: string;
|
|
7
|
+
theme?: 'light' | 'dark' | 'system';
|
|
8
|
+
}
|
|
9
|
+
declare global {
|
|
10
|
+
interface Window {
|
|
11
|
+
AuxxChat?: unknown;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
declare function boot(options: BootOptions): void;
|
|
15
|
+
declare function update(attributes: Record<string, unknown>): void;
|
|
16
|
+
declare function shutdown(): void;
|
|
17
|
+
declare const Auxx: {
|
|
18
|
+
boot: typeof boot;
|
|
19
|
+
update: typeof update;
|
|
20
|
+
shutdown: typeof shutdown;
|
|
21
|
+
};
|
|
22
|
+
export default Auxx;
|
|
23
|
+
export { boot, update, shutdown };
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AA0BA,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACpC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAA;CACpC;AAYD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,QAAQ,CAAC,EAAE,OAAO,CAAA;KACnB;CACF;AA0BD,iBAAS,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CA0DxC;AAED,iBAAS,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAOzD;AAED,iBAAS,QAAQ,IAAI,IAAI,CAYxB;AAED,QAAA,MAAM,IAAI;;;;CAA6B,CAAA;AAEvC,eAAe,IAAI,CAAA;AACnB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAA"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// packages/chat/src/client/index.ts
|
|
2
|
+
/**
|
|
3
|
+
* Browser bootstrap for `@auxx/chat`.
|
|
4
|
+
*
|
|
5
|
+
* Wraps the widget bundle that ships in `./widget-bundle` so customers can
|
|
6
|
+
* install via npm instead of pasting a `<script data-channel-id>` snippet:
|
|
7
|
+
*
|
|
8
|
+
* import Auxx from '@auxx/chat'
|
|
9
|
+
* Auxx.boot({ channelId: 'abc', userJwt, attributes: {...} })
|
|
10
|
+
* Auxx.update({ plan: 'pro' })
|
|
11
|
+
* Auxx.shutdown()
|
|
12
|
+
*
|
|
13
|
+
* Defaults to the hosted bundle at `app.auxx.ai/scripts/chat-widget.js`.
|
|
14
|
+
* Customers self-hosting can pass `widgetBase` (or set `AUXX_WIDGET_URL` at
|
|
15
|
+
* build time). `apiBase` is propagated to the bundle via
|
|
16
|
+
* `window.__AUXX_CONFIG__` *before* the script tag is injected, so the same
|
|
17
|
+
* override chain applies whether the bundle came from our CDN or from
|
|
18
|
+
* `node_modules`.
|
|
19
|
+
*
|
|
20
|
+
* `userJwt` is accepted here but only stored on the bootstrap state — phase 3
|
|
21
|
+
* wires it through the actual transport layer.
|
|
22
|
+
*/
|
|
23
|
+
import { API_URL, WIDGET_URL } from '../shared/env';
|
|
24
|
+
let state = null;
|
|
25
|
+
function ensureBrowser() {
|
|
26
|
+
if (typeof window === 'undefined' || typeof document === 'undefined') {
|
|
27
|
+
throw new Error('@auxx/chat: boot() can only run in a browser environment');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function pushAttributes(attributes) {
|
|
31
|
+
if (!Object.keys(attributes).length)
|
|
32
|
+
return;
|
|
33
|
+
const queue = (window.AuxxChat ??= []);
|
|
34
|
+
if (Array.isArray(queue)) {
|
|
35
|
+
queue.push(['identify', attributes]);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
const handle = queue;
|
|
39
|
+
handle.push?.(['identify', attributes]);
|
|
40
|
+
}
|
|
41
|
+
// Mirror onto __AUXX_CONFIG__ so `buildUserDataEnvelope()` can ship the
|
|
42
|
+
// non-sensitive bag alongside the JWT for phase-4 resolution.
|
|
43
|
+
const cfg = (window.__AUXX_CONFIG__ ??= {});
|
|
44
|
+
cfg.attributes = { ...(cfg.attributes ?? {}), ...attributes };
|
|
45
|
+
}
|
|
46
|
+
function boot(options) {
|
|
47
|
+
ensureBrowser();
|
|
48
|
+
if (state) {
|
|
49
|
+
// Same-channel re-boot is a soft refresh: we don't re-inject the script,
|
|
50
|
+
// but we do roll forward the userJwt (so the React wrapper's reboot-on-
|
|
51
|
+
// JWT-change effect actually rotates the token) and push any new
|
|
52
|
+
// attributes through the identify queue.
|
|
53
|
+
if (state.channelId === options.channelId) {
|
|
54
|
+
if (options.userJwt !== undefined) {
|
|
55
|
+
state.userJwt = options.userJwt;
|
|
56
|
+
const cfg = (window.__AUXX_CONFIG__ ??= {});
|
|
57
|
+
if (options.userJwt)
|
|
58
|
+
cfg.userJwt = options.userJwt;
|
|
59
|
+
else
|
|
60
|
+
delete cfg.userJwt;
|
|
61
|
+
}
|
|
62
|
+
if (options.attributes)
|
|
63
|
+
pushAttributes(options.attributes);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
shutdown();
|
|
67
|
+
}
|
|
68
|
+
const apiBase = options.apiBase ?? API_URL;
|
|
69
|
+
const widgetBase = options.widgetBase ?? WIDGET_URL;
|
|
70
|
+
window.__AUXX_CONFIG__ = {
|
|
71
|
+
...(window.__AUXX_CONFIG__ ?? {}),
|
|
72
|
+
apiBase,
|
|
73
|
+
...(options.userJwt ? { userJwt: options.userJwt } : {}),
|
|
74
|
+
};
|
|
75
|
+
if (options.attributes)
|
|
76
|
+
pushAttributes(options.attributes);
|
|
77
|
+
const next = {
|
|
78
|
+
channelId: options.channelId,
|
|
79
|
+
apiBase,
|
|
80
|
+
widgetBase,
|
|
81
|
+
userJwt: options.userJwt,
|
|
82
|
+
attributes: options.attributes,
|
|
83
|
+
};
|
|
84
|
+
// Reuse an already-loaded bundle if present.
|
|
85
|
+
const existing = document.querySelector(`script[data-auxx-chat][data-channel-id="${options.channelId}"]`);
|
|
86
|
+
if (existing) {
|
|
87
|
+
next.scriptTag = existing;
|
|
88
|
+
state = next;
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const tag = document.createElement('script');
|
|
92
|
+
tag.async = true;
|
|
93
|
+
tag.dataset.auxxChat = 'true';
|
|
94
|
+
tag.dataset.channelId = options.channelId;
|
|
95
|
+
if (options.theme)
|
|
96
|
+
tag.dataset.theme = options.theme;
|
|
97
|
+
tag.src = widgetBase;
|
|
98
|
+
document.head.appendChild(tag);
|
|
99
|
+
next.scriptTag = tag;
|
|
100
|
+
state = next;
|
|
101
|
+
}
|
|
102
|
+
function update(attributes) {
|
|
103
|
+
ensureBrowser();
|
|
104
|
+
if (!state) {
|
|
105
|
+
throw new Error('@auxx/chat: update() called before boot()');
|
|
106
|
+
}
|
|
107
|
+
state.attributes = { ...(state.attributes ?? {}), ...attributes };
|
|
108
|
+
pushAttributes(attributes);
|
|
109
|
+
}
|
|
110
|
+
function shutdown() {
|
|
111
|
+
if (typeof window === 'undefined')
|
|
112
|
+
return;
|
|
113
|
+
if (!state)
|
|
114
|
+
return;
|
|
115
|
+
state.scriptTag?.remove();
|
|
116
|
+
// The widget mounts inside a closed shadow DOM under a host element with
|
|
117
|
+
// a stable id; remove the host so a subsequent boot() starts cold.
|
|
118
|
+
document.getElementById('auxx-chat-widget-root')?.remove();
|
|
119
|
+
delete window.__AUXX_CONFIG__;
|
|
120
|
+
if (window.AuxxChat && !Array.isArray(window.AuxxChat)) {
|
|
121
|
+
delete window.AuxxChat;
|
|
122
|
+
}
|
|
123
|
+
state = null;
|
|
124
|
+
}
|
|
125
|
+
const Auxx = { boot, update, shutdown };
|
|
126
|
+
export default Auxx;
|
|
127
|
+
export { boot, update, shutdown };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/index.tsx"],"names":[],"mappings":"AAcA,OAAa,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAA;AAElD,MAAM,WAAW,aAAc,SAAQ,WAAW;CAAG;AAErD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CA2BnD;AAED,eAAe,QAAQ,CAAA"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// packages/chat/src/react/index.tsx
|
|
2
|
+
/**
|
|
3
|
+
* React wrapper for `@auxx/chat`. Renders nothing — runs `Auxx.boot` in an
|
|
4
|
+
* effect, calls `Auxx.update` when serialized attributes change, and
|
|
5
|
+
* `Auxx.shutdown` on unmount.
|
|
6
|
+
*
|
|
7
|
+
* <AuxxChat channelId="..." userJwt={token} attributes={{ plan: 'pro' }} />
|
|
8
|
+
*
|
|
9
|
+
* Kept on a sub-path import (`@auxx/chat/react`) so React is not pulled into
|
|
10
|
+
* the non-React bundle.
|
|
11
|
+
*/
|
|
12
|
+
import { useEffect, useRef } from 'react';
|
|
13
|
+
import Auxx, {} from '../client';
|
|
14
|
+
export function AuxxChat(props) {
|
|
15
|
+
const { channelId, userJwt, attributes, apiBase, widgetBase, theme } = props;
|
|
16
|
+
// Track whether boot() has run so attribute changes route through update().
|
|
17
|
+
const bootedRef = useRef(false);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
Auxx.boot({ channelId, userJwt, attributes, apiBase, widgetBase, theme });
|
|
20
|
+
bootedRef.current = true;
|
|
21
|
+
return () => {
|
|
22
|
+
Auxx.shutdown();
|
|
23
|
+
bootedRef.current = false;
|
|
24
|
+
};
|
|
25
|
+
// Reboot whenever the channel / JWT / hosting URLs change. Attribute
|
|
26
|
+
// changes are handled by the second effect via `update()`.
|
|
27
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
28
|
+
}, [channelId, userJwt, apiBase, widgetBase, theme]);
|
|
29
|
+
// Serialize attributes so reference-only changes don't fire spurious updates.
|
|
30
|
+
const attributesKey = attributes ? JSON.stringify(attributes) : '';
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (!bootedRef.current || !attributes)
|
|
33
|
+
return;
|
|
34
|
+
Auxx.update(attributes);
|
|
35
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
36
|
+
}, [attributesKey]);
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
export default AuxxChat;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../../src/shared/env.ts"],"names":[],"mappings":"AAwBA,eAAO,MAAM,OAAO,SAAuC,CAAA;AAE3D,eAAO,MAAM,OAAO,QACoE,CAAA;AAExF,eAAO,MAAM,UAAU,QAI8B,CAAA"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// packages/chat/src/shared/env.ts
|
|
2
|
+
/**
|
|
3
|
+
* Build-time / runtime defaults for the npm entry points (`client`, `server`,
|
|
4
|
+
* `react`). The widget *bundle* itself does not consult this file — it reads
|
|
5
|
+
* `window.__AUXX_CONFIG__` via `shared/runtime-config.ts` and falls back to
|
|
6
|
+
* the Vite-`define`d `__AUXX_API_BASE_URL__` constant.
|
|
7
|
+
*
|
|
8
|
+
* Override priority for hosts using the npm shims:
|
|
9
|
+
* 1. Explicit `Auxx.boot({ apiBase, widgetBase })` — runtime args win.
|
|
10
|
+
* 2. Build-time `process.env.AUXX_*` — customer bundler replaces at build.
|
|
11
|
+
* 3. Built-in defaults below, gated by `AUXX_ENV`.
|
|
12
|
+
*
|
|
13
|
+
* Mirrors `packages/sdk/src/env.ts`.
|
|
14
|
+
*/
|
|
15
|
+
function readEnv(key) {
|
|
16
|
+
if (typeof process === 'undefined' || !process.env)
|
|
17
|
+
return undefined;
|
|
18
|
+
const value = process.env[key];
|
|
19
|
+
if (!value)
|
|
20
|
+
return undefined;
|
|
21
|
+
const trimmed = value.trim();
|
|
22
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
23
|
+
}
|
|
24
|
+
export const IS_PROD = readEnv('AUXX_ENV') === 'production';
|
|
25
|
+
export const API_URL = readEnv('AUXX_API_URL') ?? (IS_PROD ? 'https://api.auxx.ai' : 'http://localhost:3007');
|
|
26
|
+
export const WIDGET_URL = readEnv('AUXX_WIDGET_URL') ??
|
|
27
|
+
(IS_PROD
|
|
28
|
+
? 'https://app.auxx.ai/scripts/chat-widget.js'
|
|
29
|
+
: 'http://localhost:3000/scripts/chat-widget.js');
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node-side helper for signing the user JWT that `@auxx/chat`'s browser
|
|
3
|
+
* bootstrap accepts via `Auxx.boot({ userJwt })`.
|
|
4
|
+
*
|
|
5
|
+
* Customers sign HS256 tokens on their own server using a per-channel secret
|
|
6
|
+
* stored in our `ApiKey` table (`type='chat'`, `referenceId=channelId`). The
|
|
7
|
+
* widget forwards the token with every request to `/api/chat/*`; phase 3
|
|
8
|
+
* wires verification on the server side.
|
|
9
|
+
*
|
|
10
|
+
* Default expiry is 1h. Tokens are short-lived; per-request re-verification
|
|
11
|
+
* catches expiry — no denylist.
|
|
12
|
+
*/
|
|
13
|
+
import { type SignOptions } from 'jsonwebtoken';
|
|
14
|
+
export interface SignUserJwtPayload {
|
|
15
|
+
/** Stable customer-side user id. Required. */
|
|
16
|
+
user_id: string;
|
|
17
|
+
/** Optional identifying attributes — passed through to the contact merge. */
|
|
18
|
+
email?: string;
|
|
19
|
+
name?: string;
|
|
20
|
+
/** Any additional sensitive claims the customer wants protected by JWT. */
|
|
21
|
+
[key: string]: unknown;
|
|
22
|
+
}
|
|
23
|
+
export interface SignUserJwtOptions {
|
|
24
|
+
/** JWT lifetime. Accepts seconds (number) or a vercel-ms string. Default `'1h'`. */
|
|
25
|
+
expiresIn?: SignOptions['expiresIn'];
|
|
26
|
+
}
|
|
27
|
+
export declare function signUserJwt(payload: SignUserJwtPayload, secret: string, options?: SignUserJwtOptions): string;
|
|
28
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/index.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,OAAY,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAA;AAEpD,MAAM,WAAW,kBAAkB;IACjC,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAA;IACf,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,2EAA2E;IAC3E,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,oFAAoF;IACpF,SAAS,CAAC,EAAE,WAAW,CAAC,WAAW,CAAC,CAAA;CACrC;AAED,wBAAgB,WAAW,CACzB,OAAO,EAAE,kBAAkB,EAC3B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,kBAAuB,GAC/B,MAAM,CAWR"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// packages/chat/src/server/index.ts
|
|
2
|
+
/**
|
|
3
|
+
* Node-side helper for signing the user JWT that `@auxx/chat`'s browser
|
|
4
|
+
* bootstrap accepts via `Auxx.boot({ userJwt })`.
|
|
5
|
+
*
|
|
6
|
+
* Customers sign HS256 tokens on their own server using a per-channel secret
|
|
7
|
+
* stored in our `ApiKey` table (`type='chat'`, `referenceId=channelId`). The
|
|
8
|
+
* widget forwards the token with every request to `/api/chat/*`; phase 3
|
|
9
|
+
* wires verification on the server side.
|
|
10
|
+
*
|
|
11
|
+
* Default expiry is 1h. Tokens are short-lived; per-request re-verification
|
|
12
|
+
* catches expiry — no denylist.
|
|
13
|
+
*/
|
|
14
|
+
import jwt, {} from 'jsonwebtoken';
|
|
15
|
+
export function signUserJwt(payload, secret, options = {}) {
|
|
16
|
+
if (!payload || typeof payload.user_id !== 'string' || payload.user_id.length === 0) {
|
|
17
|
+
throw new Error('signUserJwt: payload.user_id is required');
|
|
18
|
+
}
|
|
19
|
+
if (typeof secret !== 'string' || secret.length === 0) {
|
|
20
|
+
throw new Error('signUserJwt: secret is required');
|
|
21
|
+
}
|
|
22
|
+
return jwt.sign(payload, secret, {
|
|
23
|
+
algorithm: 'HS256',
|
|
24
|
+
expiresIn: options.expiresIn ?? '1h',
|
|
25
|
+
});
|
|
26
|
+
}
|