fix(documenso): skip legacy v1 document IDs in the v2 status poller
The signature-poll worker fetched every sent/partially_signed document via
GET /api/v2/envelope/{id}. Pre-cutover documents carry a bare numeric
documenso_id (e.g. "46"), which the v2 envelope endpoint rejects with 400
"Invalid envelope ID" — ~36 errors/hour on prod from 3 abandoned June-3 EOIs.
Skip documents whose documenso_id isn't an `envelope_xxx` string when the
port is on the v2 API (v1-API ports keep polling numeric ids). New v2 signing
is unaffected. Pure isPollableDocumensoId() helper, unit-tested.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L2qc3xZTfif7N4Wq3QDa8X
This commit is contained in:
@@ -9,8 +9,25 @@ import {
|
||||
handleDocumentExpired,
|
||||
handleDocumentRejected,
|
||||
} from '@/lib/services/documents.service';
|
||||
import { getPortDocumensoConfig, type DocumensoApiVersion } from '@/lib/services/port-config';
|
||||
import { logger } from '@/lib/logger';
|
||||
|
||||
/**
|
||||
* Whether a document's `documensoId` can be fetched under the port's current
|
||||
* Documenso API version. A v2 envelope id is the public `envelope_xxx` string;
|
||||
* a legacy v1 id is a bare numeric (e.g. "46"). The v2 `/api/v2/envelope/{id}`
|
||||
* endpoint rejects numerics with a 400 "Invalid envelope ID", so a port that
|
||||
* has cut over to v2 must SKIP its old v1 documents in the poll instead of
|
||||
* erroring on every cycle. Ports still on the v1 API keep polling numeric ids.
|
||||
*/
|
||||
export function isPollableDocumensoId(
|
||||
documensoId: string,
|
||||
apiVersion: DocumensoApiVersion,
|
||||
): boolean {
|
||||
if (apiVersion === 'v2' && !documensoId.startsWith('envelope_')) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
export async function processDocumensoPoll(): Promise<void> {
|
||||
// Find all documents that are in-progress signing and have a documensoId
|
||||
const pendingDocs = await db.query.documents.findMany({
|
||||
@@ -24,9 +41,25 @@ export async function processDocumensoPoll(): Promise<void> {
|
||||
|
||||
logger.info({ count: pendingDocs.length }, 'Polling Documenso for document statuses');
|
||||
|
||||
// Per-port API version, resolved once per port (cheap memo for the run).
|
||||
const apiVersionByPort = new Map<string, DocumensoApiVersion>();
|
||||
let skippedLegacy = 0;
|
||||
|
||||
for (const doc of pendingDocs) {
|
||||
if (!doc.documensoId) continue;
|
||||
|
||||
let apiVersion = apiVersionByPort.get(doc.portId);
|
||||
if (!apiVersion) {
|
||||
apiVersion = (await getPortDocumensoConfig(doc.portId)).apiVersion;
|
||||
apiVersionByPort.set(doc.portId, apiVersion);
|
||||
}
|
||||
// Skip legacy v1 documents the port's v2 API can't resolve — otherwise each
|
||||
// poll cycle 400s ("Invalid envelope ID") on abandoned pre-cutover docs.
|
||||
if (!isPollableDocumensoId(doc.documensoId, apiVersion)) {
|
||||
skippedLegacy++;
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
// Pass the doc's portId so the client uses per-port credentials
|
||||
// (admin-set Documenso URL/key/version), not the global env fallback.
|
||||
@@ -112,4 +145,11 @@ export async function processDocumensoPoll(): Promise<void> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (skippedLegacy > 0) {
|
||||
logger.info(
|
||||
{ skippedLegacy },
|
||||
'Documenso poll: skipped legacy v1 documents not resolvable on the v2 API',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user