diff options
| author | Adam Soltys <[email protected]> | 2026-09-05 19:38:10 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-09-05 19:38:10 -0700 |
| commit | ae85dc0afba70f40b333cf03c64abbbf4c8dfea0 (patch) | |
| tree | 869f84166f0ad9589ef85504d75376ef7446598d /src/features/names.js | |
| parent | efc4355b015a20fc346f3c9d985b75ae8dfd45c0 (diff) | |
| download | coinosv3-ae85dc0afba70f40b333cf03c64abbbf4c8dfea0.tar.gz coinosv3-ae85dc0afba70f40b333cf03c64abbbf4c8dfea0.zip | |
Point of sale: a coinos-pos terminal works against a name
Registrar: the owner mints a bearer POS token from Settings (NIP-98
POST /pos/token, DELETE revokes; /admin/pos/token for operators). With it
the terminal gets /pos/me, rings up sales at /pos/invoice (fiat via
coinos.io rates, or sats), reads /pos/payments, and holds a websocket at
/pos/ws that gets a payment message when the sale settles. Sales are
always minted on our node so the settle loop sees them and the ordinary
forward path delivers the sats to the name's ark address. The name's
lnurlp pins the newest unpaid sale under five minutes old — coinos.io's
/p/<name> rule — so an NFC tap or a scan pays exactly that invoice.
Wallet: a "Point of sale" section on the names card creates, copies and
revokes tokens.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01VMi2Y1oKPZ3TeeFmLej47y
Diffstat (limited to 'src/features/names.js')
| -rw-r--r-- | src/features/names.js | 25 |
1 files changed, 25 insertions, 0 deletions
diff --git a/src/features/names.js b/src/features/names.js index bd4ab4d..dc3426e 100644 --- a/src/features/names.js +++ b/src/features/names.js @@ -437,6 +437,10 @@ export function namesFeature(ctx) { copyBtn(code, t('namesZapCodeCopy'))) : null; })(), h('details', { class: 'small faint' }, + h('summary', {}, t('namesPos')), + h('p', { style: 'margin:4px 0' }, t('namesPosHow')), + posSection(st)), + h('details', { class: 'small faint' }, h('summary', {}, t('namesOwnNode')), h('p', { style: 'margin:4px 0' }, t('namesOwnNodeMenuHow')), ownNodeSection()), @@ -452,6 +456,27 @@ export function namesFeature(ctx) { claimForm(false)); } + // A coinos POS terminal (coinos-pos) takes payments to this name with a + // bearer token the registrar mints for the owner: the terminal can ring up + // sales and see them settle, never spend. Shown once, never stored — the + // token goes straight into the terminal's config at coinos.io/pos. + function posSection(st) { + const tok = ui.posToken; + const body = () => ({ name: st.name, domain: st.domain || DOMAIN() }); + return h('div', { class: 'col', style: 'gap:6px' }, + tok ? h('div', { class: 'addr-box break', style: 'font-size:10px' }, tok) : null, + h('div', { class: 'row gap6', style: 'flex-wrap:wrap' }, + h('button', { class: 'btn-ghost btn-sm', onClick: async () => { + try { ui.posToken = (await post('/pos/token', 'POST', body())).token; render(); } + catch (e) { toast(e.message); } + } }, t('namesPosCreate')), + tok ? copyBtn(tok, t('namesPosCopy')) : null, + h('button', { class: 'btn-ghost btn-sm', onClick: async () => { + try { await post('/pos/token', 'DELETE', body()); ui.posToken = null; toast(t('namesPosRevoked')); render(); } + catch (e) { toast(e.message); } + } }, t('namesPosRevoke')))); + } + // The Receive tab's default pane: your name, big and scannable. function namePane(seg) { const st = load(); |
