@holostaff/sdk 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -0
- package/dist/identity.d.ts +34 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +172 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +208 -0
- package/dist/index.js.map +1 -0
- package/dist/session.d.ts +29 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +63 -0
- package/dist/session.js.map +1 -0
- package/dist/signals.d.ts +44 -0
- package/dist/signals.d.ts.map +1 -0
- package/dist/signals.js +155 -0
- package/dist/signals.js.map +1 -0
- package/dist/transport.d.ts +40 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +113 -0
- package/dist/transport.js.map +1 -0
- package/dist/types.d.ts +39 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +18 -0
- package/dist/types.js.map +1 -0
- package/dist/widget.d.ts +38 -0
- package/dist/widget.d.ts.map +1 -0
- package/dist/widget.js +182 -0
- package/dist/widget.js.map +1 -0
- package/package.json +40 -0
package/dist/widget.js
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Widget — Wave 3e.
|
|
3
|
+
*
|
|
4
|
+
* Listens to the SSE command channel for `fire_intervention` events
|
|
5
|
+
* and renders a minimal text pill in the customer's host page. Wires
|
|
6
|
+
* dismiss / engage user actions back to /outcome.
|
|
7
|
+
*
|
|
8
|
+
* Wave 3e scope:
|
|
9
|
+
* - `text` modality only. Other modalities (voice / email / sms /
|
|
10
|
+
* phone / screen_automation) are logged and ignored — Wave 6.
|
|
11
|
+
* - Single visible widget at a time. A new event while one is open
|
|
12
|
+
* replaces it (and reports 'ignored' for the prior).
|
|
13
|
+
* - No theming. Inline-styled floating pill, fixed lower-right.
|
|
14
|
+
*
|
|
15
|
+
* The widget keeps zero dependencies on host CSS — it injects its own
|
|
16
|
+
* styles into the shadow root of a top-level container so host page
|
|
17
|
+
* rules can't bleed in or out.
|
|
18
|
+
*/
|
|
19
|
+
import { postJson } from './transport.js';
|
|
20
|
+
/** Auto-dismiss timeout — runtime doc §9.1 'ignored' outcome. */
|
|
21
|
+
const AUTO_DISMISS_MS = 30000;
|
|
22
|
+
/** Container id — single instance per page. */
|
|
23
|
+
const CONTAINER_ID = 'holostaff-widget-root';
|
|
24
|
+
/**
|
|
25
|
+
* Start the widget subsystem. Subscribes to the SSE `fire_intervention`
|
|
26
|
+
* event and shows the text pill when one arrives. Idempotent in the
|
|
27
|
+
* sense that the SDK singleton ensures one binding per session.
|
|
28
|
+
*/
|
|
29
|
+
export function startWidget(deps) {
|
|
30
|
+
if (typeof window === 'undefined' || !deps.source) {
|
|
31
|
+
return { dispose: () => { } };
|
|
32
|
+
}
|
|
33
|
+
let currentWidget = null;
|
|
34
|
+
const onFire = (rawEvent) => {
|
|
35
|
+
let parsed = null;
|
|
36
|
+
try {
|
|
37
|
+
const data = JSON.parse(rawEvent.data);
|
|
38
|
+
if (!data || typeof data.interventionId !== 'string')
|
|
39
|
+
return;
|
|
40
|
+
parsed = data;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (!parsed)
|
|
46
|
+
return;
|
|
47
|
+
// Modality gate — only text is supported in v1.
|
|
48
|
+
if (parsed.modality !== 'text') {
|
|
49
|
+
deps.cfg.onError?.(new Error(`Modality '${parsed.modality}' is not supported in this SDK build`), { method: 'WIDGET', path: '(fire_intervention)' });
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
// If a widget is already up, evict it as 'ignored' before showing the new one.
|
|
53
|
+
if (currentWidget) {
|
|
54
|
+
currentWidget.reportAndClose('ignored');
|
|
55
|
+
}
|
|
56
|
+
currentWidget = renderWidget(deps, parsed, () => {
|
|
57
|
+
if (currentWidget && currentWidget.event.interventionId === parsed.interventionId) {
|
|
58
|
+
currentWidget = null;
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
deps.source.addEventListener('fire_intervention', onFire);
|
|
63
|
+
return {
|
|
64
|
+
dispose() {
|
|
65
|
+
deps.source?.removeEventListener('fire_intervention', onFire);
|
|
66
|
+
if (currentWidget) {
|
|
67
|
+
currentWidget.detach();
|
|
68
|
+
currentWidget = null;
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function renderWidget(deps, event, onClosed) {
|
|
74
|
+
const container = ensureContainer();
|
|
75
|
+
const root = container.shadowRoot;
|
|
76
|
+
// Clear any prior content (defensive — single-widget invariant).
|
|
77
|
+
root.innerHTML = '';
|
|
78
|
+
const wrapper = document.createElement('div');
|
|
79
|
+
wrapper.className = 'pill';
|
|
80
|
+
wrapper.setAttribute('role', 'dialog');
|
|
81
|
+
wrapper.setAttribute('aria-live', 'polite');
|
|
82
|
+
wrapper.setAttribute('data-intervention-id', event.interventionId);
|
|
83
|
+
const message = document.createElement('div');
|
|
84
|
+
message.className = 'message';
|
|
85
|
+
message.textContent = event.content || event.goal;
|
|
86
|
+
const actions = document.createElement('div');
|
|
87
|
+
actions.className = 'actions';
|
|
88
|
+
const dismissBtn = document.createElement('button');
|
|
89
|
+
dismissBtn.className = 'btn dismiss';
|
|
90
|
+
dismissBtn.type = 'button';
|
|
91
|
+
dismissBtn.textContent = 'Dismiss';
|
|
92
|
+
const engageBtn = document.createElement('button');
|
|
93
|
+
engageBtn.className = 'btn engage';
|
|
94
|
+
engageBtn.type = 'button';
|
|
95
|
+
engageBtn.textContent = 'Got it';
|
|
96
|
+
actions.appendChild(dismissBtn);
|
|
97
|
+
actions.appendChild(engageBtn);
|
|
98
|
+
wrapper.appendChild(message);
|
|
99
|
+
wrapper.appendChild(actions);
|
|
100
|
+
root.appendChild(styleNode());
|
|
101
|
+
root.appendChild(wrapper);
|
|
102
|
+
let closed = false;
|
|
103
|
+
let timeoutId = setTimeout(() => {
|
|
104
|
+
instance.reportAndClose('ignored');
|
|
105
|
+
}, AUTO_DISMISS_MS);
|
|
106
|
+
const reportOutcome = (outcome) => {
|
|
107
|
+
const body = {
|
|
108
|
+
...deps.buildBody(),
|
|
109
|
+
interventionId: event.interventionId,
|
|
110
|
+
outcome,
|
|
111
|
+
};
|
|
112
|
+
void postJson(deps.cfg, `/api/runtime/sessions/${deps.getSessionId()}/outcome`, body);
|
|
113
|
+
};
|
|
114
|
+
const close = (outcome) => {
|
|
115
|
+
if (closed)
|
|
116
|
+
return;
|
|
117
|
+
closed = true;
|
|
118
|
+
if (timeoutId != null) {
|
|
119
|
+
clearTimeout(timeoutId);
|
|
120
|
+
timeoutId = null;
|
|
121
|
+
}
|
|
122
|
+
if (outcome)
|
|
123
|
+
reportOutcome(outcome);
|
|
124
|
+
try {
|
|
125
|
+
root.removeChild(wrapper);
|
|
126
|
+
}
|
|
127
|
+
catch { /* removed already */ }
|
|
128
|
+
onClosed();
|
|
129
|
+
};
|
|
130
|
+
dismissBtn.addEventListener('click', () => close('dismissed'));
|
|
131
|
+
engageBtn.addEventListener('click', () => close('engaged'));
|
|
132
|
+
const instance = {
|
|
133
|
+
event,
|
|
134
|
+
reportAndClose(outcome) { close(outcome); },
|
|
135
|
+
detach() { close(null); },
|
|
136
|
+
};
|
|
137
|
+
return instance;
|
|
138
|
+
}
|
|
139
|
+
function ensureContainer() {
|
|
140
|
+
let el = document.getElementById(CONTAINER_ID);
|
|
141
|
+
if (el)
|
|
142
|
+
return el;
|
|
143
|
+
el = document.createElement('div');
|
|
144
|
+
el.id = CONTAINER_ID;
|
|
145
|
+
el.style.cssText = 'position:fixed;right:16px;bottom:16px;z-index:2147483647;pointer-events:none';
|
|
146
|
+
el.attachShadow({ mode: 'open' });
|
|
147
|
+
document.body.appendChild(el);
|
|
148
|
+
return el;
|
|
149
|
+
}
|
|
150
|
+
function styleNode() {
|
|
151
|
+
const node = document.createElement('style');
|
|
152
|
+
// Inline styles only — shadow-DOM scoped, no host page leakage.
|
|
153
|
+
node.textContent = `
|
|
154
|
+
.pill {
|
|
155
|
+
pointer-events: auto;
|
|
156
|
+
max-width: 360px;
|
|
157
|
+
background: #111;
|
|
158
|
+
color: #fafafa;
|
|
159
|
+
border-radius: 14px;
|
|
160
|
+
box-shadow: 0 12px 32px rgba(0,0,0,0.32), 0 2px 8px rgba(0,0,0,0.12);
|
|
161
|
+
padding: 14px 16px 12px;
|
|
162
|
+
font: 14px/1.4 -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
|
|
163
|
+
}
|
|
164
|
+
.message { margin-bottom: 12px; }
|
|
165
|
+
.actions { display: flex; gap: 8px; justify-content: flex-end; }
|
|
166
|
+
.btn {
|
|
167
|
+
appearance: none;
|
|
168
|
+
border: 0;
|
|
169
|
+
padding: 6px 12px;
|
|
170
|
+
border-radius: 8px;
|
|
171
|
+
font: inherit;
|
|
172
|
+
font-size: 13px;
|
|
173
|
+
cursor: pointer;
|
|
174
|
+
}
|
|
175
|
+
.btn.dismiss { background: transparent; color: #c7c7c7; }
|
|
176
|
+
.btn.dismiss:hover { color: #fff; }
|
|
177
|
+
.btn.engage { background: #4f8bff; color: #fff; }
|
|
178
|
+
.btn.engage:hover { background: #6aa0ff; }
|
|
179
|
+
`;
|
|
180
|
+
return node;
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=widget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"widget.js","sourceRoot":"","sources":["../src/widget.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@holostaff/sdk",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Holostaff SDK — lifetime identity, stage detection, and custom signal probes for the holostaff runtime.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc -p tsconfig.json",
|
|
21
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
22
|
+
"prepublishOnly": "npm run build"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"holostaff",
|
|
26
|
+
"copilot",
|
|
27
|
+
"instrumentation",
|
|
28
|
+
"runtime"
|
|
29
|
+
],
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=18"
|
|
32
|
+
},
|
|
33
|
+
"sideEffects": false,
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"typescript": "^5.4.0"
|
|
39
|
+
}
|
|
40
|
+
}
|