all repos — underbbs @ afef280a2b1db90e2889ebf552a53c24e33ac656

decentralized social media client

convert to typescript
Iris Lightshard nilix@nilfm.cc
PGP Signature
-----BEGIN PGP SIGNATURE-----

iHUEABYKAB0WIQT/foVVmI9pK13hPWFohAcXSWbK8wUCZi0s0wAKCRBohAcXSWbK
87yTAP9r6Yn9/a1vlx/DVh+izkcQ5fhbQmdthP3UU0lmWjPloAEAg59ZGstOT9Y8
ZSmkG0MCQdfoIoF14eg7PBsEse2D3AQ=
=F69T
-----END PGP SIGNATURE-----
commit

afef280a2b1db90e2889ebf552a53c24e33ac656

parent

18b7ef774abe0d4d0eb178d3214373e6fc0c01ca

9 files changed, 272 insertions(+), 179 deletions(-)

jump to
M .gitignore.gitignore

@@ -1,2 +1,3 @@

node_modules/ -dist/main.js+dist/main.js +src/
A build.sh

@@ -0,0 +1,8 @@

+#!/bin/sh + +if [ ! -e ./src ]; then + mkdir ./src +fi + +npx tsc && +npx webpack
M package-lock.jsonpackage-lock.json

@@ -11,9 +11,11 @@ "license": "ISC",

"dependencies": { "@nostr-dev-kit/ndk": "^2.7.1", "bech32": "^2.0.0", - "nostr-tools": "^2.5.0" + "nostr-tools": "^2.5.0", + "typescript": "^5.4.5" }, "devDependencies": { + "@types/debug": "^4.1.12", "webpack": "^5.91.0", "webpack-cli": "^5.1.4" }

