Browse Source

convert all remaining DB writes & reads to SQL (with successful registration & claim)

pull/137/head
Trent Larson 1 month ago
parent
commit
8d1511e38f
  1. 153
      doc/secure-storage-implementation.md
  2. 13
      src/App.vue
  3. 6
      src/components/FeedFilters.vue
  4. 5
      src/components/GiftedDialog.vue
  5. 12
      src/components/ImageMethodDialog.vue
  6. 5
      src/components/MembersList.vue
  7. 8
      src/components/OfferDialog.vue
  8. 19
      src/components/OnboardingDialog.vue
  9. 14
      src/components/PhotoDialog.vue
  10. 12
      src/components/PushNotificationPermission.vue
  11. 8
      src/components/TopMessage.vue
  12. 7
      src/components/World/components/objects/landmarks.js
  13. 26
      src/db/databaseUtil.ts
  14. 6
      src/db/index.ts
  15. 1
      src/db/tables/accounts.ts
  16. 4
      src/libs/endorserServer.ts
  17. 159
      src/libs/util.ts
  18. 2
      src/main.capacitor.ts
  19. 5
      src/main.web.ts
  20. 21
      src/registerServiceWorker.ts
  21. 2
      src/services/deepLinks.ts
  22. 8
      src/test/index.ts
  23. 2
      src/utils/logger.ts
  24. 7
      src/views/AccountViewView.vue
  25. 11
      src/views/ClaimAddRawView.vue
  26. 5
      src/views/ClaimCertificateView.vue
  27. 5
      src/views/ClaimReportCertificateView.vue
  28. 18
      src/views/ClaimView.vue
  29. 5
      src/views/ConfirmGiftView.vue
  30. 5
      src/views/ContactAmountsView.vue
  31. 5
      src/views/ContactGiftingView.vue
  32. 5
      src/views/ContactImportView.vue
  33. 5
      src/views/ContactQRScanFullView.vue
  34. 5
      src/views/ContactQRScanShowView.vue
  35. 30
      src/views/ContactsView.vue
  36. 49
      src/views/DIDView.vue
  37. 2
      src/views/DeepLinkErrorView.vue
  38. 16
      src/views/DiscoverView.vue
  39. 25
      src/views/GiftedDetailsView.vue
  40. 12
      src/views/HelpNotificationsView.vue
  41. 16
      src/views/HelpView.vue
  42. 78
      src/views/HomeView.vue
  43. 9
      src/views/IdentitySwitcherView.vue
  44. 34
      src/views/ImportAccountView.vue
  45. 87
      src/views/ImportDerivedAccountView.vue
  46. 10
      src/views/InviteOneAcceptView.vue
  47. 43
      src/views/InviteOneView.vue
  48. 19
      src/views/LogView.vue
  49. 68
      src/views/NewActivityView.vue
  50. 15
      src/views/NewEditAccountView.vue
  51. 12
      src/views/NewEditProjectView.vue
  52. 24
      src/views/OfferDetailsView.vue
  53. 10
      src/views/OnboardMeetingListView.vue
  54. 10
      src/views/OnboardMeetingMembersView.vue
  55. 10
      src/views/OnboardMeetingSetupView.vue
  56. 19
      src/views/ProjectViewView.vue
  57. 21
      src/views/ProjectsView.vue
  58. 8
      src/views/QuickActionBvcBeginView.vue
  59. 39
      src/views/QuickActionBvcEndView.vue
  60. 21
      src/views/RecentOffersToUserProjectsView.vue
  61. 20
      src/views/RecentOffersToUserView.vue
  62. 35
      src/views/SearchAreaView.vue
  63. 22
      src/views/ShareMyContactInfoView.vue
  64. 35
      src/views/SharedPhotoView.vue
  65. 8
      src/views/StartView.vue
  66. 60
      src/views/TestView.vue
  67. 25
      src/views/UserProfileView.vue

153
doc/secure-storage-implementation.md

