@ergoblockchain/sage-widget 0.1.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/LICENSE +21 -0
- package/README.md +134 -0
- package/dist/index.cjs +51 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +26 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -0
- package/dist/react.cjs +302 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +35 -0
- package/dist/react.d.ts +35 -0
- package/dist/react.js +297 -0
- package/dist/react.js.map +1 -0
- package/dist/types-uzMz6_mP.d.cts +77 -0
- package/dist/types-uzMz6_mP.d.ts +77 -0
- package/dist/vanilla.cjs +263 -0
- package/dist/vanilla.cjs.map +1 -0
- package/dist/vanilla.d.cts +34 -0
- package/dist/vanilla.d.ts +34 -0
- package/dist/vanilla.js +258 -0
- package/dist/vanilla.js.map +1 -0
- package/package.json +84 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ergo Platform contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# @ergoblockchain/sage-widget
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@ergoblockchain/sage-widget)
|
|
4
|
+
[](./LICENSE)
|
|
5
|
+
|
|
6
|
+
Embeddable live-activity feed for **Sage** — the agent-economy concierge on [ergoblockchain.org](https://www.ergoblockchain.org). Drop a typed React component into your app, or call a vanilla DOM mount function from any framework. Every settled paid query Sage takes appears in the feed within a minute, with a clickable link to the on-chain receipt.
|
|
7
|
+
|
|
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
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @ergoblockchain/sage-widget
|
|
14
|
+
# or
|
|
15
|
+
pnpm add @ergoblockchain/sage-widget
|
|
16
|
+
# or
|
|
17
|
+
yarn add @ergoblockchain/sage-widget
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`react` and `react-dom` are optional peer deps — only required if you import from `/react`.
|
|
21
|
+
|
|
22
|
+
## Use it
|
|
23
|
+
|
|
24
|
+
### React
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
import { SageActivityFeed } from "@ergoblockchain/sage-widget/react"
|
|
28
|
+
|
|
29
|
+
export function Footer() {
|
|
30
|
+
return <SageActivityFeed limit={5} refreshMs={60_000} />
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The component renders into your DOM (no iframe), styles itself with inline styles to avoid host-CSS conflicts, and polls `/api/sage/activity` on the host you point it at.
|
|
35
|
+
|
|
36
|
+
### Vanilla / non-React
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import { mountSageFeed } from "@ergoblockchain/sage-widget/vanilla"
|
|
40
|
+
|
|
41
|
+
const handle = mountSageFeed(document.getElementById("sage-feed")!, {
|
|
42
|
+
limit: 5,
|
|
43
|
+
refreshMs: 60_000,
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
// later, if you want to tear down:
|
|
47
|
+
handle.destroy()
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Or use the canonical hosted CDN drop-in (no install needed):
|
|
51
|
+
|
|
52
|
+
```html
|
|
53
|
+
<div id="sage-feed"></div>
|
|
54
|
+
<script src="https://www.ergoblockchain.org/agents.js"
|
|
55
|
+
data-target="#sage-feed"
|
|
56
|
+
data-height="320"
|
|
57
|
+
async></script>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
That last form is an iframe variant served straight from ergoblockchain.org — total style isolation, zero install. Use the npm package when you want the markup inline (themable, accessibility-friendly, tree-shakeable).
|
|
61
|
+
|
|
62
|
+
## Just the types
|
|
63
|
+
|
|
64
|
+
If you want to render your own UI over Sage's API and skip the bundled components:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
import {
|
|
68
|
+
fetchSageActivity,
|
|
69
|
+
type SageActivityEvent,
|
|
70
|
+
type SageActivityResponse,
|
|
71
|
+
} from "@ergoblockchain/sage-widget"
|
|
72
|
+
|
|
73
|
+
const data: SageActivityResponse = await fetchSageActivity({ limit: 10 })
|
|
74
|
+
const settlements = data.events.filter((e) => e.type === "settlement")
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Render-prop / bring-your-own-design
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
<SageActivityFeed>
|
|
81
|
+
{({ response, loading }) => (
|
|
82
|
+
<MyOwnDesign events={response?.events ?? []} loading={loading} />
|
|
83
|
+
)}
|
|
84
|
+
</SageActivityFeed>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Options
|
|
88
|
+
|
|
89
|
+
| Prop | Type | Default | Notes |
|
|
90
|
+
| --------------- | --------------------------------- | ----------------------------------------- | ---------------------------------------------------------------------------------------------- |
|
|
91
|
+
| `apiBase` | `string` | `"https://www.ergoblockchain.org"` | Override if you run your own Sage deployment behind a custom domain. |
|
|
92
|
+
| `limit` | `number` | `5` | Max 25. |
|
|
93
|
+
| `refreshMs` | `number` | `60000` | Poll interval. Set to `0` to fetch once on mount and never refresh. |
|
|
94
|
+
| `onUpdate` | `(r: SageActivityResponse) => void` | — | Fired after every successful poll. |
|
|
95
|
+
| `onError` | `(err: unknown) => void` | `console.warn` | Fired on fetch failure. |
|
|
96
|
+
| `className` | `string` | — | Applied to the root container (React only). |
|
|
97
|
+
| `style` | `CSSProperties` | — | Inline style merged onto the root container (React only). |
|
|
98
|
+
| `children` | render-prop | — | Pass a function for full UI control; the component will skip the default markup. |
|
|
99
|
+
|
|
100
|
+
## Event shape
|
|
101
|
+
|
|
102
|
+
Each event in `response.events` is a typed object:
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
{
|
|
106
|
+
txId: string // 64-char hex
|
|
107
|
+
blockHeight: number
|
|
108
|
+
timestamp: number // ms epoch
|
|
109
|
+
type: "settlement" | "issuance" | "transfer"
|
|
110
|
+
inflowNanoErg: number // sum of outputs to Sage wallet
|
|
111
|
+
paymentNanoErg?: number // value of redeemed Note (settlements only)
|
|
112
|
+
noteBoxId?: string // first Note-shape input
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
For settlements, use `paymentNanoErg` (the value of the consumed Note) for "amount paid" display. `inflowNanoErg` includes change boxes when buyer and seller share an address in test setups.
|
|
117
|
+
|
|
118
|
+
## Related
|
|
119
|
+
|
|
120
|
+
- **Live demo**: [ergoblockchain.org/agent-economy#sage-activity](https://www.ergoblockchain.org/agent-economy#sage-activity)
|
|
121
|
+
- **API directly**: [`/api/sage/activity`](https://www.ergoblockchain.org/api/sage/activity) — JSON, no auth, cached 30s
|
|
122
|
+
- **Receipt format**: [`/r/sage/<settlement_tx_id>`](https://www.ergoblockchain.org/r/sage/f697e4841dd9a0c689d0b83a311130b85a0cfbab123230a6c40284b44c4cafef)
|
|
123
|
+
- **Accord Protocol**: [github.com/accord-protocol/accord-protocol](https://github.com/accord-protocol/accord-protocol)
|
|
124
|
+
- **Sage in the registry**: [accord-protocol/registry/providers/sage.json](https://github.com/accord-protocol/accord-protocol/blob/main/registry/providers/sage.json)
|
|
125
|
+
|
|
126
|
+
## Roadmap
|
|
127
|
+
|
|
128
|
+
- **v0.1.x** _(current)_ — read-only activity feed (React + vanilla + types).
|
|
129
|
+
- **v0.2** — `<SagePaymentWidget />` full chat with 402 + payment + Sonnet answer.
|
|
130
|
+
- **v0.3** — generic `<AccordActivityFeed providerId="..." />` that works for any provider in the registry, not just Sage.
|
|
131
|
+
|
|
132
|
+
## License
|
|
133
|
+
|
|
134
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/types.ts
|
|
4
|
+
var DEFAULT_API_BASE = "https://www.ergoblockchain.org";
|
|
5
|
+
var DEFAULT_LIMIT = 5;
|
|
6
|
+
var DEFAULT_REFRESH_MS = 6e4;
|
|
7
|
+
|
|
8
|
+
// src/api.ts
|
|
9
|
+
async function fetchSageActivity(opts = {}) {
|
|
10
|
+
const base = opts.apiBase ?? DEFAULT_API_BASE;
|
|
11
|
+
const limit = Math.min(Math.max(opts.limit ?? DEFAULT_LIMIT, 1), 25);
|
|
12
|
+
const url = `${base}/api/sage/activity?limit=${limit}`;
|
|
13
|
+
const res = await fetch(url, { signal: opts.signal });
|
|
14
|
+
if (!res.ok) {
|
|
15
|
+
throw new Error(`sage activity ${res.status}`);
|
|
16
|
+
}
|
|
17
|
+
return await res.json();
|
|
18
|
+
}
|
|
19
|
+
function nanoToErg(nano) {
|
|
20
|
+
if (!nano || nano <= 0) return "0";
|
|
21
|
+
const erg = nano / 1e9;
|
|
22
|
+
return erg.toFixed(9).replace(/\.?0+$/, "");
|
|
23
|
+
}
|
|
24
|
+
function relativeTime(ms, now = Date.now()) {
|
|
25
|
+
const diff = Math.max(0, now - ms);
|
|
26
|
+
const sec = Math.floor(diff / 1e3);
|
|
27
|
+
if (sec < 60) return `${sec}s ago`;
|
|
28
|
+
const min = Math.floor(sec / 60);
|
|
29
|
+
if (min < 60) return `${min}m ago`;
|
|
30
|
+
const hr = Math.floor(min / 60);
|
|
31
|
+
if (hr < 24) return `${hr}h ago`;
|
|
32
|
+
const day = Math.floor(hr / 24);
|
|
33
|
+
return `${day}d ago`;
|
|
34
|
+
}
|
|
35
|
+
function receiptUrl(txId, apiBase = DEFAULT_API_BASE) {
|
|
36
|
+
return `${apiBase}/r/sage/${txId}`;
|
|
37
|
+
}
|
|
38
|
+
function explorerUrl(txId, network = "testnet") {
|
|
39
|
+
return network === "testnet" ? `https://testnet.ergoplatform.com/transactions/${txId}` : `https://explorer.ergoplatform.com/transactions/${txId}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
exports.DEFAULT_API_BASE = DEFAULT_API_BASE;
|
|
43
|
+
exports.DEFAULT_LIMIT = DEFAULT_LIMIT;
|
|
44
|
+
exports.DEFAULT_REFRESH_MS = DEFAULT_REFRESH_MS;
|
|
45
|
+
exports.explorerUrl = explorerUrl;
|
|
46
|
+
exports.fetchSageActivity = fetchSageActivity;
|
|
47
|
+
exports.nanoToErg = nanoToErg;
|
|
48
|
+
exports.receiptUrl = receiptUrl;
|
|
49
|
+
exports.relativeTime = relativeTime;
|
|
50
|
+
//# sourceMappingURL=index.cjs.map
|
|
51
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/api.ts"],"names":[],"mappings":";;;AA6EO,IAAM,gBAAA,GAAmB;AACzB,IAAM,aAAA,GAAgB;AACtB,IAAM,kBAAA,GAAqB;;;AC5DlC,eAAsB,iBAAA,CACpB,IAAA,GAA6B,EAAC,EACC;AAC/B,EAAA,MAAM,IAAA,GAAO,KAAK,OAAA,IAAW,gBAAA;AAC7B,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,KAAK,KAAA,IAAS,aAAA,EAAe,CAAC,CAAA,EAAG,EAAE,CAAA;AACnE,EAAA,MAAM,GAAA,GAAM,CAAA,EAAG,IAAI,CAAA,yBAAA,EAA4B,KAAK,CAAA,CAAA;AACpD,EAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,GAAA,EAAK,EAAE,MAAA,EAAQ,IAAA,CAAK,QAAQ,CAAA;AACpD,EAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,cAAA,EAAiB,GAAA,CAAI,MAAM,CAAA,CAAE,CAAA;AAAA,EAC/C;AACA,EAAA,OAAQ,MAAM,IAAI,IAAA,EAAK;AACzB;AAGO,SAAS,UAAU,IAAA,EAAkC;AAC1D,EAAA,IAAI,CAAC,IAAA,IAAQ,IAAA,IAAQ,CAAA,EAAG,OAAO,GAAA;AAC/B,EAAA,MAAM,MAAM,IAAA,GAAO,GAAA;AACnB,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,CAAA,CAAE,OAAA,CAAQ,UAAU,EAAE,CAAA;AAC5C;AAGO,SAAS,YAAA,CAAa,EAAA,EAAY,GAAA,GAAc,IAAA,CAAK,KAAI,EAAW;AACzE,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,MAAM,EAAE,CAAA;AACjC,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,IAAA,GAAO,GAAI,CAAA;AAClC,EAAA,IAAI,GAAA,GAAM,EAAA,EAAI,OAAO,CAAA,EAAG,GAAG,CAAA,KAAA,CAAA;AAC3B,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,EAAE,CAAA;AAC/B,EAAA,IAAI,GAAA,GAAM,EAAA,EAAI,OAAO,CAAA,EAAG,GAAG,CAAA,KAAA,CAAA;AAC3B,EAAA,MAAM,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,EAAE,CAAA;AAC9B,EAAA,IAAI,EAAA,GAAK,EAAA,EAAI,OAAO,CAAA,EAAG,EAAE,CAAA,KAAA,CAAA;AACzB,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,EAAA,GAAK,EAAE,CAAA;AAC9B,EAAA,OAAO,GAAG,GAAG,CAAA,KAAA,CAAA;AACf;AAGO,SAAS,UAAA,CAAW,IAAA,EAAc,OAAA,GAAkB,gBAAA,EAA0B;AACnF,EAAA,OAAO,CAAA,EAAG,OAAO,CAAA,QAAA,EAAW,IAAI,CAAA,CAAA;AAClC;AAGO,SAAS,WAAA,CACd,IAAA,EACA,OAAA,GAAiC,SAAA,EACzB;AACR,EAAA,OAAO,YAAY,SAAA,GACf,CAAA,8CAAA,EAAiD,IAAI,CAAA,CAAA,GACrD,kDAAkD,IAAI,CAAA,CAAA;AAC5D","file":"index.cjs","sourcesContent":["/**\n * Public types — mirror of /api/sage/activity response shape.\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 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 SageActivityResponse,\n} from \"./types\"\n\nexport interface FetchActivityOptions {\n apiBase?: string\n limit?: number\n signal?: AbortSignal\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 = `${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\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 `${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"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { c as SageActivityResponse } from './types-uzMz6_mP.cjs';
|
|
2
|
+
export { D as DEFAULT_API_BASE, a as DEFAULT_LIMIT, b as DEFAULT_REFRESH_MS, S as SageActivityEvent, d as SageActivityType, e as SageWidgetOptions } from './types-uzMz6_mP.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Thin client over /api/sage/activity.
|
|
6
|
+
*
|
|
7
|
+
* Pure fetch + shape — no rendering, no DOM. React + vanilla mounts
|
|
8
|
+
* both call into here so the API contract lives in one place.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
interface FetchActivityOptions {
|
|
12
|
+
apiBase?: string;
|
|
13
|
+
limit?: number;
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
}
|
|
16
|
+
declare function fetchSageActivity(opts?: FetchActivityOptions): Promise<SageActivityResponse>;
|
|
17
|
+
/** nanoERG → "0.001" (trims trailing zeros, max 9 decimals). */
|
|
18
|
+
declare function nanoToErg(nano: number | undefined): string;
|
|
19
|
+
/** Cheap relative-time formatter, ASCII-only, no Intl deps. */
|
|
20
|
+
declare function relativeTime(ms: number, now?: number): string;
|
|
21
|
+
/** Receipt URL for a settled tx, given the host base. */
|
|
22
|
+
declare function receiptUrl(txId: string, apiBase?: string): string;
|
|
23
|
+
/** Explorer URL for a tx on the given network. */
|
|
24
|
+
declare function explorerUrl(txId: string, network?: "testnet" | "mainnet"): string;
|
|
25
|
+
|
|
26
|
+
export { SageActivityResponse, explorerUrl, fetchSageActivity, nanoToErg, receiptUrl, relativeTime };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { c as SageActivityResponse } from './types-uzMz6_mP.js';
|
|
2
|
+
export { D as DEFAULT_API_BASE, a as DEFAULT_LIMIT, b as DEFAULT_REFRESH_MS, S as SageActivityEvent, d as SageActivityType, e as SageWidgetOptions } from './types-uzMz6_mP.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Thin client over /api/sage/activity.
|
|
6
|
+
*
|
|
7
|
+
* Pure fetch + shape — no rendering, no DOM. React + vanilla mounts
|
|
8
|
+
* both call into here so the API contract lives in one place.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
interface FetchActivityOptions {
|
|
12
|
+
apiBase?: string;
|
|
13
|
+
limit?: number;
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
}
|
|
16
|
+
declare function fetchSageActivity(opts?: FetchActivityOptions): Promise<SageActivityResponse>;
|
|
17
|
+
/** nanoERG → "0.001" (trims trailing zeros, max 9 decimals). */
|
|
18
|
+
declare function nanoToErg(nano: number | undefined): string;
|
|
19
|
+
/** Cheap relative-time formatter, ASCII-only, no Intl deps. */
|
|
20
|
+
declare function relativeTime(ms: number, now?: number): string;
|
|
21
|
+
/** Receipt URL for a settled tx, given the host base. */
|
|
22
|
+
declare function receiptUrl(txId: string, apiBase?: string): string;
|
|
23
|
+
/** Explorer URL for a tx on the given network. */
|
|
24
|
+
declare function explorerUrl(txId: string, network?: "testnet" | "mainnet"): string;
|
|
25
|
+
|
|
26
|
+
export { SageActivityResponse, explorerUrl, fetchSageActivity, nanoToErg, receiptUrl, relativeTime };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// src/types.ts
|
|
2
|
+
var DEFAULT_API_BASE = "https://www.ergoblockchain.org";
|
|
3
|
+
var DEFAULT_LIMIT = 5;
|
|
4
|
+
var DEFAULT_REFRESH_MS = 6e4;
|
|
5
|
+
|
|
6
|
+
// src/api.ts
|
|
7
|
+
async function fetchSageActivity(opts = {}) {
|
|
8
|
+
const base = opts.apiBase ?? DEFAULT_API_BASE;
|
|
9
|
+
const limit = Math.min(Math.max(opts.limit ?? DEFAULT_LIMIT, 1), 25);
|
|
10
|
+
const url = `${base}/api/sage/activity?limit=${limit}`;
|
|
11
|
+
const res = await fetch(url, { signal: opts.signal });
|
|
12
|
+
if (!res.ok) {
|
|
13
|
+
throw new Error(`sage activity ${res.status}`);
|
|
14
|
+
}
|
|
15
|
+
return await res.json();
|
|
16
|
+
}
|
|
17
|
+
function nanoToErg(nano) {
|
|
18
|
+
if (!nano || nano <= 0) return "0";
|
|
19
|
+
const erg = nano / 1e9;
|
|
20
|
+
return erg.toFixed(9).replace(/\.?0+$/, "");
|
|
21
|
+
}
|
|
22
|
+
function relativeTime(ms, now = Date.now()) {
|
|
23
|
+
const diff = Math.max(0, now - ms);
|
|
24
|
+
const sec = Math.floor(diff / 1e3);
|
|
25
|
+
if (sec < 60) return `${sec}s ago`;
|
|
26
|
+
const min = Math.floor(sec / 60);
|
|
27
|
+
if (min < 60) return `${min}m ago`;
|
|
28
|
+
const hr = Math.floor(min / 60);
|
|
29
|
+
if (hr < 24) return `${hr}h ago`;
|
|
30
|
+
const day = Math.floor(hr / 24);
|
|
31
|
+
return `${day}d ago`;
|
|
32
|
+
}
|
|
33
|
+
function receiptUrl(txId, apiBase = DEFAULT_API_BASE) {
|
|
34
|
+
return `${apiBase}/r/sage/${txId}`;
|
|
35
|
+
}
|
|
36
|
+
function explorerUrl(txId, network = "testnet") {
|
|
37
|
+
return network === "testnet" ? `https://testnet.ergoplatform.com/transactions/${txId}` : `https://explorer.ergoplatform.com/transactions/${txId}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export { DEFAULT_API_BASE, DEFAULT_LIMIT, DEFAULT_REFRESH_MS, explorerUrl, fetchSageActivity, nanoToErg, receiptUrl, relativeTime };
|
|
41
|
+
//# sourceMappingURL=index.js.map
|
|
42
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/api.ts"],"names":[],"mappings":";AA6EO,IAAM,gBAAA,GAAmB;AACzB,IAAM,aAAA,GAAgB;AACtB,IAAM,kBAAA,GAAqB;;;AC5DlC,eAAsB,iBAAA,CACpB,IAAA,GAA6B,EAAC,EACC;AAC/B,EAAA,MAAM,IAAA,GAAO,KAAK,OAAA,IAAW,gBAAA;AAC7B,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,KAAK,KAAA,IAAS,aAAA,EAAe,CAAC,CAAA,EAAG,EAAE,CAAA;AACnE,EAAA,MAAM,GAAA,GAAM,CAAA,EAAG,IAAI,CAAA,yBAAA,EAA4B,KAAK,CAAA,CAAA;AACpD,EAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,GAAA,EAAK,EAAE,MAAA,EAAQ,IAAA,CAAK,QAAQ,CAAA;AACpD,EAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,cAAA,EAAiB,GAAA,CAAI,MAAM,CAAA,CAAE,CAAA;AAAA,EAC/C;AACA,EAAA,OAAQ,MAAM,IAAI,IAAA,EAAK;AACzB;AAGO,SAAS,UAAU,IAAA,EAAkC;AAC1D,EAAA,IAAI,CAAC,IAAA,IAAQ,IAAA,IAAQ,CAAA,EAAG,OAAO,GAAA;AAC/B,EAAA,MAAM,MAAM,IAAA,GAAO,GAAA;AACnB,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,CAAA,CAAE,OAAA,CAAQ,UAAU,EAAE,CAAA;AAC5C;AAGO,SAAS,YAAA,CAAa,EAAA,EAAY,GAAA,GAAc,IAAA,CAAK,KAAI,EAAW;AACzE,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,MAAM,EAAE,CAAA;AACjC,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,IAAA,GAAO,GAAI,CAAA;AAClC,EAAA,IAAI,GAAA,GAAM,EAAA,EAAI,OAAO,CAAA,EAAG,GAAG,CAAA,KAAA,CAAA;AAC3B,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,EAAE,CAAA;AAC/B,EAAA,IAAI,GAAA,GAAM,EAAA,EAAI,OAAO,CAAA,EAAG,GAAG,CAAA,KAAA,CAAA;AAC3B,EAAA,MAAM,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,EAAE,CAAA;AAC9B,EAAA,IAAI,EAAA,GAAK,EAAA,EAAI,OAAO,CAAA,EAAG,EAAE,CAAA,KAAA,CAAA;AACzB,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,EAAA,GAAK,EAAE,CAAA;AAC9B,EAAA,OAAO,GAAG,GAAG,CAAA,KAAA,CAAA;AACf;AAGO,SAAS,UAAA,CAAW,IAAA,EAAc,OAAA,GAAkB,gBAAA,EAA0B;AACnF,EAAA,OAAO,CAAA,EAAG,OAAO,CAAA,QAAA,EAAW,IAAI,CAAA,CAAA;AAClC;AAGO,SAAS,WAAA,CACd,IAAA,EACA,OAAA,GAAiC,SAAA,EACzB;AACR,EAAA,OAAO,YAAY,SAAA,GACf,CAAA,8CAAA,EAAiD,IAAI,CAAA,CAAA,GACrD,kDAAkD,IAAI,CAAA,CAAA;AAC5D","file":"index.js","sourcesContent":["/**\n * Public types — mirror of /api/sage/activity response shape.\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 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 SageActivityResponse,\n} from \"./types\"\n\nexport interface FetchActivityOptions {\n apiBase?: string\n limit?: number\n signal?: AbortSignal\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 = `${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\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 `${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"]}
|
package/dist/react.cjs
ADDED
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
|
|
6
|
+
// src/react/SageActivityFeed.tsx
|
|
7
|
+
|
|
8
|
+
// src/types.ts
|
|
9
|
+
var DEFAULT_API_BASE = "https://www.ergoblockchain.org";
|
|
10
|
+
var DEFAULT_LIMIT = 5;
|
|
11
|
+
var DEFAULT_REFRESH_MS = 6e4;
|
|
12
|
+
|
|
13
|
+
// src/api.ts
|
|
14
|
+
async function fetchSageActivity(opts = {}) {
|
|
15
|
+
const base = opts.apiBase ?? DEFAULT_API_BASE;
|
|
16
|
+
const limit = Math.min(Math.max(opts.limit ?? DEFAULT_LIMIT, 1), 25);
|
|
17
|
+
const url = `${base}/api/sage/activity?limit=${limit}`;
|
|
18
|
+
const res = await fetch(url, { signal: opts.signal });
|
|
19
|
+
if (!res.ok) {
|
|
20
|
+
throw new Error(`sage activity ${res.status}`);
|
|
21
|
+
}
|
|
22
|
+
return await res.json();
|
|
23
|
+
}
|
|
24
|
+
function nanoToErg(nano) {
|
|
25
|
+
if (!nano || nano <= 0) return "0";
|
|
26
|
+
const erg = nano / 1e9;
|
|
27
|
+
return erg.toFixed(9).replace(/\.?0+$/, "");
|
|
28
|
+
}
|
|
29
|
+
function relativeTime(ms, now = Date.now()) {
|
|
30
|
+
const diff = Math.max(0, now - ms);
|
|
31
|
+
const sec = Math.floor(diff / 1e3);
|
|
32
|
+
if (sec < 60) return `${sec}s ago`;
|
|
33
|
+
const min = Math.floor(sec / 60);
|
|
34
|
+
if (min < 60) return `${min}m ago`;
|
|
35
|
+
const hr = Math.floor(min / 60);
|
|
36
|
+
if (hr < 24) return `${hr}h ago`;
|
|
37
|
+
const day = Math.floor(hr / 24);
|
|
38
|
+
return `${day}d ago`;
|
|
39
|
+
}
|
|
40
|
+
function receiptUrl(txId, apiBase = DEFAULT_API_BASE) {
|
|
41
|
+
return `${apiBase}/r/sage/${txId}`;
|
|
42
|
+
}
|
|
43
|
+
function explorerUrl(txId, network = "testnet") {
|
|
44
|
+
return network === "testnet" ? `https://testnet.ergoplatform.com/transactions/${txId}` : `https://explorer.ergoplatform.com/transactions/${txId}`;
|
|
45
|
+
}
|
|
46
|
+
var ONE_MIN = 6e4;
|
|
47
|
+
function SageActivityFeed(props) {
|
|
48
|
+
const {
|
|
49
|
+
apiBase,
|
|
50
|
+
limit = DEFAULT_LIMIT,
|
|
51
|
+
refreshMs = DEFAULT_REFRESH_MS,
|
|
52
|
+
onUpdate,
|
|
53
|
+
onError,
|
|
54
|
+
className,
|
|
55
|
+
style,
|
|
56
|
+
children
|
|
57
|
+
} = props;
|
|
58
|
+
const [response, setResponse] = react.useState(null);
|
|
59
|
+
const [error, setError] = react.useState(null);
|
|
60
|
+
const [loading, setLoading] = react.useState(true);
|
|
61
|
+
const [now, setNow] = react.useState(() => Date.now());
|
|
62
|
+
const onUpdateRef = react.useRef(onUpdate);
|
|
63
|
+
const onErrorRef = react.useRef(onError);
|
|
64
|
+
react.useEffect(() => {
|
|
65
|
+
onUpdateRef.current = onUpdate;
|
|
66
|
+
}, [onUpdate]);
|
|
67
|
+
react.useEffect(() => {
|
|
68
|
+
onErrorRef.current = onError;
|
|
69
|
+
}, [onError]);
|
|
70
|
+
react.useEffect(() => {
|
|
71
|
+
let cancelled = false;
|
|
72
|
+
const abort = new AbortController();
|
|
73
|
+
async function load() {
|
|
74
|
+
try {
|
|
75
|
+
const data = await fetchSageActivity({
|
|
76
|
+
apiBase,
|
|
77
|
+
limit,
|
|
78
|
+
signal: abort.signal
|
|
79
|
+
});
|
|
80
|
+
if (cancelled) return;
|
|
81
|
+
setResponse(data);
|
|
82
|
+
setError(null);
|
|
83
|
+
setLoading(false);
|
|
84
|
+
onUpdateRef.current?.(data);
|
|
85
|
+
} catch (err) {
|
|
86
|
+
if (cancelled || err.name === "AbortError") return;
|
|
87
|
+
setError(err);
|
|
88
|
+
setLoading(false);
|
|
89
|
+
(onErrorRef.current ?? console.warn)(err);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
load();
|
|
93
|
+
const pollId = refreshMs > 0 ? setInterval(load, refreshMs) : void 0;
|
|
94
|
+
const tickId = setInterval(() => setNow(Date.now()), ONE_MIN / 4);
|
|
95
|
+
return () => {
|
|
96
|
+
cancelled = true;
|
|
97
|
+
abort.abort();
|
|
98
|
+
if (pollId) clearInterval(pollId);
|
|
99
|
+
clearInterval(tickId);
|
|
100
|
+
};
|
|
101
|
+
}, [apiBase, limit, refreshMs]);
|
|
102
|
+
if (children) {
|
|
103
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: children({ loading, response, error }) });
|
|
104
|
+
}
|
|
105
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { ...rootStyle, ...style }, children: [
|
|
106
|
+
/* @__PURE__ */ jsxRuntime.jsx(Header, { network: response?.network ?? "testnet" }),
|
|
107
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
108
|
+
List,
|
|
109
|
+
{
|
|
110
|
+
loading,
|
|
111
|
+
events: response?.events ?? [],
|
|
112
|
+
network: response?.network ?? "testnet",
|
|
113
|
+
apiBase,
|
|
114
|
+
now
|
|
115
|
+
}
|
|
116
|
+
),
|
|
117
|
+
error ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: errorStyle, children: "Could not reach the activity feed." }) : null
|
|
118
|
+
] });
|
|
119
|
+
}
|
|
120
|
+
function Header({ network }) {
|
|
121
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: headerStyle, children: [
|
|
122
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: dotStyle }),
|
|
123
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: labelStyle, children: [
|
|
124
|
+
"Live \xB7 Ergo ",
|
|
125
|
+
network
|
|
126
|
+
] }),
|
|
127
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
128
|
+
"a",
|
|
129
|
+
{
|
|
130
|
+
href: "https://www.ergoblockchain.org/agent-economy#sage-activity",
|
|
131
|
+
target: "_blank",
|
|
132
|
+
rel: "noopener noreferrer",
|
|
133
|
+
style: linkStyle,
|
|
134
|
+
children: "Sage on chain"
|
|
135
|
+
}
|
|
136
|
+
)
|
|
137
|
+
] });
|
|
138
|
+
}
|
|
139
|
+
function List({
|
|
140
|
+
loading,
|
|
141
|
+
events,
|
|
142
|
+
network,
|
|
143
|
+
apiBase,
|
|
144
|
+
now
|
|
145
|
+
}) {
|
|
146
|
+
if (loading) return /* @__PURE__ */ jsxRuntime.jsx("div", { style: emptyStyle, children: "Loading\u2026" });
|
|
147
|
+
if (events.length === 0)
|
|
148
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: emptyStyle, children: "No activity yet \u2014 be the first to ask Sage a paid query." });
|
|
149
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { children: events.map((evt) => /* @__PURE__ */ jsxRuntime.jsx(Row, { evt, network, apiBase, now }, evt.txId)) });
|
|
150
|
+
}
|
|
151
|
+
function Row({
|
|
152
|
+
evt,
|
|
153
|
+
network,
|
|
154
|
+
apiBase,
|
|
155
|
+
now
|
|
156
|
+
}) {
|
|
157
|
+
const isSettle = evt.type === "settlement";
|
|
158
|
+
const href = isSettle ? receiptUrl(evt.txId, apiBase) : explorerUrl(evt.txId, network);
|
|
159
|
+
const amount = isSettle ? evt.paymentNanoErg ?? evt.inflowNanoErg : evt.inflowNanoErg;
|
|
160
|
+
const chipStyle = isSettle ? chipSettleStyle : chipIssueStyle;
|
|
161
|
+
const chipText = isSettle ? "Settled" : evt.type === "issuance" ? "Issued" : "Transfer";
|
|
162
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
163
|
+
"a",
|
|
164
|
+
{
|
|
165
|
+
href,
|
|
166
|
+
target: "_blank",
|
|
167
|
+
rel: "noopener noreferrer",
|
|
168
|
+
style: rowStyle,
|
|
169
|
+
children: [
|
|
170
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: chipStyle, children: chipText }),
|
|
171
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: metaStyle, children: [
|
|
172
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: txStyle, children: evt.txId }),
|
|
173
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: whenStyle, children: [
|
|
174
|
+
"block ",
|
|
175
|
+
evt.blockHeight.toLocaleString(),
|
|
176
|
+
" \xB7 ",
|
|
177
|
+
relativeTime(evt.timestamp, now)
|
|
178
|
+
] })
|
|
179
|
+
] }),
|
|
180
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: amountStyle, children: [
|
|
181
|
+
nanoToErg(amount),
|
|
182
|
+
" ",
|
|
183
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: amountUnitStyle, children: "ERG" })
|
|
184
|
+
] })
|
|
185
|
+
]
|
|
186
|
+
}
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
var rootStyle = {
|
|
190
|
+
background: "#000",
|
|
191
|
+
color: "#e5e7eb",
|
|
192
|
+
fontFamily: "'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,monospace",
|
|
193
|
+
padding: "14px 16px",
|
|
194
|
+
borderRadius: 14,
|
|
195
|
+
border: "1px solid rgba(255,255,255,.08)",
|
|
196
|
+
boxSizing: "border-box",
|
|
197
|
+
width: "100%",
|
|
198
|
+
fontSize: 14,
|
|
199
|
+
lineHeight: 1.4
|
|
200
|
+
};
|
|
201
|
+
var headerStyle = {
|
|
202
|
+
display: "flex",
|
|
203
|
+
alignItems: "center",
|
|
204
|
+
gap: 10,
|
|
205
|
+
marginBottom: 10
|
|
206
|
+
};
|
|
207
|
+
var dotStyle = {
|
|
208
|
+
width: 8,
|
|
209
|
+
height: 8,
|
|
210
|
+
borderRadius: "50%",
|
|
211
|
+
background: "#fb923c",
|
|
212
|
+
flexShrink: 0
|
|
213
|
+
};
|
|
214
|
+
var labelStyle = {
|
|
215
|
+
fontSize: 10,
|
|
216
|
+
letterSpacing: "0.25em",
|
|
217
|
+
textTransform: "uppercase",
|
|
218
|
+
color: "#fb923c"
|
|
219
|
+
};
|
|
220
|
+
var linkStyle = {
|
|
221
|
+
marginLeft: "auto",
|
|
222
|
+
fontSize: 13,
|
|
223
|
+
color: "#fed7aa",
|
|
224
|
+
textDecoration: "none"
|
|
225
|
+
};
|
|
226
|
+
var rowStyle = {
|
|
227
|
+
display: "flex",
|
|
228
|
+
alignItems: "center",
|
|
229
|
+
gap: 10,
|
|
230
|
+
padding: "8px 0",
|
|
231
|
+
borderTop: "1px solid rgba(255,255,255,.06)",
|
|
232
|
+
textDecoration: "none",
|
|
233
|
+
color: "inherit"
|
|
234
|
+
};
|
|
235
|
+
var chipBase = {
|
|
236
|
+
fontSize: 9,
|
|
237
|
+
letterSpacing: "0.2em",
|
|
238
|
+
textTransform: "uppercase",
|
|
239
|
+
padding: "2px 6px",
|
|
240
|
+
borderRadius: 4,
|
|
241
|
+
flexShrink: 0,
|
|
242
|
+
border: "1px solid"
|
|
243
|
+
};
|
|
244
|
+
var chipSettleStyle = {
|
|
245
|
+
...chipBase,
|
|
246
|
+
borderColor: "rgba(251,146,60,.4)",
|
|
247
|
+
color: "#fdba74",
|
|
248
|
+
background: "rgba(251,146,60,.1)"
|
|
249
|
+
};
|
|
250
|
+
var chipIssueStyle = {
|
|
251
|
+
...chipBase,
|
|
252
|
+
borderColor: "rgba(245,158,11,.3)",
|
|
253
|
+
color: "rgba(252,211,77,.8)",
|
|
254
|
+
background: "rgba(245,158,11,.05)"
|
|
255
|
+
};
|
|
256
|
+
var metaStyle = {
|
|
257
|
+
flex: 1,
|
|
258
|
+
minWidth: 0,
|
|
259
|
+
display: "flex",
|
|
260
|
+
flexDirection: "column"
|
|
261
|
+
};
|
|
262
|
+
var txStyle = {
|
|
263
|
+
color: "#d1d5db",
|
|
264
|
+
fontSize: 11,
|
|
265
|
+
overflow: "hidden",
|
|
266
|
+
textOverflow: "ellipsis",
|
|
267
|
+
whiteSpace: "nowrap"
|
|
268
|
+
};
|
|
269
|
+
var whenStyle = {
|
|
270
|
+
color: "#6b7280",
|
|
271
|
+
fontSize: 10,
|
|
272
|
+
marginTop: 1
|
|
273
|
+
};
|
|
274
|
+
var amountStyle = {
|
|
275
|
+
color: "#fed7aa",
|
|
276
|
+
fontSize: 12,
|
|
277
|
+
flexShrink: 0,
|
|
278
|
+
textAlign: "right"
|
|
279
|
+
};
|
|
280
|
+
var amountUnitStyle = {
|
|
281
|
+
color: "#6b7280",
|
|
282
|
+
fontSize: 9,
|
|
283
|
+
textTransform: "uppercase",
|
|
284
|
+
marginLeft: 2
|
|
285
|
+
};
|
|
286
|
+
var emptyStyle = {
|
|
287
|
+
padding: "18px 0",
|
|
288
|
+
textAlign: "center",
|
|
289
|
+
color: "#6b7280",
|
|
290
|
+
fontSize: 11
|
|
291
|
+
};
|
|
292
|
+
var errorStyle = {
|
|
293
|
+
...emptyStyle,
|
|
294
|
+
color: "#f87171"
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
exports.DEFAULT_API_BASE = DEFAULT_API_BASE;
|
|
298
|
+
exports.DEFAULT_LIMIT = DEFAULT_LIMIT;
|
|
299
|
+
exports.DEFAULT_REFRESH_MS = DEFAULT_REFRESH_MS;
|
|
300
|
+
exports.SageActivityFeed = SageActivityFeed;
|
|
301
|
+
//# sourceMappingURL=react.cjs.map
|
|
302
|
+
//# sourceMappingURL=react.cjs.map
|