@agent-analytics/paperclip-live-analytics-plugin 0.1.0 → 0.1.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/manifest.js +51 -0
- package/dist/ui/index.js +578 -0
- package/dist/worker.js +1165 -0
- package/package.json +13 -8
- package/dist/assets/index-dyBLLxDx.css +0 -1
- package/dist/index.html +0 -14
- package/index.html +0 -13
- package/paperclip-plugin.manifest.json +0 -36
- package/src/shared/agent-analytics-client.js +0 -204
- package/src/shared/constants.js +0 -41
- package/src/shared/defaults.js +0 -73
- package/src/shared/live-state.js +0 -384
- package/src/ui/App.jsx +0 -87
- package/src/ui/demo-data.js +0 -238
- package/src/ui/main.jsx +0 -11
- package/src/ui/paperclip-bridge.js +0 -126
- package/src/ui/styles.css +0 -483
- package/src/ui/surfaces/PageSurface.jsx +0 -218
- package/src/ui/surfaces/SettingsSurface.jsx +0 -236
- package/src/ui/surfaces/WidgetSurface.jsx +0 -37
- package/src/worker/index.js +0 -36
- package/src/worker/paperclip.js +0 -37
- package/src/worker/service.js +0 -535
- package/src/worker/state.js +0 -58
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-analytics/paperclip-live-analytics-plugin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Thin Paperclip plugin that exposes live Agent Analytics signals inside a company workspace.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -20,30 +20,35 @@
|
|
|
20
20
|
"agent-analytics"
|
|
21
21
|
],
|
|
22
22
|
"files": [
|
|
23
|
-
"dist",
|
|
24
|
-
"docs",
|
|
25
|
-
"src",
|
|
26
|
-
"index.html",
|
|
27
|
-
"paperclip-plugin.manifest.json",
|
|
23
|
+
"dist/**/*.js",
|
|
28
24
|
"README.md",
|
|
29
|
-
"LICENSE"
|
|
25
|
+
"LICENSE",
|
|
26
|
+
"docs/**/*.md"
|
|
30
27
|
],
|
|
31
28
|
"publishConfig": {
|
|
32
29
|
"access": "public"
|
|
33
30
|
},
|
|
34
31
|
"scripts": {
|
|
35
|
-
"build": "
|
|
32
|
+
"build": "node ./scripts/build-paperclip.mjs",
|
|
33
|
+
"build:demo": "vite build",
|
|
36
34
|
"dev": "vite",
|
|
37
35
|
"test": "node --test tests/*.test.mjs",
|
|
38
36
|
"prepack": "npm test && npm run build",
|
|
39
37
|
"pack:local": "npm pack"
|
|
40
38
|
},
|
|
39
|
+
"paperclipPlugin": {
|
|
40
|
+
"manifest": "./dist/manifest.js",
|
|
41
|
+
"worker": "./dist/worker.js",
|
|
42
|
+
"ui": "./dist/ui/"
|
|
43
|
+
},
|
|
41
44
|
"dependencies": {
|
|
45
|
+
"@paperclipai/plugin-sdk": "2026.318.0",
|
|
42
46
|
"react": "^19.2.0",
|
|
43
47
|
"react-dom": "^19.2.0"
|
|
44
48
|
},
|
|
45
49
|
"devDependencies": {
|
|
46
50
|
"@vitejs/plugin-react": "^5.1.3",
|
|
51
|
+
"esbuild": "^0.27.0",
|
|
47
52
|
"vite": "^7.2.4"
|
|
48
53
|
}
|
|
49
54
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
:root{--aa-bg: #f0e8dc;--aa-bg-deep: #e4d6c0;--aa-ink: #1f2a2a;--aa-muted: #576665;--aa-panel: rgba(255, 250, 242, .78);--aa-panel-stroke: rgba(31, 42, 42, .11);--aa-accent: #0f8b8d;--aa-accent-warm: #dc6f36;--aa-accent-cool: #265f88;--aa-live: #1a9a63;--aa-error: #b24a2f;--aa-shadow: 0 18px 50px rgba(31, 42, 42, .08);--aa-serif: "Iowan Old Style", "Palatino Linotype", "Book Antiqua", serif;--aa-sans: "IBM Plex Sans", "Avenir Next", "Segoe UI", sans-serif;--aa-mono: "IBM Plex Mono", "SFMono-Regular", monospace}*{box-sizing:border-box}body{margin:0;font-family:var(--aa-sans);color:var(--aa-ink);background:radial-gradient(circle at top left,rgba(15,139,141,.16),transparent 28%),radial-gradient(circle at top right,rgba(220,111,54,.16),transparent 22%),linear-gradient(180deg,#f8f3eb 0%,var(--aa-bg) 45%,var(--aa-bg-deep) 100%)}a{color:inherit;text-decoration:none}button,input,select{font:inherit}.aa-app{min-height:100vh;padding:24px}.aa-page-shell,.aa-settings-shell{max-width:1400px;margin:0 auto}.aa-hero,.aa-panel,.aa-widget,.aa-metric-card,.aa-asset-card{background:var(--aa-panel);border:1px solid var(--aa-panel-stroke);box-shadow:var(--aa-shadow);-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px)}.aa-hero{display:flex;justify-content:space-between;gap:24px;padding:28px;border-radius:28px}.aa-kicker{margin:0 0 8px;font-family:var(--aa-mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--aa-muted)}.aa-hero h1,.aa-panel h2,.aa-widget h2{margin:0;font-family:var(--aa-serif);line-height:1}.aa-hero h1{font-size:clamp(2.6rem,5vw,4.3rem);max-width:12ch}.aa-hero-copy{max-width:58ch;color:var(--aa-muted)}.aa-hero-status{min-width:220px;display:flex;flex-direction:column;align-items:flex-end;gap:12px}.aa-metric-grid,.aa-main-grid,.aa-evidence-grid,.aa-asset-grid,.aa-settings-grid,.aa-form-grid{display:grid;gap:18px}.aa-metric-grid{grid-template-columns:repeat(4,minmax(0,1fr));margin:18px 0}.aa-metric-card{border-radius:22px;padding:20px}.aa-metric-card span,.aa-label{display:block;font-size:.82rem;color:var(--aa-muted)}.aa-metric-card strong{display:block;margin-top:10px;font-size:2.3rem;font-family:var(--aa-serif)}.aa-main-grid{grid-template-columns:1.25fr 1fr;align-items:start}.aa-panel,.aa-widget,.aa-asset-card{border-radius:26px;padding:22px}.aa-panel-header,.aa-widget-header,.aa-asset-topline,.aa-widget-footer,.aa-inline-actions,.aa-settings-row{display:flex;justify-content:space-between;gap:14px;align-items:flex-start}.aa-world-grid{display:grid;grid-template-columns:minmax(260px,.9fr) 1.1fr;gap:20px;align-items:center}.aa-globe{position:relative;aspect-ratio:1;border-radius:999px;background:radial-gradient(circle at 30% 30%,rgba(15,139,141,.45),transparent 44%),radial-gradient(circle at 70% 65%,rgba(220,111,54,.24),transparent 32%),linear-gradient(180deg,#173838,#0f6465);overflow:hidden;box-shadow:inset 0 0 80px #ffffff26}.aa-globe-ring{position:absolute;inset:18%;border:1px solid rgba(255,255,255,.22);border-radius:999px}.aa-globe-ring-two{inset:8%}.aa-globe-ring-three{inset:32%}.aa-globe-core{position:absolute;inset:38%;display:grid;place-items:center;border-radius:999px;background:#fffaf2eb;color:var(--aa-ink);font-family:var(--aa-mono);letter-spacing:.12em;text-transform:uppercase;font-size:.75rem}.aa-country-list,.aa-feed,.aa-settings-stack{display:grid;gap:12px}.aa-country-row,.aa-feed-row,.aa-mini-row,.aa-settings-row{padding:12px 0;border-top:1px solid rgba(31,42,42,.08)}.aa-country-row:first-child,.aa-feed-row:first-child,.aa-mini-row:first-child,.aa-settings-row:first-child{border-top:0;padding-top:0}.aa-country-row strong,.aa-mini-row strong,.aa-feed-row strong,.aa-settings-row strong{display:block}.aa-country-row span,.aa-feed-row span,.aa-settings-row span{color:var(--aa-muted);font-size:.92rem}.aa-country-bar{width:100%;height:8px;margin-top:8px;border-radius:999px;background:#265f881f;overflow:hidden}.aa-country-bar-fill{height:100%;border-radius:999px;background:linear-gradient(90deg,var(--aa-accent) 0%,var(--aa-accent-warm) 100%)}.aa-world-hot,.aa-status-pill{padding:7px 12px;border-radius:999px;font-size:.78rem;font-family:var(--aa-mono);letter-spacing:.08em;text-transform:uppercase}.aa-world-hot,.aa-status-live,.aa-status-connected,.aa-status-streaming{background:#1a9a6324;color:var(--aa-live)}.aa-status-error,.aa-status-attention{background:#b24a2f24;color:var(--aa-error)}.aa-status-idle,.aa-status-pending,.aa-status-disconnected{background:#265f881f;color:var(--aa-accent-cool)}.aa-mini-panel{background:#ffffff6b;border-radius:20px;padding:18px;border:1px solid rgba(31,42,42,.08)}.aa-mini-panel h3,.aa-assets-section h2{margin:0 0 12px;font-family:var(--aa-serif)}.aa-feed-row{display:flex;justify-content:space-between;gap:12px}.aa-feed-row time{white-space:nowrap;font-size:.85rem;color:var(--aa-muted)}.aa-assets-section{margin-top:18px}.aa-asset-grid{grid-template-columns:repeat(auto-fit,minmax(280px,1fr));margin-top:18px}.aa-asset-card{display:grid;gap:16px}.aa-asset-metrics,.aa-asset-details,.aa-asset-evidence,.aa-widget-metrics{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}.aa-asset-metrics strong,.aa-widget-metrics strong{display:block;margin-top:8px;font-family:var(--aa-serif);font-size:1.6rem}.aa-button{border:0;border-radius:999px;padding:10px 14px;cursor:pointer;transition:transform .12s ease,opacity .12s ease}.aa-button:hover{transform:translateY(-1px)}.aa-button-primary{background:var(--aa-ink);color:#fff}.aa-button-secondary{background:#0f8b8d1f;color:var(--aa-accent)}.aa-button-ghost{background:transparent;color:var(--aa-muted);border:1px solid rgba(31,42,42,.12)}.aa-widget{max-width:520px;margin:0 auto}.aa-widget-metrics{margin:18px 0}.aa-settings-grid{grid-template-columns:1.15fr .85fr}.aa-form-grid{grid-template-columns:repeat(2,minmax(0,1fr));margin-top:14px}.aa-form-grid label,.aa-auth-box label{display:grid;gap:8px;font-size:.92rem;color:var(--aa-muted)}.aa-form-grid input,.aa-form-grid select,.aa-auth-box input{border-radius:14px;border:1px solid rgba(31,42,42,.12);padding:12px 14px;background:#ffffffb8}.aa-auth-box{display:grid;gap:12px;margin-top:16px;padding:16px;border-radius:18px;background:#ffffff7a}.aa-checkbox{display:flex!important;align-items:center;gap:10px}.aa-muted-note{color:var(--aa-muted);font-size:.92rem;display:inline-flex;align-items:center}.aa-panel-warning{border-color:#dc6f3647}@media(max-width:1100px){.aa-metric-grid,.aa-main-grid,.aa-settings-grid,.aa-world-grid{grid-template-columns:1fr}.aa-hero{flex-direction:column}.aa-hero-status{align-items:flex-start}}@media(max-width:720px){.aa-app{padding:14px}.aa-metric-grid,.aa-form-grid,.aa-asset-metrics,.aa-asset-details,.aa-asset-evidence,.aa-widget-metrics{grid-template-columns:1fr 1fr}.aa-feed-row,.aa-panel-header,.aa-widget-header,.aa-widget-footer,.aa-settings-row,.aa-inline-actions{flex-direction:column}}
|
package/dist/index.html
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<title>Agent Analytics Live</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-DCET-swI.js"></script>
|
|
8
|
-
<link rel="stylesheet" crossorigin href="/assets/index-dyBLLxDx.css">
|
|
9
|
-
</head>
|
|
10
|
-
<body>
|
|
11
|
-
<div id="root"></div>
|
|
12
|
-
</body>
|
|
13
|
-
</html>
|
|
14
|
-
|
package/index.html
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<title>Agent Analytics Live</title>
|
|
7
|
-
</head>
|
|
8
|
-
<body>
|
|
9
|
-
<div id="root"></div>
|
|
10
|
-
<script type="module" src="/src/ui/main.jsx"></script>
|
|
11
|
-
</body>
|
|
12
|
-
</html>
|
|
13
|
-
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"id": "@agent-analytics/paperclip-live-analytics-plugin",
|
|
3
|
-
"name": "Agent Analytics Live",
|
|
4
|
-
"displayName": "Agent Analytics Live",
|
|
5
|
-
"version": "0.1.0",
|
|
6
|
-
"categories": ["connector", "ui"],
|
|
7
|
-
"entrypoints": {
|
|
8
|
-
"worker": "./src/worker/index.js",
|
|
9
|
-
"ui": "./dist"
|
|
10
|
-
},
|
|
11
|
-
"surfaces": [
|
|
12
|
-
{
|
|
13
|
-
"type": "page",
|
|
14
|
-
"key": "agentAnalyticsLivePage",
|
|
15
|
-
"title": "Agent Analytics Live"
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
"type": "dashboardWidget",
|
|
19
|
-
"key": "agentAnalyticsLiveWidget",
|
|
20
|
-
"title": "Agent Analytics Live"
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
"type": "settingsPage",
|
|
24
|
-
"key": "agentAnalyticsLiveSettings",
|
|
25
|
-
"title": "Agent Analytics Live Settings"
|
|
26
|
-
}
|
|
27
|
-
],
|
|
28
|
-
"capabilities": [
|
|
29
|
-
"http.outbound",
|
|
30
|
-
"plugin.state.read",
|
|
31
|
-
"plugin.state.write",
|
|
32
|
-
"companies.read",
|
|
33
|
-
"projects.read"
|
|
34
|
-
]
|
|
35
|
-
}
|
|
36
|
-
|
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AGENT_SESSION_SCOPES,
|
|
3
|
-
DEFAULT_BASE_URL,
|
|
4
|
-
PLUGIN_DISPLAY_NAME,
|
|
5
|
-
PLUGIN_ID,
|
|
6
|
-
} from './constants.js';
|
|
7
|
-
|
|
8
|
-
function createJsonHeaders(auth) {
|
|
9
|
-
const headers = {
|
|
10
|
-
'Content-Type': 'application/json',
|
|
11
|
-
};
|
|
12
|
-
if (auth?.access_token) headers.Authorization = `Bearer ${auth.access_token}`;
|
|
13
|
-
else if (auth?.api_key) headers['X-API-Key'] = auth.api_key;
|
|
14
|
-
return headers;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function buildQuery(params) {
|
|
18
|
-
return Object.entries(params)
|
|
19
|
-
.filter(([, value]) => value !== null && value !== undefined && value !== '')
|
|
20
|
-
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
|
|
21
|
-
.join('&');
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function parseSseEvent(rawEvent) {
|
|
25
|
-
const event = {
|
|
26
|
-
event: 'message',
|
|
27
|
-
data: '',
|
|
28
|
-
comment: null,
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const lines = rawEvent.split(/\r?\n/);
|
|
32
|
-
for (const line of lines) {
|
|
33
|
-
if (!line) continue;
|
|
34
|
-
if (line.startsWith(':')) {
|
|
35
|
-
event.comment = line.slice(1).trim();
|
|
36
|
-
continue;
|
|
37
|
-
}
|
|
38
|
-
const separatorIndex = line.indexOf(':');
|
|
39
|
-
const field = separatorIndex === -1 ? line : line.slice(0, separatorIndex);
|
|
40
|
-
const value = separatorIndex === -1 ? '' : line.slice(separatorIndex + 1).trimStart();
|
|
41
|
-
if (field === 'event') event.event = value;
|
|
42
|
-
if (field === 'data') event.data = event.data ? `${event.data}\n${value}` : value;
|
|
43
|
-
}
|
|
44
|
-
return event;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export class AgentAnalyticsClient {
|
|
48
|
-
constructor({
|
|
49
|
-
auth = null,
|
|
50
|
-
baseUrl = DEFAULT_BASE_URL,
|
|
51
|
-
fetchImpl = globalThis.fetch,
|
|
52
|
-
onAuthUpdate = null,
|
|
53
|
-
} = {}) {
|
|
54
|
-
this.auth = auth ? { ...auth } : null;
|
|
55
|
-
this.baseUrl = baseUrl;
|
|
56
|
-
this.fetchImpl = fetchImpl;
|
|
57
|
-
this.onAuthUpdate = onAuthUpdate;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
setAuth(auth) {
|
|
61
|
-
this.auth = auth ? { ...auth } : null;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async request(method, path, body, { retryOnRefresh = true } = {}) {
|
|
65
|
-
const response = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
66
|
-
method,
|
|
67
|
-
headers: createJsonHeaders(this.auth),
|
|
68
|
-
body: body ? JSON.stringify(body) : undefined,
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
const data = await response.json().catch(() => ({}));
|
|
72
|
-
|
|
73
|
-
if (response.status === 401 && retryOnRefresh && this.auth?.refresh_token) {
|
|
74
|
-
const refreshed = await this.refreshAgentSession().catch(() => null);
|
|
75
|
-
if (refreshed?.access_token) {
|
|
76
|
-
return this.request(method, path, body, { retryOnRefresh: false });
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (!response.ok) {
|
|
81
|
-
throw new Error(data.message || data.error || `HTTP ${response.status}`);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return data;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async startPaperclipAuth({ companyId, label } = {}) {
|
|
88
|
-
return this.request(
|
|
89
|
-
'POST',
|
|
90
|
-
'/agent-sessions/start',
|
|
91
|
-
{
|
|
92
|
-
mode: 'detached',
|
|
93
|
-
client_type: 'paperclip',
|
|
94
|
-
client_name: PLUGIN_DISPLAY_NAME,
|
|
95
|
-
client_instance_id: companyId || null,
|
|
96
|
-
label: label || `Paperclip Company ${companyId || ''}`.trim(),
|
|
97
|
-
scopes: AGENT_SESSION_SCOPES,
|
|
98
|
-
metadata: {
|
|
99
|
-
platform: 'paperclip',
|
|
100
|
-
plugin_id: PLUGIN_ID,
|
|
101
|
-
company_id: companyId || null,
|
|
102
|
-
},
|
|
103
|
-
},
|
|
104
|
-
{ retryOnRefresh: false }
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
async exchangeAgentSession(authRequestId, exchangeCode) {
|
|
109
|
-
return this.request(
|
|
110
|
-
'POST',
|
|
111
|
-
'/agent-sessions/exchange',
|
|
112
|
-
{
|
|
113
|
-
auth_request_id: authRequestId,
|
|
114
|
-
exchange_code: exchangeCode,
|
|
115
|
-
},
|
|
116
|
-
{ retryOnRefresh: false }
|
|
117
|
-
);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
async refreshAgentSession() {
|
|
121
|
-
if (!this.auth?.refresh_token) {
|
|
122
|
-
throw new Error('No refresh token available');
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const refreshed = await this.request(
|
|
126
|
-
'POST',
|
|
127
|
-
'/agent-sessions/refresh',
|
|
128
|
-
{
|
|
129
|
-
refresh_token: this.auth.refresh_token,
|
|
130
|
-
},
|
|
131
|
-
{ retryOnRefresh: false }
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
this.auth = {
|
|
135
|
-
...this.auth,
|
|
136
|
-
...refreshed.agent_session,
|
|
137
|
-
};
|
|
138
|
-
this.onAuthUpdate?.(this.auth);
|
|
139
|
-
return this.auth;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
async listProjects() {
|
|
143
|
-
return this.request('GET', '/projects');
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
async getLive(project, { window } = {}) {
|
|
147
|
-
const query = buildQuery({ project, window });
|
|
148
|
-
return this.request('GET', `/live?${query}`);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
async subscribeToStream({ project, filter, signal, onConnected, onTrack, onComment }) {
|
|
152
|
-
const query = buildQuery({
|
|
153
|
-
project,
|
|
154
|
-
filter,
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
const response = await this.fetchImpl(`${this.baseUrl}/stream?${query}`, {
|
|
158
|
-
method: 'GET',
|
|
159
|
-
headers: createJsonHeaders(this.auth),
|
|
160
|
-
signal,
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
if (!response.ok || !response.body) {
|
|
164
|
-
const payload = await response.text().catch(() => '');
|
|
165
|
-
throw new Error(payload || `Stream failed with HTTP ${response.status}`);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const reader = response.body.getReader();
|
|
169
|
-
const decoder = new TextDecoder();
|
|
170
|
-
let buffer = '';
|
|
171
|
-
|
|
172
|
-
while (true) {
|
|
173
|
-
const { done, value } = await reader.read();
|
|
174
|
-
if (done) break;
|
|
175
|
-
|
|
176
|
-
buffer += decoder.decode(value, { stream: true });
|
|
177
|
-
let boundary = buffer.indexOf('\n\n');
|
|
178
|
-
while (boundary !== -1) {
|
|
179
|
-
const rawEvent = buffer.slice(0, boundary);
|
|
180
|
-
buffer = buffer.slice(boundary + 2);
|
|
181
|
-
const event = parseSseEvent(rawEvent);
|
|
182
|
-
|
|
183
|
-
if (event.comment) {
|
|
184
|
-
onComment?.(event.comment);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
if (event.data) {
|
|
188
|
-
let parsed = {};
|
|
189
|
-
try {
|
|
190
|
-
parsed = JSON.parse(event.data);
|
|
191
|
-
} catch {
|
|
192
|
-
parsed = { raw: event.data };
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if (event.event === 'connected') onConnected?.(parsed);
|
|
196
|
-
if (event.event === 'track') onTrack?.(parsed);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
boundary = buffer.indexOf('\n\n');
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
package/src/shared/constants.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
export const PLUGIN_ID = '@agent-analytics/paperclip-live-analytics-plugin';
|
|
2
|
-
export const PLUGIN_DISPLAY_NAME = 'Agent Analytics Live';
|
|
3
|
-
export const DEFAULT_BASE_URL = 'https://api.agentanalytics.sh';
|
|
4
|
-
export const DEFAULT_LIVE_WINDOW_SECONDS = 60;
|
|
5
|
-
export const DEFAULT_POLL_INTERVAL_SECONDS = 15;
|
|
6
|
-
export const MIN_LIVE_WINDOW_SECONDS = 10;
|
|
7
|
-
export const MAX_LIVE_WINDOW_SECONDS = 300;
|
|
8
|
-
export const MIN_POLL_INTERVAL_SECONDS = 5;
|
|
9
|
-
export const MAX_POLL_INTERVAL_SECONDS = 60;
|
|
10
|
-
export const DEFAULT_SNOOZE_MINUTES = 30;
|
|
11
|
-
export const MAX_ENABLED_ASSET_STREAMS = 10;
|
|
12
|
-
export const LIVE_STREAM_CHANNEL = 'agent-analytics-live';
|
|
13
|
-
export const STATE_NAMESPACE = 'agent-analytics-live';
|
|
14
|
-
|
|
15
|
-
export const DATA_KEYS = {
|
|
16
|
-
livePageLoad: 'live.page.load',
|
|
17
|
-
liveWidgetLoad: 'live.widget.load',
|
|
18
|
-
settingsLoad: 'settings.load',
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export const ACTION_KEYS = {
|
|
22
|
-
authStart: 'auth.start',
|
|
23
|
-
authComplete: 'auth.complete',
|
|
24
|
-
authDisconnect: 'auth.disconnect',
|
|
25
|
-
authReconnect: 'auth.reconnect',
|
|
26
|
-
settingsSave: 'settings.save',
|
|
27
|
-
mappingUpsert: 'mapping.upsert',
|
|
28
|
-
mappingRemove: 'mapping.remove',
|
|
29
|
-
assetSnooze: 'asset.snooze',
|
|
30
|
-
assetUnsnooze: 'asset.unsnooze',
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export const AGENT_SESSION_SCOPES = [
|
|
34
|
-
'account:read',
|
|
35
|
-
'projects:write',
|
|
36
|
-
'analytics:read',
|
|
37
|
-
'live:read',
|
|
38
|
-
];
|
|
39
|
-
|
|
40
|
-
export const ASSET_KINDS = ['website', 'docs', 'app', 'api', 'other'];
|
|
41
|
-
|
package/src/shared/defaults.js
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
DEFAULT_BASE_URL,
|
|
3
|
-
DEFAULT_LIVE_WINDOW_SECONDS,
|
|
4
|
-
DEFAULT_POLL_INTERVAL_SECONDS,
|
|
5
|
-
} from './constants.js';
|
|
6
|
-
|
|
7
|
-
export function createDefaultSettings() {
|
|
8
|
-
return {
|
|
9
|
-
agentAnalyticsBaseUrl: DEFAULT_BASE_URL,
|
|
10
|
-
liveWindowSeconds: DEFAULT_LIVE_WINDOW_SECONDS,
|
|
11
|
-
pollIntervalSeconds: DEFAULT_POLL_INTERVAL_SECONDS,
|
|
12
|
-
monitoredAssets: [],
|
|
13
|
-
pluginEnabled: true,
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function createDefaultAuthState() {
|
|
18
|
-
return {
|
|
19
|
-
mode: 'agent_session',
|
|
20
|
-
accessToken: null,
|
|
21
|
-
refreshToken: null,
|
|
22
|
-
accessExpiresAt: null,
|
|
23
|
-
refreshExpiresAt: null,
|
|
24
|
-
accountSummary: null,
|
|
25
|
-
tier: null,
|
|
26
|
-
status: 'disconnected',
|
|
27
|
-
pendingAuthRequest: null,
|
|
28
|
-
lastValidatedAt: null,
|
|
29
|
-
lastError: null,
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function createDefaultSnoozeState() {
|
|
34
|
-
return {};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function createEmptyCompanyLiveState() {
|
|
38
|
-
return {
|
|
39
|
-
type: 'live_state',
|
|
40
|
-
generatedAt: Date.now(),
|
|
41
|
-
pluginEnabled: true,
|
|
42
|
-
authStatus: 'disconnected',
|
|
43
|
-
tier: null,
|
|
44
|
-
account: null,
|
|
45
|
-
connection: {
|
|
46
|
-
status: 'idle',
|
|
47
|
-
label: 'Not connected',
|
|
48
|
-
detail: 'Connect Agent Analytics from settings to start the live feed.',
|
|
49
|
-
},
|
|
50
|
-
metrics: {
|
|
51
|
-
activeVisitors: 0,
|
|
52
|
-
activeSessions: 0,
|
|
53
|
-
eventsPerMinute: 0,
|
|
54
|
-
assetsConfigured: 0,
|
|
55
|
-
assetsVisible: 0,
|
|
56
|
-
countriesTracked: 0,
|
|
57
|
-
},
|
|
58
|
-
world: {
|
|
59
|
-
hotCountry: null,
|
|
60
|
-
countries: [],
|
|
61
|
-
},
|
|
62
|
-
evidence: {
|
|
63
|
-
topPages: [],
|
|
64
|
-
topEvents: [],
|
|
65
|
-
recentEvents: [],
|
|
66
|
-
countries: [],
|
|
67
|
-
},
|
|
68
|
-
assets: [],
|
|
69
|
-
snoozedAssets: [],
|
|
70
|
-
warnings: [],
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|