@ -131,14 +131,165 @@ async function getAccount(did: string): Promise<Account | undefined> {
);
// Fallback to Dexie if needed
if (USE_DEXIE_DB && !account) {
if (USE_DEXIE_DB) {
account = await db.accounts.get(did);
}
return account;
}
```
#### A. Modifying Code
When converting from Dexie.js to SQL-based implementation, follow these patterns:
1. **Database Access Pattern**
```typescript
// Before (Dexie)
const result = await db.table.where("field").equals(value).first();
// After (SQL)
const platform = PlatformServiceFactory.getInstance();
let result = await platform.dbQuery(
"SELECT * FROM table WHERE field = ?",
[value]
);
result = databaseUtil.mapQueryResultToValues(result);
// Fallback to Dexie if needed
if (USE_DEXIE_DB) {
result = await db.table.where("field").equals(value).first();
}
```
2. **Update Operations**
```typescript
// Before (Dexie)
await db.table.where("id").equals(id).modify(changes);
// After (SQL)
// For settings updates, use the utility methods:
await databaseUtil.updateDefaultSettings(changes);
// OR
await databaseUtil.updateAccountSettings(did, changes);
// For other tables, use direct SQL:
const platform = PlatformServiceFactory.getInstance();
await platform.dbExec(
"UPDATE table SET field1 = ?, field2 = ? WHERE id = ?",
[changes.field1, changes.field2, id]
);
// Fallback to Dexie if needed
if (USE_DEXIE_DB) {
await db.table.where("id").equals(id).modify(changes);
}
```
3. **Insert Operations**
```typescript
// Before (Dexie)
await db.table.add(item);
// After (SQL)
const platform = PlatformServiceFactory.getInstance();
const columns = Object.keys(item);
const values = Object.values(item);
const placeholders = values.map(() => '?').join(', ');
const sql = `INSERT INTO table (${columns.join(', ')}) VALUES (${placeholders})`;
await platform.dbExec(sql, values);
// Fallback to Dexie if needed
if (USE_DEXIE_DB) {
await db.table.add(item);
}
```
4. **Delete Operations**
```typescript
// Before (Dexie)
await db.table.where("id").equals(id).delete();
// After (SQL)
const platform = PlatformServiceFactory.getInstance();
await platform.dbExec("DELETE FROM table WHERE id = ?", [id]);
// Fallback to Dexie if needed
if (USE_DEXIE_DB) {
await db.table.where("id").equals(id).delete();
}
```
5. **Result Processing**
```typescript
// Before (Dexie)
const items = await db.table.toArray();
// After (SQL)
const platform = PlatformServiceFactory.getInstance();
let items = await platform.dbQuery("SELECT * FROM table");
items = databaseUtil.mapQueryResultToValues(items);
// Fallback to Dexie if needed
if (USE_DEXIE_DB) {
items = await db.table.toArray();
}
```
6. **Using Utility Methods**
When working with settings or other common operations, use the utility methods in `db/index.ts`:
```typescript
// Settings operations
await databaseUtil.updateDefaultSettings(settings);
await databaseUtil.updateAccountSettings(did, settings);
const settings = await databaseUtil.retrieveSettingsForDefaultAccount();
const settings = await databaseUtil.retrieveSettingsForActiveAccount();
// Logging operations
await databaseUtil.logToDb(message);
await databaseUtil.logConsoleAndDb(message, showInConsole);
```
Key Considerations:
- Always use `databaseUtil.mapQueryResultToValues()` to process SQL query results
- Use utility methods from `db/index.ts` when available instead of direct SQL
- Keep Dexie fallbacks wrapped in `if (USE_DEXIE_DB)` checks
- For queries that return results, use `let` variables to allow Dexie fallback to override
- For updates/inserts/deletes, execute both SQL and Dexie operations when `USE_DEXIE_DB` is true
Example Migration:
```typescript
// Before (Dexie)
export async function updateSettings(settings: Settings): Promise<void> {
await db.settings.put(settings);
}
// After (SQL)
export async function updateSettings(settings: Settings): Promise<void> {
const platform = PlatformServiceFactory.getInstance();
const { sql, params } = generateUpdateStatement(
settings,
"settings",
"id = ?",
[settings.id]
);
await platform.dbExec(sql, params);
}
```
Remember to:
- Create database access code to use the platform service, putting it in front of the Dexie version
- Instead of removing Dexie-specific code, keep it.
- For creates & updates & deletes, the duplicate code is fine.
- For queries where we use the results, make the setting from SQL into a 'let' variable, then wrap the Dexie code in a check for USE_DEXIE_DB from app.ts and if
it's true then use that result instead of the SQL code's result.
- Consider data migration needs, and warn if there are any potential migration problems
## Success Criteria
1. **Functionality**

13
src/App.vue

@ -330,8 +330,11 @@
<script lang="ts">
import { Vue, Component } from "vue-facing-decorator";
import { logConsoleAndDb, retrieveSettingsForActiveAccount } from "./db/index";
import { NotificationIface } from "./constants/app";
import { NotificationIface, USE_DEXIE_DB } from "./constants/app";
import * as databaseUtil from "./db/databaseUtil";
import { retrieveSettingsForActiveAccount } from "./db/index";
import { logConsoleAndDb } from "./db/databaseUtil";
import { logger } from "./utils/logger";
interface Settings {
@ -396,7 +399,11 @@ export default class App extends Vue {
try {
logger.log("Retrieving settings for the active account...");
const settings: Settings = await retrieveSettingsForActiveAccount();
let settings: Settings =
await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
logger.log("Retrieved settings:", settings);
const notifyingNewActivity = !!settings?.notifyingNewActivityTime;

6
src/components/FeedFilters.vue

@ -101,6 +101,7 @@ import {
import { Router } from "vue-router";
import { USE_DEXIE_DB } from "@/constants/app";
import * as databaseUtil from "../db/databaseUtil";
import { MASTER_SETTINGS_KEY } from "../db/tables/settings";
import { db, retrieveSettingsForActiveAccount } from "../db/index";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
@ -125,7 +126,10 @@ export default class FeedFilters extends Vue {
async open(onCloseIfChanged: () => void) {
this.onCloseIfChanged = onCloseIfChanged;
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.hasVisibleDid = !!settings.filterFeedByVisible;
this.isNearby = !!settings.filterFeedByNearby;
if (settings.searchBoxes && settings.searchBoxes.length > 0) {

5
src/components/GiftedDialog.vue

@ -146,7 +146,10 @@ export default class GiftedDialog extends Vue {
this.offerId = offerId || "";
try {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.apiServer = settings.apiServer || "";
this.activeDid = settings.activeDid || "";

12
src/components/ImageMethodDialog.vue

@ -247,11 +247,16 @@ import axios from "axios";
import { ref } from "vue";
import { Component, Vue } from "vue-facing-decorator";
import VuePictureCropper, { cropper } from "vue-picture-cropper";
import { DEFAULT_IMAGE_API_SERVER, NotificationIface } from "../constants/app";
import {
DEFAULT_IMAGE_API_SERVER,
NotificationIface,
USE_DEXIE_DB,
} from "../constants/app";
import { retrieveSettingsForActiveAccount } from "../db/index";
import { accessToken } from "../libs/crypto";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "../services/PlatformServiceFactory";
import * as databaseUtil from "../db/databaseUtil";
const inputImageFileNameRef = ref<Blob>();
@ -334,7 +339,10 @@ export default class ImageMethodDialog extends Vue {
*/
async mounted() {
try {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
} catch (error: unknown) {
logger.error("Error retrieving settings from database:", error);

5
src/components/MembersList.vue

@ -211,7 +211,10 @@ export default class MembersList extends Vue {
contacts: Array<Contact> = [];
async created() {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
this.firstName = settings.firstName || "";

8
src/components/OfferDialog.vue

@ -82,12 +82,13 @@
<script lang="ts">
import { Vue, Component, Prop } from "vue-facing-decorator";
import { NotificationIface } from "../constants/app";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import {
createAndSubmitOffer,
serverMessageForUser,
} from "../libs/endorserServer";
import * as libsUtil from "../libs/util";
import * as databaseUtil from "../db/databaseUtil";
import { retrieveSettingsForActiveAccount } from "../db/index";
import { logger } from "../utils/logger";
@ -116,7 +117,10 @@ export default class OfferDialog extends Vue {
this.recipientDid = recipientDid;
this.recipientName = recipientName;
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.apiServer = settings.apiServer || "";
this.activeDid = settings.activeDid || "";

19
src/components/OnboardingDialog.vue

@ -234,7 +234,10 @@ export default class OnboardingDialog extends Vue {
async open(page: OnboardPage) {
this.page = page;
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
this.isRegistered = !!settings.isRegistered;
const platformService = PlatformServiceFactory.getInstance();
@ -257,18 +260,28 @@ export default class OnboardingDialog extends Vue {
this.visible = true;
if (this.page === OnboardPage.Create) {
// we'll assume that they've been through all the other pages
await updateAccountSettings(this.activeDid, {
await databaseUtil.updateAccountSettings(this.activeDid, {
finishedOnboarding: true,
});
if (USE_DEXIE_DB) {
await updateAccountSettings(this.activeDid, {
finishedOnboarding: true,
});
}
}
}
async onClickClose(done?: boolean, goHome?: boolean) {
this.visible = false;
if (done) {
await updateAccountSettings(this.activeDid, {
await databaseUtil.updateAccountSettings(this.activeDid, {
finishedOnboarding: true,
});
if (USE_DEXIE_DB) {
await updateAccountSettings(this.activeDid, {
finishedOnboarding: true,
});
}
if (goHome) {
this.$router.push({ name: "home" });
}

14
src/components/PhotoDialog.vue

@ -119,7 +119,12 @@ PhotoDialog.vue */
import axios from "axios";
import { Component, Vue } from "vue-facing-decorator";
import VuePictureCropper, { cropper } from "vue-picture-cropper";
import { DEFAULT_IMAGE_API_SERVER, NotificationIface } from "../constants/app";
import {
DEFAULT_IMAGE_API_SERVER,
NotificationIface,
USE_DEXIE_DB,
} from "../constants/app";
import * as databaseUtil from "../db/databaseUtil";
import { retrieveSettingsForActiveAccount } from "../db/index";
import { accessToken } from "../libs/crypto";
import { logger } from "../utils/logger";
@ -173,9 +178,12 @@ export default class PhotoDialog extends Vue {
* @throws {Error} When settings retrieval fails
*/
async mounted() {
logger.log("PhotoDialog mounted");
// logger.log("PhotoDialog mounted");
try {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
this.isRegistered = !!settings.isRegistered;
logger.log("isRegistered:", this.isRegistered);

12
src/components/PushNotificationPermission.vue

@ -102,7 +102,12 @@
<script lang="ts">
import { Component, Vue } from "vue-facing-decorator";
import { DEFAULT_PUSH_SERVER, NotificationIface } from "../constants/app";
import {
DEFAULT_PUSH_SERVER,
NotificationIface,
USE_DEXIE_DB,
} from "../constants/app";
import * as databaseUtil from "../db/databaseUtil";
import {
logConsoleAndDb,
retrieveSettingsForActiveAccount,
@ -169,7 +174,10 @@ export default class PushNotificationPermission extends Vue {
this.isVisible = true;
this.pushType = pushType;
try {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
let pushUrl = DEFAULT_PUSH_SERVER;
if (settings?.webPushServer) {
pushUrl = settings.webPushServer;

8
src/components/TopMessage.vue

@ -15,7 +15,8 @@
<script lang="ts">
import { Component, Vue, Prop } from "vue-facing-decorator";
import { AppString, NotificationIface } from "../constants/app";
import { AppString, NotificationIface, USE_DEXIE_DB } from "../constants/app";
import * as databaseUtil from "../db/databaseUtil";
import { retrieveSettingsForActiveAccount } from "../db/index";
@Component
@ -28,7 +29,10 @@ export default class TopMessage extends Vue {
async mounted() {
try {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
if (
settings.warnIfTestServer &&
settings.apiServer !== AppString.PROD_ENDORSER_API_SERVER

7
src/components/World/components/objects/landmarks.js

@ -3,6 +3,8 @@ import * as THREE from "three";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader";
import * as SkeletonUtils from "three/addons/utils/SkeletonUtils";
import * as TWEEN from "@tweenjs/tween.js";
import { USE_DEXIE_DB } from "../../../../constants/app";
import * as databaseUtil from "../../../../db/databaseUtil";
import { retrieveSettingsForActiveAccount } from "../../../../db";
import { getHeaders } from "../../../../libs/endorserServer";
import { logger } from "../../../../utils/logger";
@ -14,7 +16,10 @@ export async function loadLandmarks(vue, world, scene, loop) {
vue.setWorldProperty("animationDurationSeconds", ANIMATION_DURATION_SECS);
try {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
const activeDid = settings.activeDid || "";
const apiServer = settings.apiServer;
const headers = await getHeaders(activeDid);

26
src/db/databaseUtil.ts

@ -1,3 +1,8 @@
/**
* This file is the SQL replacement of the index.ts file in the db directory.
* That file will eventually be deleted.
*/
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
import { MASTER_SETTINGS_KEY, Settings } from "./tables/settings";
import { logger } from "@/utils/logger";
@ -81,7 +86,15 @@ export async function retrieveSettingsForDefaultAccount(): Promise<Settings> {
if (!result) {
return DEFAULT_SETTINGS;
} else {
return mapColumnsToValues(result.columns, result.values)[0] as Settings;
const settings = mapColumnsToValues(
result.columns,
result.values,
)[0] as Settings;
if (settings.searchBoxes) {
// @ts-expect-error - the searchBoxes field is a string in the DB
settings.searchBoxes = JSON.parse(settings.searchBoxes);
}
return settings;
}
}
@ -101,7 +114,12 @@ export async function retrieveSettingsForActiveAccount(): Promise<Settings> {
const overrideSettingsFiltered = Object.fromEntries(
Object.entries(overrideSettings).filter(([_, v]) => v !== null),
);
return { ...defaultSettings, ...overrideSettingsFiltered };
const settings = { ...defaultSettings, ...overrideSettingsFiltered };
if (settings.searchBoxes) {
// @ts-expect-error - the searchBoxes field is a string in the DB
settings.searchBoxes = JSON.parse(settings.searchBoxes);
}
return settings;
}
}
@ -160,8 +178,8 @@ export function generateInsertStatement(
model: Record<string, unknown>,
tableName: string,
): { sql: string; params: unknown[] } {
const columns = Object.keys(model);
const values = Object.values(model);
const columns = Object.keys(model).filter((key) => model[key] !== undefined);
const values = Object.values(model).filter((value) => value !== undefined);
const placeholders = values.map(() => "?").join(", ");
const insertSql = `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${placeholders})`;
return {

6
src/db/index.ts

@ -1,3 +1,9 @@
/**
* This is the original IndexedDB version of the database.
* It will eventually be replaced fully by the SQL version in databaseUtil.ts.
* Turn this on or off with the USE_DEXIE_DB constant in constants/app.ts.
*/
import BaseDexie, { Table } from "dexie";
import { encrypted, Encryption } from "@pvermeer/dexie-encrypted-addon";
import * as R from "ramda";

1
src/db/tables/accounts.ts

@ -45,6 +45,7 @@ export type Account = {
publicKeyHex: string;
};
// When finished with USE_DEXIE_DB, move these fields to Account and move identity and mnemonic here.
export type AccountEncrypted = Account & {
identityEncrBase64: string;
mnemonicEncrBase64: string;

4
src/libs/endorserServer.ts

@ -30,8 +30,8 @@ import {
} from "../constants/app";
import { Contact } from "../db/tables/contacts";
import { accessToken, deriveAddress, nextDerivationPath } from "../libs/crypto";
import { logConsoleAndDb, NonsensitiveDexie } from "../db/index";
import { NonsensitiveDexie } from "../db/index";
import { logConsoleAndDb } from "../db/databaseUtil";
import {
retrieveAccountMetadata,
retrieveFullyDecryptedAccount,

159
src/libs/util.ts

@ -490,10 +490,19 @@ export const retrieveAccountCount = async (): Promise<number> => {
};
export const retrieveAccountDids = async (): Promise<string[]> => {
// one of the few times we use accountsDBPromise directly; try to avoid more usage
const accountsDB = await accountsDBPromise;
const allAccounts = await accountsDB.accounts.toArray();
const allDids = allAccounts.map((acc) => acc.did);
const platformService = PlatformServiceFactory.getInstance();
const dbAccounts = await platformService.dbQuery(`SELECT did FROM accounts`);
let allDids =
databaseUtil
.mapQueryResultToValues(dbAccounts)
?.map((row) => row[0] as string) || [];
if (USE_DEXIE_DB) {
// this is the old way
// one of the few times we use accountsDBPromise directly; try to avoid more usage
const accountsDB = await accountsDBPromise;
const allAccounts = await accountsDB.accounts.toArray();
allDids = allAccounts.map((acc) => acc.did);
}
return allDids;
};
@ -502,30 +511,60 @@ export const retrieveAccountDids = async (): Promise<string[]> => {
export const retrieveAccountMetadata = async (
activeDid: string,
): Promise<AccountKeyInfo | undefined> => {
// one of the few times we use accountsDBPromise directly; try to avoid more usage
const accountsDB = await accountsDBPromise;
const account = (await accountsDB.accounts
.where("did")
.equals(activeDid)
.first()) as Account;
let result: AccountKeyInfo | undefined = undefined;
const platformService = PlatformServiceFactory.getInstance();
const dbAccount = await platformService.dbQuery(
`SELECT * FROM accounts WHERE did = ?`,
[activeDid],
);
const account = databaseUtil.mapQueryResultToValues(dbAccount)[0] as Account;
if (account) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { identity, mnemonic, ...metadata } = account;
return metadata;
result = metadata;
} else {
return undefined;
result = undefined;
}
if (USE_DEXIE_DB) {
// one of the few times we use accountsDBPromise directly; try to avoid more usage
const accountsDB = await accountsDBPromise;
const account = (await accountsDB.accounts
.where("did")
.equals(activeDid)
.first()) as Account;
if (account) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { identity, mnemonic, ...metadata } = account;
result = metadata;
} else {
result = undefined;
}
}
return result;
};
export const retrieveAllAccountsMetadata = async (): Promise<Account[]> => {
// one of the few times we use accountsDBPromise directly; try to avoid more usage
const accountsDB = await accountsDBPromise;
const array = await accountsDB.accounts.toArray();
return array.map((account) => {
export const retrieveAllAccountsMetadata = async (): Promise<
AccountEncrypted[]
> => {
const platformService = PlatformServiceFactory.getInstance();
const dbAccounts = await platformService.dbQuery(`SELECT * FROM accounts`);
const accounts = databaseUtil.mapQueryResultToValues(dbAccounts) as Account[];
let result = accounts.map((account) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { identity, mnemonic, ...metadata } = account;
return metadata;
});
if (USE_DEXIE_DB) {
// one of the few times we use accountsDBPromise directly; try to avoid more usage
const accountsDB = await accountsDBPromise;
const array = await accountsDB.accounts.toArray();
result = array.map((account) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { identity, mnemonic, ...metadata } = account;
return metadata;
});
}
return result;
};
export const retrieveFullyDecryptedAccount = async (
@ -583,32 +622,34 @@ export const retrieveFullyDecryptedAccount = async (
export const retrieveAllFullyDecryptedAccounts = async (): Promise<
Array<AccountKeyInfo>
> => {
const accountsDB = await accountsDBPromise;
const allAccounts = await accountsDB.accounts.toArray();
const platformService = PlatformServiceFactory.getInstance();
const queryResult = await platformService.dbQuery("SELECT * FROM accounts");
let allAccounts = databaseUtil.mapQueryResultToValues(
queryResult,
) as unknown as Account[];
if (USE_DEXIE_DB) {
const accountsDB = await accountsDBPromise;
allAccounts = await accountsDB.accounts.toArray();
}
return allAccounts;
};
/**
* Generates a new identity, saves it to the database, and sets it as the active identity.
* @return {Promise<string>} with the DID of the new identity
* Saves a new identity to both SQL and Dexie databases
*/
export const generateSaveAndActivateIdentity = async (): Promise<string> => {
const mnemonic = generateSeed();
// address is 0x... ETH address, without "did:eth:"
const [address, privateHex, publicHex, derivationPath] =
deriveAddress(mnemonic);
const newId = newIdentifier(address, publicHex, privateHex, derivationPath);
const identity = JSON.stringify(newId);
// one of the few times we use accountsDBPromise directly; try to avoid more usage
export async function saveNewIdentity(
identity: string,
mnemonic: string,
newId: { did: string; keys: Array<{ publicKeyHex: string }> },
derivationPath: string,
): Promise<void> {
try {
// add to the new sql db
const platformService = PlatformServiceFactory.getInstance();
const secrets = await platformService.dbQuery(
`SELECT secretBase64 FROM secret`,
);
if (secrets.values.length === 0 || secrets.values[0].length === 0) {
if (!secrets?.values?.length || !secrets.values[0]?.length) {
throw new Error(
"No initial encryption supported. We recommend you clear your data and start over.",
);
@ -634,6 +675,7 @@ export const generateSaveAndActivateIdentity = async (): Promise<string> => {
await databaseUtil.updateDefaultSettings({ activeDid: newId.did });
if (USE_DEXIE_DB) {
// one of the few times we use accountsDBPromise directly; try to avoid more usage
const accountsDB = await accountsDBPromise;
await accountsDB.accounts.add({
dateCreated: new Date().toISOString(),
@ -643,7 +685,6 @@ export const generateSaveAndActivateIdentity = async (): Promise<string> => {
mnemonic: mnemonic,
publicKeyHex: newId.keys[0].publicKeyHex,
});
await updateDefaultSettings({ activeDid: newId.did });
}
} catch (error) {
@ -652,6 +693,22 @@ export const generateSaveAndActivateIdentity = async (): Promise<string> => {
"Failed to set default settings. Please try again or restart the app.",
);
}
}
/**
* Generates a new identity, saves it to the database, and sets it as the active identity.
* @return {Promise<string>} with the DID of the new identity
*/
export const generateSaveAndActivateIdentity = async (): Promise<string> => {
const mnemonic = generateSeed();
// address is 0x... ETH address, without "did:eth:"
const [address, privateHex, publicHex, derivationPath] =
deriveAddress(mnemonic);
const newId = newIdentifier(address, publicHex, privateHex, derivationPath);
const identity = JSON.stringify(newId);
await saveNewIdentity(identity, mnemonic, newId, derivationPath);
await databaseUtil.updateAccountSettings(newId.did, { isRegistered: false });
if (USE_DEXIE_DB) {
await updateAccountSettings(newId.did, { isRegistered: false });
@ -673,9 +730,19 @@ export const registerAndSavePasskey = async (
passkeyCredIdHex,
publicKeyHex: Buffer.from(publicKeyBytes).toString("hex"),
};
// one of the few times we use accountsDBPromise directly; try to avoid more usage
const accountsDB = await accountsDBPromise;
await accountsDB.accounts.add(account);
const insertStatement = databaseUtil.generateInsertStatement(
account,
"accounts",
);
await PlatformServiceFactory.getInstance().dbExec(
insertStatement.sql,
insertStatement.params,
);
if (USE_DEXIE_DB) {
// one of the few times we use accountsDBPromise directly; try to avoid more usage
const accountsDB = await accountsDBPromise;
await accountsDB.accounts.add(account);
}
return account;
};
@ -683,13 +750,22 @@ export const registerSaveAndActivatePasskey = async (
keyName: string,
): Promise<Account> => {
const account = await registerAndSavePasskey(keyName);
await updateDefaultSettings({ activeDid: account.did });
await updateAccountSettings(account.did, { isRegistered: false });
await databaseUtil.updateDefaultSettings({ activeDid: account.did });
await databaseUtil.updateAccountSettings(account.did, {
isRegistered: false,
});
if (USE_DEXIE_DB) {
await updateDefaultSettings({ activeDid: account.did });
await updateAccountSettings(account.did, { isRegistered: false });
}
return account;
};
export const getPasskeyExpirationSeconds = async (): Promise<number> => {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
return (
(settings?.passkeyExpirationMinutes ?? DEFAULT_PASSKEY_EXPIRATION_MINUTES) *
60
@ -705,7 +781,10 @@ export const sendTestThroughPushServer = async (
subscriptionJSON: PushSubscriptionJSON,
skipFilter: boolean,
): Promise<AxiosResponse> => {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
let pushUrl: string = DEFAULT_PUSH_SERVER as string;
if (settings?.webPushServer) {
pushUrl = settings.webPushServer;

2
src/main.capacitor.ts

@ -34,7 +34,7 @@ import router from "./router";
import { handleApiError } from "./services/api";
import { AxiosError } from "axios";
import { DeepLinkHandler } from "./services/deepLinks";
import { logConsoleAndDb } from "./db";
import { logConsoleAndDb } from "./db/databaseUtil";
import { logger } from "./utils/logger";
logger.log("[Capacitor] Starting initialization");

5
src/main.web.ts

@ -3,7 +3,10 @@ import { initBackend } from "absurd-sql/dist/indexeddb-main-thread";
import { initializeApp } from "./main.common";
// Only import service worker for web builds
if (process.env.VITE_PLATFORM !== 'electron' && process.env.VITE_PWA_ENABLED === 'true') {
if (
process.env.VITE_PLATFORM !== "electron" &&
process.env.VITE_PWA_ENABLED === "true"
) {
import("./registerServiceWorker"); // Web PWA support
}

21
src/registerServiceWorker.ts

@ -3,17 +3,20 @@
import { register } from "register-service-worker";
// Check if we're in an Electron environment
const isElectron = process.env.VITE_PLATFORM === 'electron' ||
process.env.VITE_DISABLE_PWA === 'true' ||
window.navigator.userAgent.toLowerCase().includes('electron');
const isElectron =
process.env.VITE_PLATFORM === "electron" ||
process.env.VITE_DISABLE_PWA === "true" ||
window.navigator.userAgent.toLowerCase().includes("electron");
// Only register service worker if:
// 1. Not in Electron
// 2. PWA is explicitly enabled
// 3. In production mode
if (!isElectron &&
process.env.VITE_PWA_ENABLED === "true" &&
process.env.NODE_ENV === "production") {
if (
!isElectron &&
process.env.VITE_PWA_ENABLED === "true" &&
process.env.NODE_ENV === "production"
) {
register(`${process.env.BASE_URL}sw.js`, {
ready() {
console.log("Service worker is active.");
@ -42,11 +45,11 @@ if (!isElectron &&
} else {
console.log(
`Service worker registration skipped - ${
isElectron
? "running in Electron"
isElectron
? "running in Electron"
: process.env.VITE_PWA_ENABLED !== "true"
? "PWA not enabled"
: "not in production mode"
}`
}`,
);
}

