Enriching publisher plugin error capture & unify its database setup and migration paths#35
Enriching publisher plugin error capture & unify its database setup and migration paths#35
Conversation
- Make Drizzle migrations the single source of truth, replacing dual raw DDL + Drizzle paths in setup.js - Auto-run migrations on plugin startup (zero manual steps for updates) - Add bootstrap guard for databases created by old setup.js (seeds __drizzle_migrations journal so Drizzle can take over) - Fix migration 0001 FK incompatibility: change PKs from serial (BIGINT UNSIGNED) to int AUTO_INCREMENT to match int FK columns - Add 0002 migration for error_details column and private_key rename - Fix migration folder path resolution for tsup flat bundle output - Improve setup.js: hide password input, fix Mode 1 config overwrite, replace raw DDL with migrate(), update wording - Add structured error details to publishing attempts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Mode 1 is now "Start fresh" with a warning about table deletion - Mode 2 is now "Update existing configuration" - Mode 3 remains "Add wallets only"
There was a problem hiding this comment.
Pull request overview
This PR enhances the DKG publisher plugin by persisting structured error context for failed publishing attempts and consolidating database setup/migration flows around Drizzle migrations (including bootstrapping legacy databases without a migration journal).
Changes:
- Add
error_detailsJSON support end-to-end (DB column + error serialization + propagation through publishing/queue pipeline). - Introduce migration-journal bootstrapping for legacy (setup.js raw-DDL) databases and run migrations on plugin startup.
- Update schema/migrations to use
int AUTO_INCREMENTPKs (and FK handling) and renameprivate_key_encrypted→private_key; refactorsetup.jsto use Drizzle migrations.
Reviewed changes
Copilot reviewed 17 out of 18 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/plugin-dkg-publisher/src/services/index.ts | Runs migration bootstrap + migrations during service initialization. |
| packages/plugin-dkg-publisher/src/services/errorUtils.ts | New helper to serialize errors into structured JSON for persistence. |
| packages/plugin-dkg-publisher/src/services/QueueService.ts | Propagates/serializes errorDetails into failed publishing attempts. |
| packages/plugin-dkg-publisher/src/services/PublishingService.ts | Returns structured error details from DKG publish failures. |
| packages/plugin-dkg-publisher/src/services/AssetService.ts | Extends attempt-update payload to include errorDetails. |
| packages/plugin-dkg-publisher/src/services/WalletService.ts | Removes legacy remapping for privateKeyEncrypted → privateKey. |
| packages/plugin-dkg-publisher/src/database/bootstrap.ts | Bootstraps __drizzle_migrations for legacy DBs so Drizzle can take over. |
| packages/plugin-dkg-publisher/src/database/index.ts | Runs migrations via a dedicated connection and updates migrations folder path. |
| packages/plugin-dkg-publisher/src/database/schema.ts | Switches PKs to int().autoincrement(), adds error_details JSON, renames private_key. |
| packages/plugin-dkg-publisher/src/database/migrations/0001_amused_dexter_bennett.sql | Adjusts PK/FK types and drops/re-adds FKs around column changes. |
| packages/plugin-dkg-publisher/src/database/migrations/0002_add_error_details.sql | Adds error_details column and renames private_key_encrypted → private_key. |
| packages/plugin-dkg-publisher/src/database/migrations/meta/_journal.json | Adds journal entry for migration 0002. |
| packages/plugin-dkg-publisher/src/database/migrations/meta/0002_snapshot.json | Snapshot update for migration 0002 state. |
| packages/plugin-dkg-publisher/setup.js | Replaces raw DDL with Drizzle migrations; adds legacy bootstrap and UX improvements. |
| packages/plugin-dkg-publisher/migrate.js | Removes standalone migration script. |
| package.json | Updates dependency set (including dkg.js). |
| package-lock.json | Lockfile refresh reflecting dependency changes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| function sanitize(value: unknown): unknown { | ||
| if (value === null || value === undefined) return value; | ||
| if (typeof value === "bigint") return value.toString(); | ||
| if (typeof value === "function") return undefined; | ||
| if (typeof value !== "object") return value; | ||
|
|
||
| if (seen.has(value as object)) return "[Circular]"; | ||
| seen.add(value as object); | ||
|
|
||
| if (Array.isArray(value)) { | ||
| return value.map(sanitize); | ||
| } | ||
|
|
||
| const result: Record<string, unknown> = {}; | ||
| for (const key of Object.keys(value as Record<string, unknown>)) { | ||
| if (key === "stack") continue; | ||
| result[key] = sanitize((value as Record<string, unknown>)[key]); | ||
| } | ||
| return result; |
There was a problem hiding this comment.
serializeErrorDetails claims to capture useful Error properties, but nested Error instances (e.g. via cause) are currently sanitized as plain objects, which drops non-enumerable fields like name/message (and you also always skip stack). This means nested causes won’t be meaningfully captured. Consider special-casing Error inside sanitize (and/or aligning the docstring) so nested errors retain name/message (and optionally a truncated stack) while still protecting against cycles.
| import { Database, createDatabase, runMigrations } from "../database"; | ||
| import { bootstrapMigrationJournal } from "../database/bootstrap"; |
There was a problem hiding this comment.
Database is imported here but never used, which will fail linting/TS settings that disallow unused imports. Remove it or use it for an explicit type annotation where needed.
Summary
This PR adds structured error details to publishing attempts and unifies the publisher plugin's database management under Drizzle migrations as the single source of truth.
Structured error details
error_detailsJSON column onpublishing_attemptstable for capturing rich error context from DKG publish failureserrorUtils.tsutility for extracting structured error info (error type, message, stack traces, nested causes)PublishingServiceandQueueServiceupdated to store and propagate structured error details through the publishing pipelineUnified database migrations
bootstrapMigrationJournal()+runMigrations()during initialization. Users pulling updates get schema changes automatically with zero manual steps.setup.js(no__drizzle_migrationstable) are detected and have their migration journal seeded so Drizzle can take over without re-running CREATE TABLE.migrate(). Mode 1 (Fresh) drops all tables then runs migrations. Mode 2 (Update) applies only pending migrations.char(36)toserial(BIGINT UNSIGNED) but FK columns toint(signed). MySQL requires exact type match. Fixed by usingint AUTO_INCREMENTfor PKs and explicitly dropping/re-adding FK constraints around column type changes.private_key_encrypted→private_key(folded into migration 0002 alongsideerror_details)migrate.js— No longer needed since migrations auto-run on startup andsetup.jshandles all setup paths.Setup script improvements
Files changed
src/services/errorUtils.tssrc/services/PublishingService.tserror_detailson failed attemptssrc/services/QueueService.tssrc/services/AssetService.tssrc/database/bootstrap.tssrc/database/index.tssrc/database/schema.tsserial→int().autoincrement()for PKs;private_key_encrypted→private_keysrc/database/migrations/0001_*.sqlserial→int AUTO_INCREMENTsrc/database/migrations/0002_*.sqlerror_detailscolumn, renamesprivate_key_encrypted→private_keysrc/database/migrations/meta/*src/database/migrations/20250905_*.sqlsrc/services/index.tssrc/services/WalletService.tsprivateKeyEncryptedremappingsetup.jsmigrate(), added bootstrap guard, UX fixes, reordered modesmigrate.jspackage.jsondkg.jsdependencypackage-lock.jsonAll paths relative to
packages/plugin-dkg-publisher/unless otherwise noted.Test plan
error_detailscolumn andprivate_keycolumn__drizzle_migrations→ start plugin → verify bootstrap seeds journal + applies pending migrationserror_detailsJSON is populated inpublishing_attemptsnpm run dev→ verify auto-migration runs on startupnpm run buildpasses inpackages/plugin-dkg-publisher🤖 Generated with Claude Code