feat: get many endpoints (#2226)

Co-authored-by: Lucas Smith <me@lucasjamessmith.me>
This commit is contained in:
Catalin Pit
2025-12-24 02:02:02 +02:00
committed by GitHub
parent aa1cada79b
commit 90fdba8000
12 changed files with 927 additions and 0 deletions
+97
View File
@@ -18,6 +18,8 @@ const ZDocumentIdSchema = z.string().regex(/^document_\d+$/);
const ZTemplateIdSchema = z.string().regex(/^template_\d+$/);
const ZEnvelopeIdSchema = z.string().regex(/^envelope_.{2,}$/);
const MAX_ENVELOPE_IDS_PER_REQUEST = 20;
export type EnvelopeIdOptions =
| {
type: 'envelopeId';
@@ -32,6 +34,20 @@ export type EnvelopeIdOptions =
id: number;
};
export type EnvelopeIdsOptions =
| {
type: 'envelopeId';
ids: string[];
}
| {
type: 'documentId';
ids: number[];
}
| {
type: 'templateId';
ids: number[];
};
/**
* Parses an unknown document or template ID.
*
@@ -89,6 +105,87 @@ export const unsafeBuildEnvelopeIdQuery = (
.exhaustive();
};
/**
* Parses multiple document or template IDs and builds a query filter.
*
* This is UNSAFE because it does not validate access, it only validates ID format and builds the query.
*
* @throws AppError if any ID is invalid or if the array exceeds the maximum limit
*/
export const unsafeBuildEnvelopeIdsQuery = (
options: EnvelopeIdsOptions,
expectedEnvelopeType: EnvelopeType | null,
) => {
if (!options.ids || options.ids.length === 0) {
throw new AppError(AppErrorCode.INVALID_BODY, {
message: 'At least one ID is required',
});
}
if (options.ids.length > MAX_ENVELOPE_IDS_PER_REQUEST) {
throw new AppError(AppErrorCode.INVALID_BODY, {
message: `Cannot request more than ${MAX_ENVELOPE_IDS_PER_REQUEST} envelopes at once`,
});
}
return match(options)
.with({ type: 'envelopeId' }, (value) => {
const validatedIds: string[] = [];
for (const id of value.ids) {
const parsed = ZEnvelopeIdSchema.safeParse(id);
if (!parsed.success) {
throw new AppError(AppErrorCode.INVALID_BODY, {
message: `Invalid envelope ID: ${id}`,
});
}
validatedIds.push(parsed.data);
}
if (expectedEnvelopeType) {
return {
id: { in: validatedIds },
type: expectedEnvelopeType,
};
}
return {
id: { in: validatedIds },
};
})
.with({ type: 'documentId' }, (value) => {
if (expectedEnvelopeType && expectedEnvelopeType !== EnvelopeType.DOCUMENT) {
throw new AppError(AppErrorCode.INVALID_BODY, {
message: 'Invalid document ID type',
});
}
const secondaryIds = value.ids.map((id) => mapDocumentIdToSecondaryId(id));
return {
type: EnvelopeType.DOCUMENT,
secondaryId: { in: secondaryIds },
};
})
.with({ type: 'templateId' }, (value) => {
if (expectedEnvelopeType && expectedEnvelopeType !== EnvelopeType.TEMPLATE) {
throw new AppError(AppErrorCode.INVALID_BODY, {
message: 'Invalid template ID type',
});
}
const secondaryIds = value.ids.map((id) => mapTemplateIdToSecondaryId(id));
return {
type: EnvelopeType.TEMPLATE,
secondaryId: { in: secondaryIds },
};
})
.exhaustive();
};
/**
* Maps a legacy document ID number to an envelope secondary ID.
*