2
src/services/deepLinks.ts

@ -52,7 +52,7 @@ import {
routeSchema,
DeepLinkRoute,
} from "../interfaces/deepLinks";
import { logConsoleAndDb } from "../db";
import { logConsoleAndDb } from "../db/databaseUtil";
import type { DeepLinkError } from "../interfaces/deepLinks";
/**

8
src/test/index.ts

@ -1,6 +1,7 @@
import axios from "axios";
import * as didJwt from "did-jwt";
import { AppString } from "../constants/app";
import { AppString, USE_DEXIE_DB } from "../constants/app";
import * as databaseUtil from "../db/databaseUtil";
import { retrieveSettingsForActiveAccount } from "../db";
import { SERVICE_ID } from "../libs/endorserServer";
import { deriveAddress, newIdentifier } from "../libs/crypto";
@ -16,7 +17,10 @@ export async function testServerRegisterUser() {
const identity0 = newIdentifier(addr, publicHex, privateHex, deriPath);
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
// Make a claim
const vcClaim = {

2
src/utils/logger.ts

@ -1,4 +1,4 @@
import { logToDb } from "../db";
import { logToDb } from "../db/databaseUtil";
function safeStringify(obj: unknown) {
const seen = new WeakSet();

7
src/views/AccountViewView.vue

@ -2022,9 +2022,14 @@ export default class AccountViewView extends Vue {
if ((error as any).response.status === 404) {
logger.error("The image was already deleted:", error);
await updateAccountSettings(this.activeDid, {
await databaseUtil.updateAccountSettings(this.activeDid, {
profileImageUrl: undefined,
});
if (USE_DEXIE_DB) {
await updateAccountSettings(this.activeDid, {
profileImageUrl: undefined,
});
}
this.profileImageUrl = undefined;

11
src/views/ClaimAddRawView.vue

@ -33,8 +33,10 @@ import { Component, Vue } from "vue-facing-decorator";
import { AxiosInstance } from "axios";
import QuickNav from "../components/QuickNav.vue";
import { NotificationIface } from "../constants/app";
import { logConsoleAndDb, retrieveSettingsForActiveAccount } from "../db/index";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import * as databaseUtil from "../db/databaseUtil";
import { retrieveSettingsForActiveAccount } from "../db/index";
import { logConsoleAndDb } from "../db/databaseUtil";
import * as serverUtil from "../libs/endorserServer";
import * as libsUtil from "../libs/util";
import { errorStringForLog } from "../libs/endorserServer";
@ -77,7 +79,10 @@ export default class ClaimAddRawView extends Vue {
* Initialize settings from active account
*/
private async initializeSettings() {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
}

5
src/views/ClaimCertificateView.vue

