commit 3ac235f222527d06b509d8781b0b3355ef301108
Author: William Casarin <jb55@jb55.com>
Date: Sun, 21 Aug 2022 11:18:56 -0700
initial commit
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
8 files changed, 751 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,5 @@
+lightning-master/
+lightning.tar.gz
+.direnv/
+.envrc
+shell.nix
diff --git a/AegishjalmrRed.svg b/AegishjalmrRed.svg
@@ -0,0 +1,219 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="550"
+ height="550"
+ version="1.1"
+ id="svg130"
+ sodipodi:docname="AegishjalmrRed.svg"
+ viewBox="0 0 550 550"
+ inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <defs
+ id="defs134">
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient1215">
+ <stop
+ style="stop-color:#ffc006;stop-opacity:1;"
+ offset="0"
+ id="stop1211" />
+ <stop
+ style="stop-color:#ff2a06;stop-opacity:1;"
+ offset="1"
+ id="stop1213" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient1215"
+ id="linearGradient1217"
+ x1="27.528861"
+ y1="276.08156"
+ x2="527.52886"
+ y2="276.08156"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview132"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1"
+ showgrid="false"
+ inkscape:zoom="1.2105668"
+ inkscape:cx="448.13719"
+ inkscape:cy="296.96833"
+ inkscape:window-width="1920"
+ inkscape:window-height="1060"
+ inkscape:window-x="0"
+ inkscape:window-y="20"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg130" />
+ <g
+ id="g306"
+ style="stroke:none;fill:url(#linearGradient1217);stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none">
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"
+ d="m 277.5293,232.58203 c -23.98291,0 -43.5,19.51709 -43.5,43.5 0,23.98291 19.51709,43.5 43.5,43.5 23.9829,0 43.5,-19.51709 43.5,-43.5 0,-23.98291 -19.5171,-43.5 -43.5,-43.5 z m 0,7 c 20.19983,0 36.5,16.30017 36.5,36.5 0,20.19983 -16.30017,36.5 -36.5,36.5 -20.19983,0 -36.5,-16.30017 -36.5,-36.5 0,-20.19983 16.30017,-36.5 36.5,-36.5 z"
+ id="circle107" />
+ <g
+ id="a"
+ stroke="#000000"
+ stroke-width="7"
+ transform="translate(27.528861,26.081557)"
+ style="stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill:url(#linearGradient1217);fill-opacity:1;stroke-width:6;stroke-dasharray:none">
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"
+ d="m 0,246.5 v 7 h 250 v -7 z"
+ id="path109" />
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"
+ d="m 5,196.5 v 7 c 14.027764,0 24.110114,5.67622 31.017578,14.31055 C 42.925042,226.44488 46.5,238.20001 46.5,250 c 0,11.79999 -3.574958,23.55512 -10.482422,32.18945 C 29.110114,290.82378 19.027764,296.5 5,296.5 v 7 c 15.972206,0 28.389901,-6.8238 36.482422,-16.93945 C 49.574943,276.4449 53.5,263.19999 53.5,250 53.5,236.80001 49.574943,223.5551 41.482422,213.43945 33.389901,203.3238 20.972206,196.5 5,196.5 Z"
+ id="path111" />
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"
+ d="m 96.5,215 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z"
+ id="path113" />
+ </g>
+ <g
+ id="use116"
+ stroke="#000000"
+ stroke-width="7"
+ transform="rotate(45,232.28122,296.27106)"
+ style="stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill:url(#linearGradient1217);fill-opacity:1;stroke-width:6;stroke-dasharray:none">
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"
+ d="m 0,246.5 v 7 h 250 v -7 z"
+ id="path985" />
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"
+ d="m 5,196.5 v 7 c 14.027764,0 24.110114,5.67622 31.017578,14.31055 C 42.925042,226.44488 46.5,238.20001 46.5,250 c 0,11.79999 -3.574958,23.55512 -10.482422,32.18945 C 29.110114,290.82378 19.027764,296.5 5,296.5 v 7 c 15.972206,0 28.389901,-6.8238 36.482422,-16.93945 C 49.574943,276.4449 53.5,263.19999 53.5,250 53.5,236.80001 49.574943,223.5551 41.482422,213.43945 33.389901,203.3238 20.972206,196.5 5,196.5 Z"
+ id="path987" />
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"
+ d="m 96.5,215 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z"
+ id="path989" />
+ </g>
+ <g
+ id="use118"
+ stroke="#000000"
+ stroke-width="7"
+ transform="rotate(90,250.72365,276.80521)"
+ style="stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill:url(#linearGradient1217);fill-opacity:1;stroke-width:6;stroke-dasharray:none">
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"
+ d="m 0,246.5 v 7 h 250 v -7 z"
+ id="path993" />
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"
+ d="m 5,196.5 v 7 c 14.027764,0 24.110114,5.67622 31.017578,14.31055 C 42.925042,226.44488 46.5,238.20001 46.5,250 c 0,11.79999 -3.574958,23.55512 -10.482422,32.18945 C 29.110114,290.82378 19.027764,296.5 5,296.5 v 7 c 15.972206,0 28.389901,-6.8238 36.482422,-16.93945 C 49.574943,276.4449 53.5,263.19999 53.5,250 53.5,236.80001 49.574943,223.5551 41.482422,213.43945 33.389901,203.3238 20.972206,196.5 5,196.5 Z"
+ id="path995" />
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"
+ d="m 96.5,215 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z"
+ id="path997" />
+ </g>
+ <g
+ id="use120"
+ stroke="#000000"
+ stroke-width="7"
+ transform="rotate(135,258.36277,268.74219)"
+ style="stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill:url(#linearGradient1217);fill-opacity:1;stroke-width:6;stroke-dasharray:none">
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"
+ d="m 0,246.5 v 7 h 250 v -7 z"
+ id="path1001" />
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"
+ d="m 5,196.5 v 7 c 14.027764,0 24.110114,5.67622 31.017578,14.31055 C 42.925042,226.44488 46.5,238.20001 46.5,250 c 0,11.79999 -3.574958,23.55512 -10.482422,32.18945 C 29.110114,290.82378 19.027764,296.5 5,296.5 v 7 c 15.972206,0 28.389901,-6.8238 36.482422,-16.93945 C 49.574943,276.4449 53.5,263.19999 53.5,250 53.5,236.80001 49.574943,223.5551 41.482422,213.43945 33.389901,203.3238 20.972206,196.5 5,196.5 Z"
+ id="path1003" />
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"
+ d="m 96.5,215 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z"
+ id="path1005" />
+ </g>
+ <g
+ id="use122"
+ stroke="#000000"
+ stroke-width="7"
+ transform="rotate(180,263.76443,263.04078)"
+ style="stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill:url(#linearGradient1217);fill-opacity:1;stroke-width:6;stroke-dasharray:none">
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"
+ d="m 0,246.5 v 7 h 250 v -7 z"
+ id="path1009" />
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"
+ d="m 5,196.5 v 7 c 14.027764,0 24.110114,5.67622 31.017578,14.31055 C 42.925042,226.44488 46.5,238.20001 46.5,250 c 0,11.79999 -3.574958,23.55512 -10.482422,32.18945 C 29.110114,290.82378 19.027764,296.5 5,296.5 v 7 c 15.972206,0 28.389901,-6.8238 36.482422,-16.93945 C 49.574943,276.4449 53.5,263.19999 53.5,250 53.5,236.80001 49.574943,223.5551 41.482422,213.43945 33.389901,203.3238 20.972206,196.5 5,196.5 Z"
+ id="path1011" />
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"
+ d="m 96.5,215 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z"
+ id="path1013" />
+ </g>
+ <g
+ id="use124"
+ stroke="#000000"
+ stroke-width="7"
+ transform="rotate(-45,295.24766,229.81051)"
+ style="stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill:url(#linearGradient1217);fill-opacity:1;stroke-width:6;stroke-dasharray:none">
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"
+ d="m 0,246.5 v 7 h 250 v -7 z"
+ id="path1017" />
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"
+ d="m 5,196.5 v 7 c 14.027764,0 24.110114,5.67622 31.017578,14.31055 C 42.925042,226.44488 46.5,238.20001 46.5,250 c 0,11.79999 -3.574958,23.55512 -10.482422,32.18945 C 29.110114,290.82378 19.027764,296.5 5,296.5 v 7 c 15.972206,0 28.389901,-6.8238 36.482422,-16.93945 C 49.574943,276.4449 53.5,263.19999 53.5,250 53.5,236.80001 49.574943,223.5551 41.482422,213.43945 33.389901,203.3238 20.972206,196.5 5,196.5 Z"
+ id="path1019" />
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"
+ d="m 96.5,215 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z"
+ id="path1021" />
+ </g>
+ <g
+ id="use126"
+ stroke="#000000"
+ stroke-width="7"
+ transform="rotate(-90,276.80521,249.27635)"
+ style="stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill:url(#linearGradient1217);fill-opacity:1;stroke-width:6;stroke-dasharray:none">
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"
+ d="m 0,246.5 v 7 h 250 v -7 z"
+ id="path1025" />
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"
+ d="m 5,196.5 v 7 c 14.027764,0 24.110114,5.67622 31.017578,14.31055 C 42.925042,226.44488 46.5,238.20001 46.5,250 c 0,11.79999 -3.574958,23.55512 -10.482422,32.18945 C 29.110114,290.82378 19.027764,296.5 5,296.5 v 7 c 15.972206,0 28.389901,-6.8238 36.482422,-16.93945 C 49.574943,276.4449 53.5,263.19999 53.5,250 53.5,236.80001 49.574943,223.5551 41.482422,213.43945 33.389901,203.3238 20.972206,196.5 5,196.5 Z"
+ id="path1027" />
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"
+ d="m 96.5,215 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z"
+ id="path1029" />
+ </g>
+ <g
+ id="use128"
+ stroke="#000000"
+ stroke-width="7"
+ transform="rotate(-135,269.16611,257.33936)"
+ style="stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill:url(#linearGradient1217);fill-opacity:1;stroke-width:6;stroke-dasharray:none">
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);fill-opacity:1;stroke:none;stroke-width:6;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
+ d="m 0,246.5 2.8284271,7 250.0000029,0 v -7 z"
+ id="path1033"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"
+ d="m 5,196.5 v 7 c 14.027764,0 24.110114,5.67622 31.017578,14.31055 C 42.925042,226.44488 46.5,238.20001 46.5,250 c 0,11.79999 -3.574958,23.55512 -10.482422,32.18945 C 29.110114,290.82378 19.027764,296.5 5,296.5 v 7 c 15.972206,0 28.389901,-6.8238 36.482422,-16.93945 C 49.574943,276.4449 53.5,263.19999 53.5,250 53.5,236.80001 49.574943,223.5551 41.482422,213.43945 33.389901,203.3238 20.972206,196.5 5,196.5 Z"
+ id="path1035" />
+ <path
+ style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"
+ d="m 96.5,215 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z"
+ id="path1037" />
+ </g>
+ </g>
+</svg>
diff --git a/Makefile b/Makefile
@@ -0,0 +1,3 @@
+
+dist:
+ rsync -avzP ./ charon:public/runes/
diff --git a/index.html b/index.html
@@ -0,0 +1,30 @@
+
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+
+ <title>CLN Rune Workshop</title>
+ <link rel="stylesheet" href="style.css" />
+ </head>
+ <body>
+ <div id="container">
+ <header>
+ <img width="140px" height="140px" src="AegishjalmrRed.svg" >
+ <div>
+ <h1>Rune Workshop</h1>
+ <h3>Craft CoreLN Authentication Runes</h3>
+ </div>
+ </header>
+ <section id="rune">
+ <h2>Command</h2>
+ <textarea id="command"></textarea>
+ </section>
+ <section id="workshop">
+ </section>
+ </div>
+ </body>
+ <script src="rune-workshop.js?v=2" ></script>
+</html>
+
diff --git a/rune-workshop.js b/rune-workshop.js
@@ -0,0 +1,372 @@
+
+let STATE = {}
+
+async function go() {
+ const el = document.querySelector("#workshop")
+
+ el.innerHTML = await render_workshop()
+
+ load_selected()
+
+ setInterval(try_update_command, 10000)
+}
+
+function now_unix() {
+ return Math.floor(new Date().getTime() / 1000)
+}
+
+function try_update_command() {
+ let r = STATE.restrictions
+ if (r && r.duration) {
+ let updated = now_unix() + r.duration
+ if (updated != r.time) {
+ r.time = updated
+ update_command(STATE.restrictions)
+ }
+ }
+}
+
+function get_rpcs() {
+ return fetch("schemas.json").then(res => res.json())
+}
+
+function load_selected() {
+ //const method = window.location.hash.substr(1) || "commando"
+
+ //select_method(method)
+}
+
+function duration_scale_multiplier(v) {
+ switch (v) {
+ case "minutes": return 60
+ case "hours": return 60*60
+ case "days": return 60*60*24
+ case "weeks": return 60*60*24*7
+ case "months": return 60*60*24*30
+ case "years": return 60*60*24*365
+ }
+
+ return 0
+}
+
+function change_duration() {
+ const value = document.querySelector("#duration-input").value
+ const scale = document.querySelector("#duration-scale").value
+ const mod = duration_scale_multiplier(scale)
+
+ let r = STATE.restrictions = STATE.restrictions || {}
+
+ if (value) {
+ r.duration = mod * value
+ r.time = (Math.floor(new Date().getTime() / 1000)) + r.duration
+ } else {
+ delete r.time
+ delete r.duration
+ }
+
+ update_command(r)
+}
+
+function render_time_restriction()
+{
+ return `
+ <span class="param-name">Duration</span>
+ <input type="number" onkeyup="change_duration()" id="duration-input"></input>
+ <select onchange="change_duration()" id="duration-scale">
+ <option value=minutes>Minutes</option>
+ <option value=hours>Hours</option>
+ <option value=days>Days</option>
+ <option value=weeks>Weeks</option>
+ <option value=months>Months</option>
+ <option value=years>Years</option>
+ </select>
+ `
+}
+
+function render_rate_restriction()
+{
+ return `
+ <span class="param-name">Rate</span>
+ <input type="number" onkeyup="change_rate(this)" id="rate-input"></input>
+ Requests Per Minute
+ `
+}
+
+function change_rate(el) {
+ const r = STATE.restrictions = STATE.restrictions || {}
+
+ r.rate = el.value
+
+ update_command(r)
+}
+
+function render_generic_restrictions_section(rpcs)
+{
+ return `
+ <h2>Restrictions</h2>
+ <div>
+ ${render_time_restriction()}
+ </div>
+ <div>
+ ${render_rate_restriction()}
+ </div>
+ <div>
+ <span class="param-name">Method</span>
+ ${render_method_selector(rpcs)}
+ </div>
+ `
+}
+
+async function render_workshop() {
+ const rpcs = await get_rpcs()
+ STATE.rpcs = rpcs
+
+ return `
+ ${render_generic_restrictions_section(rpcs)}
+ <div id="method">
+ </div>
+ `
+}
+
+function select_method(sel) {
+ const method = sel.value
+ const el = document.querySelector("#method")
+ STATE.restrictions = STATE.restrictions || {}
+ STATE.restrictions.params = {}
+
+ if (method) {
+ let rpc = STATE.rpcs[method]
+ rpc.method = method
+ update_restriction({method})
+ el.innerHTML = render_rpc(rpc)
+ } else {
+ update_command(STATE.restrictions)
+ el.innerHTML = ""
+ }
+
+}
+
+function render_rpc(rpc) {
+ const params = render_params(rpc)
+
+ return `
+ <h2>${rpc.method} parameters</h2>
+
+ ${params}
+
+ <pre>${JSON.stringify(rpc,null,4)}</pre>
+ `
+}
+
+function render_params(rpc) {
+ const required = rpc.required.reduce((obj, param) => {
+ obj[param] = true
+ return obj
+ }, {})
+
+ const params = Object.keys(rpc.properties)
+
+ return params.map(p => render_param(required, rpc, p)).join("\n")
+}
+
+function render_type(p)
+{
+ let type = p.type;
+ if (p.type === "array" && p.items) {
+ type = `[${p.items.type}]`
+ }
+ return `<span class="badge type-${p.type}">${type}</span>`
+}
+
+function get_description(p)
+{
+ if (p.oneOf) {
+ return p.oneOf.map(o => o.description).filter(d => d).join("<br/><br/>")
+ }
+
+ return p.description;
+}
+
+/*
+ * 58 object
+ * 54 string
+ * 22 array
+ * 21 u32
+ * 18 pubkey
+ * 15 msat
+ * 13 u64
+ * 11 hex
+ * 11 boolean
+ * 10 u16
+ * 7 short_channel_id
+ * 6 number
+ * 6 hash
+ * 6 feerate
+ * 4 outpoint
+ * 3 txid
+ * 3 secret
+ * 3 integer
+ * 2 msat_or_all
+ * 1 short_channel_id_dir
+ * 1 outputdesc
+ * 1 msat_or_any
+ * 1 hexstr
+ * 1 addresstype
+ */
+function get_type(p) {
+ // TODO: oneOf stuff
+ return p.type
+}
+
+function get_input_type(type) {
+ switch (type) {
+ case "u16":
+ case "number":
+ case "u32":
+ case "u64": return "number"
+
+ case "string": return "text"
+ default: return "text"
+ }
+}
+
+function render_type_options(type)
+{
+ if (type === 'number') {
+ return `
+ <option value="=">Equals</option>
+ <option value=">">Greater Than</option>
+ <option value="<">Less Than</option>
+ `
+ }
+
+ return `
+ <option value="=">Equals</option>
+ <option value="^">Starts With</option>
+ `
+}
+
+function update_restriction(data)
+{
+ let r = STATE.restrictions = STATE.restrictions || {}
+ r = r.params = r.params || {}
+
+ let v = r[data.method] = r[data.method] || {}
+
+ if (data.param_name) {
+ const selkey = selector_key(data.method, data.param_name)
+ const value = document.querySelector(`#${selkey}-input`).value
+ const op = document.querySelector(`#${selkey}`).value
+ v[data.param_name] = {value,op}
+ if (value === "") {
+ delete v[data.param_name]
+ }
+ }
+
+ update_command(STATE.restrictions)
+}
+
+function update_command(r)
+{
+ const command_el = document.querySelector("#command")
+ command_el.value = build_command(r)
+}
+
+function restriction(v, old=true) {
+ if (old) {
+ return v
+ } else {
+ return [v]
+ }
+}
+
+function build_command(r)
+{
+ let rs = []
+ if (r.params) {
+ for (const method of Object.keys(r.params)) {
+ rs.push(restriction(`method=${method}`))
+
+ for (const pname of Object.keys(r.params[method])) {
+ const {value, op} = r.params[method][pname]
+ rs.push(restriction(`pname${pname}${op}${value}`))
+ }
+ }
+ }
+
+ if (r.rate) {
+ rs.push(restriction(`rate=${r.rate}`))
+ }
+
+ if (r.time) {
+ rs.push(restriction(`time<${r.time}`))
+ }
+
+ const out = JSON.stringify(rs)
+
+ return `lightning-cli commando-rune restrictions='${out}'`
+}
+
+function selector_key(method, param_name)
+{
+ return method + param_name
+}
+
+function render_restriction_tool(rpc, param_name, param)
+{
+ const type = get_type(param) || "string"
+ const input_type = get_input_type(type)
+
+ const method = rpc.method
+ const json_p = JSON.stringify({ method, param_name, param })
+ const selkey = selector_key(method, param_name)
+ const updater = `update_restriction(${json_p})`
+
+ return `
+ <div class="restriction-tool">
+ <select onchange='${updater}' id="${selkey}">
+ ${render_type_options(input_type)}
+ </select>
+ <input id='${selkey}-input' onkeyup='${updater}' type="${input_type}"></input>
+ </div>
+ `
+}
+
+function render_param(required, rpc, param) {
+ const p = rpc.properties[param]
+
+ const is_req = !!required[param]
+ const req = is_req ? "param-required" : ""
+ const desc = get_description(p)
+ const typ = get_type(p)
+
+ return `
+ <span class="param-name ${req}">${param}</span>
+ ${render_type(p)}
+ <!--
+ <span class="required">${is_req? "required" : ""}</span>
+ -->
+ <blockquote>
+ ${desc}
+ ${render_restriction_tool(rpc, param, p)}
+ </blockquote>
+ `
+}
+
+function render_method_selector(rpcs) {
+ let methods = Object.keys(rpcs)
+ methods.unshift("")
+
+ const options = methods.map(method =>
+ `<option id="${method}" value="${method}">${method}</option>`)
+ .join("\n")
+
+ return `
+ <select id="method_selector" onchange="select_method(this)">
+ ${options}
+ </select>
+ `
+}
+
+
+go()
diff --git a/schemas.json b/schemas.json
@@ -0,0 +1 @@
+{"addgossip": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["message"], "properties": {"message": {"type": "hex", "description": "The raw, hex-encoded, gossip message to add to the local gossip view."}}}, "autocleaninvoice": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": [], "properties": {"expired_by": {"type": "u64", "description": "How long an invoice must be expired (seconds) before we delete it."}, "cycle_seconds": {"type": "u64", "description": "The interval (in seconds) between cleaning expired invoices"}}}, "checkmessage": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["message", "zbase"], "properties": {"message": {"type": "string", "description": "Message to be checked against the signature."}, "zbase": {"type": "string", "description": "The Zbase32 encoded signature to verify."}, "pubkey": {"type": "pubkey", "description": "The Zbase32 encoded signature to verify."}}}, "close": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["id"], "properties": {"id": {"type": "string", "description": "peer id, channel id or short_channel_id"}, "unilateraltimeout": {"type": "u32", "description": ""}, "destination": {"type": "string", "description": ""}, "fee_negotiation_step": {"type": "string", "description": ""}, "wrong_funding": {"type": "txid", "description": ""}, "force_lease_closed": {"type": "boolean", "description": ""}, "feerange": {"type": "array", "items": {"type": "feerate"}, "description": ""}}}, "commando": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["peer_id", "method"], "properties": {"peer_id": {"type": "pubkey", "description": "peer to command"}, "method": {"type": "string", "description": "method to invoke on peer"}, "params": {"oneOf": [{"type": "array", "description": "array of positional parameters"}, {"type": "object", "description": "parameters for method"}]}, "rune": {"type": "string", "description": "rune to authorize the command"}}}, "commando-rune": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": [], "properties": {"rune": {"type": "string", "description": "optional rune to add to"}, "restrictions": {"oneOf": [{"type": "array", "description": "array of restrictions to add to rune", "items": {"type": "string"}}, {"type": "string", "description": "single restrictions to add to rune, or readonly."}]}}}, "connect": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["id"], "properties": {"id": {"type": "string", "description": ""}, "host": {"type": "string", "description": "The hostname of the node."}, "port": {"type": "u16", "description": "Port to try connecting to"}}}, "createinvoice": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["invstring", "label", "preimage"], "properties": {"invstring": {"type": "string", "description": ""}, "label": {"type": "string", "description": ""}, "preimage": {"type": "hex", "description": ""}}}, "createonion": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["hops", "assocdata"], "properties": {"hops": {"type": "array", "description": "", "items": {"type": "object", "additionalProperties": false, "required": ["pubkey", "payload"], "properties": {"pubkey": {"type": "pubkey"}, "payload": {"type": "hex"}}}}, "assocdata": {"type": "hex", "description": ""}, "session_key": {"type": "secret"}, "onion_size": {"type": "u16"}}}, "datastore": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["key"], "properties": {"key": {"oneOf": [{"type": "array", "description": "key is an array of values (though a single value is treated as a one-element array), to form a heirarchy. Using the first element of the key as the plugin name (e.g. [ 'summary' ]) is recommended. A key can either have children or a value, never both: parents are created and removed automatically.", "items": {"type": "string"}}, {"type": "string"}]}, "string": {"type": "string", "description": ""}, "hex": {"type": "hex", "description": ""}, "mode": {"type": "string", "enum": ["must-create", "must-replace", "create-or-replace", "must-append", "create-or-append"], "description": ""}, "generation": {"type": "u64", "description": "If specified, means that the update will fail if the previously-existing data is not exactly that generation. This allows for simple atomicity. This is only legal with mode \u201cmust-replace\u201d or \u201cmust-append\u201d."}}}, "deldatastore": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["key"], "properties": {"key": {"oneOf": [{"type": "array", "description": "key is an array of values (though a single value is treated as a one-element array), to form a heirarchy. Using the first element of the key as the plugin name (e.g. [ 'summary' ]) is recommended. A key can either have children or a value, never both: parents are created and removed automatically.", "items": {"type": "string"}}, {"type": "string"}]}, "generation": {"type": "u64", "description": "If specified, means that the update will fail if the previously-existing data is not exactly that generation. This allows for simple atomicity. This is only legal with mode \u201cmust-replace\u201d or \u201cmust-append\u201d."}}}, "delexpiredinvoice": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": [], "properties": {"maxexpirytime": {"type": "u64", "description": ""}}}, "delinvoice": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["label", "status"], "properties": {"label": {"oneOf": [{"type": "string", "description": ""}, {"type": "integer", "description": ""}]}, "status": {"type": "string", "enum": ["paid", "expired", "unpaid"]}, "desconly": {"type": "boolean"}}}, "disconnect": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["id"], "properties": {"id": {"type": "pubkey"}, "force": {"type": "boolean"}}}, "emergencyrecover": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [], "additionalProperties": false, "properties": {}}, "feerates": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["style"], "properties": {"style": {"type": "string", "enum": ["perkb", "perkw"]}}}, "fundchannel": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["id", "amount"], "properties": {"id": {"type": "pubkey", "description": "id is the peer id obtained from connect."}, "amount": {"type": "msat_or_all"}, "feerate": {"type": "feerate"}, "announce": {"type": "boolean"}, "minconf": {"type": "u32"}, "push_msat": {"type": "msat"}, "close_to": {"type": "string"}, "request_amt": {"type": "msat"}, "compact_lease": {"type": "string"}, "utxos": {"type": "array", "items": {"type": "outpoint"}}, "mindepth": {"description": "Number of confirmations required before we consider the channel active", "type": "u32"}}}, "fundpsbt": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["satoshi", "feerate", "startweight"], "properties": {"satoshi": {"type": "msat"}, "feerate": {"type": "feerate"}, "startweight": {"type": "u32"}, "minconf": {"type": "u32"}, "reserve": {"type": "u32", "description": "reserve is a number: if non-zero number then reserveinputs is called (successfully, with exclusive true) on the returned PSBT for this number of blocks (default: 72)."}, "locktime": {"type": "u32"}, "min_witness_weight": {"type": "u32"}, "excess_as_change": {"type": "boolean"}}}, "getinfo": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [], "additionalProperties": false, "properties": {}}, "getroute": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": ["id", "amount_msat", "riskfactor"], "properties": {"id": {"type": "pubkey", "description": ""}, "amount_msat": {"type": "msat", "description": ""}, "riskfactor": {"type": "u64", "description": ""}, "cltv": {"type": "number", "description": ""}, "fromid": {"type": "pubkey", "description": ""}, "fuzzpercent": {"type": "u32", "description": ""}, "exclude": {"type": "array", "description": "", "items": {"type": "string"}}, "maxhops": {"type": "u32", "description": ""}}}, "invoice": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["amount_msat", "label", "description"], "properties": {"amount_msat": {"type": "msat_or_any", "description": ""}, "description": {"type": "string", "description": ""}, "label": {"oneOf": [{"type": "string", "description": ""}, {"type": "integer", "description": ""}]}, "expiry": {"type": "u64", "description": ""}, "fallbacks": {"type": "array", "description": "", "items": {"type": "string"}}, "preimage": {"type": "hex", "description": ""}, "exposeprivatechannels": {"oneOf": [{"type": "boolean", "description": ""}, {"type": "array", "items": {"type": "short_channel_id"}}, {"type": "short_channel_id"}]}, "cltv": {"type": "u32", "description": ""}, "deschashonly": {"type": "boolean", "description": ""}}}, "keysend": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["destination", "amount_msat"], "properties": {"destination": {"type": "pubkey"}, "amount_msat": {"type": "msat"}, "label": {"type": "string"}, "maxfeepercent": {"type": "number"}, "retry_for": {"type": "u32"}, "maxdelay": {"type": "u32"}, "exemptfee": {"type": "msat"}, "routehints": {"type": "array", "items": {"type": "array", "items": {"type": "object", "additionalProperties": false, "required": ["id", "scid", "feebase", "feeprop", "expirydelta"], "properties": {"id": {"type": "pubkey"}, "scid": {"type": "short_channel_id"}, "feebase": {"type": "msat"}, "feeprop": {"type": "u32"}, "expirydelta": {"type": "u16"}}}}}, "extratlvs": {"type": "object", "additionalProperties": true, "required": []}}}, "listchannels": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [], "additionalProperties": false, "properties": {"short_channel_id": {"type": "short_channel_id", "description": "If short_channel_id is a short channel id, then only known channels with a matching short_channel_id are returned. Otherwise, it must be null."}, "source": {"type": "pubkey", "description": "If source is a node id, then only channels leading from that node id are returned."}, "destination": {"type": "pubkey", "description": "If destination is a node id, then only channels leading to that node id are returned."}}}, "listdatastore": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": [], "properties": {"key": {"oneOf": [{"type": "array", "description": "key is an array of values (though a single value is treated as a one-element array), to form a heirarchy. Using the first element of the key as the plugin name (e.g. [ 'summary' ]) is recommended. A key can either have children or a value, never both: parents are created and removed automatically.", "items": {"type": "string"}}, {"type": "string", "description": ""}]}}}, "listforwards": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [], "properties": {"status": {"type": "string", "enum": ["offered", "settled", "local_failed", "failed"]}, "in_channel": {"type": "short_channel_id"}, "out_channel": {"type": "short_channel_id"}}}, "listfunds": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [], "additionalProperties": false, "properties": {"spent": {"type": "boolean", "description": "Should outputs that are already spent be included in the result?"}}}, "listinvoices": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": [], "properties": {"label": {"oneOf": [{"type": "string", "description": ""}, {"type": "integer", "description": ""}]}, "invstring": {"type": "string", "description": ""}, "payment_hash": {"type": "hex", "description": ""}, "offer_id": {"type": "string", "description": ""}}}, "listnodes": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [], "additionalProperties": false, "properties": {"id": {"type": "pubkey"}}}, "listpays": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [], "additionalProperties": false, "properties": {"bolt11": {"type": "string"}, "payment_hash": {"type": "hash"}, "status": {"type": "string", "enum": ["pending", "complete", "failed"]}}}, "listpeers": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [], "additionalProperties": false, "properties": {"id": {"type": "pubkey", "description": "If supplied, limits the result to just the peer with the given ID, if it exists."}, "level": {"type": "string", "description": "Supplying level will show log entries related to that peer at the given log level. Valid log levels are \u201cio\u201d, \u201cdebug\u201d, \u201cinfo\u201d, and \u201cunusual\u201d."}}}, "listsendpays": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [], "additionalProperties": false, "properties": {"bolt11": {"type": "string"}, "payment_hash": {"type": "hash"}, "status": {"type": "string", "enum": ["pending", "complete", "failed"]}}}, "listtransactions": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [], "additionalProperties": false, "properties": {}}, "makesecret": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["hex"], "properties": {"hex": {"type": "hex", "description": "This will be used for deriving the secret"}}}, "newaddr": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [], "additionalProperties": false, "properties": {"addresstype": {"type": "string", "enum": ["bech32", "p2sh-segwit", "all"]}}}, "pay": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["bolt11"], "properties": {"bolt11": {"type": "string"}, "amount_msat": {"type": "msat"}, "label": {"type": "string"}, "riskfactor": {"type": "number"}, "maxfeepercent": {"type": "number"}, "retry_for": {"type": "u16"}, "maxdelay": {"type": "u16"}, "exemptfee": {"type": "msat"}, "localofferid": {"type": "hex"}, "exclude": {"type": "array", "items": {"oneOf": [{"type": "short_channel_id_dir"}, {"type": "pubkey"}]}}, "maxfee": {"type": "msat"}, "description": {"type": "string"}}}, "ping": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": ["id"], "additionalProperties": false, "properties": {"id": {"type": "pubkey"}, "len": {"type": "number"}, "pongbytes": {"type": "number"}}}, "recoverchannel": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["scb"], "scb": {"type": "array", "description": "SCB of the channels in an array", "items": {"type": "hexstr"}}}, "sendonion": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["onion", "first_hop", "payment_hash"], "properties": {"onion": {"type": "hex"}, "first_hop": {"type": "object", "required": ["id", "amount_msat", "delay"], "properties": {"id": {"type": "pubkey"}, "amount_msat": {"type": "msat"}, "delay": {"type": "u16"}}}, "payment_hash": {"type": "hash"}, "label": {"type": "string"}, "shared_secrets": {"type": "array", "items": {"type": "secret"}}, "partid": {"type": "u16"}, "bolt11": {"type": "string"}, "amount_msat": {"type": "msat"}, "destination": {"type": "pubkey"}, "localofferid": {"type": "hash"}, "groupid": {"type": "u64"}}}, "sendpay": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["route", "payment_hash"], "properties": {"route": {"type": "array", "items": {"type": "object", "required": ["amount_msat", "id", "delay", "channel"], "properties": {"amount_msat": {"type": "msat"}, "msatoshi": {"deprecated": "true"}, "id": {"type": "pubkey"}, "delay": {"type": "u16"}, "channel": {"type": "short_channel_id"}}}}, "payment_hash": {"type": "hash"}, "label": {"type": "string"}, "amount_msat": {"type": "msat"}, "bolt11": {"type": "string"}, "payment_secret": {"type": "secret"}, "partid": {"type": "u16"}, "localofferid": {"type": "hex"}, "groupid": {"type": "u64"}}}, "sendpsbt": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["psbt"], "properties": {"psbt": {"type": "string"}, "reserve": {"type": "boolean"}}}, "signmessage": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": ["message"], "additionalProperties": false, "properties": {"message": {"type": "string"}}}, "signpsbt": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["psbt"], "properties": {"psbt": {"type": "string"}, "signonly": {"type": "array", "items": {"type": "u32"}}}}, "staticbackup": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [], "additionalProperties": false, "properties": {}}, "stop": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": [], "properties": {}}, "txdiscard": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["txid"], "properties": {"txid": {"type": "txid"}}}, "txprepare": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["outputs"], "properties": {"outputs": {"type": "array", "items": {"type": "outputdesc"}}, "feerate": {"type": "feerate"}, "minconf": {"type": "u32"}, "utxos": {"type": "array", "items": {"type": "outpoint"}}}}, "txsend": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["txid"], "properties": {"txid": {"type": "txid"}}}, "utxopsbt": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["satoshi", "feerate", "startweight", "utxos"], "properties": {"satoshi": {"type": "msat"}, "feerate": {"type": "feerate"}, "startweight": {"type": "u32"}, "utxos": {"type": "array", "items": {"type": "outpoint"}}, "reserve": {"type": "u32", "description": "reserve is a number: if non-zero number then reserveinputs is called (successfully, with exclusive true) on the returned PSBT for this number of blocks (default: 72)."}, "reservedok": {"type": "boolean"}, "locktime": {"type": "u32"}, "min_witness_weight": {"type": "u32"}, "excess_as_change": {"type": "boolean"}}}, "waitanyinvoice": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": [], "properties": {"lastpay_index": {"type": "u64"}, "timeout": {"type": "u64"}}}, "waitinvoice": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["label"], "properties": {"label": {"type": "string"}}}, "waitsendpay": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["payment_hash"], "properties": {"payment_hash": {"type": "hash"}, "timeout": {"type": "u32"}, "partid": {"type": "u64"}, "groupid": {"type": "u64"}}}, "withdraw": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["destination"], "properties": {"destination": {"type": "string"}, "satoshi": {"type": "msat_or_all"}, "feerate": {"type": "feerate"}, "minconf": {"type": "u16"}, "utxos": {"type": "array", "items": {"type": "outpoint"}}}}}+
\ No newline at end of file
diff --git a/style.css b/style.css
@@ -0,0 +1,94 @@
+
+body {
+ background-color: #333;
+ color: #ddd;
+ font-family: -apple-system, -system-ui, sans-serif;
+}
+
+select {
+ cursor: pointer;
+ padding: 6px;
+ border-radius: 8px;
+
+ background-color: #666;
+ margin: 20px 0 20px 0;
+}
+
+.param-name {
+ color: white;
+}
+
+.badge {
+ font-size: 0.7em;
+ padding: 3px;
+ background-color: #666;
+ color: white;
+ border-radius: 5px;
+}
+
+.param-required {
+ font-weight: bold;
+}
+
+.type-required {
+ background-color: #BE72CE;
+}
+
+.required {
+ font-size: 0.6em;
+ color: #888;
+}
+
+header {
+ margin-bottom: 20px;
+}
+
+#command {
+ width: 100%;
+ height: 50px;
+}
+
+.type-string {
+ background-color: #006400;
+}
+
+
+option {
+ color: white;
+}
+
+header {
+ display: flex;
+ align-items: center;
+}
+
+#container {
+ margin: auto;
+ max-width: 800px;
+}
+
+@media (min-width: 400px)
+.container {
+ width: 85%;
+ padding: 0;
+}
+
+h1,h3{
+ margin: 0;
+}
+
+h2 {
+ margin: 20px 0 20px 0;
+}
+
+h1 {
+ color: #FF7D06;
+}
+
+h2,h3 {
+ color: #FFB906;
+}
+
+header > img {
+ margin-right: 20px;
+}
diff --git a/sync-schemas.xonsh b/sync-schemas.xonsh
@@ -0,0 +1,26 @@
+#!/usr/bin/env xonsh
+
+import os
+import json
+import sys
+
+# fetch latest
+rm -rf lightning-master
+curl -sL https://github.com/ElementsProject/lightning/archive/master.tar.gz > lightning.tar.gz
+tar xf lightning.tar.gz
+
+schemas = $(ls -1 lightning-master/doc/schemas/*.request.json).strip().split("\n")
+
+out = {}
+for schema in schemas:
+ filename = os.path.basename(schema)
+ [method,_,_] = filename.split(".")
+ with open(schema) as f:
+ content = "".join(f.readlines())
+ out[method] = json.loads(content)
+
+
+print("Writing schemas.json", file=sys.stderr)
+
+with open("schemas.json", "w") as f:
+ f.write(json.dumps(out))