Merge pull request 'feat: support a public browser demo of the kiosk' (#88) from feat/web-demo into dev
Reviewed-on: #88
This commit is contained in:
commit
59e8a9de02
10 changed files with 80 additions and 4 deletions
|
|
@ -73,6 +73,18 @@ VITE_SPIRE_SEED=
|
||||||
# Show "Under Service" screen and block all transactions
|
# Show "Under Service" screen and block all transactions
|
||||||
# VITE_MAINTENANCE_MODE=true
|
# VITE_MAINTENANCE_MODE=true
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Public Web Demo
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# Set ONLY for the browser demo build (atm.demo.aiolabs.dev). Leave blank on
|
||||||
|
# every real machine. When set it:
|
||||||
|
# - keeps the mouse cursor visible (kiosk builds hide it)
|
||||||
|
# - mints one extra, never-used LNbits wallet named with this exact string,
|
||||||
|
# so the throwaway accounts the demo creates (one per page load, each with
|
||||||
|
# its own ephemeral identity) can be swept by name instead of guessed at.
|
||||||
|
# VITE_DEMO_TAG=bitspire-web-demo
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Mock Fallback (Production Safety)
|
# Mock Fallback (Production Safety)
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
"dev:vite": "vite",
|
"dev:vite": "vite",
|
||||||
"electron:dev": "tsc -p electron/tsconfig.json && tsc -p electron/tsconfig.preload.json && electron dist-electron/main.js",
|
"electron:dev": "tsc -p electron/tsconfig.json && tsc -p electron/tsconfig.preload.json && electron dist-electron/main.js",
|
||||||
"build": "vue-tsc --noEmit && vite build && tsc -p electron/tsconfig.json && tsc -p electron/tsconfig.preload.json && npx esbuild electron/fund-atm.ts --bundle --platform=node --format=cjs --external:better-sqlite3 --outfile=dist-electron/fund-atm.bundle.cjs",
|
"build": "vue-tsc --noEmit && vite build && tsc -p electron/tsconfig.json && tsc -p electron/tsconfig.preload.json && npx esbuild electron/fund-atm.ts --bundle --platform=node --format=cjs --external:better-sqlite3 --outfile=dist-electron/fund-atm.bundle.cjs",
|
||||||
|
"build:web": "vite build",
|
||||||
"build:electron": "pnpm build && electron-builder",
|
"build:electron": "pnpm build && electron-builder",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"typecheck": "vue-tsc --noEmit",
|
"typecheck": "vue-tsc --noEmit",
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,13 @@ const router = createRouter({
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Kiosk chrome (hidden cursor) is the default — every real machine is a
|
||||||
|
// touchscreen. The public web demo (VITE_DEMO_TAG) runs in a normal browser,
|
||||||
|
// where an invisible pointer just reads as broken.
|
||||||
|
if (!import.meta.env.VITE_DEMO_TAG) {
|
||||||
|
document.documentElement.classList.add('kiosk')
|
||||||
|
}
|
||||||
|
|
||||||
// Create Pinia store
|
// Create Pinia store
|
||||||
const pinia = createPinia()
|
const pinia = createPinia()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -505,6 +505,31 @@ export async function initializeLightningServices(options?: {
|
||||||
}
|
}
|
||||||
console.log('[Lightning] LNbits wallet:', lnbitsWalletId)
|
console.log('[Lightning] LNbits wallet:', lnbitsWalletId)
|
||||||
|
|
||||||
|
// ── Public web demo: stamp the throwaway account so it can be swept ──────
|
||||||
|
// The browser demo (atm.demo.aiolabs.dev) runs with an EPHEMERAL identity —
|
||||||
|
// a fresh keypair per page load — so LNbits mints a new account + a fresh
|
||||||
|
// auto-credited wallet for every visitor. That isolation is the point (a
|
||||||
|
// single baked-in key would be credited exactly once and then drain), but it
|
||||||
|
// leaves throwaway accounts behind, and nothing in an auto-created row says
|
||||||
|
// "demo": pubkey-set/prvkey-NULL also describes a real ATM.
|
||||||
|
//
|
||||||
|
// A nostr pubkey can't carry a marker (you'd have to grind a vanity prefix,
|
||||||
|
// far too slow to do on page load), and the account/wallet the server
|
||||||
|
// auto-creates isn't nameable by the client. So we mint one extra,
|
||||||
|
// never-used wallet whose NAME is the tag: sweeping is then an exact string
|
||||||
|
// match on wallet name rather than a heuristic about what looks disposable.
|
||||||
|
//
|
||||||
|
// Unset on every real machine, so this is inert outside the demo build. The
|
||||||
|
// call is fire-and-forget: losing the marker degrades cleanup, not the demo.
|
||||||
|
const demoTag = (import.meta.env.VITE_DEMO_TAG as string | undefined)?.trim()
|
||||||
|
if (demoTag) {
|
||||||
|
void lnbits
|
||||||
|
.createWallet(demoTag)
|
||||||
|
// Never log the reply — create_wallet returns adminkey/inkey.
|
||||||
|
.then(() => console.log('[Lightning] Demo marker wallet created:', demoTag))
|
||||||
|
.catch((e) => console.warn('[Lightning] Demo marker wallet failed:', e))
|
||||||
|
}
|
||||||
|
|
||||||
// #70 P1: pull operator pubkey + fee config from LNbits over the authenticated
|
// #70 P1: pull operator pubkey + fee config from LNbits over the authenticated
|
||||||
// transport (spirekeeper#41 `get_machine_config`). A seed-only machine has no
|
// transport (spirekeeper#41 `get_machine_config`). A seed-only machine has no
|
||||||
// VITE_OPERATOR_PUBKEYS, so without this it can't trust its fee config and sits
|
// VITE_OPERATOR_PUBKEYS, so without this it can't trust its fee config and sits
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,13 @@
|
||||||
@import 'tailwindcss';
|
@import 'tailwindcss';
|
||||||
@import 'tw-animate-css';
|
@import 'tw-animate-css';
|
||||||
|
|
||||||
/* Hide cursor completely on touchscreen kiosk */
|
/* Hide cursor completely on touchscreen kiosk.
|
||||||
*,
|
Scoped to .kiosk (set on <html> by main.ts) so the public web demo, which
|
||||||
*::before,
|
runs in an ordinary browser with a mouse, keeps a visible pointer. */
|
||||||
*::after {
|
.kiosk,
|
||||||
|
.kiosk *,
|
||||||
|
.kiosk *::before,
|
||||||
|
.kiosk *::after {
|
||||||
cursor: none !important;
|
cursor: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "turbo dev",
|
"dev": "turbo dev",
|
||||||
"build": "turbo build",
|
"build": "turbo build",
|
||||||
|
"build:web": "turbo build:web",
|
||||||
"test": "turbo test",
|
"test": "turbo test",
|
||||||
"lint": "turbo lint",
|
"lint": "turbo lint",
|
||||||
"format": "prettier --write .",
|
"format": "prettier --write .",
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ import type {
|
||||||
CreateInvoiceBody,
|
CreateInvoiceBody,
|
||||||
PayInvoiceBody,
|
PayInvoiceBody,
|
||||||
WalletInfo,
|
WalletInfo,
|
||||||
|
CreatedWallet,
|
||||||
MachineConfigResponse,
|
MachineConfigResponse,
|
||||||
SubscribePaymentsBody,
|
SubscribePaymentsBody,
|
||||||
SubscribeAck,
|
SubscribeAck,
|
||||||
|
|
@ -211,6 +212,17 @@ export class LnbitsClient {
|
||||||
return data ?? []
|
return data ?? []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an additional wallet on the calling account (`create_wallet`).
|
||||||
|
*
|
||||||
|
* Account-scoped (AUTH_ACCOUNT): the envelope carries no `wallet_id`, which
|
||||||
|
* is what makes the server resolve auth to the Account rather than a Wallet.
|
||||||
|
* NOT wrapped in `idempotent()` — a retry would mint a duplicate wallet.
|
||||||
|
*/
|
||||||
|
async createWallet(name: string): Promise<CreatedWallet> {
|
||||||
|
return this.sendRpc<CreatedWallet>('create_wallet', { body: { name } })
|
||||||
|
}
|
||||||
|
|
||||||
/** Pull server-delivered machine config (operator pubkey + fee config) over
|
/** Pull server-delivered machine config (operator pubkey + fee config) over
|
||||||
* the authenticated transport — spirekeeper's `get_machine_config` RPC
|
* the authenticated transport — spirekeeper's `get_machine_config` RPC
|
||||||
* (bitspire#70 P1). Lets a seed-only ATM configure itself with no per-machine
|
* (bitspire#70 P1). Lets a seed-only ATM configure itself with no per-machine
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ export type {
|
||||||
CreateInvoiceBody,
|
CreateInvoiceBody,
|
||||||
PayInvoiceBody,
|
PayInvoiceBody,
|
||||||
WalletInfo,
|
WalletInfo,
|
||||||
|
CreatedWallet,
|
||||||
SubscribePaymentsBody,
|
SubscribePaymentsBody,
|
||||||
SubscribeAck,
|
SubscribeAck,
|
||||||
SubscribePush,
|
SubscribePush,
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,15 @@ export interface WalletInfo {
|
||||||
balance: number
|
balance: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Reply shape of the `create_wallet` RPC — unlike WalletInfo it carries the
|
||||||
|
* fresh wallet's keys, so never log it verbatim. */
|
||||||
|
export interface CreatedWallet {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
adminkey: string
|
||||||
|
inkey: string
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Subscriptions
|
// Subscriptions
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,11 @@
|
||||||
"dependsOn": ["^build"],
|
"dependsOn": ["^build"],
|
||||||
"outputs": ["dist/**", ".next/**", "!.next/cache/**"]
|
"outputs": ["dist/**", ".next/**", "!.next/cache/**"]
|
||||||
},
|
},
|
||||||
|
"build:web": {
|
||||||
|
"dependsOn": ["^build"],
|
||||||
|
"outputs": ["dist/**"],
|
||||||
|
"env": ["VITE_*"]
|
||||||
|
},
|
||||||
"dev": {
|
"dev": {
|
||||||
"cache": false,
|
"cache": false,
|
||||||
"persistent": true
|
"persistent": true
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue