This commit is contained in:
n 2025-04-12 21:45:22 +01:00
parent 79e65e3860
commit 727064aafb
11 changed files with 430 additions and 105 deletions

@ -9,6 +9,7 @@
"version": "1.0.0",
"license": "MIT",
"dependencies": {
"jsqr": "^1.4.0",
"nostr-login": "^1.7.11",
"nostr-tools": "^2.12.0",
"qrcode": "^1.5.4",
@ -5311,6 +5312,12 @@
"json5": "lib/cli.js"
}
},
"node_modules/jsqr": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/jsqr/-/jsqr-1.4.0.tgz",
"integrity": "sha512-dxLob7q65Xg2DvstYkRpkYtmKm2sPJ9oFhrhmudT1dZvNFFTlroai3AWSpLey/w5vMcLBXRgOJsbXpdN9HzU/A==",
"license": "Apache-2.0"
},
"node_modules/keyv": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",

@ -93,12 +93,16 @@ export async function loginWithNostrLogin(): Promise<string | null> {
executePostAuthQueue();
return result.pubkey;
} else if (result.error) {
// If we have a specific error message from the authentication service
console.error("Authentication failed with message:", result.error);
throw new Error(result.error);
}
return null;
} catch (error) {
console.error("Error using Nostr login:", error);
return null;
throw error; // Rethrow to allow the caller to handle specific error messages
}
}

