@invergent/website-widget 2.10.5 → 2.11.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/{agent-ia0JiKMG.d.cts → agent-Ca1Gsh1n.d.cts} +22 -0
- package/dist/{agent-ia0JiKMG.d.ts → agent-Ca1Gsh1n.d.ts} +22 -0
- package/dist/{chunk-55XSYQGO.js → chunk-COLKSBR6.js} +49 -9
- package/dist/chunk-COLKSBR6.js.map +1 -0
- package/dist/index.cjs +47 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/surogates-widget.global.js +34 -9
- package/dist/surogates-widget.global.js.map +1 -1
- package/dist/ui.cjs +107 -7
- package/dist/ui.cjs.map +1 -1
- package/dist/ui.d.cts +1 -1
- package/dist/ui.d.ts +1 -1
- package/dist/ui.js +61 -1
- package/dist/ui.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-55XSYQGO.js.map +0 -1
package/dist/ui.cjs
CHANGED
|
@@ -81,6 +81,14 @@ var SurogatesNetworkError = class extends SurogatesError {
|
|
|
81
81
|
this.name = "SurogatesNetworkError";
|
|
82
82
|
}
|
|
83
83
|
};
|
|
84
|
+
var SurogatesPaywallError = class extends SurogatesError {
|
|
85
|
+
constructor(message, opts) {
|
|
86
|
+
super(message, { status: 402, ...opts.detail !== void 0 && { detail: opts.detail } });
|
|
87
|
+
this.name = "SurogatesPaywallError";
|
|
88
|
+
this.code = opts.code;
|
|
89
|
+
if (opts.buyUrl !== void 0) this.buyUrl = opts.buyUrl;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
84
92
|
|
|
85
93
|
// src/protocol.ts
|
|
86
94
|
async function resolvePairing(pairingBase, publishableKey, doFetchImpl = fetch) {
|
|
@@ -132,16 +140,27 @@ async function doFetch(url, init) {
|
|
|
132
140
|
}
|
|
133
141
|
return response;
|
|
134
142
|
}
|
|
135
|
-
async function
|
|
143
|
+
async function extractDetailValue(response) {
|
|
136
144
|
try {
|
|
137
145
|
const body = await response.json();
|
|
138
|
-
return
|
|
146
|
+
return body?.detail;
|
|
139
147
|
} catch {
|
|
140
148
|
return void 0;
|
|
141
149
|
}
|
|
142
150
|
}
|
|
143
151
|
async function raiseForStatus(response, action) {
|
|
144
|
-
const
|
|
152
|
+
const detailValue = await extractDetailValue(response);
|
|
153
|
+
const detail = typeof detailValue === "string" ? detailValue : void 0;
|
|
154
|
+
if (response.status === 402) {
|
|
155
|
+
const structured = detailValue && typeof detailValue === "object" ? detailValue : {};
|
|
156
|
+
const code = typeof structured.code === "string" ? structured.code : detail || "payment_required";
|
|
157
|
+
const buyUrl = typeof structured.buy_url === "string" ? structured.buy_url : void 0;
|
|
158
|
+
throw new SurogatesPaywallError(`${action} requires access (402)`, {
|
|
159
|
+
code,
|
|
160
|
+
...buyUrl !== void 0 && { buyUrl },
|
|
161
|
+
...detail !== void 0 && { detail }
|
|
162
|
+
});
|
|
163
|
+
}
|
|
145
164
|
if (response.status === 401 || response.status === 403) {
|
|
146
165
|
throw new SurogatesAuthError(`${action} rejected (${response.status})`, {
|
|
147
166
|
status: response.status,
|
|
@@ -167,13 +186,18 @@ async function raiseForStatus(response, action) {
|
|
|
167
186
|
...detail !== void 0 && { detail }
|
|
168
187
|
});
|
|
169
188
|
}
|
|
170
|
-
async function bootstrap(apiUrl, publishableKey, agentId) {
|
|
189
|
+
async function bootstrap(apiUrl, publishableKey, agentId, firebaseIdToken) {
|
|
171
190
|
const response = await doFetch(apiUrl + withAgentId(PATH_BOOTSTRAP, agentId), {
|
|
172
191
|
method: "POST",
|
|
173
192
|
headers: {
|
|
174
193
|
Authorization: `Bearer ${publishableKey}`,
|
|
175
194
|
"Content-Type": "application/json"
|
|
176
|
-
}
|
|
195
|
+
},
|
|
196
|
+
// Binds a signed-in end user to the visitor session — required
|
|
197
|
+
// before a monetized agent accepts messages. Anonymous
|
|
198
|
+
// bootstraps send no body at all, preserving the historical wire
|
|
199
|
+
// shape byte-for-byte.
|
|
200
|
+
...firebaseIdToken ? { body: JSON.stringify({ firebase_id_token: firebaseIdToken }) } : {}
|
|
177
201
|
});
|
|
178
202
|
if (!response.ok) {
|
|
179
203
|
await raiseForStatus(response, "Bootstrap");
|
|
@@ -477,6 +501,7 @@ var WebsiteAgent = class extends client.AbstractAgent {
|
|
|
477
501
|
}
|
|
478
502
|
this.apiUrl = config.apiUrl.replace(/\/+$/, "");
|
|
479
503
|
this.publishableKey = config.publishableKey;
|
|
504
|
+
this.getFirebaseIdToken = config.getFirebaseIdToken;
|
|
480
505
|
}
|
|
481
506
|
/**
|
|
482
507
|
* Ensure we have a live session cookie + CSRF token.
|
|
@@ -489,10 +514,12 @@ var WebsiteAgent = class extends client.AbstractAgent {
|
|
|
489
514
|
*/
|
|
490
515
|
async ensureBootstrapped() {
|
|
491
516
|
if (this.bootstrapResult) return this.bootstrapResult;
|
|
517
|
+
const firebaseIdToken = this.getFirebaseIdToken ? await this.getFirebaseIdToken() : void 0;
|
|
492
518
|
this.bootstrapResult = await bootstrap(
|
|
493
519
|
this.apiUrl,
|
|
494
520
|
this.publishableKey,
|
|
495
|
-
this.agentId
|
|
521
|
+
this.agentId,
|
|
522
|
+
firebaseIdToken ?? void 0
|
|
496
523
|
);
|
|
497
524
|
return this.bootstrapResult;
|
|
498
525
|
}
|
|
@@ -586,7 +613,20 @@ var WebsiteAgent = class extends client.AbstractAgent {
|
|
|
586
613
|
if (ctx.terminated) return;
|
|
587
614
|
ctx.terminated = true;
|
|
588
615
|
const message = err instanceof Error ? err.message : String(err);
|
|
589
|
-
|
|
616
|
+
let code = "error";
|
|
617
|
+
if (err instanceof SurogatesAuthError) {
|
|
618
|
+
code = "auth";
|
|
619
|
+
} else if (err instanceof SurogatesPaywallError) {
|
|
620
|
+
code = "paywall";
|
|
621
|
+
this.lastPaywall = {
|
|
622
|
+
code: err.code,
|
|
623
|
+
...err.buyUrl !== void 0 && { buyUrl: err.buyUrl }
|
|
624
|
+
};
|
|
625
|
+
if (err.code === "sign_in_required") {
|
|
626
|
+
this.bootstrapResult = void 0;
|
|
627
|
+
this.cursor = 0;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
590
630
|
subscriber.next({
|
|
591
631
|
type: client.EventType.RUN_ERROR,
|
|
592
632
|
message,
|
|
@@ -901,6 +941,31 @@ var WIDGET_STYLES = `
|
|
|
901
941
|
flex-shrink: 0;
|
|
902
942
|
}
|
|
903
943
|
|
|
944
|
+
.surg-paywall {
|
|
945
|
+
display: flex;
|
|
946
|
+
flex-direction: column;
|
|
947
|
+
gap: 8px;
|
|
948
|
+
margin: 0 16px;
|
|
949
|
+
padding: 12px;
|
|
950
|
+
background: #fffbeb;
|
|
951
|
+
border: 1px solid #fde68a;
|
|
952
|
+
color: #92400e;
|
|
953
|
+
border-radius: 10px;
|
|
954
|
+
font-size: 13px;
|
|
955
|
+
flex-shrink: 0;
|
|
956
|
+
}
|
|
957
|
+
.surg-paywall-cta {
|
|
958
|
+
align-self: flex-start;
|
|
959
|
+
padding: 6px 14px;
|
|
960
|
+
background: var(--surg-accent, #0f172a);
|
|
961
|
+
color: #ffffff;
|
|
962
|
+
border-radius: 8px;
|
|
963
|
+
font-size: 13px;
|
|
964
|
+
font-weight: 600;
|
|
965
|
+
text-decoration: none;
|
|
966
|
+
}
|
|
967
|
+
.surg-paywall-cta:hover { opacity: 0.9; }
|
|
968
|
+
|
|
904
969
|
.surg-composer {
|
|
905
970
|
display: flex;
|
|
906
971
|
gap: 8px;
|
|
@@ -1029,6 +1094,21 @@ function snapshot(messages) {
|
|
|
1029
1094
|
}
|
|
1030
1095
|
return out;
|
|
1031
1096
|
}
|
|
1097
|
+
function safeBuyUrl(url) {
|
|
1098
|
+
return url && /^https?:\/\//i.test(url) ? url : void 0;
|
|
1099
|
+
}
|
|
1100
|
+
function paywallCopy(code) {
|
|
1101
|
+
if (code === "sign_in_required") {
|
|
1102
|
+
return "This assistant requires an account. Get access, sign in on this site, then send your message again.";
|
|
1103
|
+
}
|
|
1104
|
+
if (code === "subscription_required") {
|
|
1105
|
+
return "This assistant requires an active subscription.";
|
|
1106
|
+
}
|
|
1107
|
+
if (code === "insufficient_tokens") {
|
|
1108
|
+
return "You\u2019re out of tokens for this assistant.";
|
|
1109
|
+
}
|
|
1110
|
+
return "This assistant requires paid access.";
|
|
1111
|
+
}
|
|
1032
1112
|
function friendlyError(err) {
|
|
1033
1113
|
if (err instanceof SurogatesAuthError) {
|
|
1034
1114
|
return "This chat isn\u2019t accepting messages from this site yet. The site owner needs to allow this origin.";
|
|
@@ -1062,6 +1142,7 @@ function Widget({ agent, config, registerOpenControl, onOpenChange }) {
|
|
|
1062
1142
|
const [messages, setMessages] = hooks.useState(() => snapshot(agent.messages));
|
|
1063
1143
|
const [running, setRunning] = hooks.useState(false);
|
|
1064
1144
|
const [error, setError] = hooks.useState(null);
|
|
1145
|
+
const [paywall, setPaywall] = hooks.useState(null);
|
|
1065
1146
|
const [input, setInput] = hooks.useState("");
|
|
1066
1147
|
const [agentName, setAgentName] = hooks.useState("");
|
|
1067
1148
|
const title = config.title || agentName || "Assistant";
|
|
@@ -1075,10 +1156,16 @@ function Widget({ agent, config, registerOpenControl, onOpenChange }) {
|
|
|
1075
1156
|
onRunStartedEvent: () => {
|
|
1076
1157
|
setRunning(true);
|
|
1077
1158
|
setError(null);
|
|
1159
|
+
setPaywall(null);
|
|
1078
1160
|
},
|
|
1079
1161
|
onRunFinishedEvent: () => setRunning(false),
|
|
1080
1162
|
onRunErrorEvent: ({ event }) => {
|
|
1081
1163
|
setRunning(false);
|
|
1164
|
+
const code = event.code;
|
|
1165
|
+
if (code === "paywall") {
|
|
1166
|
+
setPaywall(agent.lastPaywall ?? { code: "payment_required" });
|
|
1167
|
+
return;
|
|
1168
|
+
}
|
|
1082
1169
|
setError(friendlyError(event));
|
|
1083
1170
|
}
|
|
1084
1171
|
});
|
|
@@ -1167,6 +1254,19 @@ function Widget({ agent, config, registerOpenControl, onOpenChange }) {
|
|
|
1167
1254
|
] })
|
|
1168
1255
|
] }),
|
|
1169
1256
|
error && /* @__PURE__ */ jsxRuntime.jsx("div", { class: "surg-error", children: error }),
|
|
1257
|
+
paywall && /* @__PURE__ */ jsxRuntime.jsxs("div", { class: "surg-paywall", children: [
|
|
1258
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: paywallCopy(paywall.code) }),
|
|
1259
|
+
safeBuyUrl(paywall.buyUrl) && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1260
|
+
"a",
|
|
1261
|
+
{
|
|
1262
|
+
class: "surg-paywall-cta",
|
|
1263
|
+
href: safeBuyUrl(paywall.buyUrl),
|
|
1264
|
+
target: "_blank",
|
|
1265
|
+
rel: "noopener noreferrer",
|
|
1266
|
+
children: "Get access"
|
|
1267
|
+
}
|
|
1268
|
+
)
|
|
1269
|
+
] }),
|
|
1170
1270
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { class: "surg-composer", children: [
|
|
1171
1271
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1172
1272
|
"textarea",
|