From e8f8f57023cf207aaa1779a23a4e7a456ca379e4 Mon Sep 17 00:00:00 2001 From: John Blackbourn Date: Wed, 21 Jan 2026 11:39:36 +0100 Subject: [PATCH 1/3] Update the PLC error message formatting. --- src/cli/lib/plc-error.ts | 16 ++++++++++------ test/cli/plc-error.test.ts | 15 ++++++--------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/cli/lib/plc-error.ts b/src/cli/lib/plc-error.ts index b2bde68..871d3db 100644 --- a/src/cli/lib/plc-error.ts +++ b/src/cli/lib/plc-error.ts @@ -1,5 +1,10 @@ import { PlcClientError } from '@did-plc/lib'; +const useColor = process.stderr.isTTY && !process.env.NO_COLOR; +const red = useColor ? '\x1b[31m' : ''; +const yellow = useColor ? '\x1b[33m' : ''; +const reset = useColor ? '\x1b[0m' : ''; + interface PlcErrorOptions { includeData?: boolean; } @@ -14,17 +19,16 @@ interface PlcErrorContext { * The @did-plc/lib library throws PlcClientError which has: * - status: HTTP status code * - data: Response body from PLC server (often contains error details) - * - message: Generic axios error message + * - message: Generic axios error message (e.g. "Request failed with status code 400") */ export function formatPlcError(err: PlcClientError, { includeData = true }: PlcErrorOptions = {}): string { - // Check if this is a PlcClientError with additional data const data = err.data as string | { message?: string; error?: string } | undefined; if (err.status && data && includeData) { const details = typeof data === 'string' ? data : data.message || data.error || JSON.stringify(data); - return `${err.message} (${err.status}): ${details}`; + return `(${err.status}) ${details}`; } if (err.status) { - return `${err.message} (${err.status})`; + return `(${err.status})`; } return err.message; } @@ -34,9 +38,9 @@ export function formatPlcError(err: PlcClientError, { includeData = true }: PlcE */ export function logPlcError(prefix: string, err: PlcClientError, context: PlcErrorContext = {}): void { const hints = diagnosePlcError(err, context); - console.error(`\x1b[31m${prefix}: ${formatPlcError(err, { includeData: hints.length === 0 })}\x1b[0m`); + console.error(`${red}${prefix}: ${formatPlcError(err, { includeData: hints.length === 0 })}${reset}`); for (const hint of hints) { - console.error(`\x1b[33m - ${hint}\x1b[0m`); + console.error(`${yellow} - ${hint}${reset}`); } } diff --git a/test/cli/plc-error.test.ts b/test/cli/plc-error.test.ts index 243b126..3f42189 100644 --- a/test/cli/plc-error.test.ts +++ b/test/cli/plc-error.test.ts @@ -12,44 +12,41 @@ describe('formatPlcError', () => { const err = new Error('Request failed with status code 400'); err.status = 400; err.data = 'Invalid signature on op'; - assert.strictEqual(formatPlcError(err), 'Request failed with status code 400 (400): Invalid signature on op'); + assert.strictEqual(formatPlcError(err), '(400) Invalid signature on op'); }); it('formats PlcClientError with object data containing message', () => { const err = new Error('Request failed with status code 400'); err.status = 400; err.data = { message: 'Key not found' }; - assert.strictEqual(formatPlcError(err), 'Request failed with status code 400 (400): Key not found'); + assert.strictEqual(formatPlcError(err), '(400) Key not found'); }); it('formats PlcClientError with object data containing error', () => { const err = new Error('Request failed with status code 500'); err.status = 500; err.data = { error: 'Internal server error' }; - assert.strictEqual(formatPlcError(err), 'Request failed with status code 500 (500): Internal server error'); + assert.strictEqual(formatPlcError(err), '(500) Internal server error'); }); it('JSON stringifies object data without message or error', () => { const err = new Error('Request failed with status code 400'); err.status = 400; err.data = { code: 'INVALID_OP', details: 'bad' }; - assert.strictEqual( - formatPlcError(err), - 'Request failed with status code 400 (400): {"code":"INVALID_OP","details":"bad"}', - ); + assert.strictEqual(formatPlcError(err), '(400) {"code":"INVALID_OP","details":"bad"}'); }); it('excludes data when includeData is false', () => { const err = new Error('Request failed with status code 400'); err.status = 400; err.data = 'Some detailed error message'; - assert.strictEqual(formatPlcError(err, { includeData: false }), 'Request failed with status code 400 (400)'); + assert.strictEqual(formatPlcError(err, { includeData: false }), '(400)'); }); it('returns status without data when error has status but no data', () => { const err = new Error('Request failed with status code 404'); err.status = 404; - assert.strictEqual(formatPlcError(err), 'Request failed with status code 404 (404)'); + assert.strictEqual(formatPlcError(err), '(404)'); }); }); From e3f6816a48d11d2fe6f6d841f715eda34d31ada2 Mon Sep 17 00:00:00 2001 From: John Blackbourn Date: Wed, 21 Jan 2026 11:39:50 +0100 Subject: [PATCH 2/3] Rename this function. --- index.ts | 2 +- src/cli/did-service-add.ts | 4 ++-- src/did.ts | 4 ++-- src/plc.ts | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/index.ts b/index.ts index 5987846..fb0a8a2 100644 --- a/index.ts +++ b/index.ts @@ -13,7 +13,7 @@ export { PLC_DIRECTORY_URL, FAIR_SERVICE_TYPE, FAIR_SERVICE_ID, - updateDID, + setFairServiceUrl, addVerificationKey, addRotationKey, revokeVerificationKey, diff --git a/src/cli/did-service-add.ts b/src/cli/did-service-add.ts index 1820dd0..ac21e96 100644 --- a/src/cli/did-service-add.ts +++ b/src/cli/did-service-add.ts @@ -3,7 +3,7 @@ import { parseArgs } from 'node:util'; import { PlcClientError } from '@did-plc/lib'; import { importRotationKeyPair } from '../keys.js'; -import { updateDID } from '../plc.js'; +import { setFairServiceUrl } from '../plc.js'; import { loadRotationKey, SigningKeyError } from '../signing.js'; import { logPlcError } from './lib/plc-error.js'; import { rotationKeyHelp } from './lib/help.js'; @@ -88,7 +88,7 @@ const { keypair, publicKey: signerPublicKey } = await importRotationKeyPair(priv console.log(`Updating DID ${did}...`); try { - await updateDID({ + await setFairServiceUrl({ did, serviceUrl: url, signer: keypair, diff --git a/src/did.ts b/src/did.ts index 1f21de7..0507913 100644 --- a/src/did.ts +++ b/src/did.ts @@ -32,7 +32,7 @@ function createGenesisOperation({ verificationKey, rotationKeys }: GenesisOperat * * This creates the initial operation for a new PLC DID for a FAIR package. * The operation does NOT include the FAIR service - this should be - * added in a subsequent updateDID() operation after the DID is created. + * added in a subsequent setFairServiceUrl() operation after the DID is created. */ interface GenerateDIDOptions { verificationKey: string; @@ -66,7 +66,7 @@ interface CreateDIDOptions { /** * Creates a new FAIR package DID and submits it to the PLC directory. * - * This creates the DID without a FAIR service initially. Use updateDID() + * This creates the DID without a FAIR service initially. Use setFairServiceUrl() * to add the service URL after the DID is created. */ export async function createDID({ diff --git a/src/plc.ts b/src/plc.ts index 8798c04..4682326 100644 --- a/src/plc.ts +++ b/src/plc.ts @@ -101,12 +101,12 @@ export async function submitDID({ op, did, plcUrl = PLC_DIRECTORY_URL }: SubmitD } /** - * Updates the FAIR service URL for an existing DID. + * Sets the FAIR service URL for an existing DID. * * This adds or updates the FAIR package management service endpoint * in the DID document. */ -export async function updateDID({ +export async function setFairServiceUrl({ did, serviceUrl, signer, From 9751115bd82e9d842182eb3bbb17f8809490de77 Mon Sep 17 00:00:00 2001 From: John Blackbourn Date: Wed, 21 Jan 2026 11:40:08 +0100 Subject: [PATCH 3/3] Allow this to be globally overridden with an environment variable. --- src/plc.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plc.ts b/src/plc.ts index 4682326..69f550e 100644 --- a/src/plc.ts +++ b/src/plc.ts @@ -21,8 +21,10 @@ export const FAIR_SERVICE_ID = 'fairpm_repo'; /** * Default PLC directory URL. + * + * Can be overridden via the PLC_DIRECTORY_URL environment variable (for testing). */ -export const PLC_DIRECTORY_URL = 'https://plc.directory'; +export const PLC_DIRECTORY_URL = process.env.PLC_DIRECTORY_URL ?? 'https://plc.directory'; /** * Creates a PLC directory client.