forked from jsnbuchanan/crowd-funder-for-time-pwa
Refactoring for cleanup
This commit is contained in:
70
sample.txt
Normal file
70
sample.txt
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
|
||||||
|
> kickstart-for-time-pwa@0.1.0 build
|
||||||
|
> vue-cli-service build
|
||||||
|
|
||||||
|
All browser targets in the browserslist configuration have supported ES module.
|
||||||
|
Therefore we don't build two separate bundles for differential loading.
|
||||||
|
|
||||||
|
|
||||||
|
ERROR Failed to compile with 6 errors8:44:37 PM
|
||||||
|
|
||||||
|
error in ./src/views/AccountViewView.vue?vue&type=script&lang=ts
|
||||||
|
|
||||||
|
Module not found: Error: Package path ./index is not exported from package /home/matthew/projects/kick-starter-for-time-pwa/node_modules/axios (see exports field in /home/matthew/projects/kick-starter-for-time-pwa/node_modules/axios/package.json)
|
||||||
|
|
||||||
|
error in src/libs/endorserServer.ts:226:53
|
||||||
|
|
||||||
|
TS18047: 'error' is possibly 'null'.
|
||||||
|
224 | error instanceof Error
|
||||||
|
225 | ? error.message
|
||||||
|
> 226 | : typeof error === "object" && "message" in error
|
||||||
|
| ^^^^^
|
||||||
|
227 | ? (error as { message: string }).message
|
||||||
|
228 | : "Unknown error";
|
||||||
|
229 |
|
||||||
|
|
||||||
|
error in src/views/AccountViewView.vue:474:29
|
||||||
|
|
||||||
|
TS2304: Cannot find name 'IdentityType'.
|
||||||
|
472 | * @param {IdentityType} identity - Object containing identity information.
|
||||||
|
473 | */
|
||||||
|
> 474 | processIdentity(identity: IdentityType) {
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
475 | this.publicHex = identity.keys[0].publicKeyHex;
|
||||||
|
476 | this.publicBase64 = Buffer.from(this.publicHex, "hex").toString("base64");
|
||||||
|
477 | this.derivationPath = identity.keys[0].meta.derivationPath;
|
||||||
|
|
||||||
|
error in src/views/AccountViewView.vue:491:7
|
||||||
|
|
||||||
|
TS18046: 'err' is of type 'unknown'.
|
||||||
|
489 | handleError(err: unknown) {
|
||||||
|
490 | if (
|
||||||
|
> 491 | err.message ===
|
||||||
|
| ^^^
|
||||||
|
492 | "Attempted to load account records with no identity available."
|
||||||
|
493 | ) {
|
||||||
|
494 | this.limitsMessage = "No identity.";
|
||||||
|
|
||||||
|
error in src/views/AccountViewView.vue:645:34
|
||||||
|
|
||||||
|
TS2345: Argument of type 'unknown' is not assignable to parameter of type 'Error | AxiosError<unknown, any>'.
|
||||||
|
643 | }
|
||||||
|
644 | } catch (error) {
|
||||||
|
> 645 | this.handleRateLimitsError(error);
|
||||||
|
| ^^^^^
|
||||||
|
646 | }
|
||||||
|
647 |
|
||||||
|
648 | this.loadingLimits = false;
|
||||||
|
|
||||||
|
error in src/views/AccountViewView.vue:726:40
|
||||||
|
|
||||||
|
TS2345: Argument of type 'Account' is not assignable to parameter of type 'IAccount'.
|
||||||
|
Property 'privateHex' is missing in type 'Account' but required in type 'IAccount'.
|
||||||
|
724 | await db.settings.update(MASTER_SETTINGS_KEY, { activeDid: account.did });
|
||||||
|
725 |
|
||||||
|
> 726 | this.updateActiveAccountProperties(account);
|
||||||
|
| ^^^^^^^
|
||||||
|
727 | }
|
||||||
|
728 |
|
||||||
|
729 | /**
|
||||||
|
|
||||||
@@ -1,17 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* Represents an account stored in the database.
|
||||||
|
*/
|
||||||
export type Account = {
|
export type Account = {
|
||||||
id?: number; // auto-generated by Dexie
|
/**
|
||||||
|
* Auto-generated ID by Dexie.
|
||||||
|
*/
|
||||||
|
id?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The date the account was created.
|
||||||
|
*/
|
||||||
dateCreated: string;
|
dateCreated: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The derivation path for the account.
|
||||||
|
*/
|
||||||
derivationPath: string;
|
derivationPath: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decentralized Identifier (DID) for the account.
|
||||||
|
*/
|
||||||
did: string;
|
did: string;
|
||||||
// stringified JSON containing underlying key material of type IIdentifier
|
|
||||||
// https://github.com/uport-project/veramo/blob/next/packages/core-types/src/types/IIdentifier.ts
|
/**
|
||||||
|
* Stringified JSON containing underlying key material.
|
||||||
|
* Based on the IIdentifier type from Veramo.
|
||||||
|
* @see {@link https://github.com/uport-project/veramo/blob/next/packages/core-types/src/types/IIdentifier.ts}
|
||||||
|
*/
|
||||||
identity: string;
|
identity: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The public key in hexadecimal format.
|
||||||
|
*/
|
||||||
publicKeyHex: string;
|
publicKeyHex: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mnemonic passphrase for the account.
|
||||||
|
*/
|
||||||
mnemonic: string;
|
mnemonic: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
// mark encrypted field by starting with a $ character
|
/**
|
||||||
// see https://github.com/PVermeer/dexie-addon-suite-monorepo/tree/master/packages/dexie-encrypted-addon
|
* Schema for the accounts table in the database.
|
||||||
|
* Fields starting with a $ character are encrypted.
|
||||||
|
* @see {@link https://github.com/PVermeer/dexie-addon-suite-monorepo/tree/master/packages/dexie-encrypted-addon}
|
||||||
|
*/
|
||||||
export const AccountsSchema = {
|
export const AccountsSchema = {
|
||||||
accounts:
|
accounts:
|
||||||
"++id, dateCreated, derivationPath, did, $identity, $mnemonic, publicKeyHex",
|
"++id, dateCreated, derivationPath, did, $identity, $mnemonic, publicKeyHex",
|
||||||
|
|||||||
@@ -112,15 +112,23 @@ export function isHiddenDid(did: string) {
|
|||||||
/**
|
/**
|
||||||
always returns text, maybe UNNAMED_VISIBLE or UNKNOWN_ENTITY
|
always returns text, maybe UNNAMED_VISIBLE or UNKNOWN_ENTITY
|
||||||
**/
|
**/
|
||||||
export function didInfo(did: string, activeDid: string, allMyDids: string[], contacts: Contact[]): string {
|
export function didInfo(
|
||||||
|
did: string,
|
||||||
|
activeDid: string,
|
||||||
|
allMyDids: string[],
|
||||||
|
contacts: Contact[],
|
||||||
|
): string {
|
||||||
const myId = R.find(R.equals(did), allMyDids);
|
const myId = R.find(R.equals(did), allMyDids);
|
||||||
if (myId) return `You${myId !== activeDid ? " (Alt ID)" : ""}`;
|
if (myId) return `You${myId !== activeDid ? " (Alt ID)" : ""}`;
|
||||||
|
|
||||||
const contact = R.find(c => c.did === did, contacts);
|
const contact = R.find((c) => c.did === did, contacts);
|
||||||
return contact ? contact.name || "Someone Unnamed in Contacts" :
|
return contact
|
||||||
!did ? "Unspecified Person" :
|
? contact.name || "Someone Unnamed in Contacts"
|
||||||
isHiddenDid(did) ? "Someone Not In Network" :
|
: !did
|
||||||
"Someone Not In Contacts";
|
? "Unspecified Person"
|
||||||
|
: isHiddenDid(did)
|
||||||
|
? "Someone Not In Network"
|
||||||
|
: "Someone Not In Contacts";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ResultWithType {
|
export interface ResultWithType {
|
||||||
@@ -166,7 +174,9 @@ export async function createAndSubmitGive(
|
|||||||
agent: fromDid ? { identifier: fromDid } : undefined,
|
agent: fromDid ? { identifier: fromDid } : undefined,
|
||||||
description: description || undefined,
|
description: description || undefined,
|
||||||
object: hours ? { amountOfThisGood: hours, unitCode: "HUR" } : undefined,
|
object: hours ? { amountOfThisGood: hours, unitCode: "HUR" } : undefined,
|
||||||
fulfills: fulfillsProjectHandleId ? { "@type": "PlanAction", identifier: fulfillsProjectHandleId } : undefined,
|
fulfills: fulfillsProjectHandleId
|
||||||
|
? { "@type": "PlanAction", identifier: fulfillsProjectHandleId }
|
||||||
|
: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
const vcPayload = {
|
const vcPayload = {
|
||||||
@@ -209,20 +219,21 @@ export async function createAndSubmitGive(
|
|||||||
});
|
});
|
||||||
|
|
||||||
return { type: "success", response };
|
return { type: "success", response };
|
||||||
|
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
const errorMessage: string =
|
const errorMessage: string =
|
||||||
error instanceof Error ? error.message :
|
error instanceof Error
|
||||||
(typeof error === "object" && error?.message) ? error.message :
|
? error.message
|
||||||
"Unknown error";
|
: typeof error === "object" && "message" in error
|
||||||
|
? (error as { message: string }).message
|
||||||
|
: "Unknown error";
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: "error",
|
type: "error",
|
||||||
error: {
|
error: {
|
||||||
error: errorMessage,
|
error: errorMessage,
|
||||||
userMessage: "Failed to create and submit the claim."
|
userMessage: "Failed to create and submit the claim.",
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -310,6 +310,21 @@ interface Notification {
|
|||||||
text: string;
|
text: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IAccount {
|
||||||
|
did: string;
|
||||||
|
publicKeyHex: string;
|
||||||
|
privateHex: string;
|
||||||
|
derivationPath: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SettingsType {
|
||||||
|
activeDid?: string;
|
||||||
|
apiServer?: string;
|
||||||
|
firstName?: string;
|
||||||
|
lastName?: string;
|
||||||
|
showContactGivesInline?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
@Component({ components: { QuickNav } })
|
@Component({ components: { QuickNav } })
|
||||||
export default class AccountViewView extends Vue {
|
export default class AccountViewView extends Vue {
|
||||||
$notify!: (notification: Notification, timeout?: number) => void;
|
$notify!: (notification: Notification, timeout?: number) => void;
|
||||||
@@ -339,23 +354,56 @@ export default class AccountViewView extends Vue {
|
|||||||
alertMessage = "";
|
alertMessage = "";
|
||||||
alertTitle = "";
|
alertTitle = "";
|
||||||
|
|
||||||
public async getIdentity(activeDid: string) {
|
public async getIdentity(activeDid: string): Promise<IIdentifier | null> {
|
||||||
await accountsDB.open();
|
try {
|
||||||
const account = await accountsDB.accounts
|
// Open the accounts database
|
||||||
.where("did")
|
await accountsDB.open();
|
||||||
.equals(activeDid)
|
} catch (error) {
|
||||||
.first();
|
console.error("Failed to open accounts database:", error);
|
||||||
const identity = JSON.parse(account?.identity || "null");
|
return null;
|
||||||
return identity;
|
}
|
||||||
|
|
||||||
|
let account: { identity?: string } | undefined;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Search for the account with the matching DID (decentralized identifier)
|
||||||
|
account = await accountsDB.accounts
|
||||||
|
.where("did")
|
||||||
|
.equals(activeDid)
|
||||||
|
.first();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to find account:", error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return parsed identity or null if not found
|
||||||
|
return JSON.parse(account?.identity || "null");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getHeaders(identity: IIdentifier) {
|
/**
|
||||||
const token = await accessToken(identity);
|
* Asynchronously retrieves headers for HTTP requests.
|
||||||
const headers = {
|
*
|
||||||
"Content-Type": "application/json",
|
* @param {IIdentifier} identity - The identity object for which to generate the headers.
|
||||||
Authorization: "Bearer " + token,
|
* @returns {Promise<Record<string,string>>} A Promise that resolves to an object containing the headers.
|
||||||
};
|
*
|
||||||
return headers;
|
* @throws Will throw an error if unable to generate an access token.
|
||||||
|
*/
|
||||||
|
public async getHeaders(
|
||||||
|
identity: IIdentifier,
|
||||||
|
): Promise<Record<string, string>> {
|
||||||
|
try {
|
||||||
|
const token = await accessToken(identity);
|
||||||
|
|
||||||
|
const headers: Record<string, string> = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
return headers;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to get headers:", error);
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// call fn, copy text to the clipboard, then redo fn after 2 seconds
|
// call fn, copy text to the clipboard, then redo fn after 2 seconds
|
||||||
@@ -380,60 +428,82 @@ export default class AccountViewView extends Vue {
|
|||||||
this.numAccounts = await accountsDB.accounts.count();
|
this.numAccounts = await accountsDB.accounts.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Async function executed when the component is created.
|
||||||
|
* Initializes the component's state with values from the database,
|
||||||
|
* handles identity-related tasks, and checks limitations.
|
||||||
|
*
|
||||||
|
* @throws Will display specific messages to the user based on different errors.
|
||||||
|
*/
|
||||||
async created() {
|
async created() {
|
||||||
// Uncomment this to register this user on the test server.
|
|
||||||
// To manage within the vue devtools browser extension https://devtools.vuejs.org/
|
|
||||||
// assign this to a class variable, eg. "registerThisUser = testServerRegisterUser",
|
|
||||||
// select a component in the extension, and enter in the console: $vm.ctx.registerThisUser()
|
|
||||||
//testServerRegisterUser();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await db.open();
|
await db.open();
|
||||||
|
|
||||||
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
||||||
this.activeDid = settings?.activeDid || "";
|
|
||||||
this.apiServer = settings?.apiServer || "";
|
|
||||||
this.apiServerInput = settings?.apiServer || "";
|
|
||||||
this.firstName = settings?.firstName || "";
|
|
||||||
this.lastName = settings?.lastName || "";
|
|
||||||
this.showContactGives = !!settings?.showContactGivesInline;
|
|
||||||
|
|
||||||
|
// Initialize component state with values from the database or defaults
|
||||||
|
this.initializeState(settings);
|
||||||
|
|
||||||
|
// Get and process the identity
|
||||||
const identity = await this.getIdentity(this.activeDid);
|
const identity = await this.getIdentity(this.activeDid);
|
||||||
|
|
||||||
if (identity) {
|
if (identity) {
|
||||||
this.publicHex = identity.keys[0].publicKeyHex;
|
this.processIdentity(identity);
|
||||||
this.publicBase64 = Buffer.from(this.publicHex, "hex").toString(
|
}
|
||||||
"base64",
|
} catch (err: unknown) {
|
||||||
);
|
this.handleError(err);
|
||||||
this.derivationPath = identity.keys[0].meta.derivationPath;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
db.settings.update(MASTER_SETTINGS_KEY, {
|
/**
|
||||||
activeDid: identity.did,
|
* Initializes component state with values from the database or defaults.
|
||||||
});
|
* @param {SettingsType} settings - Object containing settings from the database.
|
||||||
this.checkLimitsFor(identity);
|
*/
|
||||||
}
|
initializeState(settings: SettingsType | undefined) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
this.activeDid = settings?.activeDid || "";
|
||||||
} catch (err: any) {
|
this.apiServer = settings?.apiServer || "";
|
||||||
if (
|
this.apiServerInput = settings?.apiServer || "";
|
||||||
err.message ===
|
this.firstName = settings?.firstName || "";
|
||||||
"Attempted to load account records with no identity available."
|
this.lastName = settings?.lastName || "";
|
||||||
) {
|
this.showContactGives = !!settings?.showContactGivesInline;
|
||||||
this.limitsMessage = "No identity.";
|
}
|
||||||
this.loadingLimits = false;
|
|
||||||
} else {
|
/**
|
||||||
this.$notify(
|
* Processes the identity and updates the component's state.
|
||||||
{
|
* @param {IdentityType} identity - Object containing identity information.
|
||||||
group: "alert",
|
*/
|
||||||
type: "danger",
|
processIdentity(identity: IdentityType) {
|
||||||
title: "Error Creating Account",
|
this.publicHex = identity.keys[0].publicKeyHex;
|
||||||
text: "Clear your cache and start over (after data backup).",
|
this.publicBase64 = Buffer.from(this.publicHex, "hex").toString("base64");
|
||||||
},
|
this.derivationPath = identity.keys[0].meta.derivationPath;
|
||||||
-1,
|
|
||||||
);
|
db.settings.update(MASTER_SETTINGS_KEY, {
|
||||||
console.error(
|
activeDid: identity.did,
|
||||||
"Telling user to clear cache at page create because:",
|
});
|
||||||
err,
|
this.checkLimitsFor(identity);
|
||||||
);
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* Handles errors and updates the component's state accordingly.
|
||||||
|
* @param {Error} err - The error object.
|
||||||
|
*/
|
||||||
|
handleError(err: unknown) {
|
||||||
|
if (
|
||||||
|
err.message ===
|
||||||
|
"Attempted to load account records with no identity available."
|
||||||
|
) {
|
||||||
|
this.limitsMessage = "No identity.";
|
||||||
|
this.loadingLimits = false;
|
||||||
|
} else {
|
||||||
|
this.$notify(
|
||||||
|
{
|
||||||
|
group: "alert",
|
||||||
|
type: "danger",
|
||||||
|
title: "Error Creating Account",
|
||||||
|
text: "Clear your cache and start over (after data backup).",
|
||||||
|
},
|
||||||
|
-1,
|
||||||
|
);
|
||||||
|
console.error("Telling user to clear cache at page create because:", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,41 +530,96 @@ export default class AccountViewView extends Vue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asynchronously exports the database into a downloadable JSON file.
|
||||||
|
*
|
||||||
|
* @throws Will notify the user if there is an export error.
|
||||||
|
*/
|
||||||
public async exportDatabase() {
|
public async exportDatabase() {
|
||||||
try {
|
try {
|
||||||
const blob = await db.export({ prettyJson: true });
|
// Generate the blob from the database
|
||||||
const url = URL.createObjectURL(blob);
|
const blob = await this.generateDatabaseBlob();
|
||||||
|
|
||||||
const downloadAnchor = this.$refs.downloadLink as HTMLAnchorElement;
|
// Create a temporary URL for the blob
|
||||||
downloadAnchor.href = url;
|
const url = this.createBlobURL(blob);
|
||||||
downloadAnchor.download = db.name + "-backup.json";
|
|
||||||
downloadAnchor.click();
|
|
||||||
|
|
||||||
|
// Trigger the download
|
||||||
|
this.downloadDatabaseBackup(url);
|
||||||
|
|
||||||
|
// Revoke the temporary URL
|
||||||
URL.revokeObjectURL(url);
|
URL.revokeObjectURL(url);
|
||||||
|
|
||||||
this.$notify(
|
// Notify the user that the download has started
|
||||||
{
|
this.notifyDownloadStarted();
|
||||||
group: "alert",
|
|
||||||
type: "toast",
|
|
||||||
title: "Download Started",
|
|
||||||
text: "See your downloads directory for the backup.",
|
|
||||||
},
|
|
||||||
5000,
|
|
||||||
);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$notify(
|
this.handleExportError(error);
|
||||||
{
|
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Export Error",
|
|
||||||
text: "See console logs for more info.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
console.error("Export Error:", error);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a blob object representing the database.
|
||||||
|
*
|
||||||
|
* @returns {Promise<Blob>} The generated blob object.
|
||||||
|
*/
|
||||||
|
private async generateDatabaseBlob(): Promise<Blob> {
|
||||||
|
return await db.export({ prettyJson: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a temporary URL for a blob object.
|
||||||
|
*
|
||||||
|
* @param {Blob} blob - The blob object.
|
||||||
|
* @returns {string} The temporary URL for the blob.
|
||||||
|
*/
|
||||||
|
private createBlobURL(blob: Blob): string {
|
||||||
|
return URL.createObjectURL(blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers the download of the database backup.
|
||||||
|
*
|
||||||
|
* @param {string} url - The temporary URL for the blob.
|
||||||
|
*/
|
||||||
|
private downloadDatabaseBackup(url: string) {
|
||||||
|
const downloadAnchor = this.$refs.downloadLink as HTMLAnchorElement;
|
||||||
|
downloadAnchor.href = url;
|
||||||
|
downloadAnchor.download = `${db.name}-backup.json`;
|
||||||
|
downloadAnchor.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifies the user that the download has started.
|
||||||
|
*/
|
||||||
|
private notifyDownloadStarted() {
|
||||||
|
this.$notify(
|
||||||
|
{
|
||||||
|
group: "alert",
|
||||||
|
type: "toast",
|
||||||
|
title: "Download Started",
|
||||||
|
text: "See your downloads directory for the backup.",
|
||||||
|
},
|
||||||
|
5000,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles errors during the database export process.
|
||||||
|
*
|
||||||
|
* @param {Error} error - The error object.
|
||||||
|
*/
|
||||||
|
private handleExportError(error: unknown) {
|
||||||
|
this.$notify(
|
||||||
|
{
|
||||||
|
group: "alert",
|
||||||
|
type: "danger",
|
||||||
|
title: "Export Error",
|
||||||
|
text: "See console logs for more info.",
|
||||||
|
},
|
||||||
|
-1,
|
||||||
|
);
|
||||||
|
console.error("Export Error:", error);
|
||||||
|
}
|
||||||
|
|
||||||
async checkLimits() {
|
async checkLimits() {
|
||||||
const identity = await this.getIdentity(this.activeDid);
|
const identity = await this.getIdentity(this.activeDid);
|
||||||
if (identity) {
|
if (identity) {
|
||||||
@@ -502,68 +627,117 @@ export default class AccountViewView extends Vue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async checkLimitsFor(identity: IIdentifier) {
|
/**
|
||||||
|
* Asynchronously checks rate limits for the given identity.
|
||||||
|
*
|
||||||
|
* Updates component state variables `limits`, `limitsMessage`, and `loadingLimits`.
|
||||||
|
*/
|
||||||
|
public async checkLimitsFor(identity: IIdentifier) {
|
||||||
this.loadingLimits = true;
|
this.loadingLimits = true;
|
||||||
this.limitsMessage = "";
|
this.limitsMessage = "";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const url = this.apiServer + "/api/report/rateLimits";
|
const resp = await this.fetchRateLimits(identity);
|
||||||
const headers = await this.getHeaders(identity);
|
|
||||||
|
|
||||||
const resp = await this.axios.get(url, { headers });
|
|
||||||
// axios throws an exception on a 400
|
|
||||||
if (resp.status === 200) {
|
if (resp.status === 200) {
|
||||||
this.limits = resp.data;
|
this.limits = resp.data;
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
} catch (error) {
|
||||||
} catch (error: any) {
|
this.handleRateLimitsError(error);
|
||||||
if (
|
|
||||||
error.message ===
|
|
||||||
"Attempted to load Give records with no identity available."
|
|
||||||
) {
|
|
||||||
this.limitsMessage = "No identity.";
|
|
||||||
this.loadingLimits = false;
|
|
||||||
} else {
|
|
||||||
const serverError = error as AxiosError;
|
|
||||||
console.error("Bad response retrieving limits: ", serverError);
|
|
||||||
|
|
||||||
const data = (serverError.response &&
|
|
||||||
serverError.response.data) as ErrorResponse;
|
|
||||||
this.limitsMessage = data?.error?.message || "Bad server response.";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loadingLimits = false;
|
this.loadingLimits = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async switchAccount(accountNum: number) {
|
/**
|
||||||
// 0 means none
|
* Fetches rate limits from the server.
|
||||||
if (accountNum === 0) {
|
*
|
||||||
await db.open();
|
* @param {IIdentifier} identity - The identity object to check rate limits for.
|
||||||
db.settings.update(MASTER_SETTINGS_KEY, {
|
* @returns {Promise<AxiosResponse>} The Axios response object.
|
||||||
activeDid: undefined,
|
*/
|
||||||
});
|
private async fetchRateLimits(identity: IIdentifier) {
|
||||||
this.activeDid = "";
|
const url = `${this.apiServer}/api/report/rateLimits`;
|
||||||
this.derivationPath = "";
|
const headers = await this.getHeaders(identity);
|
||||||
this.publicHex = "";
|
return await this.axios.get(url, { headers });
|
||||||
this.publicBase64 = "";
|
}
|
||||||
} else {
|
|
||||||
await accountsDB.open();
|
|
||||||
const accounts = await accountsDB.accounts.toArray();
|
|
||||||
const account = accounts[accountNum - 1];
|
|
||||||
|
|
||||||
await db.open();
|
/**
|
||||||
db.settings.update(MASTER_SETTINGS_KEY, {
|
* Handles errors that occur while fetching rate limits.
|
||||||
activeDid: account.did,
|
*
|
||||||
});
|
* @param {AxiosError | Error} error - The error object.
|
||||||
|
*/
|
||||||
this.activeDid = account.did;
|
private handleRateLimitsError(error: AxiosError | Error) {
|
||||||
this.derivationPath = account.derivationPath;
|
if (error instanceof AxiosError) {
|
||||||
this.publicHex = account.publicKeyHex;
|
const data = error.response?.data as ErrorResponse;
|
||||||
this.publicBase64 = Buffer.from(this.publicHex, "hex").toString("base64");
|
this.limitsMessage = data?.error?.message || "Bad server response.";
|
||||||
|
console.error("Bad response retrieving limits:", error);
|
||||||
|
} else if (
|
||||||
|
error.message ===
|
||||||
|
"Attempted to load Give records with no identity available."
|
||||||
|
) {
|
||||||
|
this.limitsMessage = "No identity.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asynchronously switches the active account based on the provided account number.
|
||||||
|
*
|
||||||
|
* @param {number} accountNum - The account number to switch to. 0 means none.
|
||||||
|
*/
|
||||||
|
public async switchAccount(accountNum: number) {
|
||||||
|
await db.open(); // Assumes db needs to be open for both cases
|
||||||
|
|
||||||
|
if (accountNum === 0) {
|
||||||
|
this.switchToNoAccount();
|
||||||
|
} else {
|
||||||
|
await this.switchToAccountNumber(accountNum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switches to no active account and clears relevant properties.
|
||||||
|
*/
|
||||||
|
private async switchToNoAccount() {
|
||||||
|
await db.settings.update(MASTER_SETTINGS_KEY, { activeDid: undefined });
|
||||||
|
this.clearActiveAccountProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears properties related to the active account.
|
||||||
|
*/
|
||||||
|
private clearActiveAccountProperties() {
|
||||||
|
this.activeDid = "";
|
||||||
|
this.derivationPath = "";
|
||||||
|
this.publicHex = "";
|
||||||
|
this.publicBase64 = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switches to an account based on its number in the list.
|
||||||
|
*
|
||||||
|
* @param {number} accountNum - The account number to switch to.
|
||||||
|
*/
|
||||||
|
private async switchToAccountNumber(accountNum: number) {
|
||||||
|
await accountsDB.open();
|
||||||
|
const accounts = await accountsDB.accounts.toArray();
|
||||||
|
const account = accounts[accountNum - 1];
|
||||||
|
|
||||||
|
await db.settings.update(MASTER_SETTINGS_KEY, { activeDid: account.did });
|
||||||
|
|
||||||
|
this.updateActiveAccountProperties(account);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates properties related to the active account.
|
||||||
|
*
|
||||||
|
* @param {AccountType} account - The account object.
|
||||||
|
*/
|
||||||
|
private updateActiveAccountProperties(account: IAccount) {
|
||||||
|
this.activeDid = account.did;
|
||||||
|
this.derivationPath = account.derivationPath;
|
||||||
|
this.publicHex = account.publicKeyHex;
|
||||||
|
this.publicBase64 = Buffer.from(this.publicHex, "hex").toString("base64");
|
||||||
|
}
|
||||||
|
|
||||||
public showContactGivesClassNames() {
|
public showContactGivesClassNames() {
|
||||||
return {
|
return {
|
||||||
"bg-slate-900": !this.showContactGives,
|
"bg-slate-900": !this.showContactGives,
|
||||||
|
|||||||
Reference in New Issue
Block a user