@ -35,7 +35,10 @@ export default class ClaimCertificateView extends Vue {
serverUtil = serverUtil;
async created() {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
const pathParams = window.location.pathname.substring(

5
src/views/ClaimReportCertificateView.vue

@ -31,7 +31,10 @@ export default class ClaimReportCertificateView extends Vue {
endorserServer = endorserServer;
async created() {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
const pathParams = window.location.pathname.substring(

18
src/views/ClaimView.vue

@ -543,13 +543,10 @@ import { GenericVerifiableCredential } from "../interfaces";
import GiftedDialog from "../components/GiftedDialog.vue";
import QuickNav from "../components/QuickNav.vue";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import {
db,
logConsoleAndDb,
retrieveSettingsForActiveAccount,
} from "../db/index";
import { Contact } from "../db/tables/contacts";
import * as databaseUtil from "../db/databaseUtil";
import { db } from "../db/index";
import { logConsoleAndDb } from "../db/databaseUtil";
import { Contact } from "../db/tables/contacts";
import * as serverUtil from "../libs/endorserServer";
import {
GenericCredWrapper,
@ -622,8 +619,11 @@ export default class ClaimView extends Vue {
}
async created() {
logger.log("ClaimView created");
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await databaseUtil.retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
const platformService = PlatformServiceFactory.getInstance();
@ -702,7 +702,6 @@ export default class ClaimView extends Vue {
}
async loadClaim(claimId: string, userDid: string) {
logger.log("[ClaimView] loadClaim called with claimId:", claimId);
const urlPath = libsUtil.isGlobalUri(claimId)
? "/api/claim/byHandle/"
: "/api/claim/";
@ -710,7 +709,6 @@ export default class ClaimView extends Vue {
const headers = await serverUtil.getHeaders(userDid);
try {
logger.log("[ClaimView] Making API request to:", url);
const resp = await this.axios.get(url, { headers });
if (resp.status === 200) {
this.veriClaim = resp.data;

5
src/views/ConfirmGiftView.vue

@ -530,7 +530,10 @@ export default class ConfirmGiftView extends Vue {
* Initializes component settings and user data
*/
private async initializeSettings() {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
const platformService = PlatformServiceFactory.getInstance();

5
src/views/ContactAmountsView.vue

@ -169,7 +169,10 @@ export default class ContactAmountssView extends Vue {
this.contact = (await db.contacts.get(contactDid)) || null;
}
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings?.activeDid || "";
this.apiServer = settings?.apiServer || "";

5
src/views/ContactGiftingView.vue

@ -100,7 +100,10 @@ export default class ContactGiftingView extends Vue {
async created() {
try {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.apiServer = settings.apiServer || "";
this.activeDid = settings.activeDid || "";

5
src/views/ContactImportView.vue

@ -344,7 +344,10 @@ export default class ContactImportView extends Vue {
* Initializes component settings from active account
*/
private async initializeSettings() {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
}

5
src/views/ContactQRScanFullView.vue

@ -164,7 +164,10 @@ export default class ContactQRScan extends Vue {
async created() {
try {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
this.givenName = settings.firstName || "";

5
src/views/ContactQRScanShowView.vue

@ -263,7 +263,10 @@ export default class ContactQRScanShow extends Vue {
async created() {
try {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
this.givenName = settings.firstName || "";

30
src/views/ContactsView.vue

@ -539,7 +539,12 @@ export default class ContactsView extends Vue {
if (response.status != 201) {
throw { error: { response: response } };
}
await updateAccountSettings(this.activeDid, { isRegistered: true });
await databaseUtil.updateAccountSettings(this.activeDid, {
isRegistered: true,
});
if (USE_DEXIE_DB) {
await updateAccountSettings(this.activeDid, { isRegistered: true });
}
this.isRegistered = true;
this.$notify(
{
@ -990,6 +995,8 @@ export default class ContactsView extends Vue {
newContact as unknown as Record<string, unknown>,
"contacts",
);
console.log("sql", sql);
console.log("params", params);
let contactPromise = platformService.dbExec(sql, params);
if (USE_DEXIE_DB) {
// @ts-expect-error since the result of this promise won't be used, and this will go away soon
@ -1023,17 +1030,27 @@ export default class ContactsView extends Vue {
text: "Do you want to register them?",
onCancel: async (stopAsking?: boolean) => {
if (stopAsking) {
await updateDefaultSettings({
await databaseUtil.updateDefaultSettings({
hideRegisterPromptOnNewContact: stopAsking,
});
if (USE_DEXIE_DB) {
await updateDefaultSettings({
hideRegisterPromptOnNewContact: stopAsking,
});
}
this.hideRegisterPromptOnNewContact = stopAsking;
}
},
onNo: async (stopAsking?: boolean) => {
if (stopAsking) {
await updateDefaultSettings({
await databaseUtil.updateDefaultSettings({
hideRegisterPromptOnNewContact: stopAsking,
});
if (USE_DEXIE_DB) {
await updateDefaultSettings({
hideRegisterPromptOnNewContact: stopAsking,
});
}
this.hideRegisterPromptOnNewContact = stopAsking;
}
},
@ -1327,9 +1344,14 @@ export default class ContactsView extends Vue {
private async toggleShowContactAmounts() {
const newShowValue = !this.showGiveNumbers;
try {
await updateDefaultSettings({
await databaseUtil.updateDefaultSettings({
showContactGivesInline: newShowValue,
});
if (USE_DEXIE_DB) {
await updateDefaultSettings({
showContactGivesInline: newShowValue,
});
}
} catch (err) {
const fullError =
"Error updating contact-amounts setting: " + errorStringForLog(err);

49
src/views/DIDView.vue

@ -232,10 +232,11 @@ import { RouteLocationNormalizedLoaded, Router } from "vue-router";
import QuickNav from "../components/QuickNav.vue";
import InfiniteScroll from "../components/InfiniteScroll.vue";
import TopMessage from "../components/TopMessage.vue";
import { NotificationIface } from "../constants/app";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import { db, retrieveSettingsForActiveAccount } from "../db/index";
import { Contact } from "../db/tables/contacts";
import { BoundingBox } from "../db/tables/settings";
import * as databaseUtil from "../db/databaseUtil";
import {
GenericCredWrapper,
GenericVerifiableCredential,
@ -253,6 +254,7 @@ import {
import * as libsUtil from "../libs/util";
import EntityIcon from "../components/EntityIcon.vue";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
/**
* DIDView Component
@ -323,7 +325,10 @@ export default class DIDView extends Vue {
* Initializes component settings from active account
*/
private async initializeSettings() {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
}
@ -370,7 +375,17 @@ export default class DIDView extends Vue {
private async loadContactInformation() {
if (!this.viewingDid) return;
this.contactFromDid = await db.contacts.get(this.viewingDid);
const platformService = PlatformServiceFactory.getInstance();
const dbContacts = await platformService.dbQuery(
"SELECT * FROM contacts WHERE did = ?",
[this.viewingDid],
);
this.contactFromDid = databaseUtil.mapQueryResultToValues(
dbContacts,
)[0] as unknown as Contact;
if (USE_DEXIE_DB) {
this.contactFromDid = await db.contacts.get(this.viewingDid);
}
if (this.contactFromDid) {
this.contactYaml = yaml.dump(this.contactFromDid);
}
@ -433,8 +448,14 @@ export default class DIDView extends Vue {
* @param contact - Contact object to be deleted
*/
async deleteContact(contact: Contact) {
await db.open();
await db.contacts.delete(contact.did);
const platformService = PlatformServiceFactory.getInstance();
await platformService.dbExec("DELETE FROM contacts WHERE did = ?", [
contact.did,
]);
if (USE_DEXIE_DB) {
await db.open();
await db.contacts.delete(contact.did);
}
this.$notify(
{
group: "alert",
@ -492,7 +513,14 @@ export default class DIDView extends Vue {
);
if (regResult.success) {
contact.registered = true;
await db.contacts.update(contact.did, { registered: true });
const platformService = PlatformServiceFactory.getInstance();
await platformService.dbExec(
"UPDATE contacts SET registered = ? WHERE did = ?",
[true, contact.did],
);
if (USE_DEXIE_DB) {
await db.contacts.update(contact.did, { registered: true });
}
this.$notify(
{
@ -781,7 +809,14 @@ export default class DIDView extends Vue {
const visibility = resp.data;
contact.seesMe = visibility;
//console.log("Visi check:", visibility, contact.seesMe, contact.did);
await db.contacts.update(contact.did, { seesMe: visibility });
const platformService = PlatformServiceFactory.getInstance();
await platformService.dbExec(
"UPDATE contacts SET seesMe = ? WHERE did = ?",
[visibility, contact.did],
);
if (USE_DEXIE_DB) {
await db.contacts.update(contact.did, { seesMe: visibility });
}
this.$notify(
{

2
src/views/DeepLinkErrorView.vue

@ -42,7 +42,7 @@
import { computed, onMounted } from "vue";
import { useRoute, useRouter } from "vue-router";
import { VALID_DEEP_LINK_ROUTES } from "../interfaces/deepLinks";
import { logConsoleAndDb } from "../db";
import { logConsoleAndDb } from "../db/databaseUtil";
import { logger } from "../utils/logger";
const route = useRoute();

16
src/views/DiscoverView.vue

@ -317,6 +317,7 @@ import TopMessage from "../components/TopMessage.vue";
import {
NotificationIface,
DEFAULT_PARTNER_API_SERVER,
USE_DEXIE_DB,
} from "../constants/app";
import {
db,
@ -325,6 +326,7 @@ import {
} from "../db/index";
import { Contact } from "../db/tables/contacts";
import { BoundingBox } from "../db/tables/settings";
import * as databaseUtil from "../db/databaseUtil";
import { PlanData } from "../interfaces";
import {
didInfo,
@ -333,6 +335,8 @@ import {
} from "../libs/endorserServer";
import { OnboardPage, retrieveAccountDids } from "../libs/util";
import { logger } from "../utils/logger";
import { UserProfile } from "@/libs/partnerServer";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
interface Tile {
indexLat: number;
indexLon: number;
@ -392,14 +396,22 @@ export default class DiscoverView extends Vue {
const searchPeople = !!this.$route.query["searchPeople"];
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = (settings.activeDid as string) || "";
this.apiServer = (settings.apiServer as string) || "";
this.partnerApiServer =
(settings.partnerApiServer as string) || this.partnerApiServer;
this.searchBox = settings.searchBoxes?.[0] || null;
this.allContacts = await db.contacts.toArray();
const platformService = PlatformServiceFactory.getInstance();
const dbContacts = await platformService.dbQuery("SELECT * FROM contacts");
this.allContacts = databaseUtil.mapQueryResultToValues(dbContacts) as unknown as Contact[];
if (USE_DEXIE_DB) {
this.allContacts = await db.contacts.toArray();
}
this.allMyDids = await retrieveAccountDids();

25
src/views/GiftedDetailsView.vue

@ -261,8 +261,13 @@ import { RouteLocationNormalizedLoaded, Router } from "vue-router";
import ImageMethodDialog from "../components/ImageMethodDialog.vue";
import QuickNav from "../components/QuickNav.vue";
import TopMessage from "../components/TopMessage.vue";
import { DEFAULT_IMAGE_API_SERVER, NotificationIface } from "../constants/app";
import {
DEFAULT_IMAGE_API_SERVER,
NotificationIface,
USE_DEXIE_DB,
} from "../constants/app";
import { db, retrieveSettingsForActiveAccount } from "../db/index";
import * as databaseUtil from "../db/databaseUtil";
import { GenericCredWrapper, GiveVerifiableCredential } from "../interfaces";
import {
createAndSubmitGive,
@ -275,6 +280,8 @@ import {
import * as libsUtil from "../libs/util";
import { retrieveAccountDids } from "../libs/util";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
import { Contact } from "@/db/tables/contacts";
@Component({
components: {
@ -421,7 +428,10 @@ export default class GiftedDetails extends Vue {
this.imageUrl = this.$route.query["shareUrl"] as string;
}
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.apiServer = settings.apiServer || "";
this.activeDid = settings.activeDid || "";
@ -429,7 +439,16 @@ export default class GiftedDetails extends Vue {
(this.giverDid && !this.giverName) ||
(this.recipientDid && !this.recipientName)
) {
const allContacts = await db.contacts.toArray();
const platformService = PlatformServiceFactory.getInstance();
const dbContacts = await platformService.dbQuery(
"SELECT * FROM contacts",
);
let allContacts = databaseUtil.mapQueryResultToValues(
dbContacts,
) as unknown as Contact[];
if (USE_DEXIE_DB) {
allContacts = await db.contacts.toArray();
}
const allMyDids = await retrieveAccountDids();
if (this.giverDid && !this.giverName) {
this.giverName = didInfo(

12
src/views/HelpNotificationsView.vue

@ -308,13 +308,15 @@
import { Component, Vue } from "vue-facing-decorator";
import QuickNav from "../components/QuickNav.vue";
import { NotificationIface } from "../constants/app";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import { DIRECT_PUSH_TITLE, sendTestThroughPushServer } from "../libs/util";
import PushNotificationPermission from "../components/PushNotificationPermission.vue";
import { db } from "../db/index";
import { MASTER_SETTINGS_KEY } from "../db/tables/settings";
import * as databaseUtil from "../db/databaseUtil";
import { Router } from "vue-router";
import { logger } from "../utils/logger";
@Component({ components: { PushNotificationPermission, QuickNav } })
export default class HelpNotificationsView extends Vue {
$notify!: (notification: NotificationIface, timeout?: number) => void;
@ -420,10 +422,16 @@ export default class HelpNotificationsView extends Vue {
DIRECT_PUSH_TITLE,
async (success: boolean, timeText: string, message?: string) => {
if (success) {
await db.settings.update(MASTER_SETTINGS_KEY, {
databaseUtil.updateDefaultSettings({
notifyingReminderMessage: message,
notifyingReminderTime: timeText,
});
if (USE_DEXIE_DB) {
await db.settings.update(MASTER_SETTINGS_KEY, {
notifyingReminderMessage: message,
notifyingReminderTime: timeText,
});
}
this.notifyingReminder = true;
this.notifyingReminderMessage = message || "";
this.notifyingReminderTime = timeText;

16
src/views/HelpView.vue

@ -579,7 +579,8 @@ import { useClipboard } from "@vueuse/core";
import * as Package from "../../package.json";
import QuickNav from "../components/QuickNav.vue";
import { NotificationIface } from "../constants/app";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import * as databaseUtil from "../db/databaseUtil";
import {
retrieveSettingsForActiveAccount,
updateAccountSettings,
@ -609,11 +610,20 @@ export default class HelpView extends Vue {
}
async unsetFinishedOnboarding() {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
if (settings.activeDid) {
await updateAccountSettings(settings.activeDid, {
await databaseUtil.updateAccountSettings(settings.activeDid, {
finishedOnboarding: false,
});
if (USE_DEXIE_DB) {
await updateAccountSettings(settings.activeDid, {
finishedOnboarding: false,
});
}
}
this.$router.push({ name: "home" });
}

78
src/views/HomeView.vue

@ -316,6 +316,7 @@ import {
AppString,
NotificationIface,
PASSKEYS_ENABLED,
USE_DEXIE_DB,
} from "../constants/app";
import {
db,
@ -329,6 +330,7 @@ import {
checkIsAnyFeedFilterOn,
MASTER_SETTINGS_KEY,
} from "../db/tables/settings";
import * as databaseUtil from "../db/databaseUtil";
import {
contactForDid,
containsNonHiddenDid,
@ -349,6 +351,7 @@ import { GiveSummaryRecord } from "../interfaces";
import * as serverUtil from "../libs/endorserServer";
import { logger } from "../utils/logger";
import { GiveRecordWithContactInfo } from "../types";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
interface Claim {
claim?: Claim; // For nested claims in Verifiable Credentials
@ -520,10 +523,22 @@ export default class HomeView extends Vue {
this.allMyDids = [newDid];
}
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.apiServer = settings.apiServer || "";
this.activeDid = settings.activeDid || "";
this.allContacts = await db.contacts.toArray();
const platformService = PlatformServiceFactory.getInstance();
const dbContacts = await platformService.dbQuery(
"SELECT * FROM contacts",
);
this.allContacts = databaseUtil.mapQueryResultToValues(
dbContacts,
) as unknown as Contact[];
if (USE_DEXIE_DB) {
this.allContacts = await db.contacts.toArray();
}
this.feedLastViewedClaimId = settings.lastViewedClaimId;
this.givenName = settings.firstName || "";
this.isFeedFilteredByVisible = !!settings.filterFeedByVisible;
@ -534,7 +549,6 @@ export default class HomeView extends Vue {
settings.lastAckedOfferToUserProjectsJwtId;
this.searchBoxes = settings.searchBoxes || [];
this.showShortcutBvc = !!settings.showShortcutBvc;
this.isAnyFeedFilterOn = checkIsAnyFeedFilterOn(settings);
if (!settings.finishedOnboarding) {
@ -552,10 +566,16 @@ export default class HomeView extends Vue {
this.activeDid,
);
if (resp.status === 200) {
await updateAccountSettings(this.activeDid, {
await databaseUtil.updateAccountSettings(this.activeDid, {
isRegistered: true,
...(await retrieveSettingsForActiveAccount()),
...(await databaseUtil.retrieveSettingsForActiveAccount()),
});
if (USE_DEXIE_DB) {
await updateAccountSettings(this.activeDid, {
isRegistered: true,
...(await retrieveSettingsForActiveAccount()),
});
}
this.isRegistered = true;
}
} catch (e) {
@ -618,7 +638,10 @@ export default class HomeView extends Vue {
* Called by mounted() and reloadFeedOnChange()
*/
private async loadSettings() {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.apiServer = settings.apiServer || "";
this.activeDid = settings.activeDid || "";
this.feedLastViewedClaimId = settings.lastViewedClaimId;
@ -642,7 +665,14 @@ export default class HomeView extends Vue {
* Called by mounted() and initializeIdentity()
*/
private async loadContacts() {
this.allContacts = await db.contacts.toArray();
const platformService = PlatformServiceFactory.getInstance();
const dbContacts = await platformService.dbQuery("SELECT * FROM contacts");
this.allContacts = databaseUtil.mapQueryResultToValues(
dbContacts,
) as unknown as Contact[];
if (USE_DEXIE_DB) {
this.allContacts = await db.contacts.toArray();
}
}
/**
@ -663,11 +693,22 @@ export default class HomeView extends Vue {
this.activeDid,
);
if (resp.status === 200) {
await updateAccountSettings(this.activeDid, {
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
await databaseUtil.updateAccountSettings(this.activeDid, {
apiServer: this.apiServer,
isRegistered: true,
...(await retrieveSettingsForActiveAccount()),
...settings,
});
if (USE_DEXIE_DB) {
await updateAccountSettings(this.activeDid, {
apiServer: this.apiServer,
isRegistered: true,
...settings,
});
}
this.isRegistered = true;
}
} catch (e) {
@ -728,7 +769,10 @@ export default class HomeView extends Vue {
* Called by mounted()
*/
private async checkOnboarding() {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
if (!settings.finishedOnboarding) {
(this.$refs.onboardingDialog as OnboardingDialog).open(OnboardPage.Home);
}
@ -790,7 +834,10 @@ export default class HomeView extends Vue {
* Called by FeedFilters component when filters change
*/
async reloadFeedOnChange() {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.isFeedFilteredByVisible = !!settings.filterFeedByVisible;
this.isFeedFilteredByNearby = !!settings.filterFeedByNearby;
this.isAnyFeedFilterOn = checkIsAnyFeedFilterOn(settings);
@ -1230,10 +1277,15 @@ export default class HomeView extends Vue {
this.feedLastViewedClaimId == null ||
this.feedLastViewedClaimId < records[0].jwtId
) {
await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, {
await databaseUtil.updateDefaultSettings({
lastViewedClaimId: records[0].jwtId,
});
if (USE_DEXIE_DB) {
await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, {
lastViewedClaimId: records[0].jwtId,
});
}
}
}

9
src/views/IdentitySwitcherView.vue

@ -105,15 +105,17 @@ import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import QuickNav from "../components/QuickNav.vue";
import { NotificationIface } from "../constants/app";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import {
accountsDBPromise,
db,
retrieveSettingsForActiveAccount,
} from "../db/index";
import { MASTER_SETTINGS_KEY } from "../db/tables/settings";
import * as databaseUtil from "../db/databaseUtil";
import { retrieveAllAccountsMetadata } from "../libs/util";
import { logger } from "../utils/logger";
@Component({ components: { QuickNav } })
export default class IdentitySwitcherView extends Vue {
$notify!: (notification: NotificationIface, timeout?: number) => void;
@ -127,7 +129,10 @@ export default class IdentitySwitcherView extends Vue {
async created() {
try {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
this.apiServerInput = settings.apiServer || "";

34
src/views/ImportAccountView.vue

@ -86,7 +86,8 @@
import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import { AppString, NotificationIface } from "../constants/app";
import { AppString, NotificationIface, USE_DEXIE_DB } from "../constants/app";
import * as databaseUtil from "../db/databaseUtil";
import {
accountsDBPromise,
db,
@ -97,9 +98,12 @@ import {
DEFAULT_ROOT_DERIVATION_PATH,
deriveAddress,
newIdentifier,
simpleEncrypt,
} from "../libs/crypto";
import { retrieveAccountCount } from "../libs/util";
import { retrieveAccountCount, saveNewIdentity } from "../libs/util";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
import { logger } from "../utils/logger";
@Component({
components: {},
})
@ -126,7 +130,10 @@ export default class ImportAccountView extends Vue {
async created() {
this.numAccounts = await retrieveAccountCount();
// get the server, to help with import on the test server
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.apiServer = settings.apiServer || "";
}
@ -155,22 +162,13 @@ export default class ImportAccountView extends Vue {
const accountsDB = await accountsDBPromise;
if (this.shouldErase) {
await accountsDB.accounts.clear();
const platformService = PlatformServiceFactory.getInstance();
await platformService.dbExec("DELETE FROM accounts");
if (USE_DEXIE_DB) {
await accountsDB.accounts.clear();
}
}
await accountsDB.accounts.add({
dateCreated: new Date().toISOString(),
derivationPath: this.derivationPath,
did: newId.did,
identity: JSON.stringify(newId),
mnemonic: mne,
publicKeyHex: newId.keys[0].publicKeyHex,
});
// record that as the active DID
await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, {
activeDid: newId.did,
});
saveNewIdentity(JSON.stringify(newId), mne, newId, this.derivationPath);
this.$router.push({ name: "account" });
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (err: any) {

87
src/views/ImportDerivedAccountView.vue

@ -80,8 +80,12 @@ import {
} from "../libs/crypto";
import { accountsDBPromise, db } from "../db/index";
import { MASTER_SETTINGS_KEY } from "../db/tables/settings";
import { retrieveAllFullyDecryptedAccounts } from "../libs/util";
import * as databaseUtil from "../db/databaseUtil";
import { retrieveAllAccountsMetadata } from "../libs/util";
import { logger } from "../utils/logger";
import { AccountEncrypted } from "@/db/tables/accounts";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
import { USE_DEXIE_DB } from "@/constants/app";
@Component({
components: {},
})
@ -94,11 +98,15 @@ export default class ImportAccountView extends Vue {
selectedArrayFirstDid = "";
async mounted() {
const accounts = await retrieveAllFullyDecryptedAccounts(); // let's match derived accounts differently so we don't need the private info
const accounts: AccountEncrypted[] = await retrieveAllAccountsMetadata();
const seedDids: Record<string, Array<string>> = {};
accounts.forEach((account) => {
const prevDids: Array<string> = seedDids[account.mnemonic] || [];
seedDids[account.mnemonic] = prevDids.concat([account.did]);
const mnemonicMaybeEncrypted =
account.mnemonic || account.mnemonicEncrBase64;
if (mnemonicMaybeEncrypted) {
const prevDids: Array<string> = seedDids[mnemonicMaybeEncrypted] || [];
seedDids[mnemonicMaybeEncrypted] = prevDids.concat([account.did]);
}
});
this.didArrays = Object.values(seedDids);
this.selectedArrayFirstDid = this.didArrays[0][0];
@ -117,14 +125,29 @@ export default class ImportAccountView extends Vue {
const selectedArray: Array<string> =
this.didArrays.find((dids) => dids[0] === this.selectedArrayFirstDid) ||
[];
const accountsDB = await accountsDBPromise; // let's match derived accounts differently so we don't need the private info
const allMatchingAccounts = await accountsDB.accounts
.where("did")
.anyOf(...selectedArray)
.toArray();
const platformService = PlatformServiceFactory.getInstance();
const qmarks = selectedArray.map(() => "?").join(",");
const queryResult = await platformService.dbQuery(
`SELECT * FROM accounts WHERE did IN (${qmarks})`,
selectedArray,
);
let allMatchingAccounts = databaseUtil.mapQueryResultToValues(
queryResult,
) as unknown as AccountEncrypted[];
if (USE_DEXIE_DB) {
const accountsDB = await accountsDBPromise; // let's match derived accounts differently so we don't need the private info
allMatchingAccounts = (await accountsDB.accounts
.where("did")
.anyOf(...selectedArray)
.toArray()) as AccountEncrypted[];
}
const accountWithMaxDeriv = allMatchingAccounts[0];
allMatchingAccounts.slice(1).forEach((account) => {
if (account.derivationPath > accountWithMaxDeriv.derivationPath) {
if (
account.derivationPath &&
accountWithMaxDeriv.derivationPath &&
account.derivationPath > accountWithMaxDeriv.derivationPath
) {
accountWithMaxDeriv.derivationPath = account.derivationPath;
}
});
@ -140,20 +163,40 @@ export default class ImportAccountView extends Vue {
const newId = newIdentifier(address, publicHex, privateHex, newDerivPath);
try {
await accountsDB.accounts.add({
dateCreated: new Date().toISOString(),
derivationPath: newDerivPath,
did: newId.did,
identity: JSON.stringify(newId),
mnemonic: mne,
publicKeyHex: newId.keys[0].publicKeyHex,
});
const { sql, params } = databaseUtil.generateInsertStatement(
{
dateCreated: new Date().toISOString(),
derivationPath: newDerivPath,
did: newId.did,
identity: JSON.stringify(newId),
mnemonic: mne,
publicKeyHex: newId.keys[0].publicKeyHex,
},
"accounts",
);
const platformService = PlatformServiceFactory.getInstance();
await platformService.dbExec(sql, params);
if (USE_DEXIE_DB) {
const accountsDB = await accountsDBPromise;
await accountsDB.accounts.add({
dateCreated: new Date().toISOString(),
derivationPath: newDerivPath,
did: newId.did,
identity: JSON.stringify(newId),
mnemonic: mne,
publicKeyHex: newId.keys[0].publicKeyHex,
});
}
// record that as the active DID
await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, {
activeDid: newId.did,
});
await platformService.dbExec("UPDATE settings SET activeDid = ?", [
newId.did,
]);
if (USE_DEXIE_DB) {
await db.settings.update(MASTER_SETTINGS_KEY, {
activeDid: newId.did,
});
}
this.$router.push({ name: "account" });
} catch (err) {
logger.error("Error saving mnemonic & updating settings:", err);

10
src/views/InviteOneAcceptView.vue

@ -42,12 +42,13 @@ import { Component, Vue } from "vue-facing-decorator";
import { Router, RouteLocationNormalized } from "vue-router";
import QuickNav from "../components/QuickNav.vue";
import { APP_SERVER, NotificationIface } from "../constants/app";
import { APP_SERVER, NotificationIface, USE_DEXIE_DB } from "../constants/app";
import {
db,
logConsoleAndDb,
retrieveSettingsForActiveAccount,
} from "../db/index";
import * as databaseUtil from "../db/databaseUtil";
import { decodeEndorserJwt } from "../libs/crypto/vc";
import { errorStringForLog } from "../libs/endorserServer";
import { generateSaveAndActivateIdentity } from "../libs/util";
@ -112,10 +113,13 @@ export default class InviteOneAcceptView extends Vue {
*/
async mounted() {
this.checkingInvite = true;
await db.open();
// Load or generate identity
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
await db.open();
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";

43
src/views/InviteOneView.vue

@ -138,11 +138,19 @@ import ContactNameDialog from "../components/ContactNameDialog.vue";
import QuickNav from "../components/QuickNav.vue";
import TopMessage from "../components/TopMessage.vue";
import InviteDialog from "../components/InviteDialog.vue";
import { APP_SERVER, AppString, NotificationIface } from "../constants/app";
import {
APP_SERVER,
AppString,
NotificationIface,
USE_DEXIE_DB,
} from "../constants/app";
import { db, retrieveSettingsForActiveAccount } from "../db/index";
import { Contact } from "../db/tables/contacts";
import * as databaseUtil from "../db/databaseUtil";
import { createInviteJwt, getHeaders } from "../libs/endorserServer";
import { PlatformServiceFactory } from "../services/PlatformServiceFactory";
import { logger } from "../utils/logger";
interface Invite {
inviteIdentifier: string;
expiresAt: string;
@ -168,8 +176,11 @@ export default class InviteOneView extends Vue {
async mounted() {
try {
await db.open();
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
await db.open();
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
this.isRegistered = !!settings.isRegistered;
@ -181,7 +192,16 @@ export default class InviteOneView extends Vue {
);
this.invites = response.data.data;
const baseContacts: Contact[] = await db.contacts.toArray();
const platformService = PlatformServiceFactory.getInstance();
const queryResult = await platformService.dbQuery(
"SELECT * FROM contacts",
);
let baseContacts = databaseUtil.mapQueryResultToValues(
queryResult,
) as unknown as Contact[];
if (USE_DEXIE_DB) {
baseContacts = await db.contacts.toArray();
}
for (const invite of this.invites) {
const contact = baseContacts.find(
(contact) => contact.did === invite.redeemedBy,
@ -328,18 +348,27 @@ export default class InviteOneView extends Vue {
);
}
addNewContact(did: string, notes: string) {
async addNewContact(did: string, notes: string) {
(this.$refs.contactNameDialog as ContactNameDialog).open(
"To Whom Did You Send The Invite?",
"Their name will be added to your contact list.",
(name) => {
async (name) => {
// the person obviously registered themselves and this user already granted visibility, so we just add them
const contact = {
did: did,
name: name,
registered: true,
};
db.contacts.add(contact);
const platformService = PlatformServiceFactory.getInstance();
const columns = Object.keys(contact);
const values = Object.values(contact);
const placeholders = values.map(() => "?").join(", ");
const sql = `INSERT INTO contacts (${columns.join(", ")}) VALUES (${placeholders})`;
await platformService.dbExec(sql, values);
if (USE_DEXIE_DB) {
await db.contacts.add(contact);
}
this.contactsRedeemed[did] = contact;
this.$notify(
{

19
src/views/LogView.vue

@ -55,6 +55,9 @@ import TopMessage from "../components/TopMessage.vue";
import { db } from "../db/index";
import { Log } from "../db/tables/logs";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "../services/PlatformServiceFactory";
import { USE_DEXIE_DB } from "../constants/app";
import * as databaseUtil from "../db/databaseUtil";
@Component({
components: {
@ -76,9 +79,19 @@ export default class LogView extends Vue {
async loadLogs() {
try {
this.error = null; // Clear any previous errors
await db.open();
// Get all logs and sort by date in reverse chronological order
const allLogs = await db.logs.toArray();
let allLogs: Log[] = [];
const platformService = PlatformServiceFactory.getInstance();
const queryResult = await platformService.dbQuery("SELECT * FROM logs");
allLogs = databaseUtil.mapQueryResultToValues(
queryResult,
) as unknown as Log[];
if (USE_DEXIE_DB) {
await db.open();
allLogs = await db.logs.toArray();
}
// Sort by date in reverse chronological order
this.logs = allLogs.sort((a, b) => {
const dateA = new Date(a.date);
const dateB = new Date(b.date);

68
src/views/NewActivityView.vue

@ -153,7 +153,7 @@ import { Component, Vue } from "vue-facing-decorator";
import GiftedDialog from "../components/GiftedDialog.vue";
import QuickNav from "../components/QuickNav.vue";
import EntityIcon from "../components/EntityIcon.vue";
import { NotificationIface } from "../constants/app";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import {
db,
retrieveSettingsForActiveAccount,
@ -169,6 +169,9 @@ import {
getNewOffersToUserProjects,
} from "../libs/endorserServer";
import { retrieveAccountDids } from "../libs/util";
import { PlatformServiceFactory } from "../services/PlatformServiceFactory";
import * as databaseUtil from "../db/databaseUtil";
import { logger } from "../utils/logger";
@Component({
components: { GiftedDialog, QuickNav, EntityIcon },
@ -194,14 +197,28 @@ export default class NewActivityView extends Vue {
async created() {
try {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.apiServer = settings.apiServer || "";
this.activeDid = settings.activeDid || "";
this.lastAckedOfferToUserJwtId = settings.lastAckedOfferToUserJwtId || "";
this.lastAckedOfferToUserProjectsJwtId =
settings.lastAckedOfferToUserProjectsJwtId || "";
this.allContacts = await db.contacts.toArray();
const platformService = PlatformServiceFactory.getInstance();
const queryResult = await platformService.dbQuery(
"SELECT * FROM contacts",
);
this.allContacts = databaseUtil.mapQueryResultToValues(
queryResult,
) as unknown as Contact[];
if (USE_DEXIE_DB) {
await db.open();
this.allContacts = await db.contacts.toArray();
}
this.allMyDids = await retrieveAccountDids();
const offersToUserData = await getNewOffersToUser(
@ -240,9 +257,14 @@ export default class NewActivityView extends Vue {
async expandOffersToUserAndMarkRead() {
this.showOffersDetails = !this.showOffersDetails;
if (this.showOffersDetails) {
await updateAccountSettings(this.activeDid, {
await databaseUtil.updateAccountSettings(this.activeDid, {
lastAckedOfferToUserJwtId: this.newOffersToUser[0].jwtId,
});
if (USE_DEXIE_DB) {
await updateAccountSettings(this.activeDid, {
lastAckedOfferToUserJwtId: this.newOffersToUser[0].jwtId,
});
}
// note that we don't update this.lastAckedOfferToUserJwtId in case they
// later choose the last one to keep the offers as new
this.$notify(
@ -263,14 +285,24 @@ export default class NewActivityView extends Vue {
);
if (index !== -1 && index < this.newOffersToUser.length - 1) {
// Set to the next offer's jwtId
await updateAccountSettings(this.activeDid, {
await databaseUtil.updateAccountSettings(this.activeDid, {
lastAckedOfferToUserJwtId: this.newOffersToUser[index + 1].jwtId,
});
if (USE_DEXIE_DB) {
await db.settings.update(this.activeDid, {
lastAckedOfferToUserJwtId: this.newOffersToUser[index + 1].jwtId,
});
}
} else {
// it's the last entry (or not found), so just keep it the same
await updateAccountSettings(this.activeDid, {
await databaseUtil.updateAccountSettings(this.activeDid, {
lastAckedOfferToUserJwtId: this.lastAckedOfferToUserJwtId,
});
if (USE_DEXIE_DB) {
await db.settings.update(this.activeDid, {
lastAckedOfferToUserJwtId: this.lastAckedOfferToUserJwtId,
});
}
}
this.$notify(
{
@ -287,10 +319,16 @@ export default class NewActivityView extends Vue {
this.showOffersToUserProjectsDetails =
!this.showOffersToUserProjectsDetails;
if (this.showOffersToUserProjectsDetails) {
await updateAccountSettings(this.activeDid, {
await databaseUtil.updateAccountSettings(this.activeDid, {
lastAckedOfferToUserProjectsJwtId:
this.newOffersToUserProjects[0].jwtId,
});
if (USE_DEXIE_DB) {
await db.settings.update(this.activeDid, {
lastAckedOfferToUserProjectsJwtId:
this.newOffersToUserProjects[0].jwtId,
});
}
// note that we don't update this.lastAckedOfferToUserProjectsJwtId in case
// they later choose the last one to keep the offers as new
this.$notify(
@ -311,16 +349,28 @@ export default class NewActivityView extends Vue {
);
if (index !== -1 && index < this.newOffersToUserProjects.length - 1) {
// Set to the next offer's jwtId
await updateAccountSettings(this.activeDid, {
await databaseUtil.updateAccountSettings(this.activeDid, {
lastAckedOfferToUserProjectsJwtId:
this.newOffersToUserProjects[index + 1].jwtId,
});
if (USE_DEXIE_DB) {
await db.settings.update(this.activeDid, {
lastAckedOfferToUserProjectsJwtId:
this.newOffersToUserProjects[index + 1].jwtId,
});
}
} else {
// it's the last entry (or not found), so just keep it the same
await updateAccountSettings(this.activeDid, {
await databaseUtil.updateAccountSettings(this.activeDid, {
lastAckedOfferToUserProjectsJwtId:
this.lastAckedOfferToUserProjectsJwtId,
});
if (USE_DEXIE_DB) {
await db.settings.update(this.activeDid, {
lastAckedOfferToUserProjectsJwtId:
this.lastAckedOfferToUserProjectsJwtId,
});
}
}
this.$notify(
{

15
src/views/NewEditAccountView.vue

@ -47,8 +47,10 @@
import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import { USE_DEXIE_DB } from "@/constants/app";
import { db, retrieveSettingsForActiveAccount } from "../db/index";
import { MASTER_SETTINGS_KEY } from "../db/tables/settings";
import * as databaseUtil from "../db/databaseUtil";
@Component({
components: {},
@ -60,17 +62,26 @@ export default class NewEditAccountView extends Vue {
// 'created' hook runs when the Vue instance is first created
async created() {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.givenName =
(settings.firstName || "") +
(settings.lastName ? ` ${settings.lastName}` : ""); // deprecated, pre v 0.1.3
}
async onClickSaveChanges() {
await db.settings.update(MASTER_SETTINGS_KEY, {
await databaseUtil.updateDefaultSettings({
firstName: this.givenName,
lastName: "", // deprecated, pre v 0.1.3
});
if (USE_DEXIE_DB) {
await db.settings.update(MASTER_SETTINGS_KEY, {
firstName: this.givenName,
lastName: "", // deprecated, pre v 0.1.3
});
}
this.$router.back();
}

12
src/views/NewEditProjectView.vue

@ -237,7 +237,9 @@ import {
DEFAULT_IMAGE_API_SERVER,
DEFAULT_PARTNER_API_SERVER,
NotificationIface,
USE_DEXIE_DB,
} from "../constants/app";
import * as databaseUtil from "../db/databaseUtil";
import { retrieveSettingsForActiveAccount } from "../db/index";
import { PlanVerifiableCredential } from "../interfaces";
import {
@ -303,7 +305,10 @@ export default class NewEditProjectView extends Vue {
async mounted() {
this.numAccounts = await retrieveAccountCount();
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
this.showGeneralAdvanced = !!settings.showGeneralAdvanced;
@ -702,7 +707,10 @@ export default class NewEditProjectView extends Vue {
) {
try {
let partnerServer = DEFAULT_PARTNER_API_SERVER;
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
if (settings.partnerApiServer) {
partnerServer = settings.partnerApiServer;
}

24
src/views/OfferDetailsView.vue

@ -180,7 +180,7 @@ import { RouteLocationNormalizedLoaded, Router } from "vue-router";
import QuickNav from "../components/QuickNav.vue";
import TopMessage from "../components/TopMessage.vue";
import { NotificationIface } from "../constants/app";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import { db, retrieveSettingsForActiveAccount } from "../db/index";
import { GenericCredWrapper, OfferVerifiableCredential } from "../interfaces";
import {
@ -193,6 +193,10 @@ import {
import * as libsUtil from "../libs/util";
import { retrieveAccountDids } from "../libs/util";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
import { Contact } from "@/db/tables/contacts";
import * as databaseUtil from "../db/databaseUtil";
/**
* Offer Details View Component
* @author Matthew Raymer
@ -398,7 +402,10 @@ export default class OfferDetailsView extends Vue {
* @throws Will not throw but logs errors
*/
private async loadAccountSettings() {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.apiServer = settings.apiServer ?? "";
this.activeDid = settings.activeDid ?? "";
this.showGeneralAdvanced = settings.showGeneralAdvanced ?? false;
@ -409,7 +416,18 @@ export default class OfferDetailsView extends Vue {
*/
private async loadRecipientInfo() {
if (this.recipientDid && !this.recipientName) {
const allContacts = await db.contacts.toArray();
let allContacts: Contact[] = [];
const platformService = PlatformServiceFactory.getInstance();
const queryResult = await platformService.dbQuery(
"SELECT * FROM contacts",
);
allContacts = databaseUtil.mapQueryResultToValues(
queryResult,
) as unknown as Contact[];
if (USE_DEXIE_DB) {
await db.open();
allContacts = await db.contacts.toArray();
}
const allMyDids = await retrieveAccountDids();
this.recipientName = didInfo(
this.recipientDid,

10
src/views/OnboardMeetingListView.vue

@ -89,13 +89,16 @@ import { Router } from "vue-router";
import QuickNav from "../components/QuickNav.vue";
import TopMessage from "../components/TopMessage.vue";
import { logConsoleAndDb, retrieveSettingsForActiveAccount } from "../db/index";
import * as databaseUtil from "../db/databaseUtil";
import { retrieveSettingsForActiveAccount } from "../db/index";
import { logConsoleAndDb } from "../db/databaseUtil";
import {
errorStringForLog,
getHeaders,
serverMessageForUser,
} from "../libs/endorserServer";
import { encryptMessage } from "../libs/crypto";
import { USE_DEXIE_DB } from "@/constants/app";
interface Meeting {
name: string;
@ -134,7 +137,10 @@ export default class OnboardMeetingListView extends Vue {
showPasswordDialog = false;
async created() {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
this.firstName = settings.firstName || "";

10
src/views/OnboardMeetingMembersView.vue

@ -45,7 +45,9 @@ import QuickNav from "../components/QuickNav.vue";
import TopMessage from "../components/TopMessage.vue";
import MembersList from "../components/MembersList.vue";
import UserNameDialog from "../components/UserNameDialog.vue";
import { logConsoleAndDb, retrieveSettingsForActiveAccount } from "../db/index";
import * as databaseUtil from "../db/databaseUtil";
import { retrieveSettingsForActiveAccount } from "../db/index";
import { logConsoleAndDb } from "../db/databaseUtil";
import { encryptMessage } from "../libs/crypto";
import {
errorStringForLog,
@ -53,6 +55,7 @@ import {
serverMessageForUser,
} from "../libs/endorserServer";
import { generateSaveAndActivateIdentity } from "../libs/util";
import { USE_DEXIE_DB } from "@/constants/app";
@Component({
components: {
@ -91,7 +94,10 @@ export default class OnboardMeetingMembersView extends Vue {
this.errorMessage = "The password is missing. Go back and try again.";
return;
}
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
this.firstName = settings.firstName || "";

10
src/views/OnboardMeetingSetupView.vue

@ -232,7 +232,9 @@ import { Component, Vue } from "vue-facing-decorator";
import QuickNav from "../components/QuickNav.vue";
import TopMessage from "../components/TopMessage.vue";
import MembersList from "../components/MembersList.vue";
import { logConsoleAndDb, retrieveSettingsForActiveAccount } from "../db/index";
import * as databaseUtil from "../db/databaseUtil";
import { retrieveSettingsForActiveAccount } from "../db/index";
import { logConsoleAndDb } from "../db/databaseUtil";
import {
errorStringForLog,
getHeaders,
@ -240,6 +242,7 @@ import {
} from "../libs/endorserServer";
import { encryptMessage } from "../libs/crypto";
import { logger } from "../utils/logger";
import { USE_DEXIE_DB } from "@/constants/app";
interface ServerMeeting {
groupId: number; // from the server
name: string; // from the server
@ -284,7 +287,10 @@ export default class OnboardMeetingView extends Vue {
}
async created() {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
this.fullName = settings.firstName || "";

19
src/views/ProjectViewView.vue

@ -624,7 +624,8 @@ import TopMessage from "../components/TopMessage.vue";
import QuickNav from "../components/QuickNav.vue";
import EntityIcon from "../components/EntityIcon.vue";
import ProjectIcon from "../components/ProjectIcon.vue";
import { NotificationIface } from "../constants/app";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import * as databaseUtil from "../db/databaseUtil";
import {
db,
logConsoleAndDb,
@ -636,6 +637,7 @@ import * as serverUtil from "../libs/endorserServer";
import { retrieveAccountDids } from "../libs/util";
import HiddenDidDialog from "../components/HiddenDidDialog.vue";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
/**
* Project View Component
* @author Matthew Raymer
@ -778,10 +780,21 @@ export default class ProjectViewView extends Vue {
* @emits Notification on profile loading errors
*/
async created() {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
this.allContacts = await db.contacts.toArray();
const platformService = PlatformServiceFactory.getInstance();
const queryResult = await platformService.dbQuery("SELECT * FROM contacts");
this.allContacts = databaseUtil.mapQueryResultToValues(
queryResult,
) as unknown as Contact[];
if (USE_DEXIE_DB) {
await db.open();
this.allContacts = await db.contacts.toArray();
}
this.isRegistered = !!settings.isRegistered;
try {

21
src/views/ProjectsView.vue

@ -269,7 +269,7 @@ import { AxiosRequestConfig } from "axios";
import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import { NotificationIface } from "../constants/app";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import { db, retrieveSettingsForActiveAccount } from "../db/index";
import EntityIcon from "../components/EntityIcon.vue";
import InfiniteScroll from "../components/InfiniteScroll.vue";
@ -278,12 +278,14 @@ import OnboardingDialog from "../components/OnboardingDialog.vue";
import ProjectIcon from "../components/ProjectIcon.vue";
import TopMessage from "../components/TopMessage.vue";
import UserNameDialog from "../components/UserNameDialog.vue";
import * as databaseUtil from "../db/databaseUtil";
import { Contact } from "../db/tables/contacts";
import { didInfo, getHeaders, getPlanFromCache } from "../libs/endorserServer";
import { OfferSummaryRecord, PlanData } from "../interfaces/records";
import * as libsUtil from "../libs/util";
import { OnboardPage } from "../libs/util";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
@Component({
components: {
EntityIcon,
@ -324,13 +326,26 @@ export default class ProjectsView extends Vue {
async mounted() {
try {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
this.isRegistered = !!settings.isRegistered;
this.givenName = settings.firstName || "";
this.allContacts = await db.contacts.toArray();
const platformService = PlatformServiceFactory.getInstance();
const queryResult = await platformService.dbQuery(
"SELECT * FROM contacts",
);
this.allContacts = databaseUtil.mapQueryResultToValues(
queryResult,
) as unknown as Contact[];
if (USE_DEXIE_DB) {
await db.open();
this.allContacts = await db.contacts.toArray();
}
this.allMyDids = await libsUtil.retrieveAccountDids();

8
src/views/QuickActionBvcBeginView.vue

@ -72,7 +72,8 @@ import { Component, Vue } from "vue-facing-decorator";
import QuickNav from "../components/QuickNav.vue";
import TopMessage from "../components/TopMessage.vue";
import { NotificationIface } from "../constants/app";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import * as databaseUtil from "../db/databaseUtil";
import { retrieveSettingsForActiveAccount } from "../db/index";
import {
BVC_MEETUPS_PROJECT_CLAIM_ID,
@ -117,7 +118,10 @@ export default class QuickActionBvcBeginView extends Vue {
}
async record() {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
const activeDid = settings.activeDid || "";
const apiServer = settings.apiServer || "";

39
src/views/QuickActionBvcEndView.vue

@ -144,7 +144,8 @@ import { Router } from "vue-router";
import QuickNav from "../components/QuickNav.vue";
import TopMessage from "../components/TopMessage.vue";
import { NotificationIface } from "../constants/app";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import * as databaseUtil from "../db/databaseUtil";
import {
accountsDBPromise,
db,
@ -165,6 +166,7 @@ import {
getHeaders,
} from "../libs/endorserServer";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
@Component({
methods: { claimSpecialDescription },
components: {
@ -191,10 +193,24 @@ export default class QuickActionBvcBeginView extends Vue {
async created() {
this.loadingConfirms = true;
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.apiServer = settings.apiServer || "";
this.activeDid = settings.activeDid || "";
this.allContacts = await db.contacts.toArray();
const platformService = PlatformServiceFactory.getInstance();
const contactQueryResult = await platformService.dbQuery(
"SELECT * FROM contacts",
);
this.allContacts = databaseUtil.mapQueryResultToValues(
contactQueryResult,
) as unknown as Contact[];
if (USE_DEXIE_DB) {
await db.open();
this.allContacts = await db.contacts.toArray();
}
let currentOrPreviousSat = DateTime.now().setZone("America/Denver");
if (currentOrPreviousSat.weekday < 6) {
@ -213,10 +229,19 @@ export default class QuickActionBvcBeginView extends Vue {
suppressMilliseconds: true,
}) || "";
const accountsDB = await accountsDBPromise;
await accountsDB.open();
const allAccounts = await accountsDB.accounts.toArray();
this.allMyDids = allAccounts.map((acc) => acc.did);
const queryResult = await platformService.dbQuery(
"SELECT did FROM accounts",
);
this.allMyDids =
databaseUtil
.mapQueryResultToValues(queryResult)
?.map((row) => row[0] as string) || [];
if (USE_DEXIE_DB) {
const accountsDB = await accountsDBPromise;
await accountsDB.open();
const allAccounts = await accountsDB.accounts.toArray();
this.allMyDids = allAccounts.map((acc) => acc.did);
}
const headers = await getHeaders(this.activeDid);
try {
const response = await fetch(

21
src/views/RecentOffersToUserProjectsView.vue

@ -83,7 +83,8 @@ import EntityIcon from "../components/EntityIcon.vue";
import GiftedDialog from "../components/GiftedDialog.vue";
import InfiniteScroll from "../components/InfiniteScroll.vue";
import QuickNav from "../components/QuickNav.vue";
import { NotificationIface } from "../constants/app";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import * as databaseUtil from "../db/databaseUtil";
import { db, retrieveSettingsForActiveAccount } from "../db/index";
import { Contact } from "../db/tables/contacts";
import { Router } from "vue-router";
@ -95,6 +96,7 @@ import {
} from "../libs/endorserServer";
import { retrieveAccountDids } from "../libs/util";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
@Component({
components: { EntityIcon, GiftedDialog, InfiniteScroll, QuickNav },
})
@ -116,13 +118,26 @@ export default class RecentOffersToUserView extends Vue {
async created() {
try {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.apiServer = settings.apiServer || "";
this.activeDid = settings.activeDid || "";
this.lastAckedOfferToUserProjectsJwtId =
settings.lastAckedOfferToUserProjectsJwtId || "";
this.allContacts = await db.contacts.toArray();
const contactQueryResult =
await PlatformServiceFactory.getInstance().dbQuery(
"SELECT * FROM contacts",
);
this.allContacts = databaseUtil.mapQueryResultToValues(
contactQueryResult,
) as unknown as Contact[];
if (USE_DEXIE_DB) {
await db.open();
this.allContacts = await db.contacts.toArray();
}
this.allMyDids = await retrieveAccountDids();

20
src/views/RecentOffersToUserView.vue

@ -76,7 +76,8 @@ import GiftedDialog from "../components/GiftedDialog.vue";
import EntityIcon from "../components/EntityIcon.vue";
import InfiniteScroll from "../components/InfiniteScroll.vue";
import QuickNav from "../components/QuickNav.vue";
import { NotificationIface } from "../constants/app";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import * as databaseUtil from "../db/databaseUtil";
import { db, retrieveSettingsForActiveAccount } from "../db/index";
import { Contact } from "../db/tables/contacts";
import { OfferSummaryRecord } from "../interfaces";
@ -87,6 +88,7 @@ import {
} from "../libs/endorserServer";
import { retrieveAccountDids } from "../libs/util";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
@Component({
components: { EntityIcon, GiftedDialog, InfiniteScroll, QuickNav },
})
@ -108,12 +110,24 @@ export default class RecentOffersToUserView extends Vue {
async created() {
try {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.apiServer = settings.apiServer || "";
this.activeDid = settings.activeDid || "";
this.lastAckedOfferToUserJwtId = settings.lastAckedOfferToUserJwtId || "";
this.allContacts = await db.contacts.toArray();
const contactQueryResult =
await PlatformServiceFactory.getInstance().dbQuery(
"SELECT * FROM contacts",
);
this.allContacts = databaseUtil.mapQueryResultToValues(
contactQueryResult,
) as unknown as Contact[];
if (USE_DEXIE_DB) {
this.allContacts = await db.contacts.toArray();
}
this.allMyDids = await retrieveAccountDids();

35
src/views/SearchAreaView.vue

@ -112,10 +112,12 @@ import {
import { Router } from "vue-router";
import QuickNav from "../components/QuickNav.vue";
import { NotificationIface } from "../constants/app";
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import * as databaseUtil from "../db/databaseUtil";
import { db, retrieveSettingsForActiveAccount } from "../db/index";
import { BoundingBox, MASTER_SETTINGS_KEY } from "../db/tables/settings";
import { logger } from "../utils/logger";
const DEFAULT_LAT_LONG_DIFF = 0.01;
const WORLD_ZOOM = 2;
const DEFAULT_ZOOM = 2;
@ -147,7 +149,10 @@ export default class SearchAreaView extends Vue {
searchBox: { name: string; bbox: BoundingBox } | null = null;
async mounted() {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.searchBox = settings.searchBoxes?.[0] || null;
this.resetLatLong();
}
@ -204,10 +209,15 @@ export default class SearchAreaView extends Vue {
westLong: this.localCenterLong - this.localLongDiff,
},
};
await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, {
searchBoxes: [newSearchBox],
});
const searchBoxes = JSON.stringify([newSearchBox]);
// @ts-expect-error - the DB requires searchBoxes to be a string
databaseUtil.updateDefaultSettings({ searchBoxes });
if (USE_DEXIE_DB) {
await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, {
searchBoxes: [newSearchBox],
});
}
this.searchBox = newSearchBox;
this.isChoosingSearchBox = false;
@ -251,11 +261,18 @@ export default class SearchAreaView extends Vue {
public async forgetSearchBox() {
try {
await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, {
searchBoxes: [],
// @ts-expect-error - the DB requires searchBoxes to be a string
await databaseUtil.updateDefaultSettings({
searchBoxes: "[]",
filterFeedByNearby: false,
});
if (USE_DEXIE_DB) {
await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, {
searchBoxes: [],
filterFeedByNearby: false,
});
}
this.searchBox = null;
this.localCenterLat = 0;
this.localCenterLong = 0;

22
src/views/ShareMyContactInfoView.vue

@ -46,11 +46,14 @@ import { Router } from "vue-router";
import { useClipboard } from "@vueuse/core";
import QuickNav from "../components/QuickNav.vue";
import TopMessage from "../components/TopMessage.vue";
import { NotificationIface, APP_SERVER } from "../constants/app";
import { NotificationIface, APP_SERVER, USE_DEXIE_DB } from "../constants/app";
import * as databaseUtil from "../db/databaseUtil";
import { db, retrieveSettingsForActiveAccount } from "../db/index";
import { retrieveAccountMetadata } from "../libs/util";
import { generateEndorserJwtUrlForAccount } from "../libs/endorserServer";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
import { logger } from "../utils/logger";
@Component({
components: { QuickNav, TopMessage },
})
@ -63,7 +66,10 @@ export default class ShareMyContactInfoView extends Vue {
}
async onClickShare() {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
const activeDid = settings.activeDid || "";
const givenName = settings.firstName || "";
const isRegistered = !!settings.isRegistered;
@ -71,7 +77,17 @@ export default class ShareMyContactInfoView extends Vue {
const account = await retrieveAccountMetadata(activeDid);
const numContacts = await db.contacts.count();
const platformService = PlatformServiceFactory.getInstance();
const contactQueryResult = await platformService.dbQuery(
"SELECT COUNT(*) FROM contacts",
);
let numContacts =
(databaseUtil.mapQueryResultToValues(
contactQueryResult,
)?.[0]?.[0] as number) || 0;
if (USE_DEXIE_DB) {
numContacts = await db.contacts.count();
}
if (account) {
const message = await generateEndorserJwtUrlForAccount(

35
src/views/SharedPhotoView.vue

@ -78,12 +78,16 @@ import {
DEFAULT_IMAGE_API_SERVER,
IMAGE_TYPE_PROFILE,
NotificationIface,
USE_DEXIE_DB,
} from "../constants/app";
import * as databaseUtil from "../db/databaseUtil";
import { db, retrieveSettingsForActiveAccount } from "../db/index";
import { MASTER_SETTINGS_KEY } from "../db/tables/settings";
import { accessToken } from "../libs/crypto";
import { base64ToBlob, SHARED_PHOTO_BASE64_KEY } from "../libs/util";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
import { Temp } from "@/db/tables/temp";
@Component({ components: { PhotoDialog, QuickNav } })
export default class SharedPhotoView extends Vue {
$notify!: (notification: NotificationIface, timeout?: number) => void;
@ -100,16 +104,32 @@ export default class SharedPhotoView extends Vue {
// 'created' hook runs when the Vue instance is first created
async mounted() {
try {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid;
const temp = await db.temp.get(SHARED_PHOTO_BASE64_KEY);
const platformService = PlatformServiceFactory.getInstance();
const tempQuery = await platformService.dbQuery(
"SELECT * FROM temp WHERE id = ?",
[SHARED_PHOTO_BASE64_KEY],
);
let temp = databaseUtil.mapQueryResultToValues(tempQuery)?.[0] as Temp;
if (USE_DEXIE_DB) {
temp = (await db.temp.get(SHARED_PHOTO_BASE64_KEY)) as unknown as Temp;
}
const imageB64 = temp?.blobB64 as string;
if (temp) {
this.imageBlob = base64ToBlob(imageB64);
// clear the temp image
db.temp.delete(SHARED_PHOTO_BASE64_KEY);
await platformService.dbExec("DELETE FROM temp WHERE id = ?", [
SHARED_PHOTO_BASE64_KEY,
]);
if (USE_DEXIE_DB) {
await db.temp.delete(SHARED_PHOTO_BASE64_KEY);
}
this.imageFileName = this.$route.query["fileName"] as string;
} else {
@ -150,9 +170,12 @@ export default class SharedPhotoView extends Vue {
recordProfile() {
(this.$refs.photoDialog as PhotoDialog).open(
async (imgUrl) => {
await db.settings.update(MASTER_SETTINGS_KEY, {
profileImageUrl: imgUrl,
});
databaseUtil.updateDefaultSettings({ profileImageUrl: imgUrl });
if (USE_DEXIE_DB) {
await db.settings.update(MASTER_SETTINGS_KEY, {
profileImageUrl: imgUrl,
});
}
this.$router.push({ name: "account" });
},
IMAGE_TYPE_PROFILE,

8
src/views/StartView.vue

@ -91,7 +91,8 @@
import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import { AppString, PASSKEYS_ENABLED } from "../constants/app";
import { AppString, PASSKEYS_ENABLED, USE_DEXIE_DB } from "../constants/app";
import * as databaseUtil from "../db/databaseUtil";
import { retrieveSettingsForActiveAccount } from "../db/index";
import {
registerSaveAndActivatePasskey,
@ -109,7 +110,10 @@ export default class StartView extends Vue {
numAccounts = 0;
async mounted() {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.givenName = settings.firstName || "";
this.numAccounts = await retrieveAccountCount();

60
src/views/TestView.vue

@ -167,11 +167,30 @@
<button
class="text-sm text-blue-600 hover:text-blue-800 underline"
@click="
sqlQuery = 'SELECT * FROM sqlite_master WHERE type=\'table\';'
sqlQuery = 'SELECT * FROM sqlite_master WHERE type=\'table\';';
executeSql();
"
>
All Tables
</button>
<button
class="text-sm text-blue-600 hover:text-blue-800 underline"
@click="
sqlQuery = 'SELECT * FROM accounts;';
executeSql();
"
>
Accounts
</button>
<button
class="text-sm text-blue-600 hover:text-blue-800 underline"
@click="
sqlQuery = 'SELECT * FROM settings;';
executeSql();
"
>
Settings
</button>
</div>
<div>
<textarea
@ -311,7 +330,8 @@ import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import QuickNav from "../components/QuickNav.vue";
import { AppString, NotificationIface } from "../constants/app";
import { AppString, NotificationIface, USE_DEXIE_DB } from "../constants/app";
import * as databaseUtil from "../db/databaseUtil";
import { db, retrieveSettingsForActiveAccount } from "../db/index";
import * as vcLib from "../libs/crypto/vc";
import * as cryptoLib from "../libs/crypto";
@ -331,6 +351,7 @@ import {
} from "../libs/util";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
import { Temp } from "@/db/tables/temp";
const inputFileNameRef = ref<Blob>();
const TEST_PAYLOAD = {
@ -369,7 +390,10 @@ export default class Help extends Vue {
cryptoLib = cryptoLib;
async mounted() {
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
this.userName = settings.firstName;
@ -399,11 +423,35 @@ export default class Help extends Vue {
});
const blobB64 = await blobToBase64(blob);
this.fileName = (file as File).name;
const temp = await db.temp.get(SHARED_PHOTO_BASE64_KEY);
const platformService = PlatformServiceFactory.getInstance();
const tempQuery = await platformService.dbQuery(
"SELECT * FROM temp WHERE id = ?",
[SHARED_PHOTO_BASE64_KEY],
);
let temp = databaseUtil.mapQueryResultToValues(
tempQuery,
)?.[0] as Temp;
if (temp) {
await db.temp.update(SHARED_PHOTO_BASE64_KEY, { blobB64 });
await platformService.dbExec(
"UPDATE temp SET blobB64 = ? WHERE id = ?",
[blobB64, SHARED_PHOTO_BASE64_KEY],
);
} else {
await db.temp.add({ id: SHARED_PHOTO_BASE64_KEY, blobB64 });
await platformService.dbExec(
"INSERT INTO temp (id, blobB64) VALUES (?, ?)",
[SHARED_PHOTO_BASE64_KEY, blobB64],
);
}
if (USE_DEXIE_DB) {
temp = (await db.temp.get(
SHARED_PHOTO_BASE64_KEY,
)) as unknown as Temp;
if (temp) {
await db.temp.update(SHARED_PHOTO_BASE64_KEY, { blobB64 });
} else {
await db.temp.add({ id: SHARED_PHOTO_BASE64_KEY, blobB64 });
}
}
}
};

25
src/views/UserProfileView.vue

@ -102,13 +102,17 @@ import TopMessage from "../components/TopMessage.vue";
import {
DEFAULT_PARTNER_API_SERVER,
NotificationIface,
USE_DEXIE_DB,
} from "../constants/app";
import * as databaseUtil from "../db/databaseUtil";
import { db } from "../db/index";
import { Contact } from "../db/tables/contacts";
import { didInfo, getHeaders } from "../libs/endorserServer";
import { UserProfile } from "../libs/partnerServer";
import { retrieveAccountDids } from "../libs/util";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
import { Settings } from "@/db/tables/settings";
@Component({
components: {
LMap,
@ -135,12 +139,29 @@ export default class UserProfileView extends Vue {
didInfo = didInfo;
async mounted() {
const settings = await db.settings.toArray();
const platformService = PlatformServiceFactory.getInstance();
const settingsQuery = await platformService.dbQuery(
"SELECT * FROM settings",
);
let settings = databaseUtil.mapQueryResultToValues(
settingsQuery,
) as Settings[];
if (USE_DEXIE_DB) {
settings = await db.settings.toArray();
}
this.activeDid = settings[0]?.activeDid || "";
this.partnerApiServer =
settings[0]?.partnerApiServer || this.partnerApiServer;
this.allContacts = await db.contacts.toArray();
const contactQuery = await platformService.dbQuery(
"SELECT * FROM contacts",
);
this.allContacts = databaseUtil.mapQueryResultToValues(
contactQuery,
) as unknown as Contact[];
if (USE_DEXIE_DB) {
this.allContacts = await db.contacts.toArray();
}
this.allMyDids = await retrieveAccountDids();
await this.loadProfile();

Loading…
Cancel
Save