Start simplifying LNURL code with NLib
This commit is contained in:
parent
0a1b6cdf4f
commit
d73fa7a311
|
@ -87,8 +87,9 @@ export { default as stringifyStable } from 'npm:fast-stable-stringify@^1.0.0';
|
||||||
// @deno-types="npm:@types/debug@^4.1.12"
|
// @deno-types="npm:@types/debug@^4.1.12"
|
||||||
export { default as Debug } from 'npm:debug@^4.3.4';
|
export { default as Debug } from 'npm:debug@^4.3.4';
|
||||||
export {
|
export {
|
||||||
|
LNURL,
|
||||||
type MapCache,
|
type MapCache,
|
||||||
NIP05,
|
NIP05,
|
||||||
} from 'https://gitlab.com/soapbox-pub/nlib/-/raw/46be9e985950547574b1735d0ae52a6a7217d056/mod.ts';
|
} from 'https://gitlab.com/soapbox-pub/nlib/-/raw/137af48cbc2639a8969d233fc24d2b959f34782a/mod.ts';
|
||||||
|
|
||||||
export type * as TypeFest from 'npm:type-fest@^4.3.0';
|
export type * as TypeFest from 'npm:type-fest@^4.3.0';
|
||||||
|
|
|
@ -2,16 +2,15 @@ import { Conf } from '@/config.ts';
|
||||||
import { addRelays } from '@/db/relays.ts';
|
import { addRelays } from '@/db/relays.ts';
|
||||||
import { deleteAttachedMedia } from '@/db/unattached-media.ts';
|
import { deleteAttachedMedia } from '@/db/unattached-media.ts';
|
||||||
import { findUser } from '@/db/users.ts';
|
import { findUser } from '@/db/users.ts';
|
||||||
import { Debug, type Event } from '@/deps.ts';
|
import { Debug, type Event, LNURL } from '@/deps.ts';
|
||||||
import { isEphemeralKind } from '@/kinds.ts';
|
import { isEphemeralKind } from '@/kinds.ts';
|
||||||
import { isLocallyFollowed } from '@/queries.ts';
|
import { isLocallyFollowed } from '@/queries.ts';
|
||||||
import { lnurlCallbackResponseSchema, lnurlResponseSchema } from '@/schemas/lnurl.ts';
|
import { lnurlCallbackResponseSchema } from '@/schemas/lnurl.ts';
|
||||||
import { updateStats } from '@/stats.ts';
|
import { updateStats } from '@/stats.ts';
|
||||||
import { client, eventsDB, memorelay, reqmeister } from '@/storages.ts';
|
import { client, eventsDB, memorelay, reqmeister } from '@/storages.ts';
|
||||||
import { Sub } from '@/subs.ts';
|
import { Sub } from '@/subs.ts';
|
||||||
import { getTagSet } from '@/tags.ts';
|
import { getTagSet } from '@/tags.ts';
|
||||||
import { type EventData } from '@/types.ts';
|
import { type EventData } from '@/types.ts';
|
||||||
import { lnurlDecode } from '@/utils/lnurl.ts';
|
|
||||||
import { eventAge, isRelay, nostrDate, nostrNow, Time } from '@/utils.ts';
|
import { eventAge, isRelay, nostrDate, nostrNow, Time } from '@/utils.ts';
|
||||||
import { fetchWorker } from '@/workers/fetch.ts';
|
import { fetchWorker } from '@/workers/fetch.ts';
|
||||||
import { TrendsWorker } from '@/workers/trends.ts';
|
import { TrendsWorker } from '@/workers/trends.ts';
|
||||||
|
@ -170,12 +169,9 @@ async function submitZaps(event: Event, data: EventData, signal = AbortSignal.ti
|
||||||
const amount = event.tags.find(([name]) => name === 'amount')?.[1];
|
const amount = event.tags.find(([name]) => name === 'amount')?.[1];
|
||||||
if (lnurl && amount) {
|
if (lnurl && amount) {
|
||||||
try {
|
try {
|
||||||
const url = lnurlDecode(lnurl);
|
const details = await LNURL.lookup(lnurl, { fetch: fetchWorker, signal });
|
||||||
const response = await fetchWorker(url, { signal });
|
if (details.tag === 'payRequest' && details.allowsNostr && details.nostrPubkey) {
|
||||||
const json = await response.json();
|
const callback = new URL(details.callback);
|
||||||
const result = lnurlResponseSchema.parse(json);
|
|
||||||
if (result.tag === 'payRequest' && result.allowsNostr && result.nostrPubkey) {
|
|
||||||
const callback = new URL(result.callback);
|
|
||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
params.set('amount', amount);
|
params.set('amount', amount);
|
||||||
params.set('nostr', JSON.stringify(event));
|
params.set('nostr', JSON.stringify(event));
|
||||||
|
|
|
@ -1,20 +1,8 @@
|
||||||
import { z } from '@/deps.ts';
|
import { z } from '@/deps.ts';
|
||||||
|
|
||||||
import { nostrIdSchema } from './nostr.ts';
|
|
||||||
|
|
||||||
const lnurlResponseSchema = z.object({
|
|
||||||
callback: z.string().url(),
|
|
||||||
maxSendable: z.number().int().nonnegative(),
|
|
||||||
minSendable: z.number().int().positive(),
|
|
||||||
metadata: z.string(),
|
|
||||||
tag: z.string(),
|
|
||||||
allowsNostr: z.boolean().optional(),
|
|
||||||
nostrPubkey: nostrIdSchema.optional(),
|
|
||||||
});
|
|
||||||
|
|
||||||
const lnurlCallbackResponseSchema = z.object({
|
const lnurlCallbackResponseSchema = z.object({
|
||||||
pr: z.string(),
|
pr: z.string(),
|
||||||
routes: z.unknown().array(),
|
routes: z.unknown().array(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export { lnurlCallbackResponseSchema, lnurlResponseSchema };
|
export { lnurlCallbackResponseSchema };
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
import { assertEquals } from '@/deps-test.ts';
|
|
||||||
|
|
||||||
import { lnurlDecode, lnurlEncode } from './lnurl.ts';
|
|
||||||
|
|
||||||
const lnurl = 'lnurl1dp68gurn8ghj7um5v93kketj9ehx2amn9uh8wetvdskkkmn0wahz7mrww4excup0dajx2mrv92x9xp';
|
|
||||||
const url = 'https://stacker.news/.well-known/lnurlp/odell';
|
|
||||||
|
|
||||||
Deno.test('lnurlEncode', () => {
|
|
||||||
assertEquals(lnurlEncode(url), lnurl);
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test('lnurlDecode', () => {
|
|
||||||
assertEquals(lnurlDecode(lnurl), url);
|
|
||||||
});
|
|
|
@ -1,19 +1,4 @@
|
||||||
import { bech32 } from '@/deps.ts';
|
import { LNURL } from '@/deps.ts';
|
||||||
|
|
||||||
/** Encode a URL to LNURL format. */
|
|
||||||
function lnurlEncode(url: string, limit = 2000): `lnurl1${string}` {
|
|
||||||
const data = new TextEncoder().encode(url);
|
|
||||||
const words = bech32.toWords(data);
|
|
||||||
return bech32.encode('lnurl', words, limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Decode a LNURL into a URL. */
|
|
||||||
function lnurlDecode(lnurl: string, limit = 2000): string {
|
|
||||||
const { prefix, words } = bech32.decode(lnurl, limit);
|
|
||||||
if (prefix !== 'lnurl') throw new Error('Invalid LNURL');
|
|
||||||
const data = new Uint8Array(bech32.fromWords(words));
|
|
||||||
return new TextDecoder().decode(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get an LNURL from a lud06 or lud16. */
|
/** Get an LNURL from a lud06 or lud16. */
|
||||||
function getLnurl({ lud06, lud16 }: { lud06?: string; lud16?: string }, limit?: number): string | undefined {
|
function getLnurl({ lud06, lud16 }: { lud06?: string; lud16?: string }, limit?: number): string | undefined {
|
||||||
|
@ -21,10 +6,10 @@ function getLnurl({ lud06, lud16 }: { lud06?: string; lud16?: string }, limit?:
|
||||||
if (lud16) {
|
if (lud16) {
|
||||||
const [name, host] = lud16.split('@');
|
const [name, host] = lud16.split('@');
|
||||||
if (name && host) {
|
if (name && host) {
|
||||||
const url = new URL(`/.well-known/lnurlp/${name}`, `https://${host}`).toString();
|
const url = new URL(`/.well-known/lnurlp/${name}`, `https://${host}`);
|
||||||
return lnurlEncode(url, limit);
|
return LNURL.encode(url, limit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { getLnurl, lnurlDecode, lnurlEncode };
|
export { getLnurl };
|
||||||
|
|
Loading…
Reference in New Issue