@ergoblockchain/sage-widget 0.1.0 → 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 +150 -7
- package/dist/index.cjs +227 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -3
- package/dist/index.d.ts +38 -3
- package/dist/index.js +221 -4
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +794 -11
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +10 -3
- package/dist/react.d.ts +10 -3
- package/dist/react.js +795 -13
- package/dist/react.js.map +1 -1
- package/dist/types-B5V2rsYn.d.cts +275 -0
- package/dist/types-B5V2rsYn.d.ts +275 -0
- package/dist/vanilla.cjs +855 -6
- package/dist/vanilla.cjs.map +1 -1
- package/dist/vanilla.d.cts +21 -3
- package/dist/vanilla.d.ts +21 -3
- package/dist/vanilla.js +855 -7
- package/dist/vanilla.js.map +1 -1
- package/package.json +5 -4
- package/dist/types-uzMz6_mP.d.cts +0 -77
- package/dist/types-uzMz6_mP.d.ts +0 -77
package/dist/vanilla.cjs
CHANGED
|
@@ -9,13 +9,151 @@ var DEFAULT_REFRESH_MS = 6e4;
|
|
|
9
9
|
async function fetchSageActivity(opts = {}) {
|
|
10
10
|
const base = opts.apiBase ?? DEFAULT_API_BASE;
|
|
11
11
|
const limit = Math.min(Math.max(opts.limit ?? DEFAULT_LIMIT, 1), 25);
|
|
12
|
-
const url = `${base}/api/sage/activity?limit=${limit}`;
|
|
12
|
+
const url = `${trimSlash(base)}/api/sage/activity?limit=${limit}`;
|
|
13
13
|
const res = await fetch(url, { signal: opts.signal });
|
|
14
14
|
if (!res.ok) {
|
|
15
15
|
throw new Error(`sage activity ${res.status}`);
|
|
16
16
|
}
|
|
17
17
|
return await res.json();
|
|
18
18
|
}
|
|
19
|
+
async function fetchSageQuote(opts) {
|
|
20
|
+
const res = await fetch(`${apiBase(opts)}/api/sage/quote`, {
|
|
21
|
+
method: "POST",
|
|
22
|
+
headers: jsonHeaders(opts),
|
|
23
|
+
body: JSON.stringify({
|
|
24
|
+
question: opts.question,
|
|
25
|
+
history: opts.history ?? []
|
|
26
|
+
}),
|
|
27
|
+
signal: opts.signal
|
|
28
|
+
});
|
|
29
|
+
const body = await parseJson(res);
|
|
30
|
+
if (!res.ok) throw new Error(readError(body, `sage quote ${res.status}`));
|
|
31
|
+
return body;
|
|
32
|
+
}
|
|
33
|
+
async function verifySagePayment(opts) {
|
|
34
|
+
const res = await fetch(`${apiBase(opts)}/api/sage/verify-payment`, {
|
|
35
|
+
method: "POST",
|
|
36
|
+
headers: jsonHeaders(opts),
|
|
37
|
+
body: JSON.stringify({
|
|
38
|
+
quote: opts.quote,
|
|
39
|
+
question: opts.question,
|
|
40
|
+
noteBoxId: opts.noteBoxId
|
|
41
|
+
}),
|
|
42
|
+
signal: opts.signal
|
|
43
|
+
});
|
|
44
|
+
const body = await parseJson(res);
|
|
45
|
+
if (!res.ok) throw new Error(readError(body, `sage verify-payment ${res.status}`));
|
|
46
|
+
return body;
|
|
47
|
+
}
|
|
48
|
+
async function fetchSageReceipt(id, opts = {}) {
|
|
49
|
+
const res = await fetch(`${apiBase(opts)}/api/sage/receipt/${encodeURIComponent(id)}`, {
|
|
50
|
+
headers: requestHeaders(opts),
|
|
51
|
+
signal: opts.signal
|
|
52
|
+
});
|
|
53
|
+
const body = await parseJson(res);
|
|
54
|
+
if (!res.ok) throw new Error(readError(body, `sage receipt ${res.status}`));
|
|
55
|
+
return body;
|
|
56
|
+
}
|
|
57
|
+
function createSagePaymentIntent(opts) {
|
|
58
|
+
const base = trimSlash(opts.apiBase ?? DEFAULT_API_BASE);
|
|
59
|
+
return {
|
|
60
|
+
type: "sage.payment_intent.v1",
|
|
61
|
+
network: opts.network ?? "ergo-testnet",
|
|
62
|
+
createdAt: opts.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
63
|
+
question: opts.question,
|
|
64
|
+
...opts.tenant?.id || opts.tenant?.label ? { tenant: { id: opts.tenant.id, label: opts.tenant.label } } : {},
|
|
65
|
+
quote: opts.quote,
|
|
66
|
+
amountErg: opts.quote.price,
|
|
67
|
+
receiverAddress: opts.quote.receiverAddress,
|
|
68
|
+
reserveBoxId: opts.quote.reserveBoxId,
|
|
69
|
+
taskHash: opts.quote.taskHash,
|
|
70
|
+
expiresAt: opts.quote.expiresAt,
|
|
71
|
+
deadline: opts.quote.deadline,
|
|
72
|
+
verifyEndpoint: `${base}/api/sage/verify-payment`,
|
|
73
|
+
receiptEndpointTemplate: `${base}/api/sage/receipt/{receiptId}`
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function serializeSagePaymentIntent(intent) {
|
|
77
|
+
return JSON.stringify(intent, null, 2);
|
|
78
|
+
}
|
|
79
|
+
async function streamSageChat(opts) {
|
|
80
|
+
const res = await fetch(`${apiBase(opts)}/api/sage/chat`, {
|
|
81
|
+
method: "POST",
|
|
82
|
+
headers: jsonHeaders(opts),
|
|
83
|
+
body: JSON.stringify({
|
|
84
|
+
messages: opts.messages,
|
|
85
|
+
...opts.paymentToken ? { paymentToken: opts.paymentToken } : {}
|
|
86
|
+
}),
|
|
87
|
+
signal: opts.signal
|
|
88
|
+
});
|
|
89
|
+
if (res.status === 402) {
|
|
90
|
+
const body = await parseJson(res);
|
|
91
|
+
return {
|
|
92
|
+
ok: false,
|
|
93
|
+
status: res.status,
|
|
94
|
+
text: "",
|
|
95
|
+
paymentRequired: body
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (!res.ok) {
|
|
99
|
+
const body = await parseJson(res);
|
|
100
|
+
return {
|
|
101
|
+
ok: false,
|
|
102
|
+
status: res.status,
|
|
103
|
+
text: "",
|
|
104
|
+
error: readError(body, `sage chat ${res.status}`)
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
if (!res.body) {
|
|
108
|
+
return { ok: false, status: res.status, text: "", error: "Sage chat stream missing body" };
|
|
109
|
+
}
|
|
110
|
+
const reader = res.body.getReader();
|
|
111
|
+
const decoder = new TextDecoder();
|
|
112
|
+
let buffer = "";
|
|
113
|
+
let text = "";
|
|
114
|
+
let tier;
|
|
115
|
+
while (true) {
|
|
116
|
+
const { value, done } = await reader.read();
|
|
117
|
+
if (done) break;
|
|
118
|
+
buffer += decoder.decode(value, { stream: true });
|
|
119
|
+
const parts = buffer.split("\n\n");
|
|
120
|
+
buffer = parts.pop() ?? "";
|
|
121
|
+
for (const part of parts) {
|
|
122
|
+
const event = parseSseEvent(part);
|
|
123
|
+
if (!event) continue;
|
|
124
|
+
if (event.type === "delta") text += event.text;
|
|
125
|
+
if (event.type === "tier") tier = event.tier;
|
|
126
|
+
opts.onEvent?.(event);
|
|
127
|
+
if (event.type === "error") {
|
|
128
|
+
return {
|
|
129
|
+
ok: false,
|
|
130
|
+
status: res.status,
|
|
131
|
+
text,
|
|
132
|
+
tier,
|
|
133
|
+
error: event.message
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (buffer.trim()) {
|
|
139
|
+
const event = parseSseEvent(buffer);
|
|
140
|
+
if (event) {
|
|
141
|
+
if (event.type === "delta") text += event.text;
|
|
142
|
+
if (event.type === "tier") tier = event.tier;
|
|
143
|
+
opts.onEvent?.(event);
|
|
144
|
+
if (event.type === "error") {
|
|
145
|
+
return {
|
|
146
|
+
ok: false,
|
|
147
|
+
status: res.status,
|
|
148
|
+
text,
|
|
149
|
+
tier,
|
|
150
|
+
error: event.message
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return { ok: true, status: res.status, text, tier };
|
|
156
|
+
}
|
|
19
157
|
function nanoToErg(nano) {
|
|
20
158
|
if (!nano || nano <= 0) return "0";
|
|
21
159
|
const erg = nano / 1e9;
|
|
@@ -32,16 +170,92 @@ function relativeTime(ms, now = Date.now()) {
|
|
|
32
170
|
const day = Math.floor(hr / 24);
|
|
33
171
|
return `${day}d ago`;
|
|
34
172
|
}
|
|
35
|
-
function receiptUrl(txId,
|
|
36
|
-
return `${
|
|
173
|
+
function receiptUrl(txId, apiBase2 = DEFAULT_API_BASE) {
|
|
174
|
+
return `${trimSlash(apiBase2)}/r/sage/${txId}`;
|
|
37
175
|
}
|
|
38
176
|
function explorerUrl(txId, network = "testnet") {
|
|
39
177
|
return network === "testnet" ? `https://testnet.ergoplatform.com/transactions/${txId}` : `https://explorer.ergoplatform.com/transactions/${txId}`;
|
|
40
178
|
}
|
|
179
|
+
function apiBase(opts) {
|
|
180
|
+
return trimSlash(opts.apiBase ?? DEFAULT_API_BASE);
|
|
181
|
+
}
|
|
182
|
+
function trimSlash(value) {
|
|
183
|
+
return value.replace(/\/+$/, "");
|
|
184
|
+
}
|
|
185
|
+
function requestHeaders(opts) {
|
|
186
|
+
return {
|
|
187
|
+
...opts.tenant?.id ? { "x-sage-tenant-id": opts.tenant.id } : {},
|
|
188
|
+
...opts.tenant?.headers ?? {},
|
|
189
|
+
...opts.headers ?? {}
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
function jsonHeaders(opts) {
|
|
193
|
+
return {
|
|
194
|
+
"content-type": "application/json",
|
|
195
|
+
...requestHeaders(opts)
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
async function parseJson(res) {
|
|
199
|
+
const text = await res.text();
|
|
200
|
+
if (!text) return null;
|
|
201
|
+
try {
|
|
202
|
+
return JSON.parse(text);
|
|
203
|
+
} catch {
|
|
204
|
+
return { error: text };
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
function readError(body, fallback) {
|
|
208
|
+
if (body && typeof body === "object" && "error" in body) {
|
|
209
|
+
const error = body.error;
|
|
210
|
+
if (typeof error === "string") return error;
|
|
211
|
+
}
|
|
212
|
+
return fallback;
|
|
213
|
+
}
|
|
214
|
+
function parseSseEvent(raw) {
|
|
215
|
+
let eventName = "message";
|
|
216
|
+
let data = "";
|
|
217
|
+
for (const line of raw.split("\n")) {
|
|
218
|
+
if (line.startsWith("event:")) eventName = line.slice("event:".length).trim();
|
|
219
|
+
if (line.startsWith("data:")) data += line.slice("data:".length).trim();
|
|
220
|
+
}
|
|
221
|
+
if (!data) return null;
|
|
222
|
+
let parsed;
|
|
223
|
+
try {
|
|
224
|
+
parsed = JSON.parse(data);
|
|
225
|
+
} catch {
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
if (eventName === "tier") {
|
|
229
|
+
const tier = parsed.tier === "premium" ? "premium" : "free";
|
|
230
|
+
return {
|
|
231
|
+
type: "tier",
|
|
232
|
+
tier,
|
|
233
|
+
...typeof parsed.model === "string" ? { model: parsed.model } : {}
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
if (eventName === "delta" && typeof parsed.text === "string") {
|
|
237
|
+
return { type: "delta", text: parsed.text };
|
|
238
|
+
}
|
|
239
|
+
if (eventName === "done") {
|
|
240
|
+
return {
|
|
241
|
+
type: "done",
|
|
242
|
+
...typeof parsed.stopReason === "string" ? { stopReason: parsed.stopReason } : {},
|
|
243
|
+
...typeof parsed.inputTokens === "number" ? { inputTokens: parsed.inputTokens } : {},
|
|
244
|
+
...typeof parsed.outputTokens === "number" ? { outputTokens: parsed.outputTokens } : {}
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
if (eventName === "error") {
|
|
248
|
+
return {
|
|
249
|
+
type: "error",
|
|
250
|
+
message: typeof parsed.message === "string" ? parsed.message : "Sage stream error"
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
41
255
|
|
|
42
256
|
// src/vanilla/mountSageFeed.ts
|
|
43
257
|
function mountSageFeed(target, opts = {}) {
|
|
44
|
-
const
|
|
258
|
+
const apiBase2 = opts.apiBase;
|
|
45
259
|
const limit = opts.limit ?? DEFAULT_LIMIT;
|
|
46
260
|
const refreshMs = opts.refreshMs ?? DEFAULT_REFRESH_MS;
|
|
47
261
|
let cancelled = false;
|
|
@@ -79,7 +293,7 @@ function mountSageFeed(target, opts = {}) {
|
|
|
79
293
|
list.textContent = "No activity yet \u2014 be the first to ask Sage a paid query.";
|
|
80
294
|
applyStyles(list, emptyStyle);
|
|
81
295
|
} else {
|
|
82
|
-
events.forEach((evt) => list.appendChild(renderRow(evt, response.network,
|
|
296
|
+
events.forEach((evt) => list.appendChild(renderRow(evt, response.network, apiBase2)));
|
|
83
297
|
}
|
|
84
298
|
root.appendChild(list);
|
|
85
299
|
}
|
|
@@ -118,7 +332,7 @@ function mountSageFeed(target, opts = {}) {
|
|
|
118
332
|
abort = new AbortController();
|
|
119
333
|
try {
|
|
120
334
|
const data = await fetchSageActivity({
|
|
121
|
-
apiBase,
|
|
335
|
+
apiBase: apiBase2,
|
|
122
336
|
limit,
|
|
123
337
|
signal: abort.signal
|
|
124
338
|
});
|
|
@@ -255,9 +469,644 @@ var emptyStyle = {
|
|
|
255
469
|
fontSize: "11px"
|
|
256
470
|
};
|
|
257
471
|
|
|
472
|
+
// src/vanilla/mountSagePaymentWidget.ts
|
|
473
|
+
function mountSagePaymentWidget(target, opts = {}) {
|
|
474
|
+
const apiBase2 = opts.apiBase ?? DEFAULT_API_BASE;
|
|
475
|
+
let destroyed = false;
|
|
476
|
+
let messages = [...opts.initialMessages ?? []];
|
|
477
|
+
let phase = "idle";
|
|
478
|
+
let inputValue = "";
|
|
479
|
+
let noteBoxId = "";
|
|
480
|
+
let activeQuestion = "";
|
|
481
|
+
let quoteResponse = null;
|
|
482
|
+
let paymentIntent = null;
|
|
483
|
+
let receipt = null;
|
|
484
|
+
let receiptBundle = null;
|
|
485
|
+
let error = null;
|
|
486
|
+
let tier = null;
|
|
487
|
+
const root = document.createElement("section");
|
|
488
|
+
root.setAttribute("data-sage-payment-widget", "true");
|
|
489
|
+
applyStyles2(root, rootStyle2);
|
|
490
|
+
target.appendChild(root);
|
|
491
|
+
async function send(questionRaw) {
|
|
492
|
+
const question = questionRaw.trim();
|
|
493
|
+
if (!question || isBusy()) return;
|
|
494
|
+
activeQuestion = question;
|
|
495
|
+
inputValue = "";
|
|
496
|
+
noteBoxId = "";
|
|
497
|
+
quoteResponse = null;
|
|
498
|
+
paymentIntent = null;
|
|
499
|
+
receipt = null;
|
|
500
|
+
receiptBundle = null;
|
|
501
|
+
error = null;
|
|
502
|
+
tier = null;
|
|
503
|
+
const userMessage = { role: "user", content: question };
|
|
504
|
+
messages = [...messages, userMessage];
|
|
505
|
+
opts.onMessage?.(userMessage, messages);
|
|
506
|
+
transition("quoting");
|
|
507
|
+
render();
|
|
508
|
+
try {
|
|
509
|
+
const quote = await fetchSageQuote({
|
|
510
|
+
apiBase: apiBase2,
|
|
511
|
+
tenant: opts.tenant,
|
|
512
|
+
question,
|
|
513
|
+
history: messages.slice(0, -1)
|
|
514
|
+
});
|
|
515
|
+
if (destroyed) return;
|
|
516
|
+
opts.onQuote?.(quote);
|
|
517
|
+
if (quote.premium) {
|
|
518
|
+
if (!quote.quote) throw new Error("Sage marked this question premium but did not return a quote.");
|
|
519
|
+
quoteResponse = quote;
|
|
520
|
+
paymentIntent = createSagePaymentIntent({
|
|
521
|
+
apiBase: apiBase2,
|
|
522
|
+
tenant: opts.tenant,
|
|
523
|
+
question,
|
|
524
|
+
quote: quote.quote
|
|
525
|
+
});
|
|
526
|
+
opts.onPaymentIntent?.(paymentIntent);
|
|
527
|
+
transition("payment_required");
|
|
528
|
+
render();
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
await streamAnswer(messages);
|
|
532
|
+
} catch (err) {
|
|
533
|
+
fail(err);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
async function verifyAndContinue() {
|
|
537
|
+
const quote = quoteResponse?.quote;
|
|
538
|
+
const note = noteBoxId.trim();
|
|
539
|
+
if (!quote || !activeQuestion || !note || isBusy()) return;
|
|
540
|
+
transition("verifying");
|
|
541
|
+
error = null;
|
|
542
|
+
render();
|
|
543
|
+
let verified;
|
|
544
|
+
try {
|
|
545
|
+
verified = await verifySagePayment({
|
|
546
|
+
apiBase: apiBase2,
|
|
547
|
+
tenant: opts.tenant,
|
|
548
|
+
quote,
|
|
549
|
+
question: activeQuestion,
|
|
550
|
+
noteBoxId: note
|
|
551
|
+
});
|
|
552
|
+
} catch (err) {
|
|
553
|
+
transition("payment_required");
|
|
554
|
+
fail(err, false);
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
if (destroyed) return;
|
|
558
|
+
receipt = verified;
|
|
559
|
+
opts.onReceipt?.(verified);
|
|
560
|
+
quoteResponse = null;
|
|
561
|
+
paymentIntent = null;
|
|
562
|
+
noteBoxId = "";
|
|
563
|
+
transition("streaming");
|
|
564
|
+
try {
|
|
565
|
+
receiptBundle = await fetchSageReceipt(verified.receiptId, { apiBase: apiBase2, tenant: opts.tenant });
|
|
566
|
+
opts.onReceiptBundle?.(receiptBundle);
|
|
567
|
+
emitStatus("streaming");
|
|
568
|
+
} catch (bundleErr) {
|
|
569
|
+
opts.onError?.(bundleErr);
|
|
570
|
+
}
|
|
571
|
+
try {
|
|
572
|
+
await streamAnswer(messages, verified.paymentToken);
|
|
573
|
+
} catch (err) {
|
|
574
|
+
fail(err);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
async function streamAnswer(baseMessages, paymentToken) {
|
|
578
|
+
transition("streaming");
|
|
579
|
+
messages = [...baseMessages, { role: "assistant", content: "" }];
|
|
580
|
+
render();
|
|
581
|
+
let text = "";
|
|
582
|
+
const result = await streamSageChat({
|
|
583
|
+
apiBase: apiBase2,
|
|
584
|
+
tenant: opts.tenant,
|
|
585
|
+
messages: baseMessages,
|
|
586
|
+
paymentToken,
|
|
587
|
+
onEvent(event) {
|
|
588
|
+
if (destroyed) return;
|
|
589
|
+
if (event.type === "tier") {
|
|
590
|
+
tier = event.tier;
|
|
591
|
+
opts.onTier?.(event.tier);
|
|
592
|
+
render();
|
|
593
|
+
}
|
|
594
|
+
if (event.type === "delta") {
|
|
595
|
+
text += event.text;
|
|
596
|
+
messages = [...baseMessages, { role: "assistant", content: text }];
|
|
597
|
+
render();
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
});
|
|
601
|
+
if (destroyed) return;
|
|
602
|
+
if (!result.ok) {
|
|
603
|
+
if (result.paymentRequired) {
|
|
604
|
+
const quote = await fetchSageQuote({
|
|
605
|
+
apiBase: apiBase2,
|
|
606
|
+
tenant: opts.tenant,
|
|
607
|
+
question: activeQuestion,
|
|
608
|
+
history: baseMessages.slice(0, -1)
|
|
609
|
+
});
|
|
610
|
+
opts.onQuote?.(quote);
|
|
611
|
+
quoteResponse = quote;
|
|
612
|
+
paymentIntent = quote.quote ? createSagePaymentIntent({
|
|
613
|
+
apiBase: apiBase2,
|
|
614
|
+
tenant: opts.tenant,
|
|
615
|
+
question: activeQuestion,
|
|
616
|
+
quote: quote.quote
|
|
617
|
+
}) : null;
|
|
618
|
+
if (paymentIntent) opts.onPaymentIntent?.(paymentIntent);
|
|
619
|
+
transition("payment_required");
|
|
620
|
+
render();
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
throw new Error(result.error ?? "Sage chat failed.");
|
|
624
|
+
}
|
|
625
|
+
if (result.text && result.text !== text) {
|
|
626
|
+
messages = [...baseMessages, { role: "assistant", content: result.text }];
|
|
627
|
+
}
|
|
628
|
+
transition("idle");
|
|
629
|
+
render();
|
|
630
|
+
}
|
|
631
|
+
async function launchWallet() {
|
|
632
|
+
if (!paymentIntent || !opts.walletLauncher || isBusy()) return;
|
|
633
|
+
error = null;
|
|
634
|
+
try {
|
|
635
|
+
const result = await opts.walletLauncher(paymentIntent);
|
|
636
|
+
if (result?.ok === false) {
|
|
637
|
+
throw new Error(result.error ?? "Wallet flow did not produce a Note.");
|
|
638
|
+
}
|
|
639
|
+
if (result?.noteBoxId) noteBoxId = result.noteBoxId;
|
|
640
|
+
} catch (err) {
|
|
641
|
+
error = err instanceof Error ? err.message : "Wallet flow failed.";
|
|
642
|
+
opts.onError?.(err);
|
|
643
|
+
}
|
|
644
|
+
render();
|
|
645
|
+
}
|
|
646
|
+
function render() {
|
|
647
|
+
root.innerHTML = "";
|
|
648
|
+
const header = document.createElement("header");
|
|
649
|
+
applyStyles2(header, headerStyle2);
|
|
650
|
+
const titleWrap = document.createElement("div");
|
|
651
|
+
const eyebrow = document.createElement("div");
|
|
652
|
+
eyebrow.textContent = opts.tenant?.label ?? "Ergo agent economy";
|
|
653
|
+
applyStyles2(eyebrow, eyebrowStyle);
|
|
654
|
+
const title = document.createElement("h2");
|
|
655
|
+
title.textContent = opts.title ?? "Ask Sage";
|
|
656
|
+
applyStyles2(title, titleStyle);
|
|
657
|
+
titleWrap.append(eyebrow, title);
|
|
658
|
+
const badge = document.createElement("span");
|
|
659
|
+
badge.textContent = tier ? tier.toUpperCase() : "SAGE";
|
|
660
|
+
applyStyles2(badge, badgeStyle);
|
|
661
|
+
header.append(titleWrap, badge);
|
|
662
|
+
root.appendChild(header);
|
|
663
|
+
const log = document.createElement("div");
|
|
664
|
+
applyStyles2(log, messagesStyle);
|
|
665
|
+
if (messages.length === 0) {
|
|
666
|
+
const empty = document.createElement("div");
|
|
667
|
+
empty.textContent = "Free questions answer immediately. Premium questions return an Accord Note quote.";
|
|
668
|
+
applyStyles2(empty, emptyStyle2);
|
|
669
|
+
log.appendChild(empty);
|
|
670
|
+
} else {
|
|
671
|
+
messages.forEach((message) => {
|
|
672
|
+
const bubble = document.createElement("div");
|
|
673
|
+
bubble.textContent = message.content || (message.role === "assistant" && phase === "streaming" ? "Thinking..." : "");
|
|
674
|
+
applyStyles2(bubble, message.role === "user" ? userBubbleStyle : assistantBubbleStyle);
|
|
675
|
+
log.appendChild(bubble);
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
root.appendChild(log);
|
|
679
|
+
if (quoteResponse?.quote) {
|
|
680
|
+
root.appendChild(renderPaymentPanel(quoteResponse.quote));
|
|
681
|
+
}
|
|
682
|
+
if (receipt) {
|
|
683
|
+
const a = document.createElement("a");
|
|
684
|
+
a.href = receipt.receiptUrl;
|
|
685
|
+
a.target = "_blank";
|
|
686
|
+
a.rel = "noopener noreferrer";
|
|
687
|
+
a.textContent = `Receipt: ${shortId(receipt.receiptId)}${receiptBundle ? ` \xB7 ${receiptBundle.completeness}` : ""}`;
|
|
688
|
+
applyStyles2(a, receiptStyle);
|
|
689
|
+
root.appendChild(a);
|
|
690
|
+
}
|
|
691
|
+
if (error) {
|
|
692
|
+
const err = document.createElement("div");
|
|
693
|
+
err.textContent = error;
|
|
694
|
+
applyStyles2(err, errorStyle);
|
|
695
|
+
root.appendChild(err);
|
|
696
|
+
}
|
|
697
|
+
const form = document.createElement("form");
|
|
698
|
+
applyStyles2(form, formStyle);
|
|
699
|
+
form.addEventListener("submit", (event) => {
|
|
700
|
+
event.preventDefault();
|
|
701
|
+
void send(inputValue);
|
|
702
|
+
});
|
|
703
|
+
const input = document.createElement("input");
|
|
704
|
+
input.value = inputValue;
|
|
705
|
+
input.placeholder = opts.placeholder ?? "Ask Sage about Ergo or agent payments...";
|
|
706
|
+
input.disabled = isBusy();
|
|
707
|
+
input.addEventListener("input", () => {
|
|
708
|
+
inputValue = input.value;
|
|
709
|
+
button.disabled = !inputValue.trim() || isBusy();
|
|
710
|
+
});
|
|
711
|
+
applyStyles2(input, inputStyle);
|
|
712
|
+
const button = document.createElement("button");
|
|
713
|
+
button.type = "submit";
|
|
714
|
+
button.textContent = phase === "quoting" ? "Quoting..." : phase === "streaming" ? "Streaming..." : "Send";
|
|
715
|
+
button.disabled = isBusy();
|
|
716
|
+
applyStyles2(button, sendButtonStyle);
|
|
717
|
+
form.append(input, button);
|
|
718
|
+
root.appendChild(form);
|
|
719
|
+
}
|
|
720
|
+
function renderPaymentPanel(quote) {
|
|
721
|
+
const panel = document.createElement("div");
|
|
722
|
+
applyStyles2(panel, paymentStyle);
|
|
723
|
+
const top = document.createElement("div");
|
|
724
|
+
applyStyles2(top, paymentHeaderStyle);
|
|
725
|
+
const strong = document.createElement("strong");
|
|
726
|
+
strong.textContent = "Payment required";
|
|
727
|
+
const price = document.createElement("span");
|
|
728
|
+
price.textContent = `${quote.price} ERG testnet`;
|
|
729
|
+
top.append(strong, price);
|
|
730
|
+
panel.appendChild(top);
|
|
731
|
+
const helper = document.createElement("p");
|
|
732
|
+
helper.textContent = opts.paymentInstructions?.helperText ?? "Issue an Ergo testnet Note for this quote, then paste the created Note box id.";
|
|
733
|
+
applyStyles2(helper, helperStyle);
|
|
734
|
+
if (opts.paymentInstructions?.walletUrl) {
|
|
735
|
+
const link = document.createElement("a");
|
|
736
|
+
link.href = opts.paymentInstructions.walletUrl;
|
|
737
|
+
link.target = "_blank";
|
|
738
|
+
link.rel = "noopener noreferrer";
|
|
739
|
+
link.textContent = " Wallet guide";
|
|
740
|
+
applyStyles2(link, inlineLinkStyle);
|
|
741
|
+
helper.appendChild(link);
|
|
742
|
+
}
|
|
743
|
+
panel.appendChild(helper);
|
|
744
|
+
panel.append(
|
|
745
|
+
field("Quote", quote.quoteId),
|
|
746
|
+
field("Receiver", quote.receiverAddress),
|
|
747
|
+
field("Reserve box", quote.reserveBoxId),
|
|
748
|
+
field("Task hash", quote.taskHash)
|
|
749
|
+
);
|
|
750
|
+
const testnetWarning = opts.testnetWarning === false ? null : opts.testnetWarning ?? "Testnet proof flow. The widget never signs funds; connect your own reviewed wallet layer before handling real value.";
|
|
751
|
+
if (testnetWarning) {
|
|
752
|
+
const warning = document.createElement("div");
|
|
753
|
+
warning.textContent = testnetWarning;
|
|
754
|
+
applyStyles2(warning, warningStyle);
|
|
755
|
+
panel.appendChild(warning);
|
|
756
|
+
}
|
|
757
|
+
if (opts.showPaymentIntent !== false && paymentIntent) {
|
|
758
|
+
const intent = document.createElement("div");
|
|
759
|
+
applyStyles2(intent, intentStyle);
|
|
760
|
+
const intentTop = document.createElement("div");
|
|
761
|
+
applyStyles2(intentTop, intentHeaderStyle);
|
|
762
|
+
const label2 = document.createElement("strong");
|
|
763
|
+
label2.textContent = "Payment intent";
|
|
764
|
+
const copy = document.createElement("button");
|
|
765
|
+
copy.type = "button";
|
|
766
|
+
copy.textContent = "Copy JSON";
|
|
767
|
+
copy.addEventListener("click", () => copyText(serializeSagePaymentIntent(paymentIntent)));
|
|
768
|
+
applyStyles2(copy, copyButtonStyle);
|
|
769
|
+
intentTop.append(label2, copy);
|
|
770
|
+
const code = document.createElement("code");
|
|
771
|
+
code.textContent = serializeSagePaymentIntent(paymentIntent);
|
|
772
|
+
applyStyles2(code, intentCodeStyle);
|
|
773
|
+
intent.append(intentTop, code);
|
|
774
|
+
panel.appendChild(intent);
|
|
775
|
+
}
|
|
776
|
+
if (opts.walletLauncher && paymentIntent) {
|
|
777
|
+
const wallet = document.createElement("button");
|
|
778
|
+
wallet.type = "button";
|
|
779
|
+
wallet.textContent = opts.paymentInstructions?.walletLauncherLabel ?? "Open wallet flow";
|
|
780
|
+
wallet.disabled = isBusy();
|
|
781
|
+
wallet.addEventListener("click", () => void launchWallet());
|
|
782
|
+
applyStyles2(wallet, secondaryButtonStyle);
|
|
783
|
+
panel.appendChild(wallet);
|
|
784
|
+
}
|
|
785
|
+
const label = document.createElement("label");
|
|
786
|
+
label.textContent = opts.paymentInstructions?.noteBoxLabel ?? "Note box id";
|
|
787
|
+
applyStyles2(label, labelStyle2);
|
|
788
|
+
const input = document.createElement("input");
|
|
789
|
+
input.value = noteBoxId;
|
|
790
|
+
input.placeholder = "Paste 64-char Ergo box id";
|
|
791
|
+
input.disabled = isBusy();
|
|
792
|
+
input.addEventListener("input", () => {
|
|
793
|
+
noteBoxId = input.value;
|
|
794
|
+
verify.disabled = !noteBoxId.trim() || isBusy();
|
|
795
|
+
});
|
|
796
|
+
applyStyles2(input, inputStyle);
|
|
797
|
+
label.appendChild(input);
|
|
798
|
+
panel.appendChild(label);
|
|
799
|
+
const verify = document.createElement("button");
|
|
800
|
+
verify.type = "button";
|
|
801
|
+
verify.textContent = phase === "verifying" ? "Verifying..." : "Verify payment";
|
|
802
|
+
verify.disabled = !noteBoxId.trim() || isBusy();
|
|
803
|
+
verify.addEventListener("click", () => void verifyAndContinue());
|
|
804
|
+
applyStyles2(verify, primaryButtonStyle);
|
|
805
|
+
panel.appendChild(verify);
|
|
806
|
+
return panel;
|
|
807
|
+
}
|
|
808
|
+
function field(labelText, value) {
|
|
809
|
+
const row = document.createElement("div");
|
|
810
|
+
applyStyles2(row, fieldStyle);
|
|
811
|
+
const label = document.createElement("span");
|
|
812
|
+
label.textContent = labelText;
|
|
813
|
+
applyStyles2(label, fieldLabelStyle);
|
|
814
|
+
const code = document.createElement("code");
|
|
815
|
+
code.textContent = value;
|
|
816
|
+
applyStyles2(code, fieldValueStyle);
|
|
817
|
+
const copy = document.createElement("button");
|
|
818
|
+
copy.type = "button";
|
|
819
|
+
copy.textContent = "Copy";
|
|
820
|
+
copy.addEventListener("click", () => copyText(value));
|
|
821
|
+
applyStyles2(copy, copyButtonStyle);
|
|
822
|
+
row.append(label, code, copy);
|
|
823
|
+
return row;
|
|
824
|
+
}
|
|
825
|
+
function isBusy() {
|
|
826
|
+
return phase === "quoting" || phase === "verifying" || phase === "streaming";
|
|
827
|
+
}
|
|
828
|
+
function fail(err, setErrorPhase = true) {
|
|
829
|
+
error = err instanceof Error ? err.message : "Sage request failed.";
|
|
830
|
+
if (setErrorPhase) transition("error");
|
|
831
|
+
else emitStatus(phase);
|
|
832
|
+
opts.onError?.(err);
|
|
833
|
+
render();
|
|
834
|
+
}
|
|
835
|
+
function transition(next) {
|
|
836
|
+
phase = next;
|
|
837
|
+
opts.onPhase?.(next);
|
|
838
|
+
emitStatus(next);
|
|
839
|
+
}
|
|
840
|
+
function emitStatus(next) {
|
|
841
|
+
opts.onStatus?.({
|
|
842
|
+
phase: next,
|
|
843
|
+
tier,
|
|
844
|
+
quote: quoteResponse?.quote ?? null,
|
|
845
|
+
paymentIntent,
|
|
846
|
+
receipt,
|
|
847
|
+
receiptBundle,
|
|
848
|
+
error,
|
|
849
|
+
messages,
|
|
850
|
+
activeQuestion: activeQuestion || null
|
|
851
|
+
});
|
|
852
|
+
}
|
|
853
|
+
render();
|
|
854
|
+
return {
|
|
855
|
+
send,
|
|
856
|
+
destroy() {
|
|
857
|
+
destroyed = true;
|
|
858
|
+
root.remove();
|
|
859
|
+
},
|
|
860
|
+
current: () => messages,
|
|
861
|
+
status: () => ({
|
|
862
|
+
phase,
|
|
863
|
+
tier,
|
|
864
|
+
quote: quoteResponse?.quote ?? null,
|
|
865
|
+
paymentIntent,
|
|
866
|
+
receipt,
|
|
867
|
+
receiptBundle,
|
|
868
|
+
error,
|
|
869
|
+
messages,
|
|
870
|
+
activeQuestion: activeQuestion || null
|
|
871
|
+
})
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
function applyStyles2(el, styles) {
|
|
875
|
+
Object.assign(el.style, styles);
|
|
876
|
+
}
|
|
877
|
+
function shortId(value) {
|
|
878
|
+
return value.length > 18 ? `${value.slice(0, 10)}...${value.slice(-8)}` : value;
|
|
879
|
+
}
|
|
880
|
+
function copyText(value) {
|
|
881
|
+
if (typeof navigator !== "undefined" && navigator.clipboard) {
|
|
882
|
+
void navigator.clipboard.writeText(value);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
var rootStyle2 = {
|
|
886
|
+
background: "#070707",
|
|
887
|
+
color: "#f8fafc",
|
|
888
|
+
border: "1px solid rgba(255,255,255,.1)",
|
|
889
|
+
borderRadius: "8px",
|
|
890
|
+
padding: "16px",
|
|
891
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
|
|
892
|
+
boxSizing: "border-box",
|
|
893
|
+
width: "100%",
|
|
894
|
+
maxWidth: "520px"
|
|
895
|
+
};
|
|
896
|
+
var headerStyle2 = {
|
|
897
|
+
display: "flex",
|
|
898
|
+
justifyContent: "space-between",
|
|
899
|
+
alignItems: "flex-start",
|
|
900
|
+
gap: "12px",
|
|
901
|
+
marginBottom: "12px"
|
|
902
|
+
};
|
|
903
|
+
var eyebrowStyle = {
|
|
904
|
+
color: "#fb923c",
|
|
905
|
+
fontSize: "11px",
|
|
906
|
+
letterSpacing: ".16em",
|
|
907
|
+
textTransform: "uppercase",
|
|
908
|
+
marginBottom: "4px"
|
|
909
|
+
};
|
|
910
|
+
var titleStyle = {
|
|
911
|
+
fontSize: "18px",
|
|
912
|
+
lineHeight: "1.2",
|
|
913
|
+
margin: "0"
|
|
914
|
+
};
|
|
915
|
+
var badgeStyle = {
|
|
916
|
+
color: "#0f172a",
|
|
917
|
+
background: "#fdba74",
|
|
918
|
+
borderRadius: "4px",
|
|
919
|
+
padding: "4px 7px",
|
|
920
|
+
fontSize: "10px",
|
|
921
|
+
fontWeight: "800",
|
|
922
|
+
letterSpacing: ".12em"
|
|
923
|
+
};
|
|
924
|
+
var messagesStyle = {
|
|
925
|
+
minHeight: "180px",
|
|
926
|
+
maxHeight: "360px",
|
|
927
|
+
overflow: "auto",
|
|
928
|
+
display: "flex",
|
|
929
|
+
flexDirection: "column",
|
|
930
|
+
gap: "8px",
|
|
931
|
+
padding: "12px 0"
|
|
932
|
+
};
|
|
933
|
+
var emptyStyle2 = {
|
|
934
|
+
color: "#94a3b8",
|
|
935
|
+
border: "1px dashed rgba(148,163,184,.28)",
|
|
936
|
+
borderRadius: "6px",
|
|
937
|
+
padding: "12px",
|
|
938
|
+
fontSize: "13px"
|
|
939
|
+
};
|
|
940
|
+
var bubbleBase = {
|
|
941
|
+
borderRadius: "6px",
|
|
942
|
+
padding: "9px 10px",
|
|
943
|
+
fontSize: "14px",
|
|
944
|
+
lineHeight: "1.45",
|
|
945
|
+
whiteSpace: "pre-wrap"
|
|
946
|
+
};
|
|
947
|
+
var userBubbleStyle = {
|
|
948
|
+
...bubbleBase,
|
|
949
|
+
alignSelf: "flex-end",
|
|
950
|
+
maxWidth: "88%",
|
|
951
|
+
background: "#fb923c",
|
|
952
|
+
color: "#111827"
|
|
953
|
+
};
|
|
954
|
+
var assistantBubbleStyle = {
|
|
955
|
+
...bubbleBase,
|
|
956
|
+
alignSelf: "flex-start",
|
|
957
|
+
maxWidth: "92%",
|
|
958
|
+
background: "rgba(255,255,255,.07)",
|
|
959
|
+
color: "#e5e7eb"
|
|
960
|
+
};
|
|
961
|
+
var paymentStyle = {
|
|
962
|
+
border: "1px solid rgba(251,146,60,.35)",
|
|
963
|
+
background: "rgba(251,146,60,.08)",
|
|
964
|
+
borderRadius: "8px",
|
|
965
|
+
padding: "12px",
|
|
966
|
+
display: "grid",
|
|
967
|
+
gap: "8px"
|
|
968
|
+
};
|
|
969
|
+
var paymentHeaderStyle = {
|
|
970
|
+
display: "flex",
|
|
971
|
+
justifyContent: "space-between",
|
|
972
|
+
color: "#fed7aa",
|
|
973
|
+
fontSize: "13px"
|
|
974
|
+
};
|
|
975
|
+
var helperStyle = {
|
|
976
|
+
color: "#fdba74",
|
|
977
|
+
fontSize: "12px",
|
|
978
|
+
lineHeight: "1.45",
|
|
979
|
+
margin: "0"
|
|
980
|
+
};
|
|
981
|
+
var inlineLinkStyle = {
|
|
982
|
+
color: "#67e8f9",
|
|
983
|
+
textDecoration: "none"
|
|
984
|
+
};
|
|
985
|
+
var labelStyle2 = {
|
|
986
|
+
display: "grid",
|
|
987
|
+
gap: "6px",
|
|
988
|
+
color: "#cbd5e1",
|
|
989
|
+
fontSize: "12px"
|
|
990
|
+
};
|
|
991
|
+
var fieldStyle = {
|
|
992
|
+
display: "grid",
|
|
993
|
+
gridTemplateColumns: "minmax(70px, 88px) minmax(0, 1fr) auto",
|
|
994
|
+
alignItems: "center",
|
|
995
|
+
gap: "8px",
|
|
996
|
+
fontSize: "12px"
|
|
997
|
+
};
|
|
998
|
+
var fieldLabelStyle = {
|
|
999
|
+
color: "#94a3b8"
|
|
1000
|
+
};
|
|
1001
|
+
var fieldValueStyle = {
|
|
1002
|
+
color: "#f8fafc",
|
|
1003
|
+
overflow: "hidden",
|
|
1004
|
+
textOverflow: "ellipsis",
|
|
1005
|
+
whiteSpace: "nowrap",
|
|
1006
|
+
fontSize: "11px"
|
|
1007
|
+
};
|
|
1008
|
+
var copyButtonStyle = {
|
|
1009
|
+
border: "1px solid rgba(255,255,255,.16)",
|
|
1010
|
+
background: "rgba(255,255,255,.06)",
|
|
1011
|
+
color: "#f8fafc",
|
|
1012
|
+
borderRadius: "4px",
|
|
1013
|
+
padding: "4px 7px",
|
|
1014
|
+
cursor: "pointer"
|
|
1015
|
+
};
|
|
1016
|
+
var formStyle = {
|
|
1017
|
+
display: "grid",
|
|
1018
|
+
gridTemplateColumns: "minmax(0, 1fr) auto",
|
|
1019
|
+
gap: "8px",
|
|
1020
|
+
marginTop: "12px"
|
|
1021
|
+
};
|
|
1022
|
+
var inputStyle = {
|
|
1023
|
+
width: "100%",
|
|
1024
|
+
boxSizing: "border-box",
|
|
1025
|
+
border: "1px solid rgba(255,255,255,.16)",
|
|
1026
|
+
background: "#050505",
|
|
1027
|
+
color: "#f8fafc",
|
|
1028
|
+
borderRadius: "6px",
|
|
1029
|
+
padding: "10px 11px",
|
|
1030
|
+
fontSize: "14px"
|
|
1031
|
+
};
|
|
1032
|
+
var sendButtonStyle = {
|
|
1033
|
+
border: "0",
|
|
1034
|
+
background: "#fb923c",
|
|
1035
|
+
color: "#111827",
|
|
1036
|
+
borderRadius: "6px",
|
|
1037
|
+
padding: "0 14px",
|
|
1038
|
+
fontWeight: "800",
|
|
1039
|
+
cursor: "pointer"
|
|
1040
|
+
};
|
|
1041
|
+
var primaryButtonStyle = {
|
|
1042
|
+
...sendButtonStyle,
|
|
1043
|
+
padding: "10px 12px"
|
|
1044
|
+
};
|
|
1045
|
+
var secondaryButtonStyle = {
|
|
1046
|
+
border: "1px solid rgba(103,232,249,.28)",
|
|
1047
|
+
background: "rgba(103,232,249,.08)",
|
|
1048
|
+
color: "#cffafe",
|
|
1049
|
+
borderRadius: "6px",
|
|
1050
|
+
padding: "10px 12px",
|
|
1051
|
+
fontWeight: "800",
|
|
1052
|
+
cursor: "pointer"
|
|
1053
|
+
};
|
|
1054
|
+
var warningStyle = {
|
|
1055
|
+
color: "#fde68a",
|
|
1056
|
+
background: "rgba(245,158,11,.1)",
|
|
1057
|
+
border: "1px solid rgba(245,158,11,.24)",
|
|
1058
|
+
borderRadius: "6px",
|
|
1059
|
+
padding: "8px 9px",
|
|
1060
|
+
fontSize: "12px",
|
|
1061
|
+
lineHeight: "1.45"
|
|
1062
|
+
};
|
|
1063
|
+
var intentStyle = {
|
|
1064
|
+
border: "1px solid rgba(255,255,255,.12)",
|
|
1065
|
+
background: "rgba(255,255,255,.04)",
|
|
1066
|
+
borderRadius: "6px",
|
|
1067
|
+
padding: "10px",
|
|
1068
|
+
display: "grid",
|
|
1069
|
+
gap: "8px"
|
|
1070
|
+
};
|
|
1071
|
+
var intentHeaderStyle = {
|
|
1072
|
+
display: "flex",
|
|
1073
|
+
justifyContent: "space-between",
|
|
1074
|
+
alignItems: "center",
|
|
1075
|
+
gap: "8px",
|
|
1076
|
+
color: "#e2e8f0",
|
|
1077
|
+
fontSize: "12px"
|
|
1078
|
+
};
|
|
1079
|
+
var intentCodeStyle = {
|
|
1080
|
+
display: "block",
|
|
1081
|
+
maxHeight: "130px",
|
|
1082
|
+
overflow: "auto",
|
|
1083
|
+
whiteSpace: "pre-wrap",
|
|
1084
|
+
wordBreak: "break-word",
|
|
1085
|
+
color: "#cbd5e1",
|
|
1086
|
+
fontSize: "10px",
|
|
1087
|
+
lineHeight: "1.45"
|
|
1088
|
+
};
|
|
1089
|
+
var receiptStyle = {
|
|
1090
|
+
display: "block",
|
|
1091
|
+
marginTop: "10px",
|
|
1092
|
+
color: "#67e8f9",
|
|
1093
|
+
fontSize: "13px",
|
|
1094
|
+
textDecoration: "none"
|
|
1095
|
+
};
|
|
1096
|
+
var errorStyle = {
|
|
1097
|
+
color: "#fecaca",
|
|
1098
|
+
background: "rgba(239,68,68,.12)",
|
|
1099
|
+
border: "1px solid rgba(239,68,68,.25)",
|
|
1100
|
+
borderRadius: "6px",
|
|
1101
|
+
padding: "10px",
|
|
1102
|
+
marginTop: "10px",
|
|
1103
|
+
fontSize: "13px"
|
|
1104
|
+
};
|
|
1105
|
+
|
|
258
1106
|
exports.DEFAULT_API_BASE = DEFAULT_API_BASE;
|
|
259
1107
|
exports.DEFAULT_LIMIT = DEFAULT_LIMIT;
|
|
260
1108
|
exports.DEFAULT_REFRESH_MS = DEFAULT_REFRESH_MS;
|
|
261
1109
|
exports.mountSageFeed = mountSageFeed;
|
|
1110
|
+
exports.mountSagePaymentWidget = mountSagePaymentWidget;
|
|
262
1111
|
//# sourceMappingURL=vanilla.cjs.map
|
|
263
1112
|
//# sourceMappingURL=vanilla.cjs.map
|