diff --git a/.env.development b/.env.development
index 70091e74..726f3b7a 100644
--- a/.env.development
+++ b/.env.development
@@ -1,10 +1,14 @@
-
# Only the variables that start with VITE_ are seen in the application import.meta.env in Vue.
+# Logging Configuration - Development environment gets maximum visibility
+VITE_LOG_LEVEL=debug
+
# iOS doesn't like spaces in the app title.
TIME_SAFARI_APP_TITLE="TimeSafari_Dev"
VITE_APP_SERVER=http://localhost:8080
-# This is the claim ID for actions in the BVC project, with the JWT ID on this environment (not production).
+# This is the claim ID for actions in the BVC project, with the JWT ID on this environment (not
+
+
VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01HWE8FWHQ1YGP7GFZYYPS272F
VITE_DEFAULT_ENDORSER_API_SERVER=http://localhost:3000
# Using shared server by default to ease setup, which works for shared test users.
diff --git a/.env.production b/.env.production
index bbf73a08..aef4d6a4 100644
--- a/.env.production
+++ b/.env.production
@@ -1,6 +1,7 @@
# Only the variables that start with VITE_ are seen in the application import.meta.env in Vue.
-
+# Logging Configuration - Production environment gets minimal logging for performance
+VITE_LOG_LEVEL=warn
VITE_APP_SERVER=https://timesafari.app
# This is the claim ID for actions in the BVC project.
diff --git a/.env.test b/.env.test
index a01c323c..5776e66c 100644
--- a/.env.test
+++ b/.env.test
@@ -1,9 +1,14 @@
# Only the variables that start with VITE_ are seen in the application import.meta.env in Vue.
+# Logging Configuration - Test environment gets balanced logging for debugging
+VITE_LOG_LEVEL=info
+
# iOS doesn't like spaces in the app title.
TIME_SAFARI_APP_TITLE="TimeSafari_Test"
VITE_APP_SERVER=https://test.timesafari.app
-# This is the claim ID for actions in the BVC project, with the JWT ID on this environment (not production).
+# This is the claim ID for actions in the BVC project, with the JWT ID on this environment (not
+ production).
+
VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01HWE8FWHQ1YGP7GFZYYPS272F
VITE_DEFAULT_ENDORSER_API_SERVER=https://test-api.endorser.ch
diff --git a/BUILDING.md b/BUILDING.md
index ba5649da..e1e94fcd 100644
--- a/BUILDING.md
+++ b/BUILDING.md
@@ -8,8 +8,10 @@ This guide explains how to build TimeSafari for different platforms using the co
```bash
# 🖥️ Web Development
-npm run build:web:dev # Start development server with hot reload
-npm run build:web:prod # Production build
+npm install # setup -- and pkgx.dev `dev` command before this will set environment with npm, etc
+npm run build:web:serve -- --test # Start with test endorser server
+npm run build:web:dev # Start development server with hot reload with local endorser server
+npm run build:web:prod # Production build
# 📱 Mobile Development
npm run build:ios # iOS build (opens Xcode)
@@ -2401,4 +2403,4 @@ All scripts use consistent error handling:
---
-**Note**: This documentation is maintained alongside the build system. For the most up-to-date information, refer to the actual script files and Vite configuration files in the repository.
\ No newline at end of file
+**Note**: This documentation is maintained alongside the build system. For the most up-to-date information, refer to the actual script files and Vite configuration files in the repository.
diff --git a/README.md b/README.md
index 6d987467..6992ba09 100644
--- a/README.md
+++ b/README.md
@@ -3,36 +3,9 @@
[Time Safari](https://timesafari.org/) allows people to ease into collaboration: start with expressions of gratitude
and expand to crowd-fund with time & money, then record and see the impact of contributions.
-## Database Migration Status
-
-**Current Status**: The application is undergoing a migration from Dexie (IndexedDB) to SQLite using absurd-sql. This migration is in **Phase 2** with a well-defined migration fence in place.
-
-### Migration Progress
-- ✅ **SQLite Database Service**: Fully implemented with absurd-sql
-- ✅ **Platform Service Layer**: Unified database interface across platforms
-- ✅ **Settings Migration**: Core user settings transferred
-- ✅ **Account Migration**: Identity and key management
-- 🔄 **Contact Migration**: User contact data (via import interface)
-- 📋 **Code Cleanup**: Remove unused Dexie imports
-
-### Migration Fence
-The migration is controlled by a **migration fence** that separates legacy Dexie code from the new SQLite implementation. See [Migration Fence Definition](doc/migration-fence-definition.md) for complete details.
-
-**Key Points**:
-- Legacy Dexie database is disabled by default
-- All database operations go through `PlatformServiceMixin`
-- Migration tools provide controlled access to both databases
-- Clear separation between legacy and new code
-
-### Migration Documentation
-- [Migration Guide](doc/migration-to-wa-sqlite.md) - Complete migration process
-- [Migration Fence Definition](doc/migration-fence-definition.md) - Fence boundaries and rules
-- [Database Migration Guide](doc/database-migration-guide.md) - User-facing migration tools
-
## Roadmap
-See [project.task.yaml](project.task.yaml) for current priorities.
-(Numbers at the beginning of lines are estimated hours. See [taskyaml.org](https://taskyaml.org/) for details.)
+See [ClickUp](https://sharing.clickup.com/9014278710/l/h/8cmnyhp-174/10573fec74e2ba0) for current priorities.
## Setup & Building
@@ -42,14 +15,45 @@ Quick start:
```bash
npm install
-npm run dev
+npm run build:web:serve -- --test
```
+To be able to make submissions: go to "profile" (bottom left), go to the bottom and expand "Show Advanced Settings", go to the bottom and to the "Test Page", and finally "Become User 0" to see all the functionality.
+
See [BUILDING.md](BUILDING.md) for comprehensive build instructions for all platforms (Web, Electron, iOS, Android, Docker).
## Development Database Clearing
-TimeSafari provides a simple script-based approach to clear the database for development purposes.
+TimeSafari provides a simple script-based approach to clear the local database (not the claim server) for development purposes.
+
+## Logging Configuration
+
+TimeSafari supports configurable logging levels via the `VITE_LOG_LEVEL` environment variable. This allows developers to control console output verbosity without modifying code.
+
+### Quick Usage
+
+```bash
+# Show only errors
+VITE_LOG_LEVEL=error npm run dev
+
+# Show warnings and errors
+VITE_LOG_LEVEL=warn npm run dev
+
+# Show info, warnings, and errors (default)
+VITE_LOG_LEVEL=info npm run dev
+
+# Show all log levels including debug
+VITE_LOG_LEVEL=debug npm run dev
+```
+
+### Available Levels
+
+- **`error`**: Critical errors only
+- **`warn`**: Warnings and errors (default for production web)
+- **`info`**: Info, warnings, and errors (default for development/capacitor)
+- **`debug`**: All log levels including verbose debugging
+
+See [Logging Configuration Guide](doc/logging-configuration.md) for complete details.
### Quick Usage
```bash
@@ -126,7 +130,6 @@ const apiUrl = `${APP_SERVER}/api/claim/123`;
### Documentation
-- [Domain Configuration System](docs/domain-configuration.md) - Complete guide
- [Constants and Configuration](src/constants/app.ts) - Core constants
## Tests
diff --git a/doc/logging-configuration.md b/doc/logging-configuration.md
new file mode 100644
index 00000000..2ef2a6d2
--- /dev/null
+++ b/doc/logging-configuration.md
@@ -0,0 +1,117 @@
+# Logging Configuration Guide
+
+## Overview
+
+TimeSafari now supports configurable logging levels via the `VITE_LOG_LEVEL` environment variable. This allows developers to control the verbosity of console output without modifying code.
+
+## Available Log Levels
+
+| Level | Value | Description | Console Output |
+|-------|-------|-------------|----------------|
+| `error` | 0 | Errors only | Critical errors only |
+| `warn` | 1 | Warnings and errors | Warnings and errors |
+| `info` | 2 | Info, warnings, and errors | General information, warnings, and errors |
+| `debug` | 3 | All log levels | Verbose debugging information |
+
+## Environment Variable
+
+Set the `VITE_LOG_LEVEL` environment variable to control logging:
+
+```bash
+# Show only errors
+VITE_LOG_LEVEL=error
+
+# Show warnings and errors (default for production web)
+VITE_LOG_LEVEL=warn
+
+# Show info, warnings, and errors (default for development/capacitor)
+VITE_LOG_LEVEL=info
+
+# Show all log levels including debug
+VITE_LOG_LEVEL=debug
+```
+
+## Default Behavior by Platform
+
+The logger automatically selects appropriate default log levels based on your platform and environment:
+
+- **Production Web**: `warn` (warnings and errors only)
+- **Electron**: `error` (errors only - very quiet)
+- **Development/Capacitor**: `info` (info and above)
+
+## Usage Examples
+
+### Setting Log Level in Development
+
+```bash
+# In your terminal before running the app
+export VITE_LOG_LEVEL=debug
+npm run dev
+
+# Or inline
+VITE_LOG_LEVEL=debug npm run dev
+```
+
+### Setting Log Level in Production
+
+```bash
+# For verbose production logging
+VITE_LOG_LEVEL=info npm run build:web
+
+# For minimal production logging
+VITE_LOG_LEVEL=warn npm run build:web
+```
+
+### Programmatic Access
+
+The logger provides methods to check current configuration:
+
+```typescript
+import { logger } from '@/utils/logger';
+
+// Get current log level
+const currentLevel = logger.getCurrentLevel(); // 'info'
+
+// Check if a level is enabled
+const debugEnabled = logger.isLevelEnabled('debug'); // false if level < debug
+
+// Get available levels
+const levels = logger.getAvailableLevels(); // ['error', 'warn', 'info', 'debug']
+```
+
+## Database Logging
+
+Database logging continues to work regardless of console log level settings. All log messages are still stored in the database for debugging and audit purposes.
+
+## Migration Notes
+
+- **Existing code**: No changes required - logging behavior remains the same
+- **New feature**: Use `VITE_LOG_LEVEL` to override default behavior
+- **Backward compatible**: All existing logging calls work as before
+
+## Best Practices
+
+1. **Development**: Use `VITE_LOG_LEVEL=debug` for maximum visibility
+2. **Testing**: Use `VITE_LOG_LEVEL=info` for balanced output
+3. **Production**: Use `VITE_LOG_LEVEL=warn` for minimal noise
+4. **Debugging**: Temporarily set `VITE_LOG_LEVEL=debug` to troubleshoot issues
+
+## Troubleshooting
+
+### No Logs Appearing
+
+Check your `VITE_LOG_LEVEL` setting:
+```bash
+echo $VITE_LOG_LEVEL
+```
+
+### Too Many Logs
+
+Reduce verbosity by setting a lower log level:
+```bash
+VITE_LOG_LEVEL=warn
+```
+
+### Platform-Specific Issues
+
+Remember that Electron is very quiet by default. Use `VITE_LOG_LEVEL=info` to see more output in Electron builds.
diff --git a/package-lock.json b/package-lock.json
index 6d19bd08..814a71ad 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "timesafari",
- "version": "1.0.6",
+ "version": "1.0.7-beta",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "timesafari",
- "version": "1.0.6",
+ "version": "1.0.7-beta",
"dependencies": {
"@capacitor-community/electron": "^5.0.1",
"@capacitor-community/sqlite": "6.0.2",
@@ -96,7 +96,7 @@
},
"devDependencies": {
"@capacitor/assets": "^3.0.5",
- "@playwright/test": "^1.45.2",
+ "@playwright/test": "^1.54.2",
"@types/dom-webcodecs": "^0.1.7",
"@types/jest": "^30.0.0",
"@types/js-yaml": "^4.0.9",
diff --git a/package.json b/package.json
index cd34bc17..7b27258d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "timesafari",
- "version": "1.0.6",
+ "version": "1.0.7-beta",
"description": "Time Safari Application",
"author": {
"name": "Time Safari Team"
@@ -204,7 +204,7 @@
},
"devDependencies": {
"@capacitor/assets": "^3.0.5",
- "@playwright/test": "^1.45.2",
+ "@playwright/test": "^1.54.2",
"@types/dom-webcodecs": "^0.1.7",
"@types/jest": "^30.0.0",
"@types/js-yaml": "^4.0.9",
diff --git a/scripts/build-web.sh b/scripts/build-web.sh
index c01bd55d..de0710a2 100755
--- a/scripts/build-web.sh
+++ b/scripts/build-web.sh
@@ -300,18 +300,20 @@ serve_build() {
exit 5
fi
- # Use a simple HTTP server to serve the build
- if command -v python3 &> /dev/null; then
+ # Use a server that supports SPA routing (serves index.html for all routes)
+ if command -v npx &> /dev/null; then
+ log_info "Starting npx serve with SPA support on port 8080..."
+ npx serve -s dist -l 8080
+ elif command -v python3 &> /dev/null; then
+ log_warn "Python HTTP server doesn't support SPA routing. Routes like /discover, /account will return 404."
log_info "Starting Python HTTP server on port 8080..."
cd dist && python3 -m http.server 8080
elif command -v python &> /dev/null; then
+ log_warn "Python HTTP server doesn't support SPA routing. Routes like /discover, /account will return 404."
log_info "Starting Python HTTP server on port 8080..."
cd dist && python -m SimpleHTTPServer 8080
- elif command -v npx &> /dev/null; then
- log_info "Starting npx serve on port 8080..."
- npx serve -s dist -l 8080
else
- log_error "No suitable HTTP server found. Install Python or npx serve."
+ log_error "No suitable HTTP server found. Install npx serve or Python."
exit 5
fi
}
diff --git a/src/App.vue b/src/App.vue
index 76acc710..8bd39b52 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -27,9 +27,13 @@
v-if="notification.type === 'toast'"
class="w-full max-w-sm mx-auto mb-3 overflow-hidden bg-slate-900/90 text-white rounded-lg shadow-md"
>
-
- {{ notification.title }}
-
{{ notification.text }}
+
+
+ {{ notification.title }}
+
+
+ {{ notification.text }}
+
@@ -46,9 +50,15 @@
>
-
- {{ notification.title }}
-
{{ truncateLongWords(notification.text) }}
+
+
+ {{ notification.title }}
+
+
+ {{ notification.text }}
+
-
- {{ notification.title }}
-
{{ truncateLongWords(notification.text) }}
+
+
+ {{ notification.title }}
+
+
+ {{ notification.text }}
+
-
- {{ notification.title }}
-
{{ truncateLongWords(notification.text) }}
+
+
+ {{ notification.title }}
+
+
+ {{ notification.text }}
+
-
- {{ notification.title }}
-
{{ truncateLongWords(notification.text) }}
+
+
+ {{ notification.title }}
+
+
+ {{ notification.text }}
+
@@ -253,7 +252,7 @@ import { GiveRecordWithContactInfo } from "@/interfaces/give";
import EntityIcon from "./EntityIcon.vue";
import { isHiddenDid } from "../libs/endorserServer";
import ProjectIcon from "./ProjectIcon.vue";
-import { createNotifyHelpers } from "@/utils/notify";
+import { createNotifyHelpers, NotifyFunction } from "@/utils/notify";
import {
NOTIFY_PERSON_HIDDEN,
NOTIFY_UNKNOWN_PERSON,
@@ -272,16 +271,9 @@ export default class ActivityListItem extends Vue {
@Prop() isRegistered!: boolean;
@Prop() activeDid!: string;
- /**
- * Function prop for handling image caching
- * Called when an image loads successfully, allowing parent to control caching behavior
- */
- @Prop({ type: Function, default: () => {} })
- onImageCache!: (imageUrl: string) => void | Promise;
-
isHiddenDid = isHiddenDid;
notify!: ReturnType;
- $notify!: (notification: any, timeout?: number) => void;
+ $notify!: NotifyFunction;
created() {
this.notify = createNotifyHelpers(this.$notify);
@@ -295,14 +287,6 @@ export default class ActivityListItem extends Vue {
this.notify.warning(NOTIFY_UNKNOWN_PERSON.message, TIMEOUTS.STANDARD);
}
- /**
- * Handle image load event - call function prop for caching
- * Allows parent to control caching behavior and validation
- */
- handleImageLoad(imageUrl: string): void {
- this.onImageCache(imageUrl);
- }
-
get fetchAmount(): string {
const claim =
(this.record.fullClaim as any)?.claim || this.record.fullClaim;
diff --git a/src/components/ContactInputForm.vue b/src/components/ContactInputForm.vue
index 35c693e4..dbbc1485 100644
--- a/src/components/ContactInputForm.vue
+++ b/src/components/ContactInputForm.vue
@@ -167,7 +167,7 @@ export default class ContactInputForm extends Vue {
*/
@Emit("qr-scan")
private handleQRScan(): void {
- console.log("[ContactInputForm] QR scan button clicked");
+ // QR scan button clicked - event emitted for parent handling
}
}
diff --git a/src/components/GiftedDialog.vue b/src/components/GiftedDialog.vue
index 6979db74..923596fd 100644
--- a/src/components/GiftedDialog.vue
+++ b/src/components/GiftedDialog.vue
@@ -81,7 +81,7 @@ import EntitySelectionStep from "../components/EntitySelectionStep.vue";
import GiftDetailsStep from "../components/GiftDetailsStep.vue";
import { PlanData } from "../interfaces/records";
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
-import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
+import { createNotifyHelpers, TIMEOUTS, NotifyFunction } from "@/utils/notify";
import {
NOTIFY_GIFT_ERROR_NEGATIVE_AMOUNT,
NOTIFY_GIFT_ERROR_NO_DESCRIPTION,
@@ -99,7 +99,7 @@ import {
mixins: [PlatformServiceMixin],
})
export default class GiftedDialog extends Vue {
- $notify!: (notification: any, timeout?: number) => void;
+ $notify!: NotifyFunction;
notify!: ReturnType;
/**
diff --git a/src/components/ImageMethodDialog.vue b/src/components/ImageMethodDialog.vue
index b6cdd9bd..0c4c5427 100644
--- a/src/components/ImageMethodDialog.vue
+++ b/src/components/ImageMethodDialog.vue
@@ -282,7 +282,7 @@ import {
NOTIFY_IMAGE_DIALOG_UNSUPPORTED_FORMAT,
createImageDialogCameraErrorMessage,
} from "../constants/notifications";
-import { createNotifyHelpers, TIMEOUTS } from "../utils/notify";
+import { createNotifyHelpers, TIMEOUTS, NotifyFunction } from "../utils/notify";
const inputImageFileNameRef = ref();
@@ -291,7 +291,7 @@ const inputImageFileNameRef = ref();
mixins: [PlatformServiceMixin],
})
export default class ImageMethodDialog extends Vue {
- $notify!: (notification: any, timeout?: number) => void;
+ $notify!: NotifyFunction;
$router!: Router;
notify = createNotifyHelpers(this.$notify);
diff --git a/src/components/ImageViewer.vue b/src/components/ImageViewer.vue
index 07486705..3e8e577f 100644
--- a/src/components/ImageViewer.vue
+++ b/src/components/ImageViewer.vue
@@ -45,7 +45,6 @@ import { logger } from "../utils/logger";
@Component({ emits: ["update:isOpen"] })
export default class ImageViewer extends Vue {
@Prop() imageUrl!: string;
- @Prop() imageData!: Blob | null;
@Prop() isOpen!: boolean;
userAgent = new UAParser();
diff --git a/src/libs/endorserServer.ts b/src/libs/endorserServer.ts
index e28b3ac9..735252f7 100644
--- a/src/libs/endorserServer.ts
+++ b/src/libs/endorserServer.ts
@@ -1348,12 +1348,12 @@ export async function createEndorserJwtVcFromClaim(
}
/**
- * Create a JWT for a RegisterAction claim.
+ * Create a JWT for a RegisterAction claim, used for registrations & invites.
*
* @param activeDid - The DID of the user creating the invite
- * @param contact - The contact to register, with a 'did' field (all optional for invites)
- * @param identifier - The identifier for the invite, usually random
- * @param expiresIn - The number of seconds until the invite expires
+ * @param contact - Optional - The contact to register, with a 'did' field (all optional for invites)
+ * @param identifier - Optional - The identifier for the invite, usually random
+ * @param expiresIn - Optional - The number of seconds until the invite expires
* @returns The JWT for the RegisterAction claim
*/
export async function createInviteJwt(
@@ -1367,7 +1367,7 @@ export async function createInviteJwt(
"@type": "RegisterAction",
agent: { identifier: activeDid },
object: SERVICE_ID,
- identifier: identifier,
+ identifier: identifier, // not sent if undefined
};
if (contact?.did) {
vcClaim.participant = { identifier: contact.did };
diff --git a/src/router/index.ts b/src/router/index.ts
index 7d1e738c..043d3d0c 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -82,6 +82,15 @@ const routes: Array = [
name: "database-migration",
component: () => import("../views/DatabaseMigration.vue"),
},
+ {
+ path: "/deep-link-error",
+ name: "deep-link-error",
+ component: () => import("../views/DeepLinkErrorView.vue"),
+ meta: {
+ title: "Invalid Deep Link",
+ requiresAuth: false,
+ },
+ },
{
path: "/did/:did?",
name: "did",
@@ -276,15 +285,6 @@ const routes: Array = [
name: "user-profile",
component: () => import("../views/UserProfileView.vue"),
},
- {
- path: "/deep-link-error",
- name: "deep-link-error",
- component: () => import("../views/DeepLinkErrorView.vue"),
- meta: {
- title: "Invalid Deep Link",
- requiresAuth: false,
- },
- },
];
const isElectron = window.location.protocol === "file:";
diff --git a/src/services/deepLinks.ts b/src/services/deepLinks.ts
index 62ae7b15..d8445607 100644
--- a/src/services/deepLinks.ts
+++ b/src/services/deepLinks.ts
@@ -179,7 +179,7 @@ export class DeepLinkHandler {
const validRoute = routeSchema.parse(path) as DeepLinkRoute;
routeName = ROUTE_MAP[validRoute].name;
} catch (error) {
- console.error(`[DeepLink] Invalid route path: ${path}`);
+ logger.error(`[DeepLink] Invalid route path: ${path}`);
// Redirect to error page with information about the invalid link
await this.router.replace({
diff --git a/src/services/platforms/WebPlatformService.ts b/src/services/platforms/WebPlatformService.ts
index 7ec13c01..a731ee22 100644
--- a/src/services/platforms/WebPlatformService.ts
+++ b/src/services/platforms/WebPlatformService.ts
@@ -693,7 +693,8 @@ export class WebPlatformService implements PlatformService {
const setClause = keys.map((key) => `${key} = ?`).join(", ");
const sql = `UPDATE settings SET ${setClause} WHERE accountDid = ?`;
const params = [...keys.map((key) => settings[key]), did];
- console.log(
+ // Log update operation for debugging
+ logger.debug(
"[WebPlatformService] updateDidSpecificSettings",
sql,
JSON.stringify(params, null, 2),
diff --git a/src/test/index.ts b/src/test/index.ts
index 28b0e349..0e92c6f8 100644
--- a/src/test/index.ts
+++ b/src/test/index.ts
@@ -1,9 +1,34 @@
import axios from "axios";
import * as didJwt from "did-jwt";
import { SERVICE_ID } from "../libs/endorserServer";
-import { deriveAddress, newIdentifier } from "../libs/crypto";
+import {
+ DEFAULT_ROOT_DERIVATION_PATH,
+ deriveAddress,
+ newIdentifier,
+} from "../libs/crypto";
import { logger } from "../utils/logger";
import { AppString } from "../constants/app";
+import { saveNewIdentity } from "@/libs/util";
+import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
+
+const TEST_USER_0_MNEMONIC =
+ "rigid shrug mobile smart veteran half all pond toilet brave review universe ship congress found yard skate elite apology jar uniform subway slender luggage";
+
+export async function testBecomeUser0() {
+ const [addr, privateHex, publicHex, deriPath] =
+ deriveAddress(TEST_USER_0_MNEMONIC);
+
+ const identity0 = newIdentifier(addr, publicHex, privateHex, deriPath);
+ await saveNewIdentity(
+ identity0,
+ TEST_USER_0_MNEMONIC,
+ DEFAULT_ROOT_DERIVATION_PATH,
+ );
+ const platformService = await PlatformServiceFactory.getInstance();
+ await platformService.updateDidSpecificSettings(identity0.did, {
+ isRegistered: true,
+ });
+}
/**
* Get User #0 to sign & submit a RegisterAction for the user's activeDid.
@@ -15,10 +40,8 @@ import { AppString } from "../constants/app";
* @throws Error if registration fails or database access fails
*/
export async function testServerRegisterUser() {
- const testUser0Mnem =
- "seminar accuse mystery assist delay law thing deal image undo guard initial shallow wrestle list fragile borrow velvet tomorrow awake explain test offer control";
-
- const [addr, privateHex, publicHex, deriPath] = deriveAddress(testUser0Mnem);
+ const [addr, privateHex, publicHex, deriPath] =
+ deriveAddress(TEST_USER_0_MNEMONIC);
const identity0 = newIdentifier(addr, publicHex, privateHex, deriPath);
@@ -32,9 +55,9 @@ export async function testServerRegisterUser() {
const vcClaim = {
"@context": "https://schema.org",
"@type": "RegisterAction",
- agent: { did: identity0.did },
+ agent: { identifier: identity0.did },
object: SERVICE_ID,
- participant: { did: settings.activeDid },
+ participant: { identifier: settings.activeDid },
};
// Make a payload for the claim
@@ -71,4 +94,5 @@ export async function testServerRegisterUser() {
const resp = await axios.post(url, payload, { headers });
logger.log("User registration result:", resp);
+ return resp;
}
diff --git a/src/utils/logger.ts b/src/utils/logger.ts
index 4b78ed3a..52ae5daa 100644
--- a/src/utils/logger.ts
+++ b/src/utils/logger.ts
@@ -2,9 +2,10 @@
* Enhanced logger with self-contained database logging
*
* Provides comprehensive logging with console and database output.
+ * Supports configurable log levels via VITE_LOG_LEVEL environment variable.
*
* @author Matthew Raymer
- * @version 2.0.0
+ * @version 2.1.0
* @since 2025-01-25
*/
@@ -46,6 +47,42 @@ export function safeStringify(obj: unknown) {
const isElectron = process.env.VITE_PLATFORM === "electron";
const isProduction = process.env.NODE_ENV === "production";
+// Log level configuration via environment variable
+const LOG_LEVELS = {
+ error: 0,
+ warn: 1,
+ info: 2,
+ debug: 3,
+} as const;
+
+type LogLevel = keyof typeof LOG_LEVELS;
+
+// Parse VITE_LOG_LEVEL environment variable
+const getLogLevel = (): LogLevel => {
+ const envLogLevel = process.env.VITE_LOG_LEVEL?.toLowerCase();
+
+ if (envLogLevel && envLogLevel in LOG_LEVELS) {
+ return envLogLevel as LogLevel;
+ }
+
+ // Default log levels based on environment
+ if (isProduction && !isElectron) {
+ return "warn"; // Production web: warnings and errors only
+ } else if (isElectron) {
+ return "error"; // Electron: errors only
+ } else {
+ return "info"; // Development/Capacitor: info and above
+ }
+};
+
+const currentLogLevel = getLogLevel();
+const currentLevelValue = LOG_LEVELS[currentLogLevel];
+
+// Helper function to check if a log level should be displayed
+const shouldLog = (level: LogLevel): boolean => {
+ return LOG_LEVELS[level] <= currentLevelValue;
+};
+
// Track initialization state to prevent circular dependencies
let isInitializing = true;
@@ -105,11 +142,11 @@ async function logToDatabase(
}
}
-// Enhanced logger with self-contained database methods
+// Enhanced logger with self-contained database methods and log level control
export const logger = {
debug: (message: string, ...args: unknown[]) => {
- // Debug logs are very verbose - only show in development mode for web
- if (!isProduction && !isElectron) {
+ // Debug logs only show if VITE_LOG_LEVEL allows it
+ if (shouldLog("debug")) {
// eslint-disable-next-line no-console
console.debug(message, ...args);
}
@@ -117,11 +154,8 @@ export const logger = {
},
log: (message: string, ...args: unknown[]) => {
- // Regular logs - show in development or for capacitor, but quiet for Electron
- if (
- (!isProduction && !isElectron) ||
- process.env.VITE_PLATFORM === "capacitor"
- ) {
+ // Regular logs - show if VITE_LOG_LEVEL allows info level
+ if (shouldLog("info")) {
// eslint-disable-next-line no-console
console.log(message, ...args);
}
@@ -132,11 +166,7 @@ export const logger = {
},
info: (message: string, ...args: unknown[]) => {
- if (
- process.env.NODE_ENV !== "production" ||
- process.env.VITE_PLATFORM === "capacitor" ||
- process.env.VITE_PLATFORM === "electron"
- ) {
+ if (shouldLog("info")) {
// eslint-disable-next-line no-console
console.info(message, ...args);
}
@@ -147,8 +177,7 @@ export const logger = {
},
warn: (message: string, ...args: unknown[]) => {
- // Always show warnings, but for Electron, suppress routine database warnings
- if (!isElectron || !message.includes("[CapacitorPlatformService]")) {
+ if (shouldLog("warn")) {
// eslint-disable-next-line no-console
console.warn(message, ...args);
}
@@ -159,9 +188,10 @@ export const logger = {
},
error: (message: string, ...args: unknown[]) => {
- // Errors will always be logged to console
- // eslint-disable-next-line no-console
- console.error(message, ...args);
+ if (shouldLog("error")) {
+ // eslint-disable-next-line no-console
+ console.error(message, ...args);
+ }
// Database logging
const messageString = safeStringify(message);
@@ -175,11 +205,11 @@ export const logger = {
},
toConsoleAndDb: async (message: string, isError = false): Promise => {
- // Console output
- if (isError) {
+ // Console output based on log level
+ if (isError && shouldLog("error")) {
// eslint-disable-next-line no-console
console.error(message);
- } else {
+ } else if (!isError && shouldLog("info")) {
// eslint-disable-next-line no-console
console.log(message);
}
@@ -194,6 +224,12 @@ export const logger = {
error: (message: string) =>
logToDatabase(`[${componentName}] ${message}`, "error"),
}),
+
+ // Log level information methods
+ getCurrentLevel: (): LogLevel => currentLogLevel,
+ getCurrentLevelValue: (): number => currentLevelValue,
+ isLevelEnabled: (level: LogLevel): boolean => shouldLog(level),
+ getAvailableLevels: (): LogLevel[] => Object.keys(LOG_LEVELS) as LogLevel[],
};
// Function to manually mark initialization as complete
diff --git a/src/views/AccountViewView.vue b/src/views/AccountViewView.vue
index 892e1ebc..81c2978e 100644
--- a/src/views/AccountViewView.vue
+++ b/src/views/AccountViewView.vue
@@ -61,7 +61,8 @@
/>
-
+
void;
+ $notify!: NotifyFunction;
$router!: Router;
// Notification helper system
diff --git a/src/views/DIDView.vue b/src/views/DIDView.vue
index 8a5aaa64..4294ec4f 100644
--- a/src/views/DIDView.vue
+++ b/src/views/DIDView.vue
@@ -7,7 +7,8 @@