Add fromPromenade method to Nip46Bunker
This commit is contained in:
+5
-3
@@ -22,7 +22,7 @@ Sessions are stored in local storage and can be:
|
|||||||
The simplest type of login is NIP 01, although it's generally a bad idea to be handling user keys. NIP 46, 44, or 07 login are preferable. However, NIP 01 can be useful for supporting signup, local profiles, or ephemeral keys.
|
The simplest type of login is NIP 01, although it's generally a bad idea to be handling user keys. NIP 46, 44, or 07 login are preferable. However, NIP 01 can be useful for supporting signup, local profiles, or ephemeral keys.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import {makeSecret} from '@welshman/signer'
|
import {makeSecret} from '@welshman/util'
|
||||||
import {loginWithNip01} from '@welshman/app'
|
import {loginWithNip01} from '@welshman/app'
|
||||||
|
|
||||||
loginWithNip01(makeSecret())
|
loginWithNip01(makeSecret())
|
||||||
@@ -54,7 +54,8 @@ The best default signing scheme is [NIP 46](https://github.com/nostr-protocol/ni
|
|||||||
The simpler `bunker://` handshake is done by asking the user to provide a bunker URL, either by QR code, or by pasting it manually into your application.
|
The simpler `bunker://` handshake is done by asking the user to provide a bunker URL, either by QR code, or by pasting it manually into your application.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import {Nip46Broker, makeSecret} from "@welshman/signer"
|
import {makeSecret} from "@welshman/util"
|
||||||
|
import {Nip46Broker} from "@welshman/signer"
|
||||||
import {loginWithNip46, nip46Perms} from "@welshman/app"
|
import {loginWithNip46, nip46Perms} from "@welshman/app"
|
||||||
import {isKeyValid} from "src/util/nostr"
|
import {isKeyValid} from "src/util/nostr"
|
||||||
|
|
||||||
@@ -96,7 +97,8 @@ if (!isKeyValid(signerPubkey)) {
|
|||||||
Alternatively, you can provide the user with a `nostrconnect://` URL which they can copy or scan with their signer. This is a better UX for users using a signer on their mobile phone.
|
Alternatively, you can provide the user with a `nostrconnect://` URL which they can copy or scan with their signer. This is a better UX for users using a signer on their mobile phone.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import {Nip46Broker, makeSecret} from "@welshman/signer"
|
import {makeSecret} from "@welshman/util"
|
||||||
|
import {Nip46Broker} from "@welshman/signer"
|
||||||
import {loginWithNip46, nip46Perms} from "@welshman/app"
|
import {loginWithNip46, nip46Perms} from "@welshman/app"
|
||||||
|
|
||||||
// Create a client secret
|
// Create a client secret
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ A Nostr signer implementation that supports multiple authentication methods and
|
|||||||
## Quick Example
|
## Quick Example
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { makeEvent } from '@welshman/util'
|
import { makeEvent, makeSecret } from '@welshman/util'
|
||||||
import { ISigner, Nip01Signer, makeSecret } from '@welshman/signer'
|
import { ISigner, Nip01Signer } from '@welshman/signer'
|
||||||
|
|
||||||
const signer: ISigner = new Nip01Signer(makeSecret())
|
const signer: ISigner = new Nip01Signer(makeSecret())
|
||||||
const options = {
|
const options = {
|
||||||
|
|||||||
@@ -20,12 +20,13 @@
|
|||||||
"prepublishOnly": "pnpm run build"
|
"prepublishOnly": "pnpm run build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@noble/curves": "^1.7.0",
|
"@jsr/fiatjaf__promenade-trusted-dealer": "^0.4.1",
|
||||||
"@noble/hashes": "^1.6.1",
|
"@noble/curves": "^1.9.7",
|
||||||
|
"@noble/hashes": "^2.0.1",
|
||||||
"@welshman/lib": "workspace:*",
|
"@welshman/lib": "workspace:*",
|
||||||
"@welshman/net": "workspace:*",
|
"@welshman/net": "workspace:*",
|
||||||
"@welshman/util": "workspace:*",
|
"@welshman/util": "workspace:*",
|
||||||
"nostr-tools": "^2.14.2"
|
"nostr-tools": "^2.18.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@capacitor/core": "^7.2.0",
|
"@capacitor/core": "^7.2.0",
|
||||||
|
|||||||
@@ -1,14 +1,36 @@
|
|||||||
import {Emitter, throttle, makePromise, defer, sleep, tryCatch, randomId} from "@welshman/lib"
|
import {trustedKeyDeal, hexShard, hexPubShard, KeyShard} from "@jsr/fiatjaf__promenade-trusted-dealer"
|
||||||
|
import {bytesToHex, hexToBytes, numberToBytesBE} from "@noble/curves/abstract/utils"
|
||||||
|
import type {AffinePoint} from "@noble/curves/abstract/curve"
|
||||||
import {
|
import {
|
||||||
|
Emitter,
|
||||||
|
uniq,
|
||||||
|
spec,
|
||||||
|
inc,
|
||||||
|
throttle,
|
||||||
|
makePromise,
|
||||||
|
defer,
|
||||||
|
sleep,
|
||||||
|
tryCatch,
|
||||||
|
randomId,
|
||||||
|
MaybeAsync,
|
||||||
|
shuffle,
|
||||||
|
} from "@welshman/lib"
|
||||||
|
import {
|
||||||
|
getPubkey,
|
||||||
|
HashedEvent,
|
||||||
makeEvent,
|
makeEvent,
|
||||||
|
makeSecret,
|
||||||
normalizeRelayUrl,
|
normalizeRelayUrl,
|
||||||
TrustedEvent,
|
|
||||||
StampedEvent,
|
|
||||||
NOSTR_CONNECT,
|
NOSTR_CONNECT,
|
||||||
hash,
|
prep,
|
||||||
own,
|
PROMENADE_REGISTER_ACCOUNT,
|
||||||
|
PROMENADE_SHARD_ACK,
|
||||||
|
PROMENADE_SHARD_SHARE,
|
||||||
|
RelayMode,
|
||||||
|
StampedEvent,
|
||||||
|
TrustedEvent,
|
||||||
} from "@welshman/util"
|
} from "@welshman/util"
|
||||||
import {publish, request, AdapterContext} from "@welshman/net"
|
import {publish, request, PublishStatus, AdapterContext} from "@welshman/net"
|
||||||
import {ISigner, EncryptionImplementation, signWithOptions, SignOptions, decrypt} from "../util.js"
|
import {ISigner, EncryptionImplementation, signWithOptions, SignOptions, decrypt} from "../util.js"
|
||||||
import {Nip01Signer} from "./nip01.js"
|
import {Nip01Signer} from "./nip01.js"
|
||||||
|
|
||||||
@@ -20,6 +42,12 @@ export const nip46Context = {
|
|||||||
debug: false,
|
debug: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const nip46Log = (...args: any[]) => {
|
||||||
|
if (nip46Context.debug) {
|
||||||
|
console.log(...args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export type Nip46Algorithm = "nip04" | "nip44"
|
export type Nip46Algorithm = "nip04" | "nip44"
|
||||||
|
|
||||||
export enum Nip46Event {
|
export enum Nip46Event {
|
||||||
@@ -58,6 +86,68 @@ export type Nip46ResponseWithError = {
|
|||||||
error: string
|
error: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type PromenadeOptions = {
|
||||||
|
secret: string
|
||||||
|
policy: [number, number]
|
||||||
|
coordinatorUrl: string
|
||||||
|
signerPubkeys: string[]
|
||||||
|
onProgress?: (progress: number) => void
|
||||||
|
generatePow: (event: HashedEvent, difficulty: number) => MaybeAsync<HashedEvent>
|
||||||
|
getPubkeyRelays: (pubkey: string, mode: RelayMode) => MaybeAsync<string[]>
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
const secret = 'fd8a80772a55d82ed963305b0f55299ac07e2fdf06d341f9e7c7223ec7bf57b0'
|
||||||
|
const pubkey = getPubkey(secret)
|
||||||
|
const coordinatorUrl = 'wss://promenade.coracle.social/'
|
||||||
|
const event = prep(
|
||||||
|
makeEvent(10002, {
|
||||||
|
tags: [["r", "wss://bucket.coracle.social/"], ["r", "wss://relay.damus.io/"], ["r", "wss://nos.lol/"]],
|
||||||
|
}),
|
||||||
|
pubkey,
|
||||||
|
)
|
||||||
|
event.sig = getSig(event, secret)
|
||||||
|
repository.publish(event)
|
||||||
|
nip46Context.debug = true
|
||||||
|
publish({event, relays: ["wss://purplepag.es/", "wss://indexer.coracle.social/"]}).then(async () => {
|
||||||
|
console.log("Published outbox relays")
|
||||||
|
const broker = await Nip46Broker.fromPromenade({
|
||||||
|
secret,
|
||||||
|
policy: [2, 3],
|
||||||
|
coordinatorUrl,
|
||||||
|
signerPubkeys: [
|
||||||
|
// '4440e4f93c9dcb0a5521f0bf949a1222698b72a1b1e3534b10537100fc94f97f',
|
||||||
|
// '23a3ff76766f5ffc852fa6f2fc5058c1306ee25927632e0f8e213af11a5b8de5',
|
||||||
|
'aa4f53d8041b88adee44cefb62fb49fdeb85d151d1a346e655850c213508ed2e',
|
||||||
|
// 'ad1c6fa1daca939685d34ab541fc9e7b450ef6295aa273addafee74a579d57fb',
|
||||||
|
// '3fcd012e970d9dfba4bc638ae9b6420e2ceca76f3b8e31d0ee3f408023a7c5fd',
|
||||||
|
// '4be49a6175734b43c7083ceac11e47bf684ffe65bd021c949bea1702409c119a',
|
||||||
|
'290238f7811a50b2b3ded97e42695f906b039fb3f5e2e2e3f77fd5a0b0c9a027',
|
||||||
|
'c66bebe38406a0b57593fcd8c893762dd9af8e488664c6d1a4eb3868b1f65526',
|
||||||
|
],
|
||||||
|
onProgress: p => console.log('progress', p),
|
||||||
|
generatePow: (e, d) => makePow(e, d).result,
|
||||||
|
getPubkeyRelays: async (k, m) => {
|
||||||
|
await forceLoadRelayList(k)
|
||||||
|
return getPubkeyRelays(k, m)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
console.log('connect', await broker.connect(broker.params.connectSecret))
|
||||||
|
console.log('sign', await broker.signEvent(makeEvent(1)))
|
||||||
|
})
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class PromenadeShardError extends Error {
|
||||||
|
constructor(
|
||||||
|
message: string,
|
||||||
|
readonly errorsBySignerPubkey: Map<string, string>,
|
||||||
|
) {
|
||||||
|
super(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const popupManager = (() => {
|
const popupManager = (() => {
|
||||||
let pendingUrl = ""
|
let pendingUrl = ""
|
||||||
let pendingSince = 0
|
let pendingSince = 0
|
||||||
@@ -188,9 +278,7 @@ export class Nip46Sender extends Emitter {
|
|||||||
try {
|
try {
|
||||||
await this.send(request)
|
await this.send(request)
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
if (nip46Context.debug) {
|
nip46Log("nip46 error:", error, request)
|
||||||
console.log("nip46 error:", error, request)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@@ -286,6 +374,154 @@ export class Nip46Broker extends Emitter {
|
|||||||
return {relays, signerPubkey, connectSecret}
|
return {relays, signerPubkey, connectSecret}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static fromBunkerUrl = (url: string) => {
|
||||||
|
const clientSecret = makeSecret()
|
||||||
|
const {relays, signerPubkey, connectSecret} = Nip46Broker.parseBunkerUrl(url)
|
||||||
|
|
||||||
|
return new Nip46Broker({
|
||||||
|
relays,
|
||||||
|
clientSecret,
|
||||||
|
signerPubkey,
|
||||||
|
connectSecret,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromPromenade = async (options: PromenadeOptions) => {
|
||||||
|
const [m, n] = options.policy
|
||||||
|
|
||||||
|
if (options.signerPubkeys.length < n) {
|
||||||
|
throw new Error("Not enough signers to create all shards")
|
||||||
|
}
|
||||||
|
|
||||||
|
const deal = trustedKeyDeal(BigInt("0x" + options.secret), m, n)
|
||||||
|
|
||||||
|
// Add the VSS commits to each shard
|
||||||
|
// for (const shard of deal.shards) {
|
||||||
|
// shard.pubShard.vssCommit = deal.commits
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Use the pubkey and adjusted secret from the deal (BIP-340 adjusted if needed)
|
||||||
|
const signer = Nip01Signer.fromSecret(options.secret)
|
||||||
|
const ourPubkey = await signer.getPubkey()
|
||||||
|
const ackRelays = await options.getPubkeyRelays(ourPubkey, RelayMode.Read)
|
||||||
|
const remainingSignerPubkeys = shuffle(uniq(options.signerPubkeys))
|
||||||
|
const errorsBySignerPubkey = new Map<string, string>()
|
||||||
|
const shardsBySignerPubkey = new Map<string, KeyShard>()
|
||||||
|
|
||||||
|
if (ackRelays.length === 0) {
|
||||||
|
throw new Error("No read relays returned for user pubkey")
|
||||||
|
}
|
||||||
|
|
||||||
|
nip46Log(`generated promenade shards for user ${ourPubkey}`, deal)
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
deal.shards.map(async (shard, i) => {
|
||||||
|
while (remainingSignerPubkeys.length > 0) {
|
||||||
|
const signerPubkey = remainingSignerPubkeys.shift()!
|
||||||
|
|
||||||
|
nip46Log(`generating proof of work for shard ${i}`)
|
||||||
|
|
||||||
|
const shardTemplate = makeEvent(PROMENADE_SHARD_SHARE, {
|
||||||
|
content: await signer.nip44.encrypt(signerPubkey, hexShard(shard)),
|
||||||
|
tags: [
|
||||||
|
["p", signerPubkey],
|
||||||
|
["coordinator", options.coordinatorUrl],
|
||||||
|
...ackRelays.map(url => ["reply", url]),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
const shardTemplateWithWork = await tryCatch(() =>
|
||||||
|
options.generatePow(prep(shardTemplate, ourPubkey), 20),
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!shardTemplateWithWork) {
|
||||||
|
errorsBySignerPubkey.set(signerPubkey, "Failed to generate work")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const shardEvent = await signer.sign(shardTemplateWithWork)
|
||||||
|
const shardRelays = await options.getPubkeyRelays(signerPubkey, RelayMode.Read)
|
||||||
|
const publishResults = await publish({relays: shardRelays, event: shardEvent})
|
||||||
|
|
||||||
|
nip46Log(`published shard ${i} to signer ${signerPubkey}`, shardRelays, publishResults)
|
||||||
|
|
||||||
|
if (!Object.values(publishResults).some(spec({status: PublishStatus.Success}))) {
|
||||||
|
errorsBySignerPubkey.set(signerPubkey, "Failed to publish shard")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const controller = new AbortController()
|
||||||
|
const signal = AbortSignal.any([controller.signal, AbortSignal.timeout(30_000)])
|
||||||
|
|
||||||
|
await request({
|
||||||
|
signal,
|
||||||
|
relays: ackRelays,
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
kinds: [PROMENADE_SHARD_ACK],
|
||||||
|
authors: [signerPubkey],
|
||||||
|
"#p": [ourPubkey],
|
||||||
|
"#e": [shardEvent.id],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
onEvent: (event: TrustedEvent, url: string) => {
|
||||||
|
nip46Log(`received ack for shard ${i} from signer ${signerPubkey} on ${url}`)
|
||||||
|
shardsBySignerPubkey.set(signerPubkey, shard)
|
||||||
|
options.onProgress?.(shardsBySignerPubkey.size / inc(n))
|
||||||
|
controller.abort()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (shardsBySignerPubkey.has(signerPubkey)) {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
errorsBySignerPubkey.set(signerPubkey, "Failed to receive shard ACK")
|
||||||
|
nip46Log(`failed to receive ack for shard ${i} from signer ${signerPubkey}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
if (shardsBySignerPubkey.size < deal.shards.length) {
|
||||||
|
throw new PromenadeShardError("Failed to publish all shards", errorsBySignerPubkey)
|
||||||
|
}
|
||||||
|
|
||||||
|
const connectSecret = randomId()
|
||||||
|
const signerSecret = makeSecret()
|
||||||
|
const signerPubkey = getPubkey(signerSecret)
|
||||||
|
const tags = [
|
||||||
|
["h", signerPubkey],
|
||||||
|
["threshold", String(m)],
|
||||||
|
["handlersecret", signerSecret],
|
||||||
|
["profile", "MAIN", connectSecret, ""],
|
||||||
|
]
|
||||||
|
|
||||||
|
for (const [pubkey, shard] of shardsBySignerPubkey) {
|
||||||
|
tags.push(["p", pubkey, hexPubShard(shard.pubShard)])
|
||||||
|
}
|
||||||
|
|
||||||
|
nip46Log(`registering coordinator account`, tags)
|
||||||
|
|
||||||
|
const relays = [options.coordinatorUrl]
|
||||||
|
const event = await signer.sign(makeEvent(PROMENADE_REGISTER_ACCOUNT, {tags}))
|
||||||
|
const accountResults = await publish({relays, event})
|
||||||
|
|
||||||
|
if (!Object.values(accountResults).some(spec({status: PublishStatus.Success}))) {
|
||||||
|
throw new Error("Failed to publish accounts to coordinator")
|
||||||
|
}
|
||||||
|
|
||||||
|
nip46Log(`successfully created promenade broker`)
|
||||||
|
|
||||||
|
const clientSecret = makeSecret()
|
||||||
|
|
||||||
|
return new Nip46Broker({
|
||||||
|
relays,
|
||||||
|
clientSecret,
|
||||||
|
signerPubkey,
|
||||||
|
connectSecret,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Getters for helper objects
|
// Getters for helper objects
|
||||||
|
|
||||||
makeSigner = () => new Nip01Signer(this.params.clientSecret)
|
makeSigner = () => new Nip01Signer(this.params.clientSecret)
|
||||||
@@ -294,9 +530,7 @@ export class Nip46Broker extends Emitter {
|
|||||||
const sender = new Nip46Sender(this.signer, this.params)
|
const sender = new Nip46Sender(this.signer, this.params)
|
||||||
|
|
||||||
sender.on(Nip46Event.Send, (data: any) => {
|
sender.on(Nip46Event.Send, (data: any) => {
|
||||||
if (nip46Context.debug) {
|
nip46Log("nip46 send:", data)
|
||||||
console.log("nip46 send:", data)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return sender
|
return sender
|
||||||
@@ -306,9 +540,7 @@ export class Nip46Broker extends Emitter {
|
|||||||
const receiver = new Nip46Receiver(this.signer, this.params)
|
const receiver = new Nip46Receiver(this.signer, this.params)
|
||||||
|
|
||||||
receiver.on(Nip46Event.Receive, (data: any) => {
|
receiver.on(Nip46Event.Receive, (data: any) => {
|
||||||
if (nip46Context.debug) {
|
nip46Log("nip46 receive:", data)
|
||||||
console.log("nip46 receive:", data)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return receiver
|
return receiver
|
||||||
@@ -467,7 +699,7 @@ export class Nip46Signer implements ISigner {
|
|||||||
|
|
||||||
sign = (template: StampedEvent, options: SignOptions = {}) =>
|
sign = (template: StampedEvent, options: SignOptions = {}) =>
|
||||||
signWithOptions(
|
signWithOptions(
|
||||||
this.getPubkey().then(pubkey => this.broker.signEvent(hash(own(template, pubkey)))),
|
this.getPubkey().then(pubkey => this.broker.signEvent(prep(template, pubkey))),
|
||||||
options,
|
options,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {hexToBytes} from "@noble/hashes/utils"
|
import {hexToBytes} from "@noble/curves/abstract/utils"
|
||||||
import * as nt04 from "nostr-tools/nip04"
|
import * as nt04 from "nostr-tools/nip04"
|
||||||
import * as nt44 from "nostr-tools/nip44"
|
import * as nt44 from "nostr-tools/nip44"
|
||||||
import {Emitter, cached} from "@welshman/lib"
|
import {Emitter, cached} from "@welshman/lib"
|
||||||
|
|||||||
Generated
+76
-6
@@ -383,12 +383,15 @@ importers:
|
|||||||
|
|
||||||
packages/signer:
|
packages/signer:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@jsr/fiatjaf__promenade-trusted-dealer':
|
||||||
|
specifier: ^0.4.1
|
||||||
|
version: 0.4.1
|
||||||
'@noble/curves':
|
'@noble/curves':
|
||||||
specifier: ^1.7.0
|
specifier: ^1.9.7
|
||||||
version: 1.8.1
|
version: 1.9.7
|
||||||
'@noble/hashes':
|
'@noble/hashes':
|
||||||
specifier: ^1.6.1
|
specifier: ^2.0.1
|
||||||
version: 1.7.1
|
version: 2.0.1
|
||||||
'@welshman/lib':
|
'@welshman/lib':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../lib
|
version: link:../lib
|
||||||
@@ -399,8 +402,8 @@ importers:
|
|||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../util
|
version: link:../util
|
||||||
nostr-tools:
|
nostr-tools:
|
||||||
specifier: ^2.14.2
|
specifier: ^2.18.2
|
||||||
version: 2.14.2(typescript@5.8.2)
|
version: 2.18.2(typescript@5.8.2)
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@capacitor/core':
|
'@capacitor/core':
|
||||||
specifier: ^7.2.0
|
specifier: ^7.2.0
|
||||||
@@ -849,6 +852,15 @@ packages:
|
|||||||
'@jridgewell/trace-mapping@0.3.9':
|
'@jridgewell/trace-mapping@0.3.9':
|
||||||
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
|
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
|
||||||
|
|
||||||
|
'@jsr/fiatjaf__promenade-trusted-dealer@0.4.1':
|
||||||
|
resolution: {integrity: sha512-K9WjpDkQGyLl5gUZBLr3Gb+b5b1r8miZmDOo4+ZlzGQgoXD2TaqT+dkBjL/yLj/pYwBcd1Bschv0xuNpguL2ZQ==, tarball: https://npm.jsr.io/~/11/@jsr/fiatjaf__promenade-trusted-dealer/0.4.1.tgz}
|
||||||
|
|
||||||
|
'@jsr/henrygd__semaphore@0.0.2':
|
||||||
|
resolution: {integrity: sha512-nrwZ8HaqU1Agb2ij8omIxaOCAsKkDHWcwS9hTRumPhZuptwh6/0BJExBd8+eClTYM7jBnZxK+cP4WJRTcHBvCA==, tarball: https://npm.jsr.io/~/11/@jsr/henrygd__semaphore/0.0.2.tgz}
|
||||||
|
|
||||||
|
'@jsr/nostr__tools@2.16.2':
|
||||||
|
resolution: {integrity: sha512-QK1XwHvAnqEwbimD+ywbLQ3T2iI+/qE/zrRgOhmtjoEGlCWgtbPTNJ6Y/MEunXr6H/MnuHV+s400i/Yk4suvGQ==, tarball: https://npm.jsr.io/~/11/@jsr/nostr__tools/2.16.2.tgz}
|
||||||
|
|
||||||
'@microsoft/api-extractor-model@7.32.1':
|
'@microsoft/api-extractor-model@7.32.1':
|
||||||
resolution: {integrity: sha512-u4yJytMYiUAnhcNQcZDTh/tVtlrzKlyKrQnLOV+4Qr/5gV+cpufWzCYAB1Q23URFqD6z2RoL2UYncM9xJVGNKA==}
|
resolution: {integrity: sha512-u4yJytMYiUAnhcNQcZDTh/tVtlrzKlyKrQnLOV+4Qr/5gV+cpufWzCYAB1Q23URFqD6z2RoL2UYncM9xJVGNKA==}
|
||||||
|
|
||||||
@@ -875,6 +887,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==}
|
resolution: {integrity: sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==}
|
||||||
engines: {node: ^14.21.3 || >=16}
|
engines: {node: ^14.21.3 || >=16}
|
||||||
|
|
||||||
|
'@noble/curves@1.9.7':
|
||||||
|
resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==}
|
||||||
|
engines: {node: ^14.21.3 || >=16}
|
||||||
|
|
||||||
'@noble/hashes@1.3.1':
|
'@noble/hashes@1.3.1':
|
||||||
resolution: {integrity: sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==}
|
resolution: {integrity: sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==}
|
||||||
engines: {node: '>= 16'}
|
engines: {node: '>= 16'}
|
||||||
@@ -887,6 +903,14 @@ packages:
|
|||||||
resolution: {integrity: sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==}
|
resolution: {integrity: sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==}
|
||||||
engines: {node: ^14.21.3 || >=16}
|
engines: {node: ^14.21.3 || >=16}
|
||||||
|
|
||||||
|
'@noble/hashes@1.8.0':
|
||||||
|
resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==}
|
||||||
|
engines: {node: ^14.21.3 || >=16}
|
||||||
|
|
||||||
|
'@noble/hashes@2.0.1':
|
||||||
|
resolution: {integrity: sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==}
|
||||||
|
engines: {node: '>= 20.19.0'}
|
||||||
|
|
||||||
'@nodelib/fs.scandir@2.1.5':
|
'@nodelib/fs.scandir@2.1.5':
|
||||||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
@@ -2331,6 +2355,14 @@ packages:
|
|||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
nostr-tools@2.18.2:
|
||||||
|
resolution: {integrity: sha512-lUCJQd9YZG3kEvxV5Zgm7qUkBpaeuvFrtqBz4TJLAxHzUn2pE7nmZZRDQmNzp5neEw20tQS3jR16o7XzzF8ncg==}
|
||||||
|
peerDependencies:
|
||||||
|
typescript: '>=5.0.0'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
typescript:
|
||||||
|
optional: true
|
||||||
|
|
||||||
nostr-wasm@0.1.0:
|
nostr-wasm@0.1.0:
|
||||||
resolution: {integrity: sha512-78BTryCLcLYv96ONU8Ws3Q1JzjlAt+43pWQhIl86xZmWeegYCNLPml7yQ+gG3vR6V5h4XGj+TxO+SS5dsThQIA==}
|
resolution: {integrity: sha512-78BTryCLcLYv96ONU8Ws3Q1JzjlAt+43pWQhIl86xZmWeegYCNLPml7yQ+gG3vR6V5h4XGj+TxO+SS5dsThQIA==}
|
||||||
|
|
||||||
@@ -3407,6 +3439,24 @@ snapshots:
|
|||||||
'@jridgewell/resolve-uri': 3.1.2
|
'@jridgewell/resolve-uri': 3.1.2
|
||||||
'@jridgewell/sourcemap-codec': 1.5.0
|
'@jridgewell/sourcemap-codec': 1.5.0
|
||||||
|
|
||||||
|
'@jsr/fiatjaf__promenade-trusted-dealer@0.4.1':
|
||||||
|
dependencies:
|
||||||
|
'@jsr/henrygd__semaphore': 0.0.2
|
||||||
|
'@jsr/nostr__tools': 2.16.2
|
||||||
|
'@noble/curves': 1.9.7
|
||||||
|
|
||||||
|
'@jsr/henrygd__semaphore@0.0.2': {}
|
||||||
|
|
||||||
|
'@jsr/nostr__tools@2.16.2':
|
||||||
|
dependencies:
|
||||||
|
'@noble/ciphers': 0.5.3
|
||||||
|
'@noble/curves': 1.2.0
|
||||||
|
'@noble/hashes': 1.3.1
|
||||||
|
'@scure/base': 1.1.1
|
||||||
|
'@scure/bip32': 1.3.1
|
||||||
|
'@scure/bip39': 1.2.1
|
||||||
|
nostr-wasm: 0.1.0
|
||||||
|
|
||||||
'@microsoft/api-extractor-model@7.32.1(@types/node@22.13.17)':
|
'@microsoft/api-extractor-model@7.32.1(@types/node@22.13.17)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@microsoft/tsdoc': 0.16.0
|
'@microsoft/tsdoc': 0.16.0
|
||||||
@@ -3457,12 +3507,20 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@noble/hashes': 1.7.1
|
'@noble/hashes': 1.7.1
|
||||||
|
|
||||||
|
'@noble/curves@1.9.7':
|
||||||
|
dependencies:
|
||||||
|
'@noble/hashes': 1.8.0
|
||||||
|
|
||||||
'@noble/hashes@1.3.1': {}
|
'@noble/hashes@1.3.1': {}
|
||||||
|
|
||||||
'@noble/hashes@1.3.2': {}
|
'@noble/hashes@1.3.2': {}
|
||||||
|
|
||||||
'@noble/hashes@1.7.1': {}
|
'@noble/hashes@1.7.1': {}
|
||||||
|
|
||||||
|
'@noble/hashes@1.8.0': {}
|
||||||
|
|
||||||
|
'@noble/hashes@2.0.1': {}
|
||||||
|
|
||||||
'@nodelib/fs.scandir@2.1.5':
|
'@nodelib/fs.scandir@2.1.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nodelib/fs.stat': 2.0.5
|
'@nodelib/fs.stat': 2.0.5
|
||||||
@@ -5047,6 +5105,18 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
typescript: 5.8.2
|
typescript: 5.8.2
|
||||||
|
|
||||||
|
nostr-tools@2.18.2(typescript@5.8.2):
|
||||||
|
dependencies:
|
||||||
|
'@noble/ciphers': 0.5.3
|
||||||
|
'@noble/curves': 1.2.0
|
||||||
|
'@noble/hashes': 1.3.1
|
||||||
|
'@scure/base': 1.1.1
|
||||||
|
'@scure/bip32': 1.3.1
|
||||||
|
'@scure/bip39': 1.2.1
|
||||||
|
nostr-wasm: 0.1.0
|
||||||
|
optionalDependencies:
|
||||||
|
typescript: 5.8.2
|
||||||
|
|
||||||
nostr-wasm@0.1.0: {}
|
nostr-wasm@0.1.0: {}
|
||||||
|
|
||||||
onchange@7.1.0:
|
onchange@7.1.0:
|
||||||
|
|||||||
Reference in New Issue
Block a user