@ergoblockchain/sage-widget 0.2.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 +44 -7
- package/dist/index.cjs +24 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -3
- package/dist/index.d.ts +13 -3
- package/dist/index.js +23 -1
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +123 -6
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +123 -6
- package/dist/react.js.map +1 -1
- package/dist/{types-yv1THHVz.d.cts → types-B5V2rsYn.d.cts} +47 -1
- package/dist/{types-yv1THHVz.d.ts → types-B5V2rsYn.d.ts} +47 -1
- package/dist/vanilla.cjs +135 -0
- package/dist/vanilla.cjs.map +1 -1
- package/dist/vanilla.d.cts +4 -3
- package/dist/vanilla.d.ts +4 -3
- package/dist/vanilla.js +135 -0
- package/dist/vanilla.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -7,12 +7,14 @@ Embeddable widgets for **Sage** — the agent-economy concierge on [ergoblockcha
|
|
|
7
7
|
|
|
8
8
|
> _Why this matters:_ Sage settles real paid AI queries on Ergo testnet. The feed makes the "agent-economy" thesis visibly provable wherever you embed it — not a marketing claim, a list of public on-chain receipts that update live.
|
|
9
9
|
|
|
10
|
-
## What v0.
|
|
10
|
+
## What v0.3 ships
|
|
11
11
|
|
|
12
12
|
- `<SagePaymentWidget />` React component.
|
|
13
13
|
- `mountSagePaymentWidget(target, opts)` vanilla DOM mount.
|
|
14
14
|
- Typed clients for quote, verify, chat stream, receipt bundle, and activity feed.
|
|
15
15
|
- Tenant metadata and host-provided payment instructions.
|
|
16
|
+
- Portable `SagePaymentIntent` JSON for host-owned wallet flows.
|
|
17
|
+
- Optional `walletLauncher(intent)` callback so your app can open a reviewed wallet flow without letting the widget sign funds.
|
|
16
18
|
- Payment lifecycle callbacks: quote, receipt, receipt bundle, tier, phase, status.
|
|
17
19
|
- Public receipt links plus machine-readable `/api/sage/receipt/<id>` links.
|
|
18
20
|
|
|
@@ -56,10 +58,18 @@ export function PaidSageBox() {
|
|
|
56
58
|
paymentInstructions={{
|
|
57
59
|
helperText: "Issue the quoted Accord Note from your testnet wallet, then paste the Note box id.",
|
|
58
60
|
walletUrl: "https://www.ergoblockchain.org/build/agent-payments",
|
|
61
|
+
walletLauncherLabel: "Open my testnet wallet",
|
|
59
62
|
}}
|
|
60
63
|
onQuote={(quote) => console.log("Sage quote", quote)}
|
|
64
|
+
onPaymentIntent={(intent) => console.log("Wallet intent", intent)}
|
|
61
65
|
onReceipt={(receipt) => console.log("Sage receipt", receipt.receiptUrl)}
|
|
62
66
|
onReceiptBundle={(bundle) => console.log("Receipt completeness", bundle.completeness)}
|
|
67
|
+
walletLauncher={async (intent) => {
|
|
68
|
+
// Your app owns wallet policy, ErgoPay/Fleet integration and signing.
|
|
69
|
+
// Return a Note box id when the wallet creates the testnet Note.
|
|
70
|
+
console.log("Create a Note for", intent.amountErg, intent.receiverAddress)
|
|
71
|
+
return { ok: true, noteBoxId: "" }
|
|
72
|
+
}}
|
|
63
73
|
/>
|
|
64
74
|
)
|
|
65
75
|
}
|
|
@@ -100,6 +110,7 @@ import { mountSagePaymentWidget } from "@ergoblockchain/sage-widget/vanilla"
|
|
|
100
110
|
|
|
101
111
|
const handle = mountSagePaymentWidget(document.getElementById("sage-chat")!, {
|
|
102
112
|
tenant: { id: "docs-footer", label: "Docs footer" },
|
|
113
|
+
onPaymentIntent: (intent) => console.log("[sage] payment intent", intent),
|
|
103
114
|
})
|
|
104
115
|
|
|
105
116
|
// You can also start a question programmatically:
|
|
@@ -139,6 +150,27 @@ if (isFullSageReceiptBundle(receipt)) {
|
|
|
139
150
|
}
|
|
140
151
|
```
|
|
141
152
|
|
|
153
|
+
### Payment intent bridge
|
|
154
|
+
|
|
155
|
+
v0.3 adds a small but important contract between the widget and your wallet layer. The widget still does **not** sign transactions. Instead it emits a portable intent:
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
import {
|
|
159
|
+
createSagePaymentIntent,
|
|
160
|
+
serializeSagePaymentIntent,
|
|
161
|
+
} from "@ergoblockchain/sage-widget"
|
|
162
|
+
|
|
163
|
+
const intent = createSagePaymentIntent({
|
|
164
|
+
question: "/deep explain Ergo Notes",
|
|
165
|
+
quote,
|
|
166
|
+
tenant: { id: "my-wallet", label: "My Wallet" },
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
console.log(serializeSagePaymentIntent(intent))
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
The intent includes network, receiver, amount, reserve box, task hash, expiry, verification endpoint, and receipt endpoint template. A wallet integration can turn it into an Ergo testnet Note, then hand the Note box id back to the widget for verification.
|
|
173
|
+
|
|
142
174
|
## Render-prop / bring-your-own-design
|
|
143
175
|
|
|
144
176
|
```tsx
|
|
@@ -177,13 +209,17 @@ if (isFullSageReceiptBundle(receipt)) {
|
|
|
177
209
|
| `onReceiptBundle` | `(bundle) => void` | Fired after the widget fetches `/api/sage/receipt/<id>`. |
|
|
178
210
|
| `onTier` | `("free" \| "premium") => void` | Fired when the stream reports model tier. |
|
|
179
211
|
| `onPhase` | `(phase) => void` | Fired on widget phase changes: idle, quoting, payment_required, verifying, streaming, error. |
|
|
180
|
-
| `
|
|
212
|
+
| `onPaymentIntent` | `(intent) => void` | Fired when a premium quote becomes a structured wallet intent. |
|
|
213
|
+
| `walletLauncher` | `(intent) => Promise<{ ok; noteBoxId? }>` | Optional host-owned wallet flow. The widget never signs itself. |
|
|
214
|
+
| `showPaymentIntent` | `boolean` | Shows or hides the default payment-intent JSON panel. Default `true`. |
|
|
215
|
+
| `testnetWarning` | `string \| false` | Default testnet safety copy. Set `false` to hide. |
|
|
216
|
+
| `onStatus` | `(status) => void` | Fired with a compact snapshot of phase, tier, quote, payment intent, receipt, receipt bundle, and error. |
|
|
181
217
|
|
|
182
|
-
`onStatus` and the vanilla `handle.status()` also include `messages
|
|
218
|
+
`onStatus` and the vanilla `handle.status()` also include `paymentIntent`, `messages`, and `activeQuestion`, so hosts can mirror widget state into their own telemetry or UI.
|
|
183
219
|
|
|
184
220
|
## Payment model
|
|
185
221
|
|
|
186
|
-
v0.
|
|
222
|
+
v0.3 deliberately does **not** sign wallet transactions inside the widget. The widget shows the quote fields, emits a portable payment intent, accepts a Note box id, verifies it through Sage, then streams the answer and exposes the receipt. Hosts can pair it with their own wallet flow, Accord tooling, ErgoPay/Fleet integration, or a manual testnet Note issuer.
|
|
187
223
|
|
|
188
224
|
For the canonical site, a successful paid flow looks like:
|
|
189
225
|
|
|
@@ -213,7 +249,7 @@ For settlements, use `paymentNanoErg` (the value of the consumed Note) for "amou
|
|
|
213
249
|
|
|
214
250
|
## Related
|
|
215
251
|
|
|
216
|
-
- **Live demo**: [ergoblockchain.org/agent-economy
|
|
252
|
+
- **Live demo**: [ergoblockchain.org/agent-economy/sage-widget](https://www.ergoblockchain.org/agent-economy/sage-widget)
|
|
217
253
|
- **API directly**: [`/api/sage/activity`](https://www.ergoblockchain.org/api/sage/activity) — JSON, no auth, cached 30s
|
|
218
254
|
- **Receipt format**: [`/r/sage/<settlement_tx_id>`](https://www.ergoblockchain.org/r/sage/f697e4841dd9a0c689d0b83a311130b85a0cfbab123230a6c40284b44c4cafef)
|
|
219
255
|
- **Accord Protocol**: [github.com/accord-protocol/accord-protocol](https://github.com/accord-protocol/accord-protocol)
|
|
@@ -232,8 +268,9 @@ npm pack --dry-run
|
|
|
232
268
|
## Roadmap
|
|
233
269
|
|
|
234
270
|
- **v0.1.x** — read-only activity feed (React + vanilla + types).
|
|
235
|
-
- **v0.2**
|
|
236
|
-
- **v0.3**
|
|
271
|
+
- **v0.2** — `<SagePaymentWidget />` paid chat with quote, manual Note verify, streaming answer, receipt link, tenant config.
|
|
272
|
+
- **v0.3** _(current source)_ — payment-intent bridge, wallet launcher callback, stronger host telemetry, clearer testnet safety copy.
|
|
273
|
+
- **v0.4** — generic `<AccordActivityFeed providerId="..." />` that works for any provider in the registry, not just Sage.
|
|
237
274
|
|
|
238
275
|
## License
|
|
239
276
|
|
package/dist/index.cjs
CHANGED
|
@@ -57,6 +57,28 @@ async function fetchSageReceipt(id, opts = {}) {
|
|
|
57
57
|
function isFullSageReceiptBundle(value) {
|
|
58
58
|
return value?.ok === true && value.completeness === "full_receipt_bundle";
|
|
59
59
|
}
|
|
60
|
+
function createSagePaymentIntent(opts) {
|
|
61
|
+
const base = trimSlash(opts.apiBase ?? DEFAULT_API_BASE);
|
|
62
|
+
return {
|
|
63
|
+
type: "sage.payment_intent.v1",
|
|
64
|
+
network: opts.network ?? "ergo-testnet",
|
|
65
|
+
createdAt: opts.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
66
|
+
question: opts.question,
|
|
67
|
+
...opts.tenant?.id || opts.tenant?.label ? { tenant: { id: opts.tenant.id, label: opts.tenant.label } } : {},
|
|
68
|
+
quote: opts.quote,
|
|
69
|
+
amountErg: opts.quote.price,
|
|
70
|
+
receiverAddress: opts.quote.receiverAddress,
|
|
71
|
+
reserveBoxId: opts.quote.reserveBoxId,
|
|
72
|
+
taskHash: opts.quote.taskHash,
|
|
73
|
+
expiresAt: opts.quote.expiresAt,
|
|
74
|
+
deadline: opts.quote.deadline,
|
|
75
|
+
verifyEndpoint: `${base}/api/sage/verify-payment`,
|
|
76
|
+
receiptEndpointTemplate: `${base}/api/sage/receipt/{receiptId}`
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function serializeSagePaymentIntent(intent) {
|
|
80
|
+
return JSON.stringify(intent, null, 2);
|
|
81
|
+
}
|
|
60
82
|
async function streamSageChat(opts) {
|
|
61
83
|
const res = await fetch(`${apiBase(opts)}/api/sage/chat`, {
|
|
62
84
|
method: "POST",
|
|
@@ -237,6 +259,7 @@ function parseSseEvent(raw) {
|
|
|
237
259
|
exports.DEFAULT_API_BASE = DEFAULT_API_BASE;
|
|
238
260
|
exports.DEFAULT_LIMIT = DEFAULT_LIMIT;
|
|
239
261
|
exports.DEFAULT_REFRESH_MS = DEFAULT_REFRESH_MS;
|
|
262
|
+
exports.createSagePaymentIntent = createSagePaymentIntent;
|
|
240
263
|
exports.explorerUrl = explorerUrl;
|
|
241
264
|
exports.fetchSageActivity = fetchSageActivity;
|
|
242
265
|
exports.fetchSageQuote = fetchSageQuote;
|
|
@@ -245,6 +268,7 @@ exports.isFullSageReceiptBundle = isFullSageReceiptBundle;
|
|
|
245
268
|
exports.nanoToErg = nanoToErg;
|
|
246
269
|
exports.receiptUrl = receiptUrl;
|
|
247
270
|
exports.relativeTime = relativeTime;
|
|
271
|
+
exports.serializeSagePaymentIntent = serializeSagePaymentIntent;
|
|
248
272
|
exports.streamSageChat = streamSageChat;
|
|
249
273
|
exports.verifySagePayment = verifySagePayment;
|
|
250
274
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/api.ts"],"names":["apiBase"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Public types for the Sage activity feed and paid chat flow.\n *\n * The source of truth is the API at https://www.ergoblockchain.org/api/sage/activity;\n * this file re-states the schema so consumers don't have to depend on the\n * server-side fetcher.\n */\n\nexport type SageActivityType = \"settlement\" | \"issuance\" | \"transfer\"\n\nexport interface SageActivityEvent {\n /** 64-char hex transaction id. */\n txId: string\n /** Block height at inclusion. */\n blockHeight: number\n /** Block timestamp (ms epoch). */\n timestamp: number\n /** Heuristic classification of the tx. */\n type: SageActivityType\n /** nanoERG flowing into the seller wallet from this tx (sum of outputs). */\n inflowNanoErg: number\n /**\n * For settlements: value of the redeemed Note (= what the buyer paid).\n * For other event types: undefined.\n *\n * Use this — not `inflowNanoErg` — when displaying \"amount paid for a\n * settled query\". `inflowNanoErg` includes change boxes in test setups\n * where the buyer and seller share an address.\n */\n paymentNanoErg?: number\n /** First input box that carries Note-shape registers, if any. */\n noteBoxId?: string\n}\n\nexport interface SageActivityResponse {\n ok: boolean\n network: \"testnet\" | \"mainnet\"\n /** Sage seller wallet address. */\n receiver: string\n /** Total number of txs ever touching the wallet, per the explorer. */\n total: number\n events: SageActivityEvent[]\n error?: string\n}\n\n/**\n * Configuration accepted by every entry point (React component +\n * vanilla mount fn). Defaults below are sensible for the canonical\n * ergoblockchain.org deployment.\n */\nexport interface SageWidgetOptions {\n /**\n * Base URL of the Sage host. Override if you run your own Sage\n * deployment behind a custom domain. Default: ergoblockchain.org.\n */\n apiBase?: string\n /**\n * Number of events to display (max 25). Default: 5.\n */\n limit?: number\n /**\n * Polling interval in ms. Default: 60000 (60s). Set to 0 to disable\n * polling — the widget will fetch once on mount and never refresh.\n */\n refreshMs?: number\n /**\n * Optional callback fired every time a fresh response arrives. Useful\n * for analytics or for triggering host-side animations on new\n * settlements.\n */\n onUpdate?: (response: SageActivityResponse) => void\n /**\n * Optional callback fired on fetch errors. Default: console.warn.\n */\n onError?: (error: unknown) => void\n}\n\nexport type SageChatRole = \"user\" | \"assistant\"\n\nexport interface SageChatMessage {\n role: SageChatRole\n content: string\n}\n\nexport interface SageTenantConfig {\n /** Stable tenant id for analytics, logs, or future multi-tenant routing. */\n id?: string\n /** Human-facing label shown in the default widgets. */\n label?: string\n /** Extra headers attached to Sage API requests. */\n headers?: Record<string, string>\n}\n\nexport interface SageQuote {\n quoteId: string\n taskHash: string\n price: string\n issuedAt?: string\n expiresAt: string\n receiverAddress: string\n reserveBoxId: string\n deadline: `+${number} blocks`\n}\n\nexport type SagePremiumReason =\n | \"explicit_command\"\n | \"code_request\"\n | \"long_answer\"\n | \"deep_research\"\n | \"multi_turn_followup\"\n\nexport interface SageQuoteResponse {\n premium: boolean\n reason?: SagePremiumReason\n rationale?: string\n quote?: SageQuote\n}\n\nexport interface SageVerifyPaymentResponse {\n ok: true\n paymentToken: string\n receiptId: string\n receiptUrl: string\n receiptApiUrl: string\n settlementTxId?: string | null\n accordSettlementId?: string\n receiptStorage?: {\n ok: boolean\n skipped?: boolean\n reason?: string\n path?: string\n aliases?: string[]\n error?: string\n }\n}\n\nexport interface SagePremiumPaymentRequired {\n error: \"premium_payment_required\"\n reason?: SagePremiumReason\n rationale?: string\n}\n\nexport type SageChatTier = \"free\" | \"premium\"\n\nexport type SageChatStreamEvent =\n | { type: \"tier\"; tier: SageChatTier; model?: string }\n | { type: \"delta\"; text: string }\n | { type: \"done\"; stopReason?: string; inputTokens?: number; outputTokens?: number }\n | { type: \"error\"; message: string }\n\nexport interface SageChatStreamResult {\n ok: boolean\n status: number\n text: string\n tier?: SageChatTier\n paymentRequired?: SagePremiumPaymentRequired\n error?: string\n}\n\nexport interface SageReceiptBundle {\n ok: true\n type: \"sage.receipt_bundle.v1\"\n version: \"v1\"\n id: string\n status: \"settled_on_chain\" | \"verified_pending_redemption\"\n completeness: \"full_receipt_bundle\" | \"full\" | \"chain_proof_only\"\n public_receipt_url: string\n api_receipt_url: string\n explorer_url: string | null\n accord?: {\n agreement_hash?: string | null\n verification_receipt_hash?: string | null\n settlement_receipt_hash?: string | null\n agreement_json?: unknown\n verification_receipt_json?: unknown\n settlement_receipt_json?: unknown\n }\n}\n\nexport interface SagePaymentWidgetOptions {\n /**\n * Base URL of the Sage host. Default: ergoblockchain.org.\n */\n apiBase?: string\n /**\n * Optional tenant metadata. Current public Sage ignores tenant routing,\n * but the widget keeps this shape stable for multi-tenant deployments.\n */\n tenant?: SageTenantConfig\n /** Initial chat messages, useful for preloaded context. */\n initialMessages?: SageChatMessage[]\n /** Placeholder text for the default input. */\n placeholder?: string\n /** Widget heading. React also accepts this through component props. */\n title?: string\n /** Optional host-specific payment copy and links. */\n paymentInstructions?: SagePaymentInstructions\n /** Called whenever a message is appended by the widget. */\n onMessage?: (message: SageChatMessage, messages: SageChatMessage[]) => void\n /** Called after Sage returns a premium quote. */\n onQuote?: (quote: SageQuoteResponse) => void\n /** Called after a payment verifies and Sage returns a receipt link. */\n onReceipt?: (receipt: SageVerifyPaymentResponse) => void\n /** Called after the widget fetches the full machine-readable receipt bundle. */\n onReceiptBundle?: (receipt: SageReceiptBundle) => void\n /** Called when the chat stream reports free vs premium tier. */\n onTier?: (tier: SageChatTier) => void\n /** Called when the widget phase changes. */\n onPhase?: (phase: SagePaymentPhase) => void\n /** Called with a compact state snapshot after important widget events. */\n onStatus?: (status: SagePaymentWidgetStatus) => void\n /** Optional callback fired on fetch or stream errors. */\n onError?: (error: unknown) => void\n}\n\nexport type SagePaymentPhase =\n | \"idle\"\n | \"quoting\"\n | \"payment_required\"\n | \"verifying\"\n | \"streaming\"\n | \"error\"\n\nexport interface SagePaymentInstructions {\n /** Short copy displayed above the Note box input. */\n helperText?: string\n /** Optional link to host payment/wallet instructions. */\n walletUrl?: string\n /** Optional custom label for the Note box input. */\n noteBoxLabel?: string\n}\n\nexport interface SagePaymentWidgetStatus {\n phase: SagePaymentPhase\n tier: SageChatTier | null\n quote: SageQuoteResponse[\"quote\"] | null\n receipt: SageVerifyPaymentResponse | null\n receiptBundle: SageReceiptBundle | null\n error: string | null\n /** Latest chat transcript known to the widget. */\n messages: SageChatMessage[]\n /** Question currently tied to the active quote/payment cycle. */\n activeQuestion: string | null\n}\n\nexport const DEFAULT_API_BASE = \"https://www.ergoblockchain.org\"\nexport const DEFAULT_LIMIT = 5\nexport const DEFAULT_REFRESH_MS = 60_000\n","/**\n * Thin client over /api/sage/activity.\n *\n * Pure fetch + shape — no rendering, no DOM. React + vanilla mounts\n * both call into here so the API contract lives in one place.\n */\n\nimport {\n DEFAULT_API_BASE,\n DEFAULT_LIMIT,\n type SageChatMessage,\n type SageChatStreamEvent,\n type SageChatStreamResult,\n type SageQuote,\n type SageQuoteResponse,\n type SageReceiptBundle,\n type SageTenantConfig,\n type SageVerifyPaymentResponse,\n type SageActivityResponse,\n} from \"./types\"\n\nexport interface FetchActivityOptions {\n apiBase?: string\n limit?: number\n signal?: AbortSignal\n}\n\nexport interface SageRequestOptions {\n apiBase?: string\n tenant?: SageTenantConfig\n headers?: Record<string, string>\n signal?: AbortSignal\n}\n\nexport interface FetchSageQuoteOptions extends SageRequestOptions {\n question: string\n history?: SageChatMessage[]\n}\n\nexport interface VerifySagePaymentOptions extends SageRequestOptions {\n quote: SageQuote\n question: string\n noteBoxId: string\n}\n\nexport interface StreamSageChatOptions extends SageRequestOptions {\n messages: SageChatMessage[]\n paymentToken?: string\n onEvent?: (event: SageChatStreamEvent) => void\n}\n\nexport async function fetchSageActivity(\n opts: FetchActivityOptions = {},\n): Promise<SageActivityResponse> {\n const base = opts.apiBase ?? DEFAULT_API_BASE\n const limit = Math.min(Math.max(opts.limit ?? DEFAULT_LIMIT, 1), 25)\n const url = `${trimSlash(base)}/api/sage/activity?limit=${limit}`\n const res = await fetch(url, { signal: opts.signal })\n if (!res.ok) {\n throw new Error(`sage activity ${res.status}`)\n }\n return (await res.json()) as SageActivityResponse\n}\n\nexport async function fetchSageQuote(\n opts: FetchSageQuoteOptions,\n): Promise<SageQuoteResponse> {\n const res = await fetch(`${apiBase(opts)}/api/sage/quote`, {\n method: \"POST\",\n headers: jsonHeaders(opts),\n body: JSON.stringify({\n question: opts.question,\n history: opts.history ?? [],\n }),\n signal: opts.signal,\n })\n const body = await parseJson(res)\n if (!res.ok) throw new Error(readError(body, `sage quote ${res.status}`))\n return body as SageQuoteResponse\n}\n\nexport async function verifySagePayment(\n opts: VerifySagePaymentOptions,\n): Promise<SageVerifyPaymentResponse> {\n const res = await fetch(`${apiBase(opts)}/api/sage/verify-payment`, {\n method: \"POST\",\n headers: jsonHeaders(opts),\n body: JSON.stringify({\n quote: opts.quote,\n question: opts.question,\n noteBoxId: opts.noteBoxId,\n }),\n signal: opts.signal,\n })\n const body = await parseJson(res)\n if (!res.ok) throw new Error(readError(body, `sage verify-payment ${res.status}`))\n return body as SageVerifyPaymentResponse\n}\n\nexport async function fetchSageReceipt(\n id: string,\n opts: SageRequestOptions = {},\n): Promise<SageReceiptBundle> {\n const res = await fetch(`${apiBase(opts)}/api/sage/receipt/${encodeURIComponent(id)}`, {\n headers: requestHeaders(opts),\n signal: opts.signal,\n })\n const body = await parseJson(res)\n if (!res.ok) throw new Error(readError(body, `sage receipt ${res.status}`))\n return body as SageReceiptBundle\n}\n\nexport function isFullSageReceiptBundle(value: SageReceiptBundle | null | undefined): boolean {\n return value?.ok === true && value.completeness === \"full_receipt_bundle\"\n}\n\nexport async function streamSageChat(\n opts: StreamSageChatOptions,\n): Promise<SageChatStreamResult> {\n const res = await fetch(`${apiBase(opts)}/api/sage/chat`, {\n method: \"POST\",\n headers: jsonHeaders(opts),\n body: JSON.stringify({\n messages: opts.messages,\n ...(opts.paymentToken ? { paymentToken: opts.paymentToken } : {}),\n }),\n signal: opts.signal,\n })\n\n if (res.status === 402) {\n const body = await parseJson(res)\n return {\n ok: false,\n status: res.status,\n text: \"\",\n paymentRequired: body as SageChatStreamResult[\"paymentRequired\"],\n }\n }\n\n if (!res.ok) {\n const body = await parseJson(res)\n return {\n ok: false,\n status: res.status,\n text: \"\",\n error: readError(body, `sage chat ${res.status}`),\n }\n }\n\n if (!res.body) {\n return { ok: false, status: res.status, text: \"\", error: \"Sage chat stream missing body\" }\n }\n\n const reader = res.body.getReader()\n const decoder = new TextDecoder()\n let buffer = \"\"\n let text = \"\"\n let tier: SageChatStreamResult[\"tier\"]\n\n while (true) {\n const { value, done } = await reader.read()\n if (done) break\n buffer += decoder.decode(value, { stream: true })\n const parts = buffer.split(\"\\n\\n\")\n buffer = parts.pop() ?? \"\"\n for (const part of parts) {\n const event = parseSseEvent(part)\n if (!event) continue\n if (event.type === \"delta\") text += event.text\n if (event.type === \"tier\") tier = event.tier\n opts.onEvent?.(event)\n if (event.type === \"error\") {\n return {\n ok: false,\n status: res.status,\n text,\n tier,\n error: event.message,\n }\n }\n }\n }\n\n if (buffer.trim()) {\n const event = parseSseEvent(buffer)\n if (event) {\n if (event.type === \"delta\") text += event.text\n if (event.type === \"tier\") tier = event.tier\n opts.onEvent?.(event)\n if (event.type === \"error\") {\n return {\n ok: false,\n status: res.status,\n text,\n tier,\n error: event.message,\n }\n }\n }\n }\n\n return { ok: true, status: res.status, text, tier }\n}\n\n/** nanoERG → \"0.001\" (trims trailing zeros, max 9 decimals). */\nexport function nanoToErg(nano: number | undefined): string {\n if (!nano || nano <= 0) return \"0\"\n const erg = nano / 1e9\n return erg.toFixed(9).replace(/\\.?0+$/, \"\")\n}\n\n/** Cheap relative-time formatter, ASCII-only, no Intl deps. */\nexport function relativeTime(ms: number, now: number = Date.now()): string {\n const diff = Math.max(0, now - ms)\n const sec = Math.floor(diff / 1000)\n if (sec < 60) return `${sec}s ago`\n const min = Math.floor(sec / 60)\n if (min < 60) return `${min}m ago`\n const hr = Math.floor(min / 60)\n if (hr < 24) return `${hr}h ago`\n const day = Math.floor(hr / 24)\n return `${day}d ago`\n}\n\n/** Receipt URL for a settled tx, given the host base. */\nexport function receiptUrl(txId: string, apiBase: string = DEFAULT_API_BASE): string {\n return `${trimSlash(apiBase)}/r/sage/${txId}`\n}\n\n/** Explorer URL for a tx on the given network. */\nexport function explorerUrl(\n txId: string,\n network: \"testnet\" | \"mainnet\" = \"testnet\",\n): string {\n return network === \"testnet\"\n ? `https://testnet.ergoplatform.com/transactions/${txId}`\n : `https://explorer.ergoplatform.com/transactions/${txId}`\n}\n\nfunction apiBase(opts: SageRequestOptions): string {\n return trimSlash(opts.apiBase ?? DEFAULT_API_BASE)\n}\n\nfunction trimSlash(value: string): string {\n return value.replace(/\\/+$/, \"\")\n}\n\nfunction requestHeaders(opts: SageRequestOptions): Record<string, string> {\n return {\n ...(opts.tenant?.id ? { \"x-sage-tenant-id\": opts.tenant.id } : {}),\n ...(opts.tenant?.headers ?? {}),\n ...(opts.headers ?? {}),\n }\n}\n\nfunction jsonHeaders(opts: SageRequestOptions): Record<string, string> {\n return {\n \"content-type\": \"application/json\",\n ...requestHeaders(opts),\n }\n}\n\nasync function parseJson(res: Response): Promise<unknown> {\n const text = await res.text()\n if (!text) return null\n try {\n return JSON.parse(text)\n } catch {\n return { error: text }\n }\n}\n\nfunction readError(body: unknown, fallback: string): string {\n if (body && typeof body === \"object\" && \"error\" in body) {\n const error = (body as { error?: unknown }).error\n if (typeof error === \"string\") return error\n }\n return fallback\n}\n\nfunction parseSseEvent(raw: string): SageChatStreamEvent | null {\n let eventName = \"message\"\n let data = \"\"\n for (const line of raw.split(\"\\n\")) {\n if (line.startsWith(\"event:\")) eventName = line.slice(\"event:\".length).trim()\n if (line.startsWith(\"data:\")) data += line.slice(\"data:\".length).trim()\n }\n if (!data) return null\n let parsed: Record<string, unknown>\n try {\n parsed = JSON.parse(data) as Record<string, unknown>\n } catch {\n return null\n }\n if (eventName === \"tier\") {\n const tier = parsed.tier === \"premium\" ? \"premium\" : \"free\"\n return {\n type: \"tier\",\n tier,\n ...(typeof parsed.model === \"string\" ? { model: parsed.model } : {}),\n }\n }\n if (eventName === \"delta\" && typeof parsed.text === \"string\") {\n return { type: \"delta\", text: parsed.text }\n }\n if (eventName === \"done\") {\n return {\n type: \"done\",\n ...(typeof parsed.stopReason === \"string\" ? { stopReason: parsed.stopReason } : {}),\n ...(typeof parsed.inputTokens === \"number\" ? { inputTokens: parsed.inputTokens } : {}),\n ...(typeof parsed.outputTokens === \"number\" ? { outputTokens: parsed.outputTokens } : {}),\n }\n }\n if (eventName === \"error\") {\n return {\n type: \"error\",\n message: typeof parsed.message === \"string\" ? parsed.message : \"Sage stream error\",\n }\n }\n return null\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/api.ts"],"names":["apiBase"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Public types for the Sage activity feed and paid chat flow.\n *\n * The source of truth is the API at https://www.ergoblockchain.org/api/sage/activity;\n * this file re-states the schema so consumers don't have to depend on the\n * server-side fetcher.\n */\n\nexport type SageActivityType = \"settlement\" | \"issuance\" | \"transfer\"\n\nexport interface SageActivityEvent {\n /** 64-char hex transaction id. */\n txId: string\n /** Block height at inclusion. */\n blockHeight: number\n /** Block timestamp (ms epoch). */\n timestamp: number\n /** Heuristic classification of the tx. */\n type: SageActivityType\n /** nanoERG flowing into the seller wallet from this tx (sum of outputs). */\n inflowNanoErg: number\n /**\n * For settlements: value of the redeemed Note (= what the buyer paid).\n * For other event types: undefined.\n *\n * Use this — not `inflowNanoErg` — when displaying \"amount paid for a\n * settled query\". `inflowNanoErg` includes change boxes in test setups\n * where the buyer and seller share an address.\n */\n paymentNanoErg?: number\n /** First input box that carries Note-shape registers, if any. */\n noteBoxId?: string\n}\n\nexport interface SageActivityResponse {\n ok: boolean\n network: \"testnet\" | \"mainnet\"\n /** Sage seller wallet address. */\n receiver: string\n /** Total number of txs ever touching the wallet, per the explorer. */\n total: number\n events: SageActivityEvent[]\n error?: string\n}\n\n/**\n * Configuration accepted by every entry point (React component +\n * vanilla mount fn). Defaults below are sensible for the canonical\n * ergoblockchain.org deployment.\n */\nexport interface SageWidgetOptions {\n /**\n * Base URL of the Sage host. Override if you run your own Sage\n * deployment behind a custom domain. Default: ergoblockchain.org.\n */\n apiBase?: string\n /**\n * Number of events to display (max 25). Default: 5.\n */\n limit?: number\n /**\n * Polling interval in ms. Default: 60000 (60s). Set to 0 to disable\n * polling — the widget will fetch once on mount and never refresh.\n */\n refreshMs?: number\n /**\n * Optional callback fired every time a fresh response arrives. Useful\n * for analytics or for triggering host-side animations on new\n * settlements.\n */\n onUpdate?: (response: SageActivityResponse) => void\n /**\n * Optional callback fired on fetch errors. Default: console.warn.\n */\n onError?: (error: unknown) => void\n}\n\nexport type SageChatRole = \"user\" | \"assistant\"\n\nexport interface SageChatMessage {\n role: SageChatRole\n content: string\n}\n\nexport interface SageTenantConfig {\n /** Stable tenant id for analytics, logs, or future multi-tenant routing. */\n id?: string\n /** Human-facing label shown in the default widgets. */\n label?: string\n /** Extra headers attached to Sage API requests. */\n headers?: Record<string, string>\n}\n\nexport type SagePaymentNetwork = \"ergo-testnet\" | \"ergo-mainnet\"\n\nexport interface SageQuote {\n quoteId: string\n taskHash: string\n price: string\n issuedAt?: string\n expiresAt: string\n receiverAddress: string\n reserveBoxId: string\n deadline: `+${number} blocks`\n}\n\nexport type SagePremiumReason =\n | \"explicit_command\"\n | \"code_request\"\n | \"long_answer\"\n | \"deep_research\"\n | \"multi_turn_followup\"\n\nexport interface SageQuoteResponse {\n premium: boolean\n reason?: SagePremiumReason\n rationale?: string\n quote?: SageQuote\n}\n\nexport interface SagePaymentIntent {\n type: \"sage.payment_intent.v1\"\n network: SagePaymentNetwork\n createdAt: string\n question: string\n tenant?: Pick<SageTenantConfig, \"id\" | \"label\">\n quote: SageQuote\n amountErg: string\n receiverAddress: string\n reserveBoxId: string\n taskHash: string\n expiresAt: string\n deadline: `+${number} blocks`\n verifyEndpoint: string\n receiptEndpointTemplate: string\n}\n\nexport interface SageWalletLaunchResult {\n ok: boolean\n /** Note box id produced by a host wallet flow. If present, the widget can prefill verification. */\n noteBoxId?: string\n /** Optional transaction id for host telemetry. Sage verifies by Note box id, not by tx id. */\n txId?: string\n error?: string\n}\n\nexport type SageWalletLauncher = (\n intent: SagePaymentIntent,\n) => Promise<SageWalletLaunchResult | void> | SageWalletLaunchResult | void\n\nexport interface SageVerifyPaymentResponse {\n ok: true\n paymentToken: string\n receiptId: string\n receiptUrl: string\n receiptApiUrl: string\n settlementTxId?: string | null\n accordSettlementId?: string\n receiptStorage?: {\n ok: boolean\n skipped?: boolean\n reason?: string\n path?: string\n aliases?: string[]\n error?: string\n }\n}\n\nexport interface SagePremiumPaymentRequired {\n error: \"premium_payment_required\"\n reason?: SagePremiumReason\n rationale?: string\n}\n\nexport type SageChatTier = \"free\" | \"premium\"\n\nexport type SageChatStreamEvent =\n | { type: \"tier\"; tier: SageChatTier; model?: string }\n | { type: \"delta\"; text: string }\n | { type: \"done\"; stopReason?: string; inputTokens?: number; outputTokens?: number }\n | { type: \"error\"; message: string }\n\nexport interface SageChatStreamResult {\n ok: boolean\n status: number\n text: string\n tier?: SageChatTier\n paymentRequired?: SagePremiumPaymentRequired\n error?: string\n}\n\nexport interface SageReceiptBundle {\n ok: true\n type: \"sage.receipt_bundle.v1\"\n version: \"v1\"\n id: string\n status: \"settled_on_chain\" | \"verified_pending_redemption\"\n completeness: \"full_receipt_bundle\" | \"full\" | \"chain_proof_only\"\n public_receipt_url: string\n api_receipt_url: string\n explorer_url: string | null\n accord?: {\n agreement_hash?: string | null\n verification_receipt_hash?: string | null\n settlement_receipt_hash?: string | null\n agreement_json?: unknown\n verification_receipt_json?: unknown\n settlement_receipt_json?: unknown\n }\n}\n\nexport interface SagePaymentWidgetOptions {\n /**\n * Base URL of the Sage host. Default: ergoblockchain.org.\n */\n apiBase?: string\n /**\n * Optional tenant metadata. Current public Sage ignores tenant routing,\n * but the widget keeps this shape stable for multi-tenant deployments.\n */\n tenant?: SageTenantConfig\n /** Initial chat messages, useful for preloaded context. */\n initialMessages?: SageChatMessage[]\n /** Placeholder text for the default input. */\n placeholder?: string\n /** Widget heading. React also accepts this through component props. */\n title?: string\n /** Optional host-specific payment copy and links. */\n paymentInstructions?: SagePaymentInstructions\n /**\n * Optional wallet launcher supplied by the host app. The package does not\n * sign transactions itself; this callback receives a structured intent that\n * your wallet layer can transform into a testnet Note.\n */\n walletLauncher?: SageWalletLauncher\n /**\n * Show the portable payment intent JSON in the default UI. Default: true.\n * Hosts with a fully custom wallet flow can set this to false.\n */\n showPaymentIntent?: boolean\n /**\n * Testnet safety copy for the default widget. Set to false to hide.\n */\n testnetWarning?: string | false\n /** Called whenever a message is appended by the widget. */\n onMessage?: (message: SageChatMessage, messages: SageChatMessage[]) => void\n /** Called after Sage returns a premium quote. */\n onQuote?: (quote: SageQuoteResponse) => void\n /** Called when a structured payment intent is produced for the active quote. */\n onPaymentIntent?: (intent: SagePaymentIntent) => void\n /** Called after a payment verifies and Sage returns a receipt link. */\n onReceipt?: (receipt: SageVerifyPaymentResponse) => void\n /** Called after the widget fetches the full machine-readable receipt bundle. */\n onReceiptBundle?: (receipt: SageReceiptBundle) => void\n /** Called when the chat stream reports free vs premium tier. */\n onTier?: (tier: SageChatTier) => void\n /** Called when the widget phase changes. */\n onPhase?: (phase: SagePaymentPhase) => void\n /** Called with a compact state snapshot after important widget events. */\n onStatus?: (status: SagePaymentWidgetStatus) => void\n /** Optional callback fired on fetch or stream errors. */\n onError?: (error: unknown) => void\n}\n\nexport type SagePaymentPhase =\n | \"idle\"\n | \"quoting\"\n | \"payment_required\"\n | \"verifying\"\n | \"streaming\"\n | \"error\"\n\nexport interface SagePaymentInstructions {\n /** Short copy displayed above the Note box input. */\n helperText?: string\n /** Optional link to host payment/wallet instructions. */\n walletUrl?: string\n /** Custom label for the wallet launcher button. */\n walletLauncherLabel?: string\n /** Optional custom label for the Note box input. */\n noteBoxLabel?: string\n}\n\nexport interface SagePaymentWidgetStatus {\n phase: SagePaymentPhase\n tier: SageChatTier | null\n quote: SageQuoteResponse[\"quote\"] | null\n paymentIntent: SagePaymentIntent | null\n receipt: SageVerifyPaymentResponse | null\n receiptBundle: SageReceiptBundle | null\n error: string | null\n /** Latest chat transcript known to the widget. */\n messages: SageChatMessage[]\n /** Question currently tied to the active quote/payment cycle. */\n activeQuestion: string | null\n}\n\nexport const DEFAULT_API_BASE = \"https://www.ergoblockchain.org\"\nexport const DEFAULT_LIMIT = 5\nexport const DEFAULT_REFRESH_MS = 60_000\n","/**\n * Thin client over /api/sage/activity.\n *\n * Pure fetch + shape — no rendering, no DOM. React + vanilla mounts\n * both call into here so the API contract lives in one place.\n */\n\nimport {\n DEFAULT_API_BASE,\n DEFAULT_LIMIT,\n type SageChatMessage,\n type SageChatStreamEvent,\n type SageChatStreamResult,\n type SagePaymentIntent,\n type SagePaymentNetwork,\n type SageQuote,\n type SageQuoteResponse,\n type SageReceiptBundle,\n type SageTenantConfig,\n type SageVerifyPaymentResponse,\n type SageActivityResponse,\n} from \"./types\"\n\nexport interface FetchActivityOptions {\n apiBase?: string\n limit?: number\n signal?: AbortSignal\n}\n\nexport interface SageRequestOptions {\n apiBase?: string\n tenant?: SageTenantConfig\n headers?: Record<string, string>\n signal?: AbortSignal\n}\n\nexport interface FetchSageQuoteOptions extends SageRequestOptions {\n question: string\n history?: SageChatMessage[]\n}\n\nexport interface VerifySagePaymentOptions extends SageRequestOptions {\n quote: SageQuote\n question: string\n noteBoxId: string\n}\n\nexport interface CreateSagePaymentIntentOptions {\n quote: SageQuote\n question: string\n apiBase?: string\n tenant?: SageTenantConfig\n network?: SagePaymentNetwork\n createdAt?: string\n}\n\nexport interface StreamSageChatOptions extends SageRequestOptions {\n messages: SageChatMessage[]\n paymentToken?: string\n onEvent?: (event: SageChatStreamEvent) => void\n}\n\nexport async function fetchSageActivity(\n opts: FetchActivityOptions = {},\n): Promise<SageActivityResponse> {\n const base = opts.apiBase ?? DEFAULT_API_BASE\n const limit = Math.min(Math.max(opts.limit ?? DEFAULT_LIMIT, 1), 25)\n const url = `${trimSlash(base)}/api/sage/activity?limit=${limit}`\n const res = await fetch(url, { signal: opts.signal })\n if (!res.ok) {\n throw new Error(`sage activity ${res.status}`)\n }\n return (await res.json()) as SageActivityResponse\n}\n\nexport async function fetchSageQuote(\n opts: FetchSageQuoteOptions,\n): Promise<SageQuoteResponse> {\n const res = await fetch(`${apiBase(opts)}/api/sage/quote`, {\n method: \"POST\",\n headers: jsonHeaders(opts),\n body: JSON.stringify({\n question: opts.question,\n history: opts.history ?? [],\n }),\n signal: opts.signal,\n })\n const body = await parseJson(res)\n if (!res.ok) throw new Error(readError(body, `sage quote ${res.status}`))\n return body as SageQuoteResponse\n}\n\nexport async function verifySagePayment(\n opts: VerifySagePaymentOptions,\n): Promise<SageVerifyPaymentResponse> {\n const res = await fetch(`${apiBase(opts)}/api/sage/verify-payment`, {\n method: \"POST\",\n headers: jsonHeaders(opts),\n body: JSON.stringify({\n quote: opts.quote,\n question: opts.question,\n noteBoxId: opts.noteBoxId,\n }),\n signal: opts.signal,\n })\n const body = await parseJson(res)\n if (!res.ok) throw new Error(readError(body, `sage verify-payment ${res.status}`))\n return body as SageVerifyPaymentResponse\n}\n\nexport async function fetchSageReceipt(\n id: string,\n opts: SageRequestOptions = {},\n): Promise<SageReceiptBundle> {\n const res = await fetch(`${apiBase(opts)}/api/sage/receipt/${encodeURIComponent(id)}`, {\n headers: requestHeaders(opts),\n signal: opts.signal,\n })\n const body = await parseJson(res)\n if (!res.ok) throw new Error(readError(body, `sage receipt ${res.status}`))\n return body as SageReceiptBundle\n}\n\nexport function isFullSageReceiptBundle(value: SageReceiptBundle | null | undefined): boolean {\n return value?.ok === true && value.completeness === \"full_receipt_bundle\"\n}\n\nexport function createSagePaymentIntent(\n opts: CreateSagePaymentIntentOptions,\n): SagePaymentIntent {\n const base = trimSlash(opts.apiBase ?? DEFAULT_API_BASE)\n return {\n type: \"sage.payment_intent.v1\",\n network: opts.network ?? \"ergo-testnet\",\n createdAt: opts.createdAt ?? new Date().toISOString(),\n question: opts.question,\n ...(opts.tenant?.id || opts.tenant?.label\n ? { tenant: { id: opts.tenant.id, label: opts.tenant.label } }\n : {}),\n quote: opts.quote,\n amountErg: opts.quote.price,\n receiverAddress: opts.quote.receiverAddress,\n reserveBoxId: opts.quote.reserveBoxId,\n taskHash: opts.quote.taskHash,\n expiresAt: opts.quote.expiresAt,\n deadline: opts.quote.deadline,\n verifyEndpoint: `${base}/api/sage/verify-payment`,\n receiptEndpointTemplate: `${base}/api/sage/receipt/{receiptId}`,\n }\n}\n\nexport function serializeSagePaymentIntent(intent: SagePaymentIntent): string {\n return JSON.stringify(intent, null, 2)\n}\n\nexport async function streamSageChat(\n opts: StreamSageChatOptions,\n): Promise<SageChatStreamResult> {\n const res = await fetch(`${apiBase(opts)}/api/sage/chat`, {\n method: \"POST\",\n headers: jsonHeaders(opts),\n body: JSON.stringify({\n messages: opts.messages,\n ...(opts.paymentToken ? { paymentToken: opts.paymentToken } : {}),\n }),\n signal: opts.signal,\n })\n\n if (res.status === 402) {\n const body = await parseJson(res)\n return {\n ok: false,\n status: res.status,\n text: \"\",\n paymentRequired: body as SageChatStreamResult[\"paymentRequired\"],\n }\n }\n\n if (!res.ok) {\n const body = await parseJson(res)\n return {\n ok: false,\n status: res.status,\n text: \"\",\n error: readError(body, `sage chat ${res.status}`),\n }\n }\n\n if (!res.body) {\n return { ok: false, status: res.status, text: \"\", error: \"Sage chat stream missing body\" }\n }\n\n const reader = res.body.getReader()\n const decoder = new TextDecoder()\n let buffer = \"\"\n let text = \"\"\n let tier: SageChatStreamResult[\"tier\"]\n\n while (true) {\n const { value, done } = await reader.read()\n if (done) break\n buffer += decoder.decode(value, { stream: true })\n const parts = buffer.split(\"\\n\\n\")\n buffer = parts.pop() ?? \"\"\n for (const part of parts) {\n const event = parseSseEvent(part)\n if (!event) continue\n if (event.type === \"delta\") text += event.text\n if (event.type === \"tier\") tier = event.tier\n opts.onEvent?.(event)\n if (event.type === \"error\") {\n return {\n ok: false,\n status: res.status,\n text,\n tier,\n error: event.message,\n }\n }\n }\n }\n\n if (buffer.trim()) {\n const event = parseSseEvent(buffer)\n if (event) {\n if (event.type === \"delta\") text += event.text\n if (event.type === \"tier\") tier = event.tier\n opts.onEvent?.(event)\n if (event.type === \"error\") {\n return {\n ok: false,\n status: res.status,\n text,\n tier,\n error: event.message,\n }\n }\n }\n }\n\n return { ok: true, status: res.status, text, tier }\n}\n\n/** nanoERG → \"0.001\" (trims trailing zeros, max 9 decimals). */\nexport function nanoToErg(nano: number | undefined): string {\n if (!nano || nano <= 0) return \"0\"\n const erg = nano / 1e9\n return erg.toFixed(9).replace(/\\.?0+$/, \"\")\n}\n\n/** Cheap relative-time formatter, ASCII-only, no Intl deps. */\nexport function relativeTime(ms: number, now: number = Date.now()): string {\n const diff = Math.max(0, now - ms)\n const sec = Math.floor(diff / 1000)\n if (sec < 60) return `${sec}s ago`\n const min = Math.floor(sec / 60)\n if (min < 60) return `${min}m ago`\n const hr = Math.floor(min / 60)\n if (hr < 24) return `${hr}h ago`\n const day = Math.floor(hr / 24)\n return `${day}d ago`\n}\n\n/** Receipt URL for a settled tx, given the host base. */\nexport function receiptUrl(txId: string, apiBase: string = DEFAULT_API_BASE): string {\n return `${trimSlash(apiBase)}/r/sage/${txId}`\n}\n\n/** Explorer URL for a tx on the given network. */\nexport function explorerUrl(\n txId: string,\n network: \"testnet\" | \"mainnet\" = \"testnet\",\n): string {\n return network === \"testnet\"\n ? `https://testnet.ergoplatform.com/transactions/${txId}`\n : `https://explorer.ergoplatform.com/transactions/${txId}`\n}\n\nfunction apiBase(opts: SageRequestOptions): string {\n return trimSlash(opts.apiBase ?? DEFAULT_API_BASE)\n}\n\nfunction trimSlash(value: string): string {\n return value.replace(/\\/+$/, \"\")\n}\n\nfunction requestHeaders(opts: SageRequestOptions): Record<string, string> {\n return {\n ...(opts.tenant?.id ? { \"x-sage-tenant-id\": opts.tenant.id } : {}),\n ...(opts.tenant?.headers ?? {}),\n ...(opts.headers ?? {}),\n }\n}\n\nfunction jsonHeaders(opts: SageRequestOptions): Record<string, string> {\n return {\n \"content-type\": \"application/json\",\n ...requestHeaders(opts),\n }\n}\n\nasync function parseJson(res: Response): Promise<unknown> {\n const text = await res.text()\n if (!text) return null\n try {\n return JSON.parse(text)\n } catch {\n return { error: text }\n }\n}\n\nfunction readError(body: unknown, fallback: string): string {\n if (body && typeof body === \"object\" && \"error\" in body) {\n const error = (body as { error?: unknown }).error\n if (typeof error === \"string\") return error\n }\n return fallback\n}\n\nfunction parseSseEvent(raw: string): SageChatStreamEvent | null {\n let eventName = \"message\"\n let data = \"\"\n for (const line of raw.split(\"\\n\")) {\n if (line.startsWith(\"event:\")) eventName = line.slice(\"event:\".length).trim()\n if (line.startsWith(\"data:\")) data += line.slice(\"data:\".length).trim()\n }\n if (!data) return null\n let parsed: Record<string, unknown>\n try {\n parsed = JSON.parse(data) as Record<string, unknown>\n } catch {\n return null\n }\n if (eventName === \"tier\") {\n const tier = parsed.tier === \"premium\" ? \"premium\" : \"free\"\n return {\n type: \"tier\",\n tier,\n ...(typeof parsed.model === \"string\" ? { model: parsed.model } : {}),\n }\n }\n if (eventName === \"delta\" && typeof parsed.text === \"string\") {\n return { type: \"delta\", text: parsed.text }\n }\n if (eventName === \"done\") {\n return {\n type: \"done\",\n ...(typeof parsed.stopReason === \"string\" ? { stopReason: parsed.stopReason } : {}),\n ...(typeof parsed.inputTokens === \"number\" ? { inputTokens: parsed.inputTokens } : {}),\n ...(typeof parsed.outputTokens === \"number\" ? { outputTokens: parsed.outputTokens } : {}),\n }\n }\n if (eventName === \"error\") {\n return {\n type: \"error\",\n message: typeof parsed.message === \"string\" ? parsed.message : \"Sage stream error\",\n }\n }\n return null\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { D as DEFAULT_API_BASE, a as DEFAULT_LIMIT, b as DEFAULT_REFRESH_MS, S as SageActivityEvent, d as SageActivityType, f as SageChatRole, i as SageChatTier, j as SagePaymentInstructions,
|
|
1
|
+
import { r as SageQuote, u as SageTenantConfig, l as SagePaymentNetwork, k as SagePaymentIntent, c as SageActivityResponse, e as SageChatMessage, s as SageQuoteResponse, t as SageReceiptBundle, g as SageChatStreamEvent, h as SageChatStreamResult, v as SageVerifyPaymentResponse } from './types-B5V2rsYn.cjs';
|
|
2
|
+
export { D as DEFAULT_API_BASE, a as DEFAULT_LIMIT, b as DEFAULT_REFRESH_MS, S as SageActivityEvent, d as SageActivityType, f as SageChatRole, i as SageChatTier, j as SagePaymentInstructions, m as SagePaymentPhase, n as SagePaymentWidgetOptions, o as SagePaymentWidgetStatus, p as SagePremiumPaymentRequired, q as SagePremiumReason, w as SageWalletLaunchResult, x as SageWalletLauncher, y as SageWidgetOptions } from './types-B5V2rsYn.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Thin client over /api/sage/activity.
|
|
@@ -28,6 +28,14 @@ interface VerifySagePaymentOptions extends SageRequestOptions {
|
|
|
28
28
|
question: string;
|
|
29
29
|
noteBoxId: string;
|
|
30
30
|
}
|
|
31
|
+
interface CreateSagePaymentIntentOptions {
|
|
32
|
+
quote: SageQuote;
|
|
33
|
+
question: string;
|
|
34
|
+
apiBase?: string;
|
|
35
|
+
tenant?: SageTenantConfig;
|
|
36
|
+
network?: SagePaymentNetwork;
|
|
37
|
+
createdAt?: string;
|
|
38
|
+
}
|
|
31
39
|
interface StreamSageChatOptions extends SageRequestOptions {
|
|
32
40
|
messages: SageChatMessage[];
|
|
33
41
|
paymentToken?: string;
|
|
@@ -38,6 +46,8 @@ declare function fetchSageQuote(opts: FetchSageQuoteOptions): Promise<SageQuoteR
|
|
|
38
46
|
declare function verifySagePayment(opts: VerifySagePaymentOptions): Promise<SageVerifyPaymentResponse>;
|
|
39
47
|
declare function fetchSageReceipt(id: string, opts?: SageRequestOptions): Promise<SageReceiptBundle>;
|
|
40
48
|
declare function isFullSageReceiptBundle(value: SageReceiptBundle | null | undefined): boolean;
|
|
49
|
+
declare function createSagePaymentIntent(opts: CreateSagePaymentIntentOptions): SagePaymentIntent;
|
|
50
|
+
declare function serializeSagePaymentIntent(intent: SagePaymentIntent): string;
|
|
41
51
|
declare function streamSageChat(opts: StreamSageChatOptions): Promise<SageChatStreamResult>;
|
|
42
52
|
/** nanoERG → "0.001" (trims trailing zeros, max 9 decimals). */
|
|
43
53
|
declare function nanoToErg(nano: number | undefined): string;
|
|
@@ -48,4 +58,4 @@ declare function receiptUrl(txId: string, apiBase?: string): string;
|
|
|
48
58
|
/** Explorer URL for a tx on the given network. */
|
|
49
59
|
declare function explorerUrl(txId: string, network?: "testnet" | "mainnet"): string;
|
|
50
60
|
|
|
51
|
-
export { SageActivityResponse, SageChatMessage, SageChatStreamEvent, SageChatStreamResult, SageQuote, SageQuoteResponse, SageReceiptBundle, SageTenantConfig, SageVerifyPaymentResponse, explorerUrl, fetchSageActivity, fetchSageQuote, fetchSageReceipt, isFullSageReceiptBundle, nanoToErg, receiptUrl, relativeTime, streamSageChat, verifySagePayment };
|
|
61
|
+
export { SageActivityResponse, SageChatMessage, SageChatStreamEvent, SageChatStreamResult, SagePaymentIntent, SagePaymentNetwork, SageQuote, SageQuoteResponse, SageReceiptBundle, SageTenantConfig, SageVerifyPaymentResponse, createSagePaymentIntent, explorerUrl, fetchSageActivity, fetchSageQuote, fetchSageReceipt, isFullSageReceiptBundle, nanoToErg, receiptUrl, relativeTime, serializeSagePaymentIntent, streamSageChat, verifySagePayment };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { D as DEFAULT_API_BASE, a as DEFAULT_LIMIT, b as DEFAULT_REFRESH_MS, S as SageActivityEvent, d as SageActivityType, f as SageChatRole, i as SageChatTier, j as SagePaymentInstructions,
|
|
1
|
+
import { r as SageQuote, u as SageTenantConfig, l as SagePaymentNetwork, k as SagePaymentIntent, c as SageActivityResponse, e as SageChatMessage, s as SageQuoteResponse, t as SageReceiptBundle, g as SageChatStreamEvent, h as SageChatStreamResult, v as SageVerifyPaymentResponse } from './types-B5V2rsYn.js';
|
|
2
|
+
export { D as DEFAULT_API_BASE, a as DEFAULT_LIMIT, b as DEFAULT_REFRESH_MS, S as SageActivityEvent, d as SageActivityType, f as SageChatRole, i as SageChatTier, j as SagePaymentInstructions, m as SagePaymentPhase, n as SagePaymentWidgetOptions, o as SagePaymentWidgetStatus, p as SagePremiumPaymentRequired, q as SagePremiumReason, w as SageWalletLaunchResult, x as SageWalletLauncher, y as SageWidgetOptions } from './types-B5V2rsYn.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Thin client over /api/sage/activity.
|
|
@@ -28,6 +28,14 @@ interface VerifySagePaymentOptions extends SageRequestOptions {
|
|
|
28
28
|
question: string;
|
|
29
29
|
noteBoxId: string;
|
|
30
30
|
}
|
|
31
|
+
interface CreateSagePaymentIntentOptions {
|
|
32
|
+
quote: SageQuote;
|
|
33
|
+
question: string;
|
|
34
|
+
apiBase?: string;
|
|
35
|
+
tenant?: SageTenantConfig;
|
|
36
|
+
network?: SagePaymentNetwork;
|
|
37
|
+
createdAt?: string;
|
|
38
|
+
}
|
|
31
39
|
interface StreamSageChatOptions extends SageRequestOptions {
|
|
32
40
|
messages: SageChatMessage[];
|
|
33
41
|
paymentToken?: string;
|
|
@@ -38,6 +46,8 @@ declare function fetchSageQuote(opts: FetchSageQuoteOptions): Promise<SageQuoteR
|
|
|
38
46
|
declare function verifySagePayment(opts: VerifySagePaymentOptions): Promise<SageVerifyPaymentResponse>;
|
|
39
47
|
declare function fetchSageReceipt(id: string, opts?: SageRequestOptions): Promise<SageReceiptBundle>;
|
|
40
48
|
declare function isFullSageReceiptBundle(value: SageReceiptBundle | null | undefined): boolean;
|
|
49
|
+
declare function createSagePaymentIntent(opts: CreateSagePaymentIntentOptions): SagePaymentIntent;
|
|
50
|
+
declare function serializeSagePaymentIntent(intent: SagePaymentIntent): string;
|
|
41
51
|
declare function streamSageChat(opts: StreamSageChatOptions): Promise<SageChatStreamResult>;
|
|
42
52
|
/** nanoERG → "0.001" (trims trailing zeros, max 9 decimals). */
|
|
43
53
|
declare function nanoToErg(nano: number | undefined): string;
|
|
@@ -48,4 +58,4 @@ declare function receiptUrl(txId: string, apiBase?: string): string;
|
|
|
48
58
|
/** Explorer URL for a tx on the given network. */
|
|
49
59
|
declare function explorerUrl(txId: string, network?: "testnet" | "mainnet"): string;
|
|
50
60
|
|
|
51
|
-
export { SageActivityResponse, SageChatMessage, SageChatStreamEvent, SageChatStreamResult, SageQuote, SageQuoteResponse, SageReceiptBundle, SageTenantConfig, SageVerifyPaymentResponse, explorerUrl, fetchSageActivity, fetchSageQuote, fetchSageReceipt, isFullSageReceiptBundle, nanoToErg, receiptUrl, relativeTime, streamSageChat, verifySagePayment };
|
|
61
|
+
export { SageActivityResponse, SageChatMessage, SageChatStreamEvent, SageChatStreamResult, SagePaymentIntent, SagePaymentNetwork, SageQuote, SageQuoteResponse, SageReceiptBundle, SageTenantConfig, SageVerifyPaymentResponse, createSagePaymentIntent, explorerUrl, fetchSageActivity, fetchSageQuote, fetchSageReceipt, isFullSageReceiptBundle, nanoToErg, receiptUrl, relativeTime, serializeSagePaymentIntent, streamSageChat, verifySagePayment };
|
package/dist/index.js
CHANGED
|
@@ -55,6 +55,28 @@ async function fetchSageReceipt(id, opts = {}) {
|
|
|
55
55
|
function isFullSageReceiptBundle(value) {
|
|
56
56
|
return value?.ok === true && value.completeness === "full_receipt_bundle";
|
|
57
57
|
}
|
|
58
|
+
function createSagePaymentIntent(opts) {
|
|
59
|
+
const base = trimSlash(opts.apiBase ?? DEFAULT_API_BASE);
|
|
60
|
+
return {
|
|
61
|
+
type: "sage.payment_intent.v1",
|
|
62
|
+
network: opts.network ?? "ergo-testnet",
|
|
63
|
+
createdAt: opts.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
64
|
+
question: opts.question,
|
|
65
|
+
...opts.tenant?.id || opts.tenant?.label ? { tenant: { id: opts.tenant.id, label: opts.tenant.label } } : {},
|
|
66
|
+
quote: opts.quote,
|
|
67
|
+
amountErg: opts.quote.price,
|
|
68
|
+
receiverAddress: opts.quote.receiverAddress,
|
|
69
|
+
reserveBoxId: opts.quote.reserveBoxId,
|
|
70
|
+
taskHash: opts.quote.taskHash,
|
|
71
|
+
expiresAt: opts.quote.expiresAt,
|
|
72
|
+
deadline: opts.quote.deadline,
|
|
73
|
+
verifyEndpoint: `${base}/api/sage/verify-payment`,
|
|
74
|
+
receiptEndpointTemplate: `${base}/api/sage/receipt/{receiptId}`
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function serializeSagePaymentIntent(intent) {
|
|
78
|
+
return JSON.stringify(intent, null, 2);
|
|
79
|
+
}
|
|
58
80
|
async function streamSageChat(opts) {
|
|
59
81
|
const res = await fetch(`${apiBase(opts)}/api/sage/chat`, {
|
|
60
82
|
method: "POST",
|
|
@@ -232,6 +254,6 @@ function parseSseEvent(raw) {
|
|
|
232
254
|
return null;
|
|
233
255
|
}
|
|
234
256
|
|
|
235
|
-
export { DEFAULT_API_BASE, DEFAULT_LIMIT, DEFAULT_REFRESH_MS, explorerUrl, fetchSageActivity, fetchSageQuote, fetchSageReceipt, isFullSageReceiptBundle, nanoToErg, receiptUrl, relativeTime, streamSageChat, verifySagePayment };
|
|
257
|
+
export { DEFAULT_API_BASE, DEFAULT_LIMIT, DEFAULT_REFRESH_MS, createSagePaymentIntent, explorerUrl, fetchSageActivity, fetchSageQuote, fetchSageReceipt, isFullSageReceiptBundle, nanoToErg, receiptUrl, relativeTime, serializeSagePaymentIntent, streamSageChat, verifySagePayment };
|
|
236
258
|
//# sourceMappingURL=index.js.map
|
|
237
259
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/api.ts"],"names":["apiBase"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Public types for the Sage activity feed and paid chat flow.\n *\n * The source of truth is the API at https://www.ergoblockchain.org/api/sage/activity;\n * this file re-states the schema so consumers don't have to depend on the\n * server-side fetcher.\n */\n\nexport type SageActivityType = \"settlement\" | \"issuance\" | \"transfer\"\n\nexport interface SageActivityEvent {\n /** 64-char hex transaction id. */\n txId: string\n /** Block height at inclusion. */\n blockHeight: number\n /** Block timestamp (ms epoch). */\n timestamp: number\n /** Heuristic classification of the tx. */\n type: SageActivityType\n /** nanoERG flowing into the seller wallet from this tx (sum of outputs). */\n inflowNanoErg: number\n /**\n * For settlements: value of the redeemed Note (= what the buyer paid).\n * For other event types: undefined.\n *\n * Use this — not `inflowNanoErg` — when displaying \"amount paid for a\n * settled query\". `inflowNanoErg` includes change boxes in test setups\n * where the buyer and seller share an address.\n */\n paymentNanoErg?: number\n /** First input box that carries Note-shape registers, if any. */\n noteBoxId?: string\n}\n\nexport interface SageActivityResponse {\n ok: boolean\n network: \"testnet\" | \"mainnet\"\n /** Sage seller wallet address. */\n receiver: string\n /** Total number of txs ever touching the wallet, per the explorer. */\n total: number\n events: SageActivityEvent[]\n error?: string\n}\n\n/**\n * Configuration accepted by every entry point (React component +\n * vanilla mount fn). Defaults below are sensible for the canonical\n * ergoblockchain.org deployment.\n */\nexport interface SageWidgetOptions {\n /**\n * Base URL of the Sage host. Override if you run your own Sage\n * deployment behind a custom domain. Default: ergoblockchain.org.\n */\n apiBase?: string\n /**\n * Number of events to display (max 25). Default: 5.\n */\n limit?: number\n /**\n * Polling interval in ms. Default: 60000 (60s). Set to 0 to disable\n * polling — the widget will fetch once on mount and never refresh.\n */\n refreshMs?: number\n /**\n * Optional callback fired every time a fresh response arrives. Useful\n * for analytics or for triggering host-side animations on new\n * settlements.\n */\n onUpdate?: (response: SageActivityResponse) => void\n /**\n * Optional callback fired on fetch errors. Default: console.warn.\n */\n onError?: (error: unknown) => void\n}\n\nexport type SageChatRole = \"user\" | \"assistant\"\n\nexport interface SageChatMessage {\n role: SageChatRole\n content: string\n}\n\nexport interface SageTenantConfig {\n /** Stable tenant id for analytics, logs, or future multi-tenant routing. */\n id?: string\n /** Human-facing label shown in the default widgets. */\n label?: string\n /** Extra headers attached to Sage API requests. */\n headers?: Record<string, string>\n}\n\nexport interface SageQuote {\n quoteId: string\n taskHash: string\n price: string\n issuedAt?: string\n expiresAt: string\n receiverAddress: string\n reserveBoxId: string\n deadline: `+${number} blocks`\n}\n\nexport type SagePremiumReason =\n | \"explicit_command\"\n | \"code_request\"\n | \"long_answer\"\n | \"deep_research\"\n | \"multi_turn_followup\"\n\nexport interface SageQuoteResponse {\n premium: boolean\n reason?: SagePremiumReason\n rationale?: string\n quote?: SageQuote\n}\n\nexport interface SageVerifyPaymentResponse {\n ok: true\n paymentToken: string\n receiptId: string\n receiptUrl: string\n receiptApiUrl: string\n settlementTxId?: string | null\n accordSettlementId?: string\n receiptStorage?: {\n ok: boolean\n skipped?: boolean\n reason?: string\n path?: string\n aliases?: string[]\n error?: string\n }\n}\n\nexport interface SagePremiumPaymentRequired {\n error: \"premium_payment_required\"\n reason?: SagePremiumReason\n rationale?: string\n}\n\nexport type SageChatTier = \"free\" | \"premium\"\n\nexport type SageChatStreamEvent =\n | { type: \"tier\"; tier: SageChatTier; model?: string }\n | { type: \"delta\"; text: string }\n | { type: \"done\"; stopReason?: string; inputTokens?: number; outputTokens?: number }\n | { type: \"error\"; message: string }\n\nexport interface SageChatStreamResult {\n ok: boolean\n status: number\n text: string\n tier?: SageChatTier\n paymentRequired?: SagePremiumPaymentRequired\n error?: string\n}\n\nexport interface SageReceiptBundle {\n ok: true\n type: \"sage.receipt_bundle.v1\"\n version: \"v1\"\n id: string\n status: \"settled_on_chain\" | \"verified_pending_redemption\"\n completeness: \"full_receipt_bundle\" | \"full\" | \"chain_proof_only\"\n public_receipt_url: string\n api_receipt_url: string\n explorer_url: string | null\n accord?: {\n agreement_hash?: string | null\n verification_receipt_hash?: string | null\n settlement_receipt_hash?: string | null\n agreement_json?: unknown\n verification_receipt_json?: unknown\n settlement_receipt_json?: unknown\n }\n}\n\nexport interface SagePaymentWidgetOptions {\n /**\n * Base URL of the Sage host. Default: ergoblockchain.org.\n */\n apiBase?: string\n /**\n * Optional tenant metadata. Current public Sage ignores tenant routing,\n * but the widget keeps this shape stable for multi-tenant deployments.\n */\n tenant?: SageTenantConfig\n /** Initial chat messages, useful for preloaded context. */\n initialMessages?: SageChatMessage[]\n /** Placeholder text for the default input. */\n placeholder?: string\n /** Widget heading. React also accepts this through component props. */\n title?: string\n /** Optional host-specific payment copy and links. */\n paymentInstructions?: SagePaymentInstructions\n /** Called whenever a message is appended by the widget. */\n onMessage?: (message: SageChatMessage, messages: SageChatMessage[]) => void\n /** Called after Sage returns a premium quote. */\n onQuote?: (quote: SageQuoteResponse) => void\n /** Called after a payment verifies and Sage returns a receipt link. */\n onReceipt?: (receipt: SageVerifyPaymentResponse) => void\n /** Called after the widget fetches the full machine-readable receipt bundle. */\n onReceiptBundle?: (receipt: SageReceiptBundle) => void\n /** Called when the chat stream reports free vs premium tier. */\n onTier?: (tier: SageChatTier) => void\n /** Called when the widget phase changes. */\n onPhase?: (phase: SagePaymentPhase) => void\n /** Called with a compact state snapshot after important widget events. */\n onStatus?: (status: SagePaymentWidgetStatus) => void\n /** Optional callback fired on fetch or stream errors. */\n onError?: (error: unknown) => void\n}\n\nexport type SagePaymentPhase =\n | \"idle\"\n | \"quoting\"\n | \"payment_required\"\n | \"verifying\"\n | \"streaming\"\n | \"error\"\n\nexport interface SagePaymentInstructions {\n /** Short copy displayed above the Note box input. */\n helperText?: string\n /** Optional link to host payment/wallet instructions. */\n walletUrl?: string\n /** Optional custom label for the Note box input. */\n noteBoxLabel?: string\n}\n\nexport interface SagePaymentWidgetStatus {\n phase: SagePaymentPhase\n tier: SageChatTier | null\n quote: SageQuoteResponse[\"quote\"] | null\n receipt: SageVerifyPaymentResponse | null\n receiptBundle: SageReceiptBundle | null\n error: string | null\n /** Latest chat transcript known to the widget. */\n messages: SageChatMessage[]\n /** Question currently tied to the active quote/payment cycle. */\n activeQuestion: string | null\n}\n\nexport const DEFAULT_API_BASE = \"https://www.ergoblockchain.org\"\nexport const DEFAULT_LIMIT = 5\nexport const DEFAULT_REFRESH_MS = 60_000\n","/**\n * Thin client over /api/sage/activity.\n *\n * Pure fetch + shape — no rendering, no DOM. React + vanilla mounts\n * both call into here so the API contract lives in one place.\n */\n\nimport {\n DEFAULT_API_BASE,\n DEFAULT_LIMIT,\n type SageChatMessage,\n type SageChatStreamEvent,\n type SageChatStreamResult,\n type SageQuote,\n type SageQuoteResponse,\n type SageReceiptBundle,\n type SageTenantConfig,\n type SageVerifyPaymentResponse,\n type SageActivityResponse,\n} from \"./types\"\n\nexport interface FetchActivityOptions {\n apiBase?: string\n limit?: number\n signal?: AbortSignal\n}\n\nexport interface SageRequestOptions {\n apiBase?: string\n tenant?: SageTenantConfig\n headers?: Record<string, string>\n signal?: AbortSignal\n}\n\nexport interface FetchSageQuoteOptions extends SageRequestOptions {\n question: string\n history?: SageChatMessage[]\n}\n\nexport interface VerifySagePaymentOptions extends SageRequestOptions {\n quote: SageQuote\n question: string\n noteBoxId: string\n}\n\nexport interface StreamSageChatOptions extends SageRequestOptions {\n messages: SageChatMessage[]\n paymentToken?: string\n onEvent?: (event: SageChatStreamEvent) => void\n}\n\nexport async function fetchSageActivity(\n opts: FetchActivityOptions = {},\n): Promise<SageActivityResponse> {\n const base = opts.apiBase ?? DEFAULT_API_BASE\n const limit = Math.min(Math.max(opts.limit ?? DEFAULT_LIMIT, 1), 25)\n const url = `${trimSlash(base)}/api/sage/activity?limit=${limit}`\n const res = await fetch(url, { signal: opts.signal })\n if (!res.ok) {\n throw new Error(`sage activity ${res.status}`)\n }\n return (await res.json()) as SageActivityResponse\n}\n\nexport async function fetchSageQuote(\n opts: FetchSageQuoteOptions,\n): Promise<SageQuoteResponse> {\n const res = await fetch(`${apiBase(opts)}/api/sage/quote`, {\n method: \"POST\",\n headers: jsonHeaders(opts),\n body: JSON.stringify({\n question: opts.question,\n history: opts.history ?? [],\n }),\n signal: opts.signal,\n })\n const body = await parseJson(res)\n if (!res.ok) throw new Error(readError(body, `sage quote ${res.status}`))\n return body as SageQuoteResponse\n}\n\nexport async function verifySagePayment(\n opts: VerifySagePaymentOptions,\n): Promise<SageVerifyPaymentResponse> {\n const res = await fetch(`${apiBase(opts)}/api/sage/verify-payment`, {\n method: \"POST\",\n headers: jsonHeaders(opts),\n body: JSON.stringify({\n quote: opts.quote,\n question: opts.question,\n noteBoxId: opts.noteBoxId,\n }),\n signal: opts.signal,\n })\n const body = await parseJson(res)\n if (!res.ok) throw new Error(readError(body, `sage verify-payment ${res.status}`))\n return body as SageVerifyPaymentResponse\n}\n\nexport async function fetchSageReceipt(\n id: string,\n opts: SageRequestOptions = {},\n): Promise<SageReceiptBundle> {\n const res = await fetch(`${apiBase(opts)}/api/sage/receipt/${encodeURIComponent(id)}`, {\n headers: requestHeaders(opts),\n signal: opts.signal,\n })\n const body = await parseJson(res)\n if (!res.ok) throw new Error(readError(body, `sage receipt ${res.status}`))\n return body as SageReceiptBundle\n}\n\nexport function isFullSageReceiptBundle(value: SageReceiptBundle | null | undefined): boolean {\n return value?.ok === true && value.completeness === \"full_receipt_bundle\"\n}\n\nexport async function streamSageChat(\n opts: StreamSageChatOptions,\n): Promise<SageChatStreamResult> {\n const res = await fetch(`${apiBase(opts)}/api/sage/chat`, {\n method: \"POST\",\n headers: jsonHeaders(opts),\n body: JSON.stringify({\n messages: opts.messages,\n ...(opts.paymentToken ? { paymentToken: opts.paymentToken } : {}),\n }),\n signal: opts.signal,\n })\n\n if (res.status === 402) {\n const body = await parseJson(res)\n return {\n ok: false,\n status: res.status,\n text: \"\",\n paymentRequired: body as SageChatStreamResult[\"paymentRequired\"],\n }\n }\n\n if (!res.ok) {\n const body = await parseJson(res)\n return {\n ok: false,\n status: res.status,\n text: \"\",\n error: readError(body, `sage chat ${res.status}`),\n }\n }\n\n if (!res.body) {\n return { ok: false, status: res.status, text: \"\", error: \"Sage chat stream missing body\" }\n }\n\n const reader = res.body.getReader()\n const decoder = new TextDecoder()\n let buffer = \"\"\n let text = \"\"\n let tier: SageChatStreamResult[\"tier\"]\n\n while (true) {\n const { value, done } = await reader.read()\n if (done) break\n buffer += decoder.decode(value, { stream: true })\n const parts = buffer.split(\"\\n\\n\")\n buffer = parts.pop() ?? \"\"\n for (const part of parts) {\n const event = parseSseEvent(part)\n if (!event) continue\n if (event.type === \"delta\") text += event.text\n if (event.type === \"tier\") tier = event.tier\n opts.onEvent?.(event)\n if (event.type === \"error\") {\n return {\n ok: false,\n status: res.status,\n text,\n tier,\n error: event.message,\n }\n }\n }\n }\n\n if (buffer.trim()) {\n const event = parseSseEvent(buffer)\n if (event) {\n if (event.type === \"delta\") text += event.text\n if (event.type === \"tier\") tier = event.tier\n opts.onEvent?.(event)\n if (event.type === \"error\") {\n return {\n ok: false,\n status: res.status,\n text,\n tier,\n error: event.message,\n }\n }\n }\n }\n\n return { ok: true, status: res.status, text, tier }\n}\n\n/** nanoERG → \"0.001\" (trims trailing zeros, max 9 decimals). */\nexport function nanoToErg(nano: number | undefined): string {\n if (!nano || nano <= 0) return \"0\"\n const erg = nano / 1e9\n return erg.toFixed(9).replace(/\\.?0+$/, \"\")\n}\n\n/** Cheap relative-time formatter, ASCII-only, no Intl deps. */\nexport function relativeTime(ms: number, now: number = Date.now()): string {\n const diff = Math.max(0, now - ms)\n const sec = Math.floor(diff / 1000)\n if (sec < 60) return `${sec}s ago`\n const min = Math.floor(sec / 60)\n if (min < 60) return `${min}m ago`\n const hr = Math.floor(min / 60)\n if (hr < 24) return `${hr}h ago`\n const day = Math.floor(hr / 24)\n return `${day}d ago`\n}\n\n/** Receipt URL for a settled tx, given the host base. */\nexport function receiptUrl(txId: string, apiBase: string = DEFAULT_API_BASE): string {\n return `${trimSlash(apiBase)}/r/sage/${txId}`\n}\n\n/** Explorer URL for a tx on the given network. */\nexport function explorerUrl(\n txId: string,\n network: \"testnet\" | \"mainnet\" = \"testnet\",\n): string {\n return network === \"testnet\"\n ? `https://testnet.ergoplatform.com/transactions/${txId}`\n : `https://explorer.ergoplatform.com/transactions/${txId}`\n}\n\nfunction apiBase(opts: SageRequestOptions): string {\n return trimSlash(opts.apiBase ?? DEFAULT_API_BASE)\n}\n\nfunction trimSlash(value: string): string {\n return value.replace(/\\/+$/, \"\")\n}\n\nfunction requestHeaders(opts: SageRequestOptions): Record<string, string> {\n return {\n ...(opts.tenant?.id ? { \"x-sage-tenant-id\": opts.tenant.id } : {}),\n ...(opts.tenant?.headers ?? {}),\n ...(opts.headers ?? {}),\n }\n}\n\nfunction jsonHeaders(opts: SageRequestOptions): Record<string, string> {\n return {\n \"content-type\": \"application/json\",\n ...requestHeaders(opts),\n }\n}\n\nasync function parseJson(res: Response): Promise<unknown> {\n const text = await res.text()\n if (!text) return null\n try {\n return JSON.parse(text)\n } catch {\n return { error: text }\n }\n}\n\nfunction readError(body: unknown, fallback: string): string {\n if (body && typeof body === \"object\" && \"error\" in body) {\n const error = (body as { error?: unknown }).error\n if (typeof error === \"string\") return error\n }\n return fallback\n}\n\nfunction parseSseEvent(raw: string): SageChatStreamEvent | null {\n let eventName = \"message\"\n let data = \"\"\n for (const line of raw.split(\"\\n\")) {\n if (line.startsWith(\"event:\")) eventName = line.slice(\"event:\".length).trim()\n if (line.startsWith(\"data:\")) data += line.slice(\"data:\".length).trim()\n }\n if (!data) return null\n let parsed: Record<string, unknown>\n try {\n parsed = JSON.parse(data) as Record<string, unknown>\n } catch {\n return null\n }\n if (eventName === \"tier\") {\n const tier = parsed.tier === \"premium\" ? \"premium\" : \"free\"\n return {\n type: \"tier\",\n tier,\n ...(typeof parsed.model === \"string\" ? { model: parsed.model } : {}),\n }\n }\n if (eventName === \"delta\" && typeof parsed.text === \"string\") {\n return { type: \"delta\", text: parsed.text }\n }\n if (eventName === \"done\") {\n return {\n type: \"done\",\n ...(typeof parsed.stopReason === \"string\" ? { stopReason: parsed.stopReason } : {}),\n ...(typeof parsed.inputTokens === \"number\" ? { inputTokens: parsed.inputTokens } : {}),\n ...(typeof parsed.outputTokens === \"number\" ? { outputTokens: parsed.outputTokens } : {}),\n }\n }\n if (eventName === \"error\") {\n return {\n type: \"error\",\n message: typeof parsed.message === \"string\" ? parsed.message : \"Sage stream error\",\n }\n }\n return null\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/api.ts"],"names":["apiBase"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Public types for the Sage activity feed and paid chat flow.\n *\n * The source of truth is the API at https://www.ergoblockchain.org/api/sage/activity;\n * this file re-states the schema so consumers don't have to depend on the\n * server-side fetcher.\n */\n\nexport type SageActivityType = \"settlement\" | \"issuance\" | \"transfer\"\n\nexport interface SageActivityEvent {\n /** 64-char hex transaction id. */\n txId: string\n /** Block height at inclusion. */\n blockHeight: number\n /** Block timestamp (ms epoch). */\n timestamp: number\n /** Heuristic classification of the tx. */\n type: SageActivityType\n /** nanoERG flowing into the seller wallet from this tx (sum of outputs). */\n inflowNanoErg: number\n /**\n * For settlements: value of the redeemed Note (= what the buyer paid).\n * For other event types: undefined.\n *\n * Use this — not `inflowNanoErg` — when displaying \"amount paid for a\n * settled query\". `inflowNanoErg` includes change boxes in test setups\n * where the buyer and seller share an address.\n */\n paymentNanoErg?: number\n /** First input box that carries Note-shape registers, if any. */\n noteBoxId?: string\n}\n\nexport interface SageActivityResponse {\n ok: boolean\n network: \"testnet\" | \"mainnet\"\n /** Sage seller wallet address. */\n receiver: string\n /** Total number of txs ever touching the wallet, per the explorer. */\n total: number\n events: SageActivityEvent[]\n error?: string\n}\n\n/**\n * Configuration accepted by every entry point (React component +\n * vanilla mount fn). Defaults below are sensible for the canonical\n * ergoblockchain.org deployment.\n */\nexport interface SageWidgetOptions {\n /**\n * Base URL of the Sage host. Override if you run your own Sage\n * deployment behind a custom domain. Default: ergoblockchain.org.\n */\n apiBase?: string\n /**\n * Number of events to display (max 25). Default: 5.\n */\n limit?: number\n /**\n * Polling interval in ms. Default: 60000 (60s). Set to 0 to disable\n * polling — the widget will fetch once on mount and never refresh.\n */\n refreshMs?: number\n /**\n * Optional callback fired every time a fresh response arrives. Useful\n * for analytics or for triggering host-side animations on new\n * settlements.\n */\n onUpdate?: (response: SageActivityResponse) => void\n /**\n * Optional callback fired on fetch errors. Default: console.warn.\n */\n onError?: (error: unknown) => void\n}\n\nexport type SageChatRole = \"user\" | \"assistant\"\n\nexport interface SageChatMessage {\n role: SageChatRole\n content: string\n}\n\nexport interface SageTenantConfig {\n /** Stable tenant id for analytics, logs, or future multi-tenant routing. */\n id?: string\n /** Human-facing label shown in the default widgets. */\n label?: string\n /** Extra headers attached to Sage API requests. */\n headers?: Record<string, string>\n}\n\nexport type SagePaymentNetwork = \"ergo-testnet\" | \"ergo-mainnet\"\n\nexport interface SageQuote {\n quoteId: string\n taskHash: string\n price: string\n issuedAt?: string\n expiresAt: string\n receiverAddress: string\n reserveBoxId: string\n deadline: `+${number} blocks`\n}\n\nexport type SagePremiumReason =\n | \"explicit_command\"\n | \"code_request\"\n | \"long_answer\"\n | \"deep_research\"\n | \"multi_turn_followup\"\n\nexport interface SageQuoteResponse {\n premium: boolean\n reason?: SagePremiumReason\n rationale?: string\n quote?: SageQuote\n}\n\nexport interface SagePaymentIntent {\n type: \"sage.payment_intent.v1\"\n network: SagePaymentNetwork\n createdAt: string\n question: string\n tenant?: Pick<SageTenantConfig, \"id\" | \"label\">\n quote: SageQuote\n amountErg: string\n receiverAddress: string\n reserveBoxId: string\n taskHash: string\n expiresAt: string\n deadline: `+${number} blocks`\n verifyEndpoint: string\n receiptEndpointTemplate: string\n}\n\nexport interface SageWalletLaunchResult {\n ok: boolean\n /** Note box id produced by a host wallet flow. If present, the widget can prefill verification. */\n noteBoxId?: string\n /** Optional transaction id for host telemetry. Sage verifies by Note box id, not by tx id. */\n txId?: string\n error?: string\n}\n\nexport type SageWalletLauncher = (\n intent: SagePaymentIntent,\n) => Promise<SageWalletLaunchResult | void> | SageWalletLaunchResult | void\n\nexport interface SageVerifyPaymentResponse {\n ok: true\n paymentToken: string\n receiptId: string\n receiptUrl: string\n receiptApiUrl: string\n settlementTxId?: string | null\n accordSettlementId?: string\n receiptStorage?: {\n ok: boolean\n skipped?: boolean\n reason?: string\n path?: string\n aliases?: string[]\n error?: string\n }\n}\n\nexport interface SagePremiumPaymentRequired {\n error: \"premium_payment_required\"\n reason?: SagePremiumReason\n rationale?: string\n}\n\nexport type SageChatTier = \"free\" | \"premium\"\n\nexport type SageChatStreamEvent =\n | { type: \"tier\"; tier: SageChatTier; model?: string }\n | { type: \"delta\"; text: string }\n | { type: \"done\"; stopReason?: string; inputTokens?: number; outputTokens?: number }\n | { type: \"error\"; message: string }\n\nexport interface SageChatStreamResult {\n ok: boolean\n status: number\n text: string\n tier?: SageChatTier\n paymentRequired?: SagePremiumPaymentRequired\n error?: string\n}\n\nexport interface SageReceiptBundle {\n ok: true\n type: \"sage.receipt_bundle.v1\"\n version: \"v1\"\n id: string\n status: \"settled_on_chain\" | \"verified_pending_redemption\"\n completeness: \"full_receipt_bundle\" | \"full\" | \"chain_proof_only\"\n public_receipt_url: string\n api_receipt_url: string\n explorer_url: string | null\n accord?: {\n agreement_hash?: string | null\n verification_receipt_hash?: string | null\n settlement_receipt_hash?: string | null\n agreement_json?: unknown\n verification_receipt_json?: unknown\n settlement_receipt_json?: unknown\n }\n}\n\nexport interface SagePaymentWidgetOptions {\n /**\n * Base URL of the Sage host. Default: ergoblockchain.org.\n */\n apiBase?: string\n /**\n * Optional tenant metadata. Current public Sage ignores tenant routing,\n * but the widget keeps this shape stable for multi-tenant deployments.\n */\n tenant?: SageTenantConfig\n /** Initial chat messages, useful for preloaded context. */\n initialMessages?: SageChatMessage[]\n /** Placeholder text for the default input. */\n placeholder?: string\n /** Widget heading. React also accepts this through component props. */\n title?: string\n /** Optional host-specific payment copy and links. */\n paymentInstructions?: SagePaymentInstructions\n /**\n * Optional wallet launcher supplied by the host app. The package does not\n * sign transactions itself; this callback receives a structured intent that\n * your wallet layer can transform into a testnet Note.\n */\n walletLauncher?: SageWalletLauncher\n /**\n * Show the portable payment intent JSON in the default UI. Default: true.\n * Hosts with a fully custom wallet flow can set this to false.\n */\n showPaymentIntent?: boolean\n /**\n * Testnet safety copy for the default widget. Set to false to hide.\n */\n testnetWarning?: string | false\n /** Called whenever a message is appended by the widget. */\n onMessage?: (message: SageChatMessage, messages: SageChatMessage[]) => void\n /** Called after Sage returns a premium quote. */\n onQuote?: (quote: SageQuoteResponse) => void\n /** Called when a structured payment intent is produced for the active quote. */\n onPaymentIntent?: (intent: SagePaymentIntent) => void\n /** Called after a payment verifies and Sage returns a receipt link. */\n onReceipt?: (receipt: SageVerifyPaymentResponse) => void\n /** Called after the widget fetches the full machine-readable receipt bundle. */\n onReceiptBundle?: (receipt: SageReceiptBundle) => void\n /** Called when the chat stream reports free vs premium tier. */\n onTier?: (tier: SageChatTier) => void\n /** Called when the widget phase changes. */\n onPhase?: (phase: SagePaymentPhase) => void\n /** Called with a compact state snapshot after important widget events. */\n onStatus?: (status: SagePaymentWidgetStatus) => void\n /** Optional callback fired on fetch or stream errors. */\n onError?: (error: unknown) => void\n}\n\nexport type SagePaymentPhase =\n | \"idle\"\n | \"quoting\"\n | \"payment_required\"\n | \"verifying\"\n | \"streaming\"\n | \"error\"\n\nexport interface SagePaymentInstructions {\n /** Short copy displayed above the Note box input. */\n helperText?: string\n /** Optional link to host payment/wallet instructions. */\n walletUrl?: string\n /** Custom label for the wallet launcher button. */\n walletLauncherLabel?: string\n /** Optional custom label for the Note box input. */\n noteBoxLabel?: string\n}\n\nexport interface SagePaymentWidgetStatus {\n phase: SagePaymentPhase\n tier: SageChatTier | null\n quote: SageQuoteResponse[\"quote\"] | null\n paymentIntent: SagePaymentIntent | null\n receipt: SageVerifyPaymentResponse | null\n receiptBundle: SageReceiptBundle | null\n error: string | null\n /** Latest chat transcript known to the widget. */\n messages: SageChatMessage[]\n /** Question currently tied to the active quote/payment cycle. */\n activeQuestion: string | null\n}\n\nexport const DEFAULT_API_BASE = \"https://www.ergoblockchain.org\"\nexport const DEFAULT_LIMIT = 5\nexport const DEFAULT_REFRESH_MS = 60_000\n","/**\n * Thin client over /api/sage/activity.\n *\n * Pure fetch + shape — no rendering, no DOM. React + vanilla mounts\n * both call into here so the API contract lives in one place.\n */\n\nimport {\n DEFAULT_API_BASE,\n DEFAULT_LIMIT,\n type SageChatMessage,\n type SageChatStreamEvent,\n type SageChatStreamResult,\n type SagePaymentIntent,\n type SagePaymentNetwork,\n type SageQuote,\n type SageQuoteResponse,\n type SageReceiptBundle,\n type SageTenantConfig,\n type SageVerifyPaymentResponse,\n type SageActivityResponse,\n} from \"./types\"\n\nexport interface FetchActivityOptions {\n apiBase?: string\n limit?: number\n signal?: AbortSignal\n}\n\nexport interface SageRequestOptions {\n apiBase?: string\n tenant?: SageTenantConfig\n headers?: Record<string, string>\n signal?: AbortSignal\n}\n\nexport interface FetchSageQuoteOptions extends SageRequestOptions {\n question: string\n history?: SageChatMessage[]\n}\n\nexport interface VerifySagePaymentOptions extends SageRequestOptions {\n quote: SageQuote\n question: string\n noteBoxId: string\n}\n\nexport interface CreateSagePaymentIntentOptions {\n quote: SageQuote\n question: string\n apiBase?: string\n tenant?: SageTenantConfig\n network?: SagePaymentNetwork\n createdAt?: string\n}\n\nexport interface StreamSageChatOptions extends SageRequestOptions {\n messages: SageChatMessage[]\n paymentToken?: string\n onEvent?: (event: SageChatStreamEvent) => void\n}\n\nexport async function fetchSageActivity(\n opts: FetchActivityOptions = {},\n): Promise<SageActivityResponse> {\n const base = opts.apiBase ?? DEFAULT_API_BASE\n const limit = Math.min(Math.max(opts.limit ?? DEFAULT_LIMIT, 1), 25)\n const url = `${trimSlash(base)}/api/sage/activity?limit=${limit}`\n const res = await fetch(url, { signal: opts.signal })\n if (!res.ok) {\n throw new Error(`sage activity ${res.status}`)\n }\n return (await res.json()) as SageActivityResponse\n}\n\nexport async function fetchSageQuote(\n opts: FetchSageQuoteOptions,\n): Promise<SageQuoteResponse> {\n const res = await fetch(`${apiBase(opts)}/api/sage/quote`, {\n method: \"POST\",\n headers: jsonHeaders(opts),\n body: JSON.stringify({\n question: opts.question,\n history: opts.history ?? [],\n }),\n signal: opts.signal,\n })\n const body = await parseJson(res)\n if (!res.ok) throw new Error(readError(body, `sage quote ${res.status}`))\n return body as SageQuoteResponse\n}\n\nexport async function verifySagePayment(\n opts: VerifySagePaymentOptions,\n): Promise<SageVerifyPaymentResponse> {\n const res = await fetch(`${apiBase(opts)}/api/sage/verify-payment`, {\n method: \"POST\",\n headers: jsonHeaders(opts),\n body: JSON.stringify({\n quote: opts.quote,\n question: opts.question,\n noteBoxId: opts.noteBoxId,\n }),\n signal: opts.signal,\n })\n const body = await parseJson(res)\n if (!res.ok) throw new Error(readError(body, `sage verify-payment ${res.status}`))\n return body as SageVerifyPaymentResponse\n}\n\nexport async function fetchSageReceipt(\n id: string,\n opts: SageRequestOptions = {},\n): Promise<SageReceiptBundle> {\n const res = await fetch(`${apiBase(opts)}/api/sage/receipt/${encodeURIComponent(id)}`, {\n headers: requestHeaders(opts),\n signal: opts.signal,\n })\n const body = await parseJson(res)\n if (!res.ok) throw new Error(readError(body, `sage receipt ${res.status}`))\n return body as SageReceiptBundle\n}\n\nexport function isFullSageReceiptBundle(value: SageReceiptBundle | null | undefined): boolean {\n return value?.ok === true && value.completeness === \"full_receipt_bundle\"\n}\n\nexport function createSagePaymentIntent(\n opts: CreateSagePaymentIntentOptions,\n): SagePaymentIntent {\n const base = trimSlash(opts.apiBase ?? DEFAULT_API_BASE)\n return {\n type: \"sage.payment_intent.v1\",\n network: opts.network ?? \"ergo-testnet\",\n createdAt: opts.createdAt ?? new Date().toISOString(),\n question: opts.question,\n ...(opts.tenant?.id || opts.tenant?.label\n ? { tenant: { id: opts.tenant.id, label: opts.tenant.label } }\n : {}),\n quote: opts.quote,\n amountErg: opts.quote.price,\n receiverAddress: opts.quote.receiverAddress,\n reserveBoxId: opts.quote.reserveBoxId,\n taskHash: opts.quote.taskHash,\n expiresAt: opts.quote.expiresAt,\n deadline: opts.quote.deadline,\n verifyEndpoint: `${base}/api/sage/verify-payment`,\n receiptEndpointTemplate: `${base}/api/sage/receipt/{receiptId}`,\n }\n}\n\nexport function serializeSagePaymentIntent(intent: SagePaymentIntent): string {\n return JSON.stringify(intent, null, 2)\n}\n\nexport async function streamSageChat(\n opts: StreamSageChatOptions,\n): Promise<SageChatStreamResult> {\n const res = await fetch(`${apiBase(opts)}/api/sage/chat`, {\n method: \"POST\",\n headers: jsonHeaders(opts),\n body: JSON.stringify({\n messages: opts.messages,\n ...(opts.paymentToken ? { paymentToken: opts.paymentToken } : {}),\n }),\n signal: opts.signal,\n })\n\n if (res.status === 402) {\n const body = await parseJson(res)\n return {\n ok: false,\n status: res.status,\n text: \"\",\n paymentRequired: body as SageChatStreamResult[\"paymentRequired\"],\n }\n }\n\n if (!res.ok) {\n const body = await parseJson(res)\n return {\n ok: false,\n status: res.status,\n text: \"\",\n error: readError(body, `sage chat ${res.status}`),\n }\n }\n\n if (!res.body) {\n return { ok: false, status: res.status, text: \"\", error: \"Sage chat stream missing body\" }\n }\n\n const reader = res.body.getReader()\n const decoder = new TextDecoder()\n let buffer = \"\"\n let text = \"\"\n let tier: SageChatStreamResult[\"tier\"]\n\n while (true) {\n const { value, done } = await reader.read()\n if (done) break\n buffer += decoder.decode(value, { stream: true })\n const parts = buffer.split(\"\\n\\n\")\n buffer = parts.pop() ?? \"\"\n for (const part of parts) {\n const event = parseSseEvent(part)\n if (!event) continue\n if (event.type === \"delta\") text += event.text\n if (event.type === \"tier\") tier = event.tier\n opts.onEvent?.(event)\n if (event.type === \"error\") {\n return {\n ok: false,\n status: res.status,\n text,\n tier,\n error: event.message,\n }\n }\n }\n }\n\n if (buffer.trim()) {\n const event = parseSseEvent(buffer)\n if (event) {\n if (event.type === \"delta\") text += event.text\n if (event.type === \"tier\") tier = event.tier\n opts.onEvent?.(event)\n if (event.type === \"error\") {\n return {\n ok: false,\n status: res.status,\n text,\n tier,\n error: event.message,\n }\n }\n }\n }\n\n return { ok: true, status: res.status, text, tier }\n}\n\n/** nanoERG → \"0.001\" (trims trailing zeros, max 9 decimals). */\nexport function nanoToErg(nano: number | undefined): string {\n if (!nano || nano <= 0) return \"0\"\n const erg = nano / 1e9\n return erg.toFixed(9).replace(/\\.?0+$/, \"\")\n}\n\n/** Cheap relative-time formatter, ASCII-only, no Intl deps. */\nexport function relativeTime(ms: number, now: number = Date.now()): string {\n const diff = Math.max(0, now - ms)\n const sec = Math.floor(diff / 1000)\n if (sec < 60) return `${sec}s ago`\n const min = Math.floor(sec / 60)\n if (min < 60) return `${min}m ago`\n const hr = Math.floor(min / 60)\n if (hr < 24) return `${hr}h ago`\n const day = Math.floor(hr / 24)\n return `${day}d ago`\n}\n\n/** Receipt URL for a settled tx, given the host base. */\nexport function receiptUrl(txId: string, apiBase: string = DEFAULT_API_BASE): string {\n return `${trimSlash(apiBase)}/r/sage/${txId}`\n}\n\n/** Explorer URL for a tx on the given network. */\nexport function explorerUrl(\n txId: string,\n network: \"testnet\" | \"mainnet\" = \"testnet\",\n): string {\n return network === \"testnet\"\n ? `https://testnet.ergoplatform.com/transactions/${txId}`\n : `https://explorer.ergoplatform.com/transactions/${txId}`\n}\n\nfunction apiBase(opts: SageRequestOptions): string {\n return trimSlash(opts.apiBase ?? DEFAULT_API_BASE)\n}\n\nfunction trimSlash(value: string): string {\n return value.replace(/\\/+$/, \"\")\n}\n\nfunction requestHeaders(opts: SageRequestOptions): Record<string, string> {\n return {\n ...(opts.tenant?.id ? { \"x-sage-tenant-id\": opts.tenant.id } : {}),\n ...(opts.tenant?.headers ?? {}),\n ...(opts.headers ?? {}),\n }\n}\n\nfunction jsonHeaders(opts: SageRequestOptions): Record<string, string> {\n return {\n \"content-type\": \"application/json\",\n ...requestHeaders(opts),\n }\n}\n\nasync function parseJson(res: Response): Promise<unknown> {\n const text = await res.text()\n if (!text) return null\n try {\n return JSON.parse(text)\n } catch {\n return { error: text }\n }\n}\n\nfunction readError(body: unknown, fallback: string): string {\n if (body && typeof body === \"object\" && \"error\" in body) {\n const error = (body as { error?: unknown }).error\n if (typeof error === \"string\") return error\n }\n return fallback\n}\n\nfunction parseSseEvent(raw: string): SageChatStreamEvent | null {\n let eventName = \"message\"\n let data = \"\"\n for (const line of raw.split(\"\\n\")) {\n if (line.startsWith(\"event:\")) eventName = line.slice(\"event:\".length).trim()\n if (line.startsWith(\"data:\")) data += line.slice(\"data:\".length).trim()\n }\n if (!data) return null\n let parsed: Record<string, unknown>\n try {\n parsed = JSON.parse(data) as Record<string, unknown>\n } catch {\n return null\n }\n if (eventName === \"tier\") {\n const tier = parsed.tier === \"premium\" ? \"premium\" : \"free\"\n return {\n type: \"tier\",\n tier,\n ...(typeof parsed.model === \"string\" ? { model: parsed.model } : {}),\n }\n }\n if (eventName === \"delta\" && typeof parsed.text === \"string\") {\n return { type: \"delta\", text: parsed.text }\n }\n if (eventName === \"done\") {\n return {\n type: \"done\",\n ...(typeof parsed.stopReason === \"string\" ? { stopReason: parsed.stopReason } : {}),\n ...(typeof parsed.inputTokens === \"number\" ? { inputTokens: parsed.inputTokens } : {}),\n ...(typeof parsed.outputTokens === \"number\" ? { outputTokens: parsed.outputTokens } : {}),\n }\n }\n if (eventName === \"error\") {\n return {\n type: \"error\",\n message: typeof parsed.message === \"string\" ? parsed.message : \"Sage stream error\",\n }\n }\n return null\n}\n"]}
|