@lightworkai.official/debug-capture 0.17.4 → 0.18.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/dist/server.d.ts +7 -3
- package/dist/server.mjs +7 -6
- package/package.json +1 -1
- package/src/server.ts +16 -9
package/dist/server.d.ts
CHANGED
|
@@ -14,11 +14,15 @@ export interface SupportProfileFact {
|
|
|
14
14
|
label: string;
|
|
15
15
|
value: string;
|
|
16
16
|
}
|
|
17
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* Whoever the host has authenticated. Email is the account key — or, for someone the host knows but holds no email
|
|
19
|
+
* for (a CIB officer with none in the ERP, 2026-10-27: every report they ever sent landed anonymous, nobody could call
|
|
20
|
+
* them back), the host's own id alone.
|
|
21
|
+
*/
|
|
18
22
|
export interface SupportUser {
|
|
19
|
-
/** The host's own id for this person, recorded so a changed email still matches. */
|
|
23
|
+
/** The host's own id for this person, recorded so a changed email still matches — the key when there is no email. */
|
|
20
24
|
id?: string | null;
|
|
21
|
-
email
|
|
25
|
+
email?: string | null;
|
|
22
26
|
name?: string | null;
|
|
23
27
|
/** What the host knows about their work — most important first. Optional; bounded on the way in. */
|
|
24
28
|
profile?: SupportProfileFact[] | null;
|
package/dist/server.mjs
CHANGED
|
@@ -23,17 +23,18 @@ function cleanProfile(profile) {
|
|
|
23
23
|
var DEFAULT_TTL_SECONDS = 120;
|
|
24
24
|
var b64 = (value) => Buffer.from(JSON.stringify(value), "utf8").toString("base64url");
|
|
25
25
|
function createSupportToken(options) {
|
|
26
|
-
const email = options.user.email?.trim().toLowerCase();
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
const email = options.user.email?.trim().toLowerCase() || null;
|
|
27
|
+
const id = options.user.id?.trim() || null;
|
|
28
|
+
if (email ? !email.includes("@") : !id)
|
|
29
|
+
throw new Error("createSupportToken: a real email, or the host's own id for this person, is required");
|
|
29
30
|
if (!options.secret || options.secret.length < 16) {
|
|
30
31
|
throw new Error("createSupportToken: the realm's reporter secret is missing or too short");
|
|
31
32
|
}
|
|
32
33
|
const now = Math.floor(Date.now() / 1000);
|
|
33
34
|
const expiresIn = Math.min(Math.max(Math.floor(options.ttlSeconds ?? DEFAULT_TTL_SECONDS), 30), 12 * 60 * 60);
|
|
34
35
|
const body = `${b64({ alg: "HS256", typ: "JWT" })}.${b64({
|
|
35
|
-
sub:
|
|
36
|
-
email,
|
|
36
|
+
sub: id ?? email,
|
|
37
|
+
...email ? { email } : {},
|
|
37
38
|
name: options.user.name?.trim() || null,
|
|
38
39
|
...cleanProfile(options.user.profile) ? { profile: cleanProfile(options.user.profile) } : {},
|
|
39
40
|
jti: randomUUID(),
|
|
@@ -59,7 +60,7 @@ function supportTokenHandler(options) {
|
|
|
59
60
|
return json({ error: "Support identity is not configured" }, 503);
|
|
60
61
|
}
|
|
61
62
|
const user = await options.user();
|
|
62
|
-
if (!user?.email)
|
|
63
|
+
if (!user?.email?.trim() && !user?.id?.trim())
|
|
63
64
|
return json({ error: "Unauthorized" }, 401);
|
|
64
65
|
try {
|
|
65
66
|
const { token, expiresIn } = createSupportToken({ secret, user, ttlSeconds: options.ttlSeconds });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lightworkai.official/debug-capture",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "Report-a-problem widget: rolling network/console/action capture, optional rrweb session replay, annotated screenshot, and submission to a Lightwork Support host",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./dist/index.mjs",
|
package/src/server.ts
CHANGED
|
@@ -34,11 +34,15 @@ export interface SupportProfileFact {
|
|
|
34
34
|
value: string;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
/**
|
|
37
|
+
/**
|
|
38
|
+
* Whoever the host has authenticated. Email is the account key — or, for someone the host knows but holds no email
|
|
39
|
+
* for (a CIB officer with none in the ERP, 2026-10-27: every report they ever sent landed anonymous, nobody could call
|
|
40
|
+
* them back), the host's own id alone.
|
|
41
|
+
*/
|
|
38
42
|
export interface SupportUser {
|
|
39
|
-
/** The host's own id for this person, recorded so a changed email still matches. */
|
|
43
|
+
/** The host's own id for this person, recorded so a changed email still matches — the key when there is no email. */
|
|
40
44
|
id?: string | null;
|
|
41
|
-
email
|
|
45
|
+
email?: string | null;
|
|
42
46
|
name?: string | null;
|
|
43
47
|
/** What the host knows about their work — most important first. Optional; bounded on the way in. */
|
|
44
48
|
profile?: SupportProfileFact[] | null;
|
|
@@ -95,8 +99,9 @@ export function createSupportToken(options: {
|
|
|
95
99
|
user: SupportUser;
|
|
96
100
|
ttlSeconds?: number;
|
|
97
101
|
}): { token: string; expiresIn: number } {
|
|
98
|
-
const email = options.user.email?.trim().toLowerCase();
|
|
99
|
-
|
|
102
|
+
const email = options.user.email?.trim().toLowerCase() || null;
|
|
103
|
+
const id = options.user.id?.trim() || null;
|
|
104
|
+
if (email ? !email.includes("@") : !id) throw new Error("createSupportToken: a real email, or the host's own id for this person, is required");
|
|
100
105
|
if (!options.secret || options.secret.length < 16) {
|
|
101
106
|
throw new Error("createSupportToken: the realm's reporter secret is missing or too short");
|
|
102
107
|
}
|
|
@@ -105,9 +110,10 @@ export function createSupportToken(options: {
|
|
|
105
110
|
const expiresIn = Math.min(Math.max(Math.floor(options.ttlSeconds ?? DEFAULT_TTL_SECONDS), 30), 12 * 60 * 60);
|
|
106
111
|
const body = `${b64({ alg: "HS256", typ: "JWT" })}.${b64({
|
|
107
112
|
// The host's own id when it has one, so the same person is recognised even
|
|
108
|
-
// if their email later changes. The email stands in when it does not
|
|
109
|
-
|
|
110
|
-
email,
|
|
113
|
+
// if their email later changes. The email stands in when it does not; with
|
|
114
|
+
// no email the id is the whole of who they are, and the claim is left out.
|
|
115
|
+
sub: id ?? email,
|
|
116
|
+
...(email ? { email } : {}),
|
|
111
117
|
name: options.user.name?.trim() || null,
|
|
112
118
|
// Only when there is one: an older support desk ignores the claim, a newer one records it.
|
|
113
119
|
...(cleanProfile(options.user.profile) ? { profile: cleanProfile(options.user.profile) } : {}),
|
|
@@ -184,7 +190,8 @@ export function supportTokenHandler(options: {
|
|
|
184
190
|
}
|
|
185
191
|
|
|
186
192
|
const user = await options.user();
|
|
187
|
-
|
|
193
|
+
// Nobody — or somebody the host cannot name by an email or an id of its own.
|
|
194
|
+
if (!user?.email?.trim() && !user?.id?.trim()) return json({ error: "Unauthorized" }, 401);
|
|
188
195
|
|
|
189
196
|
try {
|
|
190
197
|
const { token, expiresIn } = createSupportToken({ secret, user, ttlSeconds: options.ttlSeconds });
|