@@ -281,6 +283,15 @@ "funding": {

"url": "https://paulmillr.com/funding/" } }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "dev": true, + "dependencies": { + "@types/ms": "*" + } + }, "node_modules/@types/eslint": { "version": "8.56.10", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz",

@@ -311,6 +322,12 @@ "node_modules/@types/json-schema": {

"version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/ms": { + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==", "dev": true }, "node_modules/@types/node": {

@@ -1683,6 +1700,18 @@ "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",

"integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", "dependencies": { "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" } }, "node_modules/typescript-lru-cache": {
M package.jsonpackage.json

@@ -11,9 +11,11 @@ "license": "ISC",

"dependencies": { "@nostr-dev-kit/ndk": "^2.7.1", "bech32": "^2.0.0", - "nostr-tools": "^2.5.0" + "nostr-tools": "^2.5.0", + "typescript": "^5.4.5" }, "devDependencies": { + "@types/debug": "^4.1.12", "webpack": "^5.91.0", "webpack-cli": "^5.1.4" }
D src/adapter.js

@@ -1,57 +0,0 @@

-import NDK, {NDKPrivateKeySigner} from "@nostr-dev-kit/ndk"; -import * as nip19 from 'nostr-tools/nip19' -import { bech32 } from "bech32"; - -let ndk = null; - -function createAdapter() { - let adapter = { - nickname: "", - identity: null, - protocol: null, - }; - - adapter.init = ()=>{}; - adapter.getInbox = ()=>{}; - adapter.getFollowers = ()=>{}; - adapter.getFollowing = ()=>{}; - adapter.publish = ()=>{}; - adapter.updateMetadata = ()=>{}; - adapter.getMetadata = ()=>{}; - - return adapter; -} - -function toNostrAdapter(adapter, settings) { - adapter.identity = { privkey: settings.privkey }; - adapter.nickname = settings.nickname; - adapter.init = ()=> { - if (!ndk) { - let privkey_raw = nip19.decode(settings.privkey); - console.dir(privkey_raw); - ndk = new NDK({ - signer: new NDKPrivateKeySigner(privkey_raw.data), - explicitRelayUrls: [ settings.relays ] - }); - ndk.connect(); - } else { - ndk.activeUser = new NDKPrivateKeySigner(settings.privatekey); - for (let i of settings.relays) { - ndk.addExplicitRelay(i); - } - } - }; - - adapter.getInbox = () => { - const sub = ndk.subscribe({ kinds: [1] }); // Get all kind:1s - sub.on("event", (event) => console.log(event.content)); // Show the content - sub.on("eose", () => console.log("All relays have reached the end of the event stream")); - sub.on("close", () => console.log("Subscription closed")); - setTimeout(() => sub.stop(), 10000); // Stop the subscription after 10 seconds - }; - - return adapter; -} - -export default { createAdapter, toNostrAdapter } -
D src/index.js

@@ -1,119 +0,0 @@

-import adapter from "./adapter"; - -window.adapters = []; - -function $(id) { - return document.getElementById(id); -} - -function main() { - window.settings = JSON.parse(localStorage.getItem("settings"));; - if (window.settings != null) { - for (let s of window.settings.adapters) { - switch (s.protocol) { - case "nostr": - let a = adapter.toNostrAdapter(adapter.createAdapter(), s); - window.adapters.push(a); - break; - } - } - } else { - console.log("no settings exist for this client"); - window.settings = { adapters: [] }; - } -}; - -function showSettings() { - // tab bar hidden - const tabbar = $("tabbar"); - tabbar.style.display = "none"; - - // tabcontent to show settings ui - const tabcontent = $("tabcontent"); - - let html = "<p>this is our settings dialogue</p>"; - html += "<button onclick='addAdapter()'>New</button>"; - html += adapters.reduce((self, a) => { - self += `<li><a href='#' onclick='editAdapter(${a.nickname})'>${a.nickname}</a></li>` - return self; - }, "<ul id='settings_adapterlist'>"); - html += "</ul>"; - html += "<button onclick='saveSettings()'>save</button>"; - tabcontent.innerHTML = html; -} - -function addAdapter() { - const tabcontent = $("tabcontent"); - // dropdown for protocol - let html = "<select id='settings_newadapter_protocolselect' onchange='fillAdapterProtocolOptions()'>"; - html += [ "nostr" ].reduce((self, p)=>{ - self += `<option value='${p}'>${p}</option>`; - return self; - }, ""); - html += "</select>"; - // depending on protocol, different fields - // nostr: privkey, initial relays - html += "<div id='settings_newadapter_protocoloptions'>"; - html += " <input id='settings_newadapter_nickname'/>"; - html += " <input id='settings_newadapter_nostr_privkey'/>"; - html += " <input id='settings_newadapter_nostr_default_relays'/>"; - html += "</div>"; - // masto/AP: server, username, pw/apikey - // save button, back button - html += "<button onclick='saveAdapter()'>Add</button>"; - html += "<button onclick='showSettings()'>Back</button>"; - - tabcontent.innerHTML = html; -} - -function fillAdapterProtocolOptions() { - const proto = $("settings_newadapter_protocolselect"); - console.log(proto.options[proto.selectedIndex]); -} - -function saveSettings() { - if (window.settings) { - localStorage.setItem("settings", JSON.stringify(window.settings)); - } - // tab bar hidden - const tabbar = $("tabbar"); - tabbar.style.display = "block"; - - // tabcontent to show settings ui - const tabcontent = $("tabcontent"); - tabcontent.innerHTML = ""; -} - -function saveAdapter() { - let self = {}; - // get selected adapter protocol - const proto = $("settings_newadapter_protocolselect"); - console.log(proto.options[proto.selectedIndex]); - - // switch protocol - switch (proto.options[proto.selectedIndex].value) { - // nostr: save privkey - // save relays - case "nostr": - const privkey = $("settings_newadapter_nostr_privkey").value; - const relays = $("settings_newadapter_nostr_default_relays").value; - const nickname = $("settings_newadapter_nickname").value; - self = { nickname: nickname, protocol: "nostr", privkey: privkey, relays: relays.split(",").map(r=>r.trim()) }; - break; - // AP/masto: whatever - case "ap": - break; - } - window.settings.adapters.push(self); - adapters.push(adapter.toNostrAdapter(adapter.createAdapter(), self)); - localStorage.setItem("settings", JSON.stringify(window.settings)); - showSettings(); -} - -window.addAdapter = addAdapter; -window.saveAdapter = saveAdapter; -window.fillAdapterProtocolOptions = fillAdapterProtocolOptions; -window.showSettings = showSettings; -window.saveSettings = saveSettings; - -main();
A ts/adapter.ts

@@ -0,0 +1,67 @@

+import NDK, {NDKPrivateKeySigner} from "@nostr-dev-kit/ndk"; +import * as nip19 from 'nostr-tools/nip19' + +export class Adapter { + public nickname: string = ""; + public protocol: string = ""; + public identity: any | null; + + public init(): void {}; + public getInbox(): void {}; + public publish(): void {}; + public getFollowers(): any[] { return [] }; + public getFollowing(): any[] { return [] }; + public updateMetadata(): void {}; + public getMetadata(): any { return {} }; +} + +let ndk: NDK | null = null; + +function createAdapter(): Adapter { + let adapter = new Adapter(); + + adapter.init = ()=>{}; + adapter.getInbox = ()=>{}; + adapter.getFollowers = ()=>[]; + adapter.getFollowing = ()=>[]; + adapter.publish = ()=>{}; + adapter.updateMetadata = ()=>{}; + adapter.getMetadata = ()=>{return {}}; + + return adapter; +} + +function toNostrAdapter(adapter: Adapter, settings: any): Adapter { + adapter.identity = { privkey: settings.privkey }; + adapter.nickname = settings.nickname; + adapter.init = ()=> { + if (!ndk) { + let privkey_raw = nip19.decode(settings.privkey); + ndk = new NDK({ + signer: new NDKPrivateKeySigner(<string>privkey_raw.data), + explicitRelayUrls: [ settings.relays ] + }); + ndk.connect(); + } else { + ndk.signer = new NDKPrivateKeySigner(settings.privatekey); + for (let i of settings.relays) { + ndk.addExplicitRelay(i); + } + } + }; + + adapter.getInbox = () => { + if (ndk) { + const sub = ndk.subscribe({ kinds: [1] }); // Get all kind:1s + sub.on("event", (event) => console.log(event.content)); // Show the content + sub.on("eose", () => console.log("All relays have reached the end of the event stream")); + sub.on("close", () => console.log("Subscription closed")); + setTimeout(() => sub.stop(), 10000); // Stop the subscription after 10 seconds + } + }; + + return adapter; +} + +export default { createAdapter, toNostrAdapter } +
A ts/index.ts

@@ -0,0 +1,149 @@

+import adapter, {Adapter} from "./adapter"; + +function _s(key: string, value: any | null) { + const x = <any>window; + x[key] = value; +} + +function _g(key: string): any | null { + const x = <any>window; + return x[key]; +} + +function $(id: string): HTMLElement | null { + return document.getElementById(id); +} + +function main():void { + _s("settings", JSON.parse(localStorage.getItem("settings") ?? "{}")); + _s("adapters", []); + + const settings = _g("settings"); + const adapters = _g("adapters"); + if (settings != null) { + for (let s of settings.adapters) { + switch (s.protocol) { + case "nostr": + let a = adapter.toNostrAdapter(adapter.createAdapter(), s); + adapters.push(a); + break; + } + } + } else { + console.log("no settings exist for this client"); + _s("settings", { adapters: [] }); + } +}; + +function showSettings():void { + // tab bar hidden + const tabbar = $("tabbar"); + if (tabbar) { + tabbar.style.display = "none"; + } + + // tabcontent to show settings ui + const tabcontent = $("tabcontent"); + + if (tabcontent) { + let html = "<p>this is our settings dialogue</p>"; + html += "<button onclick='addAdapter()'>New</button>"; + html += _g("adapters").reduce((self: string, a: Adapter) => { + self += `<li><a href='#' onclick='editAdapter(${a.nickname})'>${a.nickname}</a></li>` + return self; + }, "<ul id='settings_adapterlist'>"); + html += "</ul>"; + html += "<button onclick='saveSettings()'>save</button>"; + tabcontent.innerHTML = html; + } +} + +function addAdapter(): void { + const tabcontent = $("tabcontent"); + if (tabcontent) { + // dropdown for protocol + let html = "<select id='settings_newadapter_protocolselect' onchange='fillAdapterProtocolOptions()'>"; + html += [ "nostr" ].reduce((self, p)=>{ + self += `<option value='${p}'>${p}</option>`; + return self; + }, ""); + html += "</select>"; + // depending on protocol, different fields + // nostr: privkey, initial relays + html += "<div id='settings_newadapter_protocoloptions'>"; + html += " <input id='settings_newadapter_nickname'/>"; + html += " <input id='settings_newadapter_nostr_privkey'/>"; + html += " <input id='settings_newadapter_nostr_default_relays'/>"; + html += "</div>"; + // masto/AP: server, username, pw/apikey + // save button, back button + html += "<button onclick='saveAdapter()'>Add</button>"; + html += "<button onclick='showSettings()'>Back</button>"; + + tabcontent.innerHTML = html; + } +} + +function fillAdapterProtocolOptions(): void { + const proto = $("settings_newadapter_protocolselect") as HTMLSelectElement; + + + + console.log(proto?.options[proto.selectedIndex] ?? "no proto"); +} + +function saveSettings(): void { + const settings = _g("settings"); + if (settings) { + localStorage.setItem("settings", JSON.stringify(settings)); + } + // tab bar hidden + const tabbar = $("tabbar"); + if (tabbar) { + tabbar.style.display = "block"; + } + + // tabcontent to show settings ui + const tabcontent = $("tabcontent"); + if (tabcontent) { + tabcontent.innerHTML = ""; + } +} + +function saveAdapter(): void { + let self: any = {}; + // get selected adapter protocol + const proto = $("settings_newadapter_protocolselect") as HTMLSelectElement; + console.log(proto.options[proto.selectedIndex]); + + // switch protocol + switch (proto.options[proto.selectedIndex].value) { + // nostr: save privkey + // save relays + case "nostr": + const privkey = ($("settings_newadapter_nostr_privkey") as HTMLInputElement)?.value ?? ""; + const relays = ($("settings_newadapter_nostr_default_relays") as HTMLInputElement)?.value ?? ""; + const nickname = ($("settings_newadapter_nickname") as HTMLInputElement)?.value ?? "" ; + self = { nickname: nickname, protocol: "nostr", privkey: privkey, relays: relays.split(",").map(r=>r.trim()) }; + break; + // AP/masto: whatever + case "ap": + break; + } + const settings = _g("settings"); + const adapters = _g("adapters"); + if (settings && adapters) { + settings.adapters.push(self); + adapters.push(adapter.toNostrAdapter(adapter.createAdapter(), self)); + localStorage.setItem("settings", JSON.stringify(settings)); + showSettings(); + } +} + +_s("addAdapter", addAdapter); +_s("saveAdapter", saveAdapter); +_s("fillAdapterProtocolOptions", fillAdapterProtocolOptions); +_s("showSettings", showSettings); +_s("saveSettings", saveSettings); + +main();
A tsconfig.json

@@ -0,0 +1,13 @@

+{ + "compilerOptions": { + "module": "preserve", + "moduleResolution": "bundler", + "noImplicitAny": true, + "strict": true, + "removeComments": false, + "preserveConstEnums": true, + "sourceMap": false, + "outDir": "./src" + }, + "include": [ "./ts/*.ts"] +}