@@ -26,12 +26,12 @@ export const Component = () => {
browser.permissions.request(PERMISSION_HOSTS).finally(() => {
// So we open popup with refreshed state, avoiding additional message passing.
// Firefox closes popup automatically.
- window.close()
+ window.close();
})
}
>
Grant permission
- )
-}
+ );
+};
diff --git a/src/popup/pages/OutOfFunds.tsx b/src/popup/pages/OutOfFunds.tsx
index 174537a0..643ce9a4 100644
--- a/src/popup/pages/OutOfFunds.tsx
+++ b/src/popup/pages/OutOfFunds.tsx
@@ -1,15 +1,15 @@
-import React from 'react'
-import { useNavigate } from 'react-router-dom'
-import { OutOfFunds } from '@/popup/components/OutOfFunds'
-import { usePopupState } from '@/popup/lib/context'
-import { ROUTES_PATH } from '@/popup/Popup'
-import type { State } from '@/popup/pages/OutOfFunds_AddFunds'
+import React from 'react';
+import { useNavigate } from 'react-router-dom';
+import { OutOfFunds } from '@/popup/components/OutOfFunds';
+import { usePopupState } from '@/popup/lib/context';
+import { ROUTES_PATH } from '@/popup/Popup';
+import type { State } from '@/popup/pages/OutOfFunds_AddFunds';
export const Component = () => {
const {
- state: { grants, walletAddress }
- } = usePopupState()
- const navigate = useNavigate()
+ state: { grants, walletAddress },
+ } = usePopupState();
+ const navigate = useNavigate();
return (
{
grantOneTime={grants.oneTime}
grantRecurring={grants.recurring}
onChooseOption={(recurring) => {
- const state: State = { recurring }
- navigate(ROUTES_PATH.OUT_OF_FUNDS_ADD_FUNDS, { state })
+ const state: State = { recurring };
+ navigate(ROUTES_PATH.OUT_OF_FUNDS_ADD_FUNDS, { state });
}}
/>
- )
-}
+ );
+};
diff --git a/src/popup/pages/OutOfFunds_AddFunds.tsx b/src/popup/pages/OutOfFunds_AddFunds.tsx
index 7847ffbb..a46f04b7 100644
--- a/src/popup/pages/OutOfFunds_AddFunds.tsx
+++ b/src/popup/pages/OutOfFunds_AddFunds.tsx
@@ -1,19 +1,19 @@
-import React from 'react'
-import { useLocation } from 'react-router-dom'
-import { AddFunds } from '@/popup/components/OutOfFunds'
-import { usePopupState, useMessage } from '@/popup/lib/context'
+import React from 'react';
+import { useLocation } from 'react-router-dom';
+import { AddFunds } from '@/popup/components/OutOfFunds';
+import { usePopupState, useMessage } from '@/popup/lib/context';
-export type State = { recurring: boolean }
+export type State = { recurring: boolean };
export const Component = () => {
- const message = useMessage()
+ const message = useMessage();
const {
- state: { grants, walletAddress }
- } = usePopupState()
- const location = useLocation()
+ state: { grants, walletAddress },
+ } = usePopupState();
+ const location = useLocation();
- const state: State = { recurring: false, ...location.state }
- const defaultAmount = grants.recurring?.value ?? grants.oneTime!.value
+ const state: State = { recurring: false, ...location.state };
+ const defaultAmount = grants.recurring?.value ?? grants.oneTime!.value;
return (
{
defaultAmount={defaultAmount}
recurring={state.recurring}
requestAddFunds={async (data) => {
- const res = await message.send('ADD_FUNDS', data)
- return res
+ const res = await message.send('ADD_FUNDS', data);
+ return res;
}}
/>
- )
-}
+ );
+};
diff --git a/src/popup/pages/Settings.tsx b/src/popup/pages/Settings.tsx
index 3ade8d10..ebc1e511 100644
--- a/src/popup/pages/Settings.tsx
+++ b/src/popup/pages/Settings.tsx
@@ -1,14 +1,14 @@
-import { ConnectWalletForm } from '@/popup/components/ConnectWalletForm'
-import { WalletInformation } from '@/popup/components/WalletInformation'
-import { usePopupState } from '@/popup/lib/context'
-import React from 'react'
+import { ConnectWalletForm } from '@/popup/components/ConnectWalletForm';
+import { WalletInformation } from '@/popup/components/WalletInformation';
+import { usePopupState } from '@/popup/lib/context';
+import React from 'react';
export const Component = () => {
- const { state } = usePopupState()
+ const { state } = usePopupState();
if (state.connected) {
- return
+ return ;
} else {
- return
+ return ;
}
-}
+};
diff --git a/src/shared/crypto.ts b/src/shared/crypto.ts
index 326466d5..078a9d3e 100644
--- a/src/shared/crypto.ts
+++ b/src/shared/crypto.ts
@@ -1,7 +1,7 @@
-import * as ed from '@noble/ed25519'
+import * as ed from '@noble/ed25519';
export async function generateEd25519KeyPair() {
- const rawPrivateKey = ed.utils.randomPrivateKey()
+ const rawPrivateKey = ed.utils.randomPrivateKey();
// PKCS#8 format (version + algorithm)
// Adding these values upfront solves the future import of the key using
// `crypto.subtle.importKey` once the WebCrypto API supports the Ed25519 algorithm.
@@ -10,26 +10,26 @@ export async function generateEd25519KeyPair() {
48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32,
...rawPrivateKey,
])
- const publicKey = await ed.getPublicKeyAsync(rawPrivateKey)
+ const publicKey = await ed.getPublicKeyAsync(rawPrivateKey);
- return { privateKey, publicKey }
+ return { privateKey, publicKey };
}
export function exportJWK(key: Uint8Array, kid: string) {
- const string = String.fromCharCode.apply(null, key)
+ const string = String.fromCharCode.apply(null, key);
- const base64 = btoa(string)
+ const base64 = btoa(string);
// Based on the JWK Spec - base64url encoded.
// https://datatracker.ietf.org/doc/html/rfc7517#section-3
const base64Url = base64
.replace(/\+/g, '-')
.replace(/\//g, '_')
- .replace(/=+$/, '')
+ .replace(/=+$/, '');
return {
kty: 'OKP',
crv: 'Ed25519',
x: base64Url,
- kid
- }
+ kid,
+ };
}
diff --git a/src/shared/defines.ts b/src/shared/defines.ts
index 97475e00..663caad8 100644
--- a/src/shared/defines.ts
+++ b/src/shared/defines.ts
@@ -1,11 +1,11 @@
-import type { LogLevelDesc } from 'loglevel'
+import type { LogLevelDesc } from 'loglevel';
-declare const CONFIG_LOG_LEVEL: LogLevelDesc
-declare const CONFIG_PERMISSION_HOSTS: { origins: string[] }
-declare const CONFIG_ALLOWED_PROTOCOLS: string[]
-declare const CONFIG_OPEN_PAYMENTS_REDIRECT_URL: string
+declare const CONFIG_LOG_LEVEL: LogLevelDesc;
+declare const CONFIG_PERMISSION_HOSTS: { origins: string[] };
+declare const CONFIG_ALLOWED_PROTOCOLS: string[];
+declare const CONFIG_OPEN_PAYMENTS_REDIRECT_URL: string;
-export const LOG_LEVEL = CONFIG_LOG_LEVEL
-export const PERMISSION_HOSTS = CONFIG_PERMISSION_HOSTS
-export const ALLOWED_PROTOCOLS = CONFIG_ALLOWED_PROTOCOLS
-export const OPEN_PAYMENTS_REDIRECT_URL = CONFIG_OPEN_PAYMENTS_REDIRECT_URL
+export const LOG_LEVEL = CONFIG_LOG_LEVEL;
+export const PERMISSION_HOSTS = CONFIG_PERMISSION_HOSTS;
+export const ALLOWED_PROTOCOLS = CONFIG_ALLOWED_PROTOCOLS;
+export const OPEN_PAYMENTS_REDIRECT_URL = CONFIG_OPEN_PAYMENTS_REDIRECT_URL;
diff --git a/src/shared/helpers.test.ts b/src/shared/helpers.test.ts
index 0793a8ba..6c43a9e6 100644
--- a/src/shared/helpers.test.ts
+++ b/src/shared/helpers.test.ts
@@ -1,124 +1,124 @@
-import { addDays, addMonths, addSeconds } from 'date-fns'
+import { addDays, addMonths, addSeconds } from 'date-fns';
import {
isOkState,
objectEquals,
removeQueryParams,
- getNextOccurrence
-} from './helpers'
+ getNextOccurrence,
+} from './helpers';
describe('objectEquals', () => {
it('should return true if objects are equal', () => {
- expect(objectEquals({}, {})).toBe(true)
- expect(objectEquals({ a: 1 }, { a: 1 })).toBe(true)
- expect(objectEquals({ b: 2, a: 1 }, { a: 1, b: 2 })).toBe(true)
- expect(objectEquals({ a: 1 }, { a: 1, b: undefined })).toBe(true)
- })
+ expect(objectEquals({}, {})).toBe(true);
+ expect(objectEquals({ a: 1 }, { a: 1 })).toBe(true);
+ expect(objectEquals({ b: 2, a: 1 }, { a: 1, b: 2 })).toBe(true);
+ expect(objectEquals({ a: 1 }, { a: 1, b: undefined })).toBe(true);
+ });
it('should return false if objects are not equal', () => {
- expect(objectEquals({ a: 1 }, { a: 2 })).toBe(false)
- expect(objectEquals({ a: 1 }, { b: 1 })).toBe(false)
- })
-})
+ expect(objectEquals({ a: 1 }, { a: 2 })).toBe(false);
+ expect(objectEquals({ a: 1 }, { b: 1 })).toBe(false);
+ });
+});
describe('removeQueryParams', () => {
it('should remove the query params from the URL', () => {
expect(removeQueryParams('https://example.com?foo=bar#baz')).toBe(
- 'https://example.com/'
- )
- })
+ 'https://example.com/',
+ );
+ });
it('should normalize the URL if there are no query params', () => {
expect(removeQueryParams('https://example.com')).toBe(
- 'https://example.com/'
- )
- })
-})
+ 'https://example.com/',
+ );
+ });
+});
describe('isOkState', () => {
it('should return true if no state is set', () => {
- expect(isOkState({})).toBe(true)
+ expect(isOkState({})).toBe(true);
expect(
- isOkState({ key_revoked: false, missing_host_permissions: false })
- ).toBe(true)
- })
+ isOkState({ key_revoked: false, missing_host_permissions: false }),
+ ).toBe(true);
+ });
it('should return false if any state is set', () => {
expect(
- isOkState({ key_revoked: true, missing_host_permissions: false })
- ).toBe(false)
+ isOkState({ key_revoked: true, missing_host_permissions: false }),
+ ).toBe(false);
expect(
- isOkState({ key_revoked: false, missing_host_permissions: true })
- ).toBe(false)
- })
-})
+ isOkState({ key_revoked: false, missing_host_permissions: true }),
+ ).toBe(false);
+ });
+});
describe('getNextOccurrence', () => {
- const now = new Date()
- const nowISO = now.toISOString()
- const dateJan = new Date('2024-01-03T00:00:00.000Z')
- const dateJanEnd = new Date('2024-01-30T00:00:00.000Z')
- const dateFeb = new Date('2023-02-03T00:00:00.000Z')
- const dateFebLeap = new Date('2024-02-29T00:00:00.000Z')
- const dateApr = new Date('2024-04-03T00:00:00.000Z')
+ const now = new Date();
+ const nowISO = now.toISOString();
+ const dateJan = new Date('2024-01-03T00:00:00.000Z');
+ const dateJanEnd = new Date('2024-01-30T00:00:00.000Z');
+ const dateFeb = new Date('2023-02-03T00:00:00.000Z');
+ const dateFebLeap = new Date('2024-02-29T00:00:00.000Z');
+ const dateApr = new Date('2024-04-03T00:00:00.000Z');
it('should return the next occurrence with /P1M', () => {
expect(
- getNextOccurrence(`R/${dateJan.toISOString()}/P1M`, dateJan)
- ).toEqual(addMonths(dateJan, 1))
+ getNextOccurrence(`R/${dateJan.toISOString()}/P1M`, dateJan),
+ ).toEqual(addMonths(dateJan, 1));
expect(
- getNextOccurrence(`R/${dateJan.toISOString()}/P1M`, addDays(dateJan, 2))
- ).toEqual(addMonths(dateJan, 1))
+ getNextOccurrence(`R/${dateJan.toISOString()}/P1M`, addDays(dateJan, 2)),
+ ).toEqual(addMonths(dateJan, 1));
expect(
- getNextOccurrence(`R/${dateJanEnd.toISOString()}/P1M`, dateJanEnd)
- ).toEqual(new Date('2024-03-01T00:00:00.000Z'))
+ getNextOccurrence(`R/${dateJanEnd.toISOString()}/P1M`, dateJanEnd),
+ ).toEqual(new Date('2024-03-01T00:00:00.000Z'));
expect(
- getNextOccurrence(`R/${dateFeb.toISOString()}/P1M`, dateFeb)
- ).toEqual(addMonths(dateFeb, 1))
+ getNextOccurrence(`R/${dateFeb.toISOString()}/P1M`, dateFeb),
+ ).toEqual(addMonths(dateFeb, 1));
expect(
- getNextOccurrence(`R/${dateFebLeap.toISOString()}/P1M`, dateFebLeap)
- ).toEqual(addMonths(dateFebLeap, 1))
+ getNextOccurrence(`R/${dateFebLeap.toISOString()}/P1M`, dateFebLeap),
+ ).toEqual(addMonths(dateFebLeap, 1));
expect(
- getNextOccurrence(`R/${dateApr.toISOString()}/P1M`, dateApr)
- ).toEqual(addMonths(dateApr, 1))
- })
+ getNextOccurrence(`R/${dateApr.toISOString()}/P1M`, dateApr),
+ ).toEqual(addMonths(dateApr, 1));
+ });
it('should return next occurrence with /P1W', () => {
expect(
- getNextOccurrence(`R/${dateJan.toISOString()}/P1W`, dateJan)
- ).toEqual(addDays(dateJan, 7))
+ getNextOccurrence(`R/${dateJan.toISOString()}/P1W`, dateJan),
+ ).toEqual(addDays(dateJan, 7));
expect(
- getNextOccurrence(`R/${dateFeb.toISOString()}/P1W`, dateFeb)
- ).toEqual(addDays(dateFeb, 7))
+ getNextOccurrence(`R/${dateFeb.toISOString()}/P1W`, dateFeb),
+ ).toEqual(addDays(dateFeb, 7));
expect(
- getNextOccurrence(`R/${dateFebLeap.toISOString()}/P1W`, dateFebLeap)
- ).toEqual(addDays(dateFebLeap, 7))
+ getNextOccurrence(`R/${dateFebLeap.toISOString()}/P1W`, dateFebLeap),
+ ).toEqual(addDays(dateFebLeap, 7));
expect(
- getNextOccurrence(`R/${dateApr.toISOString()}/P1W`, dateApr)
- ).toEqual(addDays(dateApr, 7))
- })
+ getNextOccurrence(`R/${dateApr.toISOString()}/P1W`, dateApr),
+ ).toEqual(addDays(dateApr, 7));
+ });
it('should throw if no more occurrences are possible', () => {
- const interval = `R1/${dateJan.toISOString()}/P1M`
- const errorMsg = /No next occurrence is possible/
+ const interval = `R1/${dateJan.toISOString()}/P1M`;
+ const errorMsg = /No next occurrence is possible/;
expect(() =>
- getNextOccurrence(interval, addMonths(dateJan, 0))
- ).not.toThrow(errorMsg)
+ getNextOccurrence(interval, addMonths(dateJan, 0)),
+ ).not.toThrow(errorMsg);
expect(() => getNextOccurrence(interval, addDays(dateJan, 10))).not.toThrow(
- errorMsg
- )
+ errorMsg,
+ );
expect(() => getNextOccurrence(interval, addMonths(dateJan, 1))).toThrow(
- errorMsg
- )
+ errorMsg,
+ );
expect(() => getNextOccurrence(interval, addMonths(dateJan, 2))).toThrow(
- errorMsg
- )
- })
+ errorMsg,
+ );
+ });
it('should return the next occurrence with /PT', () => {
expect(getNextOccurrence(`R/${nowISO}/PT30S`, now)).toEqual(
- addSeconds(now, 30)
- )
- })
-})
+ addSeconds(now, 30),
+ );
+ });
+});
diff --git a/src/shared/helpers.ts b/src/shared/helpers.ts
index ed68afff..5f990de2 100644
--- a/src/shared/helpers.ts
+++ b/src/shared/helpers.ts
@@ -1,25 +1,25 @@
-import type { SuccessResponse } from '@/shared/messages'
-import type { WalletAddress } from '@interledger/open-payments/dist/types'
-import { cx, CxOptions } from 'class-variance-authority'
-import { twMerge } from 'tailwind-merge'
-import { addSeconds } from 'date-fns/addSeconds'
-import { isAfter } from 'date-fns/isAfter'
-import { isBefore } from 'date-fns/isBefore'
-import { parse, toSeconds } from 'iso8601-duration'
-import type { Browser } from 'webextension-polyfill'
-import type { Storage, RepeatingInterval, AmountValue } from './types'
+import type { SuccessResponse } from '@/shared/messages';
+import type { WalletAddress } from '@interledger/open-payments/dist/types';
+import { cx, CxOptions } from 'class-variance-authority';
+import { twMerge } from 'tailwind-merge';
+import { addSeconds } from 'date-fns/addSeconds';
+import { isAfter } from 'date-fns/isAfter';
+import { isBefore } from 'date-fns/isBefore';
+import { parse, toSeconds } from 'iso8601-duration';
+import type { Browser } from 'webextension-polyfill';
+import type { Storage, RepeatingInterval, AmountValue } from './types';
export const cn = (...inputs: CxOptions) => {
- return twMerge(cx(inputs))
-}
+ return twMerge(cx(inputs));
+};
export const formatCurrency = (value: any): string => {
if (value < 1) {
- return `${Math.round(value * 100)}c`
+ return `${Math.round(value * 100)}c`;
} else {
- return `$${parseFloat(value).toFixed(2)}`
+ return `$${parseFloat(value).toFixed(2)}`;
}
-}
+};
const isWalletAddress = (o: any): o is WalletAddress => {
return (
@@ -33,65 +33,65 @@ const isWalletAddress = (o: any): o is WalletAddress => {
typeof o.authServer === 'string' &&
o.resourceServer &&
typeof o.resourceServer === 'string'
- )
-}
+ );
+};
export const getWalletInformation = async (
- walletAddressUrl: string
+ walletAddressUrl: string,
): Promise => {
const response = await fetch(walletAddressUrl, {
headers: {
- Accept: 'application/json'
- }
- })
- const json = await response.json()
+ Accept: 'application/json',
+ },
+ });
+ const json = await response.json();
if (!isWalletAddress(json)) {
- throw new Error('Invalid wallet address response.')
+ throw new Error('Invalid wallet address response.');
}
- return json
-}
+ return json;
+};
export const success = (
- payload: TPayload
+ payload: TPayload,
): SuccessResponse => ({
success: true,
- payload
-})
+ payload,
+});
export const failure = (message: string) => ({
success: false,
- message
-})
+ message,
+});
-export const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))
+export const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
export const notNullOrUndef = (
t: T | null | undefined,
- name = ''
+ name = '',
): T | never => {
if (t == null) {
- throw new Error(`Expecting not null for ${name}`)
+ throw new Error(`Expecting not null for ${name}`);
} else {
- return t
+ return t;
}
-}
+};
export function debounceAsync>(
func: (...args: T) => R,
- wait: number
+ wait: number,
) {
- let timeout: ReturnType | null = null
+ let timeout: ReturnType | null = null;
return function (...args: T) {
return new Promise>((resolve) => {
- if (timeout != null) clearTimeout(timeout)
+ if (timeout != null) clearTimeout(timeout);
timeout = setTimeout(() => {
- timeout = null
- void Promise.resolve(func(...args)).then(resolve)
- }, wait)
- })
- }
+ timeout = null;
+ void Promise.resolve(func(...args)).then(resolve);
+ }, wait);
+ });
+ };
}
// Based on https://stackoverflow.com/a/27078401
@@ -100,33 +100,33 @@ export function throttle(
wait: number,
options: Partial<{ leading: boolean; trailing: boolean }> = {
leading: false,
- trailing: false
- }
+ trailing: false,
+ },
) {
- let result: R
- let timeout: ReturnType | null = null
- let previous = 0
+ let result: R;
+ let timeout: ReturnType | null = null;
+ let previous = 0;
const later = (...args: T) => {
- previous = options.leading === false ? 0 : Date.now()
- timeout = null
- result = func(...args)
- }
+ previous = options.leading === false ? 0 : Date.now();
+ timeout = null;
+ result = func(...args);
+ };
return (...args: T) => {
- const now = Date.now()
- if (!previous && options.leading === false) previous = now
- const remaining = wait - (now - previous)
+ const now = Date.now();
+ if (!previous && options.leading === false) previous = now;
+ const remaining = wait - (now - previous);
if (remaining <= 0 || remaining > wait) {
if (timeout) {
- clearTimeout(timeout)
- timeout = null
+ clearTimeout(timeout);
+ timeout = null;
}
- previous = now
- result = func(...args)
+ previous = now;
+ result = func(...args);
} else if (!timeout && options.trailing !== false) {
- timeout = setTimeout(later, remaining, ...args)
+ timeout = setTimeout(later, remaining, ...args);
}
- return result
- }
+ return result;
+ };
}
/**
@@ -147,61 +147,61 @@ export function throttle(
* ```
*/
export class ThrottleBatch {
- private argsList: Args[] = []
- private throttled: () => void
+ private argsList: Args[] = [];
+ private throttled: () => void;
constructor(
private func: (...arg: Args) => R,
private argsReducer: (args: Args[]) => [...Args],
- wait: number
+ wait: number,
) {
- this.throttled = throttle(() => this.flush(), wait, { leading: true })
+ this.throttled = throttle(() => this.flush(), wait, { leading: true });
}
enqueue(...data: Args) {
- this.argsList.push(data)
- void this.throttled()
+ this.argsList.push(data);
+ void this.throttled();
}
flush() {
- if (!this.argsList.length) return
- const args = this.argsReducer(this.argsList.slice())
- this.argsList = []
- return this.func(...args)
+ if (!this.argsList.length) return;
+ const args = this.argsReducer(this.argsList.slice());
+ this.argsList = [];
+ return this.func(...args);
}
}
export function debounceSync(
func: (...args: T) => R,
- wait: number
+ wait: number,
) {
- let timeout: ReturnType | null = null
+ let timeout: ReturnType | null = null;
return function (...args: T) {
return new Promise((resolve) => {
- if (timeout != null) clearTimeout(timeout)
+ if (timeout != null) clearTimeout(timeout);
timeout = setTimeout(() => {
- timeout = null
- resolve(func(...args))
- }, wait)
- })
- }
+ timeout = null;
+ resolve(func(...args));
+ }, wait);
+ });
+ };
}
export function convert(value: bigint, source: number, target: number) {
- const scaleDiff = target - source
+ const scaleDiff = target - source;
if (scaleDiff > 0) {
- return value * BigInt(Math.pow(10, scaleDiff))
+ return value * BigInt(Math.pow(10, scaleDiff));
}
- return value / BigInt(Math.pow(10, -scaleDiff))
+ return value / BigInt(Math.pow(10, -scaleDiff));
}
export function bigIntMax(a: T, b: T): T {
- return BigInt(a) > BigInt(b) ? a : b
+ return BigInt(a) > BigInt(b) ? a : b;
}
-type TranslationKeys = keyof typeof import('../_locales/en/messages.json')
+type TranslationKeys = keyof typeof import('../_locales/en/messages.json');
-export type Translation = ReturnType
+export type Translation = ReturnType;
export function tFactory(browser: Pick) {
/**
* Helper over calling cumbersome `this.browser.i18n.getMessage(key)` with
@@ -209,52 +209,52 @@ export function tFactory(browser: Pick) {
*/
return (
key: T,
- substitutions?: string | string[]
- ) => browser.i18n.getMessage(key, substitutions)
+ substitutions?: string | string[],
+ ) => browser.i18n.getMessage(key, substitutions);
}
-type Primitive = string | number | boolean | null | undefined
+type Primitive = string | number | boolean | null | undefined;
// Warn: Not a nested object equals or a deepEquals function
export function objectEquals>(a: T, b: T) {
- const keysA = Object.keys(a)
- const keysB = Object.keys(b)
- return JSON.stringify(a, keysA.sort()) === JSON.stringify(b, keysB.sort())
+ const keysA = Object.keys(a);
+ const keysB = Object.keys(b);
+ return JSON.stringify(a, keysA.sort()) === JSON.stringify(b, keysB.sort());
}
export const removeQueryParams = (urlString: string) => {
- const url = new URL(urlString)
- return url.origin + url.pathname
-}
+ const url = new URL(urlString);
+ return url.origin + url.pathname;
+};
export const isOkState = (state: Storage['state']) => {
- return Object.values(state).every((value) => value === false)
-}
+ return Object.values(state).every((value) => value === false);
+};
const REPEATING_INTERVAL_REGEX =
- /^R(\d*)\/(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z)\/(P.+)$/
+ /^R(\d*)\/(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z)\/(P.+)$/;
export const getNextOccurrence = (
interval: RepeatingInterval,
- base = new Date()
+ base = new Date(),
): Date => {
- const match = interval.match(REPEATING_INTERVAL_REGEX)
+ const match = interval.match(REPEATING_INTERVAL_REGEX);
if (!match) {
- throw new Error(`Invalid interval: ${interval}`)
+ throw new Error(`Invalid interval: ${interval}`);
}
- const count = match[1] ? parseInt(match[1], 10) : null
- const startDate = new Date(match[2])
- const pattern = parse(match[3])
- const seconds = toSeconds(pattern, base)
+ const count = match[1] ? parseInt(match[1], 10) : null;
+ const startDate = new Date(match[2]);
+ const pattern = parse(match[3]);
+ const seconds = toSeconds(pattern, base);
if (count && isAfter(base, addSeconds(startDate, count * seconds))) {
- throw new Error('No next occurrence is possible beyond given time')
+ throw new Error('No next occurrence is possible beyond given time');
}
- let date = new Date(startDate)
+ let date = new Date(startDate);
while (!isBefore(base, date)) {
- date = addSeconds(date, seconds)
+ date = addSeconds(date, seconds);
}
- return date
-}
+ return date;
+};
diff --git a/src/shared/logger.ts b/src/shared/logger.ts
index 4476dd30..bae7ad04 100644
--- a/src/shared/logger.ts
+++ b/src/shared/logger.ts
@@ -1,26 +1,26 @@
-import log from 'loglevel'
+import log from 'loglevel';
// TODO: Disable debug logging in production
export const createLogger = (level: log.LogLevelDesc = 'DEBUG') => {
/** This disables all logging below the given level, */
- log.setLevel(level, false)
+ log.setLevel(level, false);
- const factory = log.methodFactory
+ const factory = log.methodFactory;
log.methodFactory = (methodName, logLevel, loggerName) => {
- const raw = factory(methodName, logLevel, loggerName)
+ const raw = factory(methodName, logLevel, loggerName);
return function (...args) {
const messages = [
`%c${loggerName as string}`,
'font-weight: bold; text-transform: uppercase; background: #2f8785; padding-inline: 5px;',
- ...args
- ]
- raw(...messages)
- }
- }
- log.rebuild()
+ ...args,
+ ];
+ raw(...messages);
+ };
+ };
+ log.rebuild();
- return log
-}
+ return log;
+};
-export type Logger = log.RootLogger
+export type Logger = log.RootLogger;
diff --git a/src/shared/messages.ts b/src/shared/messages.ts
index d3c1e1c8..f9dea560 100644
--- a/src/shared/messages.ts
+++ b/src/shared/messages.ts
@@ -1,251 +1,256 @@
-import type { WalletAddress, OutgoingPayment } from '@interledger/open-payments'
-import type { Browser } from 'webextension-polyfill'
-import type { AmountValue, Storage } from '@/shared/types'
-import type { PopupState } from '@/popup/lib/context'
+import type {
+ WalletAddress,
+ OutgoingPayment,
+} from '@interledger/open-payments';
+import type { Browser } from 'webextension-polyfill';
+import type { AmountValue, Storage } from '@/shared/types';
+import type { PopupState } from '@/popup/lib/context';
// #region MessageManager
export interface SuccessResponse {
- success: true
- payload: TPayload
+ success: true;
+ payload: TPayload;
}
export interface ErrorResponse {
- success: false
- message: string
+ success: false;
+ message: string;
}
export type Response =
| SuccessResponse
- | ErrorResponse
+ | ErrorResponse;
-type MessageMap = Record
+type MessageMap = Record;
type MessagesWithInput = {
- [K in keyof T as T[K]['input'] extends never ? never : K]: T[K]
-}
+ [K in keyof T as T[K]['input'] extends never ? never : K]: T[K];
+};
type MessagesWithoutInput = {
- [K in keyof T as T[K]['input'] extends never ? K : never]: T[K]
-}
+ [K in keyof T as T[K]['input'] extends never ? K : never]: T[K];
+};
export class MessageManager