@coristen/widget 0.1.1 → 0.1.2
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 +39 -39
- package/dist/api.d.ts +2 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -16876
- package/dist/load-error.d.ts +1 -0
- package/dist/server.js +1 -69
- package/dist/styles.css +1 -1
- package/package.json +70 -70
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function widgetLoadError(error: Error): "A Coristen public key is required. Pass an apiKey that starts with coristen_pk_." | "This website is not allowed to use this support widget." | "This Coristen public key is invalid or no longer active." | "Support chat is not configured yet." | "Support chat is temporarily unavailable. Please try again.";
|
package/dist/server.js
CHANGED
|
@@ -1,69 +1 @@
|
|
|
1
|
-
|
|
2
|
-
function envKey() {
|
|
3
|
-
return globalThis.process?.env?.CORISTEN_KEY;
|
|
4
|
-
}
|
|
5
|
-
function parseKey(value) {
|
|
6
|
-
if (!value)
|
|
7
|
-
throw new Error("Coristen: CORISTEN_KEY is missing.");
|
|
8
|
-
if (!value.startsWith("coristen_key_"))
|
|
9
|
-
throw new Error("Coristen: CORISTEN_KEY must start with coristen_key_.");
|
|
10
|
-
const [workspaceId, secret, extra] = value.slice("coristen_key_".length).split(".");
|
|
11
|
-
if (!workspaceId || !secret || extra !== undefined)
|
|
12
|
-
throw new Error("Coristen: CORISTEN_KEY is malformed.");
|
|
13
|
-
return { workspaceId, secret };
|
|
14
|
-
}
|
|
15
|
-
function encode(value) {
|
|
16
|
-
const bytes = typeof value === "string" ? new TextEncoder().encode(value) : value;
|
|
17
|
-
let binary = "";
|
|
18
|
-
for (const byte of bytes)
|
|
19
|
-
binary += String.fromCharCode(byte);
|
|
20
|
-
return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
|
|
21
|
-
}
|
|
22
|
-
async function sign(value, secret) {
|
|
23
|
-
const key = await crypto.subtle.importKey("raw", new TextEncoder().encode(secret), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
24
|
-
return encode(new Uint8Array(await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(value))));
|
|
25
|
-
}
|
|
26
|
-
var headers = {
|
|
27
|
-
"cache-control": "private, no-store, max-age=0",
|
|
28
|
-
vary: "cookie, authorization"
|
|
29
|
-
};
|
|
30
|
-
function coristenIdentity(resolve, options = {}) {
|
|
31
|
-
return {
|
|
32
|
-
GET: async (request) => {
|
|
33
|
-
try {
|
|
34
|
-
const { workspaceId, secret } = parseKey(options.key ?? envKey());
|
|
35
|
-
const user = await resolve(request);
|
|
36
|
-
if (!user?.id?.trim())
|
|
37
|
-
return Response.json({ error: { code: "authentication_required" } }, { status: 401, headers });
|
|
38
|
-
if (user.id.length > 200)
|
|
39
|
-
throw new Error("Coristen: customer id must be 200 characters or fewer.");
|
|
40
|
-
const expiresInSeconds = options.expiresInSeconds ?? 15 * 60;
|
|
41
|
-
if (!Number.isFinite(expiresInSeconds) || expiresInSeconds < 60 || expiresInSeconds > 3600)
|
|
42
|
-
throw new Error("Coristen: identity lifetime must be 60-3600 seconds.");
|
|
43
|
-
const now = Math.floor(Date.now() / 1000);
|
|
44
|
-
const header = encode(JSON.stringify({ alg: "HS256", typ: "JWT" }));
|
|
45
|
-
const payload = encode(JSON.stringify({
|
|
46
|
-
sub: user.id,
|
|
47
|
-
name: user.name,
|
|
48
|
-
email: user.email,
|
|
49
|
-
workspaceId,
|
|
50
|
-
iat: now,
|
|
51
|
-
exp: now + expiresInSeconds
|
|
52
|
-
}));
|
|
53
|
-
const input = `${header}.${payload}`;
|
|
54
|
-
const identityToken = `${input}.${await sign(input, secret)}`;
|
|
55
|
-
return Response.json({
|
|
56
|
-
publishableKey: `coristen_pk_${workspaceId}`,
|
|
57
|
-
identityToken,
|
|
58
|
-
user: { id: user.id, name: user.name, email: user.email }
|
|
59
|
-
}, { headers });
|
|
60
|
-
} catch (error) {
|
|
61
|
-
console.error(error);
|
|
62
|
-
return Response.json({ error: { code: "identity_unavailable" } }, { status: 500, headers });
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
export {
|
|
68
|
-
coristenIdentity
|
|
69
|
-
};
|
|
1
|
+
function f(){return globalThis.process?.env?.CORISTEN_KEY}function m(e){if(!e)throw Error("Coristen: CORISTEN_KEY is missing.");if(!e.startsWith("coristen_key_"))throw Error("Coristen: CORISTEN_KEY must start with coristen_key_.");let[t,n,r]=e.slice(13).split(".");if(!t||!n||r!==void 0)throw Error("Coristen: CORISTEN_KEY is malformed.");return{workspaceId:t,secret:n}}function a(e){let t=typeof e==="string"?new TextEncoder().encode(e):e,n="";for(let r of t)n+=String.fromCharCode(r);return btoa(n).replaceAll("+","-").replaceAll("/","_").replaceAll("=","")}async function w(e,t){let n=await crypto.subtle.importKey("raw",new TextEncoder().encode(t),{name:"HMAC",hash:"SHA-256"},!1,["sign"]);return a(new Uint8Array(await crypto.subtle.sign("HMAC",n,new TextEncoder().encode(e))))}var o={"cache-control":"private, no-store, max-age=0",vary:"cookie, authorization"};function g(e,t={}){return{GET:async(n)=>{try{let{workspaceId:r,secret:u}=m(t.key??f()),s=await e(n);if(!s?.id?.trim())return Response.json({error:{code:"authentication_required"}},{status:401,headers:o});if(s.id.length>200)throw Error("Coristen: customer id must be 200 characters or fewer.");let i=t.expiresInSeconds??900;if(!Number.isFinite(i)||i<60||i>3600)throw Error("Coristen: identity lifetime must be 60-3600 seconds.");let c=Math.floor(Date.now()/1000),y=a(JSON.stringify({alg:"HS256",typ:"JWT"})),l=a(JSON.stringify({sub:s.id,name:s.name,email:s.email,workspaceId:r,iat:c,exp:c+i})),d=`${y}.${l}`,p=`${d}.${await w(d,u)}`;return Response.json({publishableKey:`coristen_pk_${r}`,identityToken:p,user:{id:s.id,name:s.name,email:s.email}},{headers:o})}catch(r){return console.error(r),Response.json({error:{code:"identity_unavailable"}},{status:500,headers:o})}}}}export{g as coristenIdentity};
|