Browse Source

Merge branch 'active_did_redux' of ssh://173.199.124.46:222/trent_larson/crowd-funder-for-time-pwa into active_did_redux

pull/188/head
Matthew Raymer 1 day ago
parent
commit
2b3c83c21c
  1. 30
      README.md
  2. 10
      src/db-sql/migration.ts
  3. 13
      src/libs/endorserServer.ts
  4. 37
      src/services/migrationService.ts
  5. 7
      src/views/AccountViewView.vue

30
README.md

@ -7,17 +7,6 @@ and expand to crowd-fund with time & money, then record and see the impact of co
See [ClickUp](https://sharing.clickup.com/9014278710/l/h/8cmnyhp-174/10573fec74e2ba0) for current priorities. See [ClickUp](https://sharing.clickup.com/9014278710/l/h/8cmnyhp-174/10573fec74e2ba0) for current priorities.
## Known Issues
### Critical Vue Reactivity Bug
A critical Vue reactivity bug was discovered during ActiveDid migration testing where component properties fail to trigger template updates correctly.
**Impact**: The `newDirectOffersActivityNumber` element in HomeView.vue requires a watcher workaround to render correctly.
**Status**: Workaround implemented, investigation ongoing.
**Documentation**: See [Vue Reactivity Bug Report](doc/vue-reactivity-bug-report.md) for details.
## Setup & Building ## Setup & Building
Quick start: Quick start:
@ -79,16 +68,16 @@ TimeSafari supports configurable logging levels via the `VITE_LOG_LEVEL` environ
```bash ```bash
# Show only errors # Show only errors
VITE_LOG_LEVEL=error npm run dev VITE_LOG_LEVEL=error npm run build:web:dev
# Show warnings and errors # Show warnings and errors
VITE_LOG_LEVEL=warn npm run dev VITE_LOG_LEVEL=warn npm run build:web:dev
# Show info, warnings, and errors (default) # Show info, warnings, and errors (default)
VITE_LOG_LEVEL=info npm run dev VITE_LOG_LEVEL=info npm run build:web:dev
# Show all log levels including debug # Show all log levels including debug
VITE_LOG_LEVEL=debug npm run dev VITE_LOG_LEVEL=debug npm run build:web:dev
``` ```
### Available Levels ### Available Levels
@ -316,6 +305,17 @@ timesafari/
└── 📄 doc/README-BUILD-GUARD.md # Guard system documentation └── 📄 doc/README-BUILD-GUARD.md # Guard system documentation
``` ```
## Known Issues
### Critical Vue Reactivity Bug
A critical Vue reactivity bug was discovered during ActiveDid migration testing where component properties fail to trigger template updates correctly.
**Impact**: The `newDirectOffersActivityNumber` element in HomeView.vue requires a watcher workaround to render correctly.
**Status**: Workaround implemented, investigation ongoing.
**Documentation**: See [Vue Reactivity Bug Report](doc/vue-reactivity-bug-report.md) for details.
## 🤝 Contributing ## 🤝 Contributing
1. **Follow the Build Architecture Guard** - Update BUILDING.md when modifying build files 1. **Follow the Build Architecture Guard** - Update BUILDING.md when modifying build files

10
src/db-sql/migration.ts

@ -188,19 +188,19 @@ export async function runMigrations<T>(
sqlQuery: (sql: string, params?: unknown[]) => Promise<T>, sqlQuery: (sql: string, params?: unknown[]) => Promise<T>,
extractMigrationNames: (result: T) => Set<string>, extractMigrationNames: (result: T) => Set<string>,
): Promise<void> { ): Promise<void> {
logger.info("[Migration] Starting database migrations"); logger.debug("[Migration] Starting database migrations");
for (const migration of MIGRATIONS) { for (const migration of MIGRATIONS) {
logger.debug("[Migration] Registering migration:", migration.name); logger.debug("[Migration] Registering migration:", migration.name);
registerMigration(migration); registerMigration(migration);
} }
logger.info("[Migration] Running migration service"); logger.debug("[Migration] Running migration service");
await runMigrationsService(sqlExec, sqlQuery, extractMigrationNames); await runMigrationsService(sqlExec, sqlQuery, extractMigrationNames);
logger.info("[Migration] Database migrations completed"); logger.debug("[Migration] Database migrations completed");
// Bootstrapping: Ensure active account is selected after migrations // Bootstrapping: Ensure active account is selected after migrations
logger.info("[Migration] Running bootstrapping hooks"); logger.debug("[Migration] Running bootstrapping hooks");
try { try {
// Check if we have accounts but no active selection // Check if we have accounts but no active selection
const accountsResult = await sqlQuery("SELECT COUNT(*) FROM accounts"); const accountsResult = await sqlQuery("SELECT COUNT(*) FROM accounts");
@ -218,7 +218,7 @@ export async function runMigrations<T>(
: null; : null;
if (accountsCount > 0 && (!activeDid || activeDid === "")) { if (accountsCount > 0 && (!activeDid || activeDid === "")) {
logger.info("[Migration] Auto-selecting first account as active"); logger.debug("[Migration] Auto-selecting first account as active");
const firstAccountResult = await sqlQuery( const firstAccountResult = await sqlQuery(
"SELECT did FROM accounts ORDER BY dateCreated, did LIMIT 1", "SELECT did FROM accounts ORDER BY dateCreated, did LIMIT 1",
); );

13
src/libs/endorserServer.ts

@ -16,7 +16,7 @@
* @module endorserServer * @module endorserServer
*/ */
import { Axios, AxiosRequestConfig } from "axios"; import { Axios, AxiosRequestConfig, AxiosResponse } from "axios";
import { Buffer } from "buffer"; import { Buffer } from "buffer";
import { sha256 } from "ethereum-cryptography/sha256"; import { sha256 } from "ethereum-cryptography/sha256";
import { LRUCache } from "lru-cache"; import { LRUCache } from "lru-cache";
@ -1131,7 +1131,7 @@ export async function createAndSubmitClaim(
// Enhanced diagnostic logging for claim submission // Enhanced diagnostic logging for claim submission
const requestId = `claim_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; const requestId = `claim_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
logger.info("[Claim Submission] 🚀 Starting claim submission:", { logger.debug("[Claim Submission] 🚀 Starting claim submission:", {
requestId, requestId,
apiServer, apiServer,
requesterDid: issuerDid, requesterDid: issuerDid,
@ -1157,7 +1157,7 @@ export async function createAndSubmitClaim(
}, },
}); });
logger.info("[Claim Submission] ✅ Claim submitted successfully:", { logger.debug("[Claim Submission] ✅ Claim submitted successfully:", {
requestId, requestId,
status: response.status, status: response.status,
handleId: response.data?.handleId, handleId: response.data?.handleId,
@ -1754,7 +1754,7 @@ export async function fetchImageRateLimits(
axios: Axios, axios: Axios,
issuerDid: string, issuerDid: string,
imageServer?: string, imageServer?: string,
) { ): Promise<AxiosResponse | null> {
const server = imageServer || DEFAULT_IMAGE_API_SERVER; const server = imageServer || DEFAULT_IMAGE_API_SERVER;
const url = server + "/image-limits"; const url = server + "/image-limits";
const headers = await getHeaders(issuerDid); const headers = await getHeaders(issuerDid);
@ -1788,7 +1788,7 @@ export async function fetchImageRateLimits(
}; };
}; };
logger.warn("[Image Server] Image rate limits check failed:", { logger.error("[Image Server] Image rate limits check failed:", {
did: issuerDid, did: issuerDid,
server: server, server: server,
errorCode: axiosError.response?.data?.error?.code, errorCode: axiosError.response?.data?.error?.code,
@ -1796,7 +1796,6 @@ export async function fetchImageRateLimits(
httpStatus: axiosError.response?.status, httpStatus: axiosError.response?.status,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}); });
return null;
throw error;
} }
} }

37
src/services/migrationService.ts

@ -595,7 +595,7 @@ export async function runMigrations<T>(
try { try {
migrationLog("📋 [Migration] Starting migration process..."); migrationLog("📋 [Migration] Starting migration process...");
// Step 1: Create migrations table if it doesn't exist // Create migrations table if it doesn't exist
// Note: We use IF NOT EXISTS here because this is infrastructure, not a business migration // Note: We use IF NOT EXISTS here because this is infrastructure, not a business migration
await sqlExec(` await sqlExec(`
CREATE TABLE IF NOT EXISTS migrations ( CREATE TABLE IF NOT EXISTS migrations (
@ -604,41 +604,14 @@ export async function runMigrations<T>(
); );
`); `);
// Step 2: Handle migration name changes (master branch compatibility) // Step 2: Get list of already applied migrations
// Map old migration names to new ones
const migrationNameMap = new Map([
// No longer needed - migrations consolidated into single 003
]);
// Update any old migration names to new ones
for (const [oldName, newName] of migrationNameMap) {
try {
await sqlExec("UPDATE migrations SET name = ? WHERE name = ?", [
newName,
oldName,
]);
if (
await sqlQuery("SELECT 1 FROM migrations WHERE name = ? LIMIT 1", [
newName,
])
) {
migrationLog(
`🔄 [Migration] Renamed migration: ${oldName}${newName}`,
);
}
} catch (error) {
// Ignore errors - migration might not exist
}
}
// Step 3: Get list of already applied migrations
const appliedMigrationsResult = await sqlQuery( const appliedMigrationsResult = await sqlQuery(
"SELECT name FROM migrations", "SELECT name FROM migrations",
); );
const appliedMigrations = extractMigrationNames(appliedMigrationsResult); const appliedMigrations = extractMigrationNames(appliedMigrationsResult);
// Step 4: Get all registered migrations // Step 3: Get all registered migrations
const migrations = migrationRegistry.getMigrations(); const migrations = migrationRegistry.getMigrations();
if (migrations.length === 0) { if (migrations.length === 0) {
@ -653,7 +626,7 @@ export async function runMigrations<T>(
let appliedCount = 0; let appliedCount = 0;
let skippedCount = 0; let skippedCount = 0;
// Step 5: Process each migration // Step 4: Process each migration
for (const migration of migrations) { for (const migration of migrations) {
// Check 1: Is it recorded as applied in migrations table? // Check 1: Is it recorded as applied in migrations table?
const isRecordedAsApplied = appliedMigrations.has(migration.name); const isRecordedAsApplied = appliedMigrations.has(migration.name);
@ -775,7 +748,7 @@ export async function runMigrations<T>(
} }
} }
// Step 5: Final validation - verify all migrations are properly recorded // Step 6: Final validation - verify all migrations are properly recorded
const finalMigrationsResult = await sqlQuery("SELECT name FROM migrations"); const finalMigrationsResult = await sqlQuery("SELECT name FROM migrations");
const finalAppliedMigrations = extractMigrationNames(finalMigrationsResult); const finalAppliedMigrations = extractMigrationNames(finalMigrationsResult);

7
src/views/AccountViewView.vue

@ -1446,12 +1446,11 @@ export default class AccountViewView extends Vue {
this.DEFAULT_IMAGE_API_SERVER, this.DEFAULT_IMAGE_API_SERVER,
); );
if (imageResp.status === 200) { if (imageResp && imageResp.status === 200) {
this.imageLimits = imageResp.data; this.imageLimits = imageResp.data;
} else { } else {
this.limitsMessage = ACCOUNT_VIEW_CONSTANTS.LIMITS.NO_IMAGE_ACCESS; this.limitsMessage = ACCOUNT_VIEW_CONSTANTS.LIMITS.NO_IMAGE_ACCESS;
this.notify.warning(ACCOUNT_VIEW_CONSTANTS.LIMITS.CANNOT_UPLOAD_IMAGES); this.notify.warning(ACCOUNT_VIEW_CONSTANTS.LIMITS.CANNOT_UPLOAD_IMAGES);
return;
} }
const endorserResp = await fetchEndorserRateLimits( const endorserResp = await fetchEndorserRateLimits(
@ -1465,7 +1464,6 @@ export default class AccountViewView extends Vue {
} else { } else {
this.limitsMessage = ACCOUNT_VIEW_CONSTANTS.LIMITS.NO_LIMITS_FOUND; this.limitsMessage = ACCOUNT_VIEW_CONSTANTS.LIMITS.NO_LIMITS_FOUND;
this.notify.warning(ACCOUNT_VIEW_CONSTANTS.LIMITS.BAD_SERVER_RESPONSE); this.notify.warning(ACCOUNT_VIEW_CONSTANTS.LIMITS.BAD_SERVER_RESPONSE);
return;
} }
} catch (error) { } catch (error) {
this.limitsMessage = this.limitsMessage =
@ -1482,6 +1480,7 @@ export default class AccountViewView extends Vue {
error: error instanceof Error ? error.message : String(error), error: error instanceof Error ? error.message : String(error),
did: did, did: did,
apiServer: this.apiServer, apiServer: this.apiServer,
imageServer: this.DEFAULT_IMAGE_API_SERVER,
partnerApiServer: this.partnerApiServer, partnerApiServer: this.partnerApiServer,
errorCode: axiosError?.response?.data?.error?.code, errorCode: axiosError?.response?.data?.error?.code,
errorMessage: axiosError?.response?.data?.error?.message, errorMessage: axiosError?.response?.data?.error?.message,
@ -1996,7 +1995,7 @@ export default class AccountViewView extends Vue {
error: error instanceof Error ? error.message : String(error), error: error instanceof Error ? error.message : String(error),
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}); });
throw new Error("Failed to load profile"); return null;
} }
} }

Loading…
Cancel
Save