@ -52,11 +52,27 @@ document.addEventListener('DOMContentLoaded', () => {
updateUIBasedOnAuth();
} else {
console.log('Login attempt failed, showing error');
alert('Login failed. Please make sure you have a Nostr extension installed (like Alby or nos2x).');
alert('Login failed. Authentication with nostr-login was unsuccessful. Please check the console for error details.');
}
} catch (error) {
console.error('Authentication error:', error);
alert(`Authentication error: ${error instanceof Error ? error.message : 'Unknown error'}`);
let errorMessage = 'Authentication error';
if (error instanceof Error) {
if (error.message.includes('Rejected') || error.message.includes('Cancelled')) {
errorMessage = 'Login was cancelled. Please try again when you are ready to authenticate.';
} else {
errorMessage = error.message;
}
} else if (error && typeof error === 'object' && 'error' in error) {
const errorValue = error.error;
errorMessage = typeof errorValue === 'string' ? errorValue : errorMessage;
} else {
errorMessage = String(error || 'Unknown error');
}
alert(errorMessage);
}
});
}
@ -271,7 +287,7 @@ async function handleConnectRelay(): Promise<void> {
updateUIBasedOnAuth();
updateRelayStatus('Authentication successful. Connecting...', 'connecting');
} else {
updateRelayStatus('Authentication failed. Please try again or install a Nostr extension like Alby or nos2x.', 'error');
updateRelayStatus('Authentication failed. Please try again. nostr-login authentication was unsuccessful.', 'error');
return;
}
} catch (error) {

@ -17,6 +17,9 @@ import type { NostrRelayService } from './services/NostrRelayService';
// Create a singleton instance of the client event store
const clientEventStore = new ClientEventStore();
// Track events that have been published to avoid duplicates
const publishedEvents = new Set<string>();
// The table UI component (initialized in setup)
let clientEventsTable: ClientEventsTable | null = null;
@ -216,12 +219,46 @@ export function trackOutgoingEvent(event: NostrEvent): string | null {
console.warn(`Expected KIND 21120 event, got ${event.kind}`);
}
// Check if this event is already tracked
const existingEvent = clientEventStore.getEvent(event.id);
if (existingEvent) {
console.log(`Event ${event.id} is already being tracked, not adding again`);
return event.id;
}
// Check if this event has already been published
if (publishedEvents.has(event.id)) {
console.log(`Event ${event.id} has already been published, not adding again`);
return event.id;
}
// Add to the store
const eventId = clientEventStore.addOutgoingEvent(event);
console.log(`Tracked outgoing event: ${eventId}`);
return eventId;
}
/**
* Mark an event as published to prevent duplicate publishing
* @param eventId The ID of the event that was published
*/
export function markEventAsPublished(eventId: string): void {
if (!eventId) return;
// Add to the set of published events
publishedEvents.add(eventId);
console.log(`Marked event ${eventId} as published`);
}
/**
* Check if an event has already been published
* @param eventId The ID of the event to check
* @returns True if the event has been published, false otherwise
*/
export function isEventPublished(eventId: string): boolean {
return publishedEvents.has(eventId);
}
/**
* Handle a pending 21120 event before it's published
* @param event The event being prepared

@ -41,7 +41,9 @@ import {
initClientEventHandler,
trackOutgoingEvent,
handleIncomingResponse,
reconnectRelayService
reconnectRelayService,
markEventAsPublished,
isEventPublished
} from './client-event-handler';
import type { NostrEvent } from './converter';
// Import functions from internal modules
@ -609,10 +611,35 @@ function initNostrLogin(): void {
authManager.setAuthenticated(true, pubkey);
}
}).catch(err => {
console.warn("Not currently connected to Nostr extension:", err);
console.warn("Not currently connected to Nostr provider:", err);
});
} else {
console.warn("Nostr extension not available");
console.warn("Nostr provider not available. Using nostr-login if available.");
// Try to use nostr-login library if available
if (NostrLogin) {
try {
console.log("Using nostr-login in initNostrLogin");
const nostrLogin = new NostrLogin();
nostrLogin.getPublicKey().then((pubkey: string) => {
if (pubkey) {
console.log(`Found pubkey from nostr-login: ${pubkey.slice(0, 8)}...`);
// Update UI to show pubkey
updateClientPubkeyDisplay(pubkey);
// Update auth state in the service
authManager.setAuthenticated(true, pubkey);
}
}).catch((err: Error) => {
console.warn("Not currently connected to nostr-login:", err);
});
} catch (nostrLoginError) {
console.error('nostr-login error:', nostrLoginError);
}
} else {
console.warn("No Nostr provider available");
}
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
@ -651,11 +678,9 @@ async function ensureAuthenticated(): Promise<boolean> {
return true;
}
// Not authenticated, check if extension is available
if (!window.nostr) {
console.warn("Nostr extension not available");
return false;
}
// Not authenticated, try to use nostr-login or extension
// We no longer need to check window.nostr because loginWithNostrLogin handles that
console.log("No active authentication, attempting to authenticate with nostr-login...");
try {
// Try to get the user's public key
@ -698,6 +723,12 @@ async function handlePublishEvent(): Promise<void> {
showLoading(publishResultDiv, 'Publishing to relay...');
try {
// Check if this event has already been published
if (event.id && isEventPublished(event.id)) {
showSuccess(publishResultDiv, "Event was already published, not sending duplicate");
return;
}
// Track the event before publishing
console.log('Tracking outgoing event:', event.id);
trackOutgoingEvent(event);
@ -705,6 +736,12 @@ async function handlePublishEvent(): Promise<void> {
// Publish the event
console.log('Publishing event to relay:', relayUrl);
const result = await publishToRelay(event, relayUrl);
// Mark the event as published to prevent duplicates
if (event.id) {
markEventAsPublished(event.id);
}
showSuccess(publishResultDiv, result);
// Force reconnect to ensure we're subscribed for the response
@ -782,6 +819,12 @@ async function handlePublishEvent(): Promise<void> {
publishResultDiv.innerHTML += '<br><span>Attempting to publish...</span>';
try {
// Check if this event has already been published
if (event.id && isEventPublished(event.id)) {
showSuccess(publishResultDiv, "Event was already published, not sending duplicate");
return;
}
// Track the event in our client store
console.log('Tracking outgoing event:', event.id);
trackOutgoingEvent(event);
@ -789,6 +832,12 @@ async function handlePublishEvent(): Promise<void> {
// Publish the event
console.log('Publishing event to relay:', relayUrl);
const result = await publishToRelay(event, relayUrl);
// Mark the event as published to prevent duplicates
if (event.id) {
markEventAsPublished(event.id);
}
showSuccess(publishResultDiv, result);
// Force reconnect to ensure we're subscribed for the response
@ -1595,12 +1644,32 @@ document.addEventListener('DOMContentLoaded', function(): void {
// Try to get pubkey again after DOM is ready
if (window.nostr) {
window.nostr.getPublicKey().then(pubkey => {
console.log(`DOM ready: Retrieved pubkey: ${pubkey.slice(0, 8)}...`);
window.nostr.getPublicKey().then((pubkey: string) => {
console.log(`DOM ready: Retrieved pubkey from extension: ${pubkey.slice(0, 8)}...`);
localStorage.setItem('userPublicKey', pubkey);
}).catch(err => {
console.warn("DOM ready: Failed to get pubkey:", err);
}).catch((err: Error) => {
console.warn("DOM ready: Failed to get pubkey from extension:", err);
});
} else if (NostrLogin) {
// Try to use nostr-login if window.nostr is not available
try {
console.log("DOM ready: Using nostr-login to get pubkey");
const nostrLogin = new NostrLogin();
nostrLogin.getPublicKey().then((pubkey: string) => {
if (pubkey) {
console.log(`DOM ready: Retrieved pubkey from nostr-login: ${pubkey.slice(0, 8)}...`);
localStorage.setItem('userPublicKey', pubkey);
updateClientPubkeyDisplay(pubkey);
}
}).catch((err: Error) => {
console.warn("DOM ready: Failed to get pubkey from nostr-login:", err);
});
} catch (nostrLoginError) {
console.error('DOM ready: nostr-login error:', nostrLoginError);
}
} else {
console.warn("DOM ready: No Nostr provider available");
}
// Set default HTTP request

@ -190,7 +190,7 @@ export class Nostr21121Creator {
// Always add reference to the request event
if (requestEvent.id) {
tags.push(['e', requestEvent.id, '', 'reply']);
tags.push(['e', requestEvent.id]);
}
// Add kind reference

@ -438,6 +438,12 @@ if (publishRelayInput) {
// Import the tracking function from client-event-handler
import('./client-event-handler').then(module => {
// Check if this event is already published
if (signedEvent.id && module.isEventPublished(signedEvent.id)) {
showSuccess(publishResult, "Event was already published, not sending duplicate");
return;
}
// Track the event before publishing
try {
module.trackOutgoingEvent(signedEvent);
@ -449,6 +455,10 @@ if (publishRelayInput) {
// Publish the event using the publishToRelay function
publishToRelay(signedEvent, relayUrl)
.then((result: string) => {
// Mark the event as published to prevent duplicates
if (signedEvent.id) {
module.markEventAsPublished(signedEvent.id);
}
showSuccess(publishResult, result);
})
.catch((error: Error) => {
@ -685,16 +695,10 @@ if (publishRelayInput) {
// Initialize event listeners when the DOM is fully loaded
document.addEventListener('DOMContentLoaded', () => {
// Set up the click event handler without any automatic encryption
const convertButton = document.getElementById('convertButton');
// The Convert button event listener is already set in client.ts
// so we don't set it here to avoid duplicate calls and double events
const publishButton = document.getElementById('publishButton');
if (convertButton) {
convertButton.addEventListener('click', (): void => {
void displayConvertedEvent();
});
}
// Add a handler for the publish button to check if an event is available
if (publishButton) {
publishButton.addEventListener('click', (): void => {

@ -4,9 +4,9 @@
* Stateless authentication service that directly uses the Nostr extension.
* Removed all localStorage and session dependencies.
*/
import type * as nostrTools from 'nostr-tools';
/**
* Interface for authentication operation results
*/
@ -64,32 +64,122 @@ export class AuthenticationService {
*/
public async authenticate(): Promise<AuthResult> {
try {
// Check if a Nostr extension is available
if (!window.nostr) {
return {
success: false,
error: 'Nostr extension not found. Please install Alby or nos2x.'
};
console.log("AuthenticationService: Using nostr-login for authentication");
// Try to use nostr-login library if available
const nostrLoginModule = typeof require !== 'undefined' ? require('nostr-login') : null;
if (nostrLoginModule && nostrLoginModule.init) {
try {
console.log("nostr-login loaded, initializing...");
// Initialize nostr-login which sets up window.nostr
await nostrLoginModule.init({
// Options for nostr-login
darkMode: document.body.getAttribute('data-theme') === 'dark',
noBanner: true, // Don't show the banner
});
console.log("nostr-login initialized, window.nostr should be available");
// Check if window.nostr was successfully set up
if (window.nostr) {
console.log("Attempting to get pubkey through window.nostr...");
// Get pubkey through window.nostr
const pubkey = await window.nostr.getPublicKey();
console.log("window.nostr.getPublicKey returned:", pubkey);
if (pubkey) {
console.log(`Authentication successful with pubkey: ${pubkey.substring(0, 8)}...`);
// Cache the pubkey in memory
this.cachedPubkey = pubkey;
// Notify listeners of authentication change
this.notifyAuthStateChanged(true, pubkey);
// Set the global nostrPubkey for backwards compatibility with existing code
if (window) {
window.nostrPubkey = pubkey;
}
return {
success: true,
pubkey
};
}
} else {
console.error('nostr-login initialized but window.nostr is not available');
}
} catch (nostrLoginError) {
console.error('nostr-login error:', nostrLoginError);
console.error('nostr-login stack:', nostrLoginError instanceof Error ? nostrLoginError.stack : 'No stack available');
console.error('nostr-login error details:', JSON.stringify(nostrLoginError));
// Check for specific error types
const errorMessage = nostrLoginError instanceof Error ? nostrLoginError.message : String(nostrLoginError);
if (errorMessage.includes('Already started')) {
console.warn('nostr-login was already initialized, this is usually not a problem');
// Continue with window.nostr if it's available despite the "Already started" error
if (window.nostr) {
try {
console.log("nostr-login already initialized, using window.nostr directly");
const pubkey = await window.nostr.getPublicKey();
if (pubkey) {
console.log(`Authentication successful with pubkey: ${pubkey.substring(0, 8)}...`);
this.cachedPubkey = pubkey;
this.notifyAuthStateChanged(true, pubkey);
if (window) {
window.nostrPubkey = pubkey;
}
return {
success: true,
pubkey
};
}
} catch (directNostrError) {
console.error('Direct window.nostr error:', directNostrError);
}
}
} else if (errorMessage.includes('Rejected by user') || errorMessage.includes('Cancelled')) {
console.warn('User rejected or cancelled the nostr-login authentication');
return {
success: false,
error: 'Authentication was cancelled by the user. Please try again.'
};
}
// Fall back to window.nostr if NostrLogin fails for other reasons
}
}
// Directly request the public key from the Nostr extension
const pubkey = await window.nostr.getPublicKey();
if (pubkey) {
// Cache the pubkey in memory
this.cachedPubkey = pubkey;
// Fall back to window.nostr if NostrLogin is not available
if (window.nostr) {
console.log("Falling back to window.nostr");
// Notify listeners of authentication change
this.notifyAuthStateChanged(true, pubkey);
// Directly request the public key from the Nostr extension
const pubkey = await window.nostr.getPublicKey();
// Set the global nostrPubkey for backwards compatibility with existing code
if (window) {
window.nostrPubkey = pubkey;
if (pubkey) {
// Cache the pubkey in memory
this.cachedPubkey = pubkey;
// Notify listeners of authentication change
this.notifyAuthStateChanged(true, pubkey);
// Set the global nostrPubkey for backwards compatibility with existing code
if (window) {
window.nostrPubkey = pubkey;
}
return {
success: true,
pubkey
};
}
} else {
return {
success: true,
pubkey
success: false,
error: 'Authentication failed. No Nostr provider found.'
};
}
@ -119,9 +209,52 @@ export class AuthenticationService {
return true;
}
// No cached pubkey, try to get it from the extension
// Try to use nostr-login library if available
const nostrLoginModule = typeof require !== 'undefined' ? require('nostr-login') : null;
if (nostrLoginModule && nostrLoginModule.init) {
try {
console.log("Using nostr-login to check authentication");
// Initialize nostr-login which sets up window.nostr
await nostrLoginModule.init({
darkMode: document.body.getAttribute('data-theme') === 'dark',
noBanner: true, // Don't show the banner
});
console.log("nostr-login initialized for auth check, window.nostr should be available");
// Check if window.nostr was successfully set up
if (window.nostr) {
console.log("Attempting to get pubkey through window.nostr for auth check...");
// Get pubkey through window.nostr
const pubkey = await window.nostr.getPublicKey();
console.log("window.nostr.getPublicKey returned for auth check:", pubkey);
if (pubkey) {
console.log(`Authentication check successful with pubkey: ${pubkey.substring(0, 8)}...`);
this.cachedPubkey = pubkey;
// Set the global nostrPubkey for backwards compatibility
if (window) {
window.nostrPubkey = pubkey;
}
return true;
}
} else {
console.error('nostr-login initialized but window.nostr is not available for auth check');
}
} catch (nostrLoginError) {
console.error('Failed to get pubkey from nostr-login:', nostrLoginError);
console.error('nostr-login stack:', nostrLoginError instanceof Error ? nostrLoginError.stack : 'No stack available');
console.error('nostr-login error details:', JSON.stringify(nostrLoginError));
// Fall back to window.nostr if NostrLogin fails
}
}
// Fall back to window.nostr if NostrLogin is not available
if (window.nostr) {
try {
console.log("Falling back to window.nostr to check authentication");
const pubkey = await window.nostr.getPublicKey();
if (pubkey) {
this.cachedPubkey = pubkey;
@ -163,12 +296,52 @@ export class AuthenticationService {
public async getPubkey(): Promise<string | null> {
// If we have a cached pubkey, return it
if (this.cachedPubkey) {
console.log(`Using cached pubkey: ${this.cachedPubkey.substring(0, 8)}...`);
return this.cachedPubkey;
}
// Try to get pubkey from extension
// Try to use nostr-login library if available
const nostrLoginModule = typeof require !== 'undefined' ? require('nostr-login') : null;
if (nostrLoginModule && nostrLoginModule.init) {
try {
console.log("Using nostr-login to get pubkey");
// Initialize nostr-login which sets up window.nostr
await nostrLoginModule.init({
darkMode: document.body.getAttribute('data-theme') === 'dark',
noBanner: true, // Don't show the banner
});
console.log("nostr-login initialized in getPubkey, window.nostr should be available");
// Check if window.nostr was successfully set up
if (window.nostr) {
console.log("Attempting to get pubkey through window.nostr in getPubkey...");
// Get pubkey through window.nostr
const pubkey = await window.nostr.getPublicKey();
console.log("window.nostr.getPublicKey returned in getPubkey:", pubkey);
if (pubkey) {
console.log(`getPubkey successful with: ${pubkey.substring(0, 8)}...`);
this.cachedPubkey = pubkey;
return pubkey;
}
} else {
console.error('nostr-login initialized but window.nostr is not available in getPubkey');
}
} catch (nostrLoginError) {
console.error('Failed to get pubkey from nostr-login:', nostrLoginError);
console.error('NostrLogin stack:', nostrLoginError instanceof Error ? nostrLoginError.stack : 'No stack available');
console.error('NostrLogin error details:', JSON.stringify(nostrLoginError));
// Fall back to window.nostr if NostrLogin fails
}
}
// Fall back to window.nostr if NostrLogin is not available
try {
if (window.nostr) {
console.log("Falling back to window.nostr to get pubkey");
const pubkey = await window.nostr.getPublicKey();
if (pubkey) {
this.cachedPubkey = pubkey;

@ -96,7 +96,7 @@ export class Nostr21121Service {
// Always add reference to the request event
if (requestEvent.id) {
tags.push(['e', requestEvent.id, '']);
tags.push(['e', requestEvent.id]);
}
// Get the pubkey of the request creator (client) for encryption

@ -192,21 +192,41 @@ export class Nostr31120Service {
}
}
// Check if window.nostr (Nostr browser extension) is available
if (!window.nostr) {
throw new Error('No Nostr browser extension found. Please install a NIP-07 compatible extension.');
// Try to use nostr-login library if available
const NostrLogin = typeof require !== 'undefined' ? require('nostr-login') : null;
let nostrProvider = null;
// Try nostr-login first
if (NostrLogin) {
try {
console.log("Using nostr-login in Nostr31120Service");
nostrProvider = new NostrLogin();
} catch (nostrLoginError) {
console.error('NostrLogin error:', nostrLoginError);
// Fall back to window.nostr
}
}
// Get user's public key using the extension
// Fall back to window.nostr if nostr-login is not available
if (!nostrProvider && window.nostr) {
nostrProvider = window.nostr;
}
// Check if we have a Nostr provider
if (!nostrProvider) {
throw new Error('No Nostr provider found. Authentication with nostr-login was unsuccessful.');
}
// Get user's public key using the Nostr provider
let userPubkey: string;
try {
userPubkey = await window.nostr!.getPublicKey();
userPubkey = await nostrProvider.getPublicKey();
if (!userPubkey) {
throw new Error('Failed to get public key from Nostr extension');
throw new Error('Failed to get public key from Nostr provider');
}
} catch (error) {
console.error('Error getting public key from Nostr extension:', error);
throw new Error('Failed to get your public key. Please make sure your Nostr extension is working.');
console.error('Error getting public key from Nostr provider:', error);
throw new Error('Failed to get your public key. Authentication with nostr-login was unsuccessful.');
}
// Generate or use a provided server pubkey
@ -269,14 +289,14 @@ export class Nostr31120Service {
content: content || 'HTTP-over-Nostr server',
};
// Sign the event using the browser extension
// Sign the event using the Nostr provider
let signedEvent: NostrEvent;
try {
signedEvent = await window.nostr!.signEvent(unsignedEvent);
console.log('Event signed successfully with Nostr extension');
signedEvent = await nostrProvider.signEvent(unsignedEvent);
console.log('Event signed successfully with Nostr provider');
} catch (error) {
console.error('Error signing event with Nostr extension:', error);
throw new Error('Failed to sign the event with your Nostr extension');
console.error('Error signing event with Nostr provider:', error);
throw new Error('Failed to sign the event. Authentication with nostr-login was unsuccessful.');
}
// Publish to relay
@ -362,14 +382,39 @@ export class Nostr31120Service {
content: content || 'HTTP-over-Nostr server',
};
// Sign the event using the browser extension
// Sign the event using the Nostr provider
let signedEvent: NostrEvent;
try {
signedEvent = await window.nostr!.signEvent(unsignedEvent);
console.log('Event signed successfully with Nostr extension');
// Try to use nostr-login library if available
const NostrLogin = typeof require !== 'undefined' ? require('nostr-login') : null;
let nostrProvider = null;
// Try nostr-login first
if (NostrLogin) {
try {
console.log("Using nostr-login in processEventWithServerKey");
nostrProvider = new NostrLogin();
} catch (nostrLoginError) {
console.error('NostrLogin error:', nostrLoginError);
// Fall back to window.nostr
}
}
// Fall back to window.nostr if nostr-login is not available
if (!nostrProvider && window.nostr) {
nostrProvider = window.nostr;
}
// Check if we have a Nostr provider
if (!nostrProvider) {
throw new Error('No Nostr provider found. Authentication with nostr-login was unsuccessful.');
}
signedEvent = await nostrProvider.signEvent(unsignedEvent);
console.log('Event signed successfully with Nostr provider');
} catch (error) {
console.error('Error signing event with Nostr extension:', error);
throw new Error('Failed to sign the event with your Nostr extension');
console.error('Error signing event with Nostr provider:', error);
throw new Error('Failed to sign the event. Authentication with nostr-login was unsuccessful.');
}
// Publish to relay

46
package-lock.json generated

@ -17,7 +17,6 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"license": "MIT",
"engines": {
"node": ">=8"
}
@ -26,7 +25,6 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
@ -41,7 +39,6 @@
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"license": "MIT",
"engines": {
"node": ">=6"
}
@ -50,7 +47,6 @@
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
"integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
"license": "ISC",
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
@ -61,7 +57,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
},
@ -72,14 +67,12 @@
"node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"license": "MIT"
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/decamelize": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
@ -87,20 +80,17 @@
"node_modules/dijkstrajs": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
"integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==",
"license": "MIT"
"integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA=="
},
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"license": "MIT"
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"node_modules/find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
"license": "MIT",
"dependencies": {
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
@ -113,7 +103,6 @@
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"license": "ISC",
"engines": {
"node": "6.* || 8.* || >= 10.*"
}
@ -122,7 +111,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"license": "MIT",
"engines": {
"node": ">=8"
}
@ -130,14 +118,12 @@
"node_modules/jsqr": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/jsqr/-/jsqr-1.4.0.tgz",
"integrity": "sha512-dxLob7q65Xg2DvstYkRpkYtmKm2sPJ9oFhrhmudT1dZvNFFTlroai3AWSpLey/w5vMcLBXRgOJsbXpdN9HzU/A==",
"license": "Apache-2.0"
"integrity": "sha512-dxLob7q65Xg2DvstYkRpkYtmKm2sPJ9oFhrhmudT1dZvNFFTlroai3AWSpLey/w5vMcLBXRgOJsbXpdN9HzU/A=="
},
"node_modules/locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
"license": "MIT",
"dependencies": {
"p-locate": "^4.1.0"
},
@ -149,7 +135,6 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"license": "MIT",
"dependencies": {
"p-try": "^2.0.0"
},
@ -164,7 +149,6 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"license": "MIT",
"dependencies": {
"p-limit": "^2.2.0"
},
@ -176,7 +160,6 @@
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"license": "MIT",
"engines": {
"node": ">=6"
}
@ -185,7 +168,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"license": "MIT",
"engines": {
"node": ">=8"
}
@ -194,7 +176,6 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz",
"integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==",
"license": "MIT",
"engines": {
"node": ">=10.13.0"
}
@ -203,7 +184,6 @@
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz",
"integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==",
"license": "MIT",
"dependencies": {
"dijkstrajs": "^1.0.1",
"pngjs": "^5.0.0",
@ -220,7 +200,6 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
@ -228,20 +207,17 @@
"node_modules/require-main-filename": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
"license": "ISC"
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
},
"node_modules/set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
"license": "ISC"
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
},
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@ -255,7 +231,6 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
},
@ -266,14 +241,12 @@
"node_modules/which-module": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
"integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==",
"license": "ISC"
"integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="
},
"node_modules/wrap-ansi": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
@ -286,14 +259,12 @@
"node_modules/y18n": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
"license": "ISC"
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="
},
"node_modules/yargs": {
"version": "15.4.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
"integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
"license": "MIT",
"dependencies": {
"cliui": "^6.0.0",
"decamelize": "^1.2.0",
@ -315,7 +286,6 @@
"version": "18.1.3",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
"integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
"license": "ISC",
"dependencies": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"