generated from coulomb/repo-seed
Add Binect SDK implementation, Explorer, and test suite
SDK (@binect/js): - BinectClient with domain sub-clients (documents, sendings, accounts, attachments, invoices) - HTTP Basic Auth, native fetch only (no runtime dependencies) - TypeScript types matching Binect API vocabulary - Status predicates and polling helpers in helpers.ts - Structured error handling (BinectApiError, BinectAuthError) Explorer: - Standalone browser-based API explorer (explorer/index.html) - Interactive testing without code Tests: - Unit tests for client, types, errors, helpers, http - E2E tests for upload/delete and send/cancel workflows Also includes: - Architecture Decision Records (ADRs) - Example DIN 5008 letter PDFs for testing - API specification research notes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
352
src/clients/documents.ts
Normal file
352
src/clients/documents.ts
Normal file
@@ -0,0 +1,352 @@
|
||||
import type { HttpClient } from '../http.js';
|
||||
import type {
|
||||
Document,
|
||||
DocumentUploadOptions,
|
||||
DocumentUploadRequestBody,
|
||||
DocumentTransformation,
|
||||
CoverPageOptions,
|
||||
DocumentAttribute,
|
||||
ListResponse,
|
||||
PaginationOptions,
|
||||
} from '../types.js';
|
||||
|
||||
/**
|
||||
* Client for document-related API operations.
|
||||
* Handles document upload, retrieval, modification, and preview.
|
||||
*/
|
||||
export class DocumentsClient {
|
||||
constructor(private readonly http: HttpClient) {}
|
||||
|
||||
/**
|
||||
* Upload a new document (letter or serial letter).
|
||||
* POST /documents
|
||||
*
|
||||
* @param options - Document upload options including base64-encoded PDF content
|
||||
* @returns The created document with validation results
|
||||
*/
|
||||
async upload(options: DocumentUploadOptions): Promise<Document> {
|
||||
// Transform user-friendly options to API request body format
|
||||
const requestBody: DocumentUploadRequestBody = {
|
||||
content: {
|
||||
filename: options.filename,
|
||||
content: options.content,
|
||||
},
|
||||
};
|
||||
|
||||
// Add options if any are specified
|
||||
if (options.simplex !== undefined || options.color !== undefined ||
|
||||
options.envelope !== undefined || options.franking !== undefined ||
|
||||
options.productionCountry !== undefined) {
|
||||
requestBody.options = {
|
||||
simplex: options.simplex,
|
||||
color: options.color,
|
||||
envelope: options.envelope,
|
||||
franking: options.franking,
|
||||
productionCountry: options.productionCountry,
|
||||
};
|
||||
}
|
||||
|
||||
// Add attributes if specified
|
||||
if (options.attributes) {
|
||||
requestBody.attributes = options.attributes;
|
||||
}
|
||||
|
||||
// Add split params if specified
|
||||
if (options.splitToken !== undefined || options.pagesPerLetter !== undefined) {
|
||||
requestBody.splitParams = {
|
||||
splitToken: options.splitToken,
|
||||
splitAfterNumberOfPages: options.pagesPerLetter,
|
||||
};
|
||||
}
|
||||
|
||||
// Add response format if specified
|
||||
if (options.responseFormat !== undefined) {
|
||||
requestBody.responseFormat = options.responseFormat;
|
||||
}
|
||||
|
||||
return this.http.request<Document>({
|
||||
method: 'POST',
|
||||
path: '/documents',
|
||||
body: requestBody,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* List all shippable documents (status 2).
|
||||
* GET /documents
|
||||
*
|
||||
* @param pagination - Optional pagination parameters
|
||||
* @returns List of shippable documents
|
||||
*/
|
||||
async list(pagination?: PaginationOptions): Promise<ListResponse<Document>> {
|
||||
return this.http.request<ListResponse<Document>>({
|
||||
method: 'GET',
|
||||
path: '/documents',
|
||||
query: pagination,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* List all documents with errors (status 7).
|
||||
* GET /documents/errors
|
||||
*
|
||||
* @param pagination - Optional pagination parameters
|
||||
* @returns List of erroneous documents
|
||||
*/
|
||||
async listErrors(pagination?: PaginationOptions): Promise<ListResponse<Document>> {
|
||||
return this.http.request<ListResponse<Document>>({
|
||||
method: 'GET',
|
||||
path: '/documents/errors',
|
||||
query: pagination,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific document by ID.
|
||||
* GET /documents/{documentID}
|
||||
*
|
||||
* @param documentId - The document ID
|
||||
* @returns The document details
|
||||
*/
|
||||
async get(documentId: string): Promise<Document> {
|
||||
return this.http.request<Document>({
|
||||
method: 'GET',
|
||||
path: `/documents/${encodeURIComponent(documentId)}`,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a document.
|
||||
* DELETE /documents/{documentID}
|
||||
*
|
||||
* @param documentId - The document ID to delete
|
||||
*/
|
||||
async delete(documentId: string): Promise<void> {
|
||||
await this.http.request<void>({
|
||||
method: 'DELETE',
|
||||
path: `/documents/${encodeURIComponent(documentId)}`,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all attributes for a document.
|
||||
* GET /documents/{documentID}/attributes
|
||||
*
|
||||
* @param documentId - The document ID
|
||||
* @returns Key-value attributes
|
||||
*/
|
||||
async getAttributes(documentId: string): Promise<Record<string, string>> {
|
||||
return this.http.request<Record<string, string>>({
|
||||
method: 'GET',
|
||||
path: `/documents/${encodeURIComponent(documentId)}/attributes`,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set attributes for a document.
|
||||
* POST /documents/{documentID}/attributes
|
||||
*
|
||||
* @param documentId - The document ID
|
||||
* @param attributes - Array of key-value attributes to set
|
||||
*/
|
||||
async setAttributes(documentId: string, attributes: DocumentAttribute[]): Promise<void> {
|
||||
await this.http.request<void>({
|
||||
method: 'POST',
|
||||
path: `/documents/${encodeURIComponent(documentId)}/attributes`,
|
||||
body: attributes,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific attribute value.
|
||||
* GET /documents/{documentID}/attributes/{key}
|
||||
*
|
||||
* @param documentId - The document ID
|
||||
* @param key - The attribute key
|
||||
* @returns The attribute value
|
||||
*/
|
||||
async getAttribute(documentId: string, key: string): Promise<string> {
|
||||
return this.http.request<string>({
|
||||
method: 'GET',
|
||||
path: `/documents/${encodeURIComponent(documentId)}/attributes/${encodeURIComponent(key)}`,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a specific attribute value.
|
||||
* PUT /documents/{documentID}/attributes/{key}
|
||||
*
|
||||
* @param documentId - The document ID
|
||||
* @param key - The attribute key
|
||||
* @param value - The new attribute value
|
||||
*/
|
||||
async updateAttribute(documentId: string, key: string, value: string): Promise<void> {
|
||||
await this.http.request<void>({
|
||||
method: 'PUT',
|
||||
path: `/documents/${encodeURIComponent(documentId)}/attributes/${encodeURIComponent(key)}`,
|
||||
body: { value },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a specific attribute.
|
||||
* DELETE /documents/{documentID}/attributes/{key}
|
||||
*
|
||||
* @param documentId - The document ID
|
||||
* @param key - The attribute key to delete
|
||||
*/
|
||||
async deleteAttribute(documentId: string, key: string): Promise<void> {
|
||||
await this.http.request<void>({
|
||||
method: 'DELETE',
|
||||
path: `/documents/${encodeURIComponent(documentId)}/attributes/${encodeURIComponent(key)}`,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply transformations (scaling/offset) to a document.
|
||||
* PUT /documents/{documentID}/transformations
|
||||
*
|
||||
* @param documentId - The document ID
|
||||
* @param transformation - Transformation parameters
|
||||
* @returns The updated document
|
||||
*/
|
||||
async applyTransformation(
|
||||
documentId: string,
|
||||
transformation: DocumentTransformation
|
||||
): Promise<Document> {
|
||||
return this.http.request<Document>({
|
||||
method: 'PUT',
|
||||
path: `/documents/${encodeURIComponent(documentId)}/transformations`,
|
||||
body: transformation,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Revert transformations to original document.
|
||||
* DELETE /documents/{documentID}/transformations
|
||||
*
|
||||
* @param documentId - The document ID
|
||||
* @returns The updated document
|
||||
*/
|
||||
async revertTransformation(documentId: string): Promise<Document> {
|
||||
return this.http.request<Document>({
|
||||
method: 'DELETE',
|
||||
path: `/documents/${encodeURIComponent(documentId)}/transformations`,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a cover page to a document.
|
||||
* PUT /documents/{documentID}/coverpage
|
||||
*
|
||||
* @param documentId - The document ID
|
||||
* @param options - Cover page options with base64-encoded PDF
|
||||
* @returns The updated document
|
||||
*/
|
||||
async addCoverPage(documentId: string, options: CoverPageOptions): Promise<Document> {
|
||||
return this.http.request<Document>({
|
||||
method: 'PUT',
|
||||
path: `/documents/${encodeURIComponent(documentId)}/coverpage`,
|
||||
body: options,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the cover page from a document.
|
||||
* DELETE /documents/{documentID}/coverpage
|
||||
*
|
||||
* @param documentId - The document ID
|
||||
* @returns The updated document
|
||||
*/
|
||||
async removeCoverPage(documentId: string): Promise<Document> {
|
||||
return this.http.request<Document>({
|
||||
method: 'DELETE',
|
||||
path: `/documents/${encodeURIComponent(documentId)}/coverpage`,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get PDF preview of a document.
|
||||
* GET /documents/{documentID}/pdf
|
||||
*
|
||||
* @param documentId - The document ID
|
||||
* @returns Response containing PDF data
|
||||
*/
|
||||
async getPdf(documentId: string): Promise<Response> {
|
||||
return this.http.requestRaw({
|
||||
method: 'GET',
|
||||
path: `/documents/${encodeURIComponent(documentId)}/pdf`,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get PNG preview of a document (first page).
|
||||
* GET /documents/{documentID}/png
|
||||
*
|
||||
* @param documentId - The document ID
|
||||
* @returns Response containing PNG data
|
||||
*/
|
||||
async getPng(documentId: string): Promise<Response> {
|
||||
return this.http.requestRaw({
|
||||
method: 'GET',
|
||||
path: `/documents/${encodeURIComponent(documentId)}/png`,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attachments for a document.
|
||||
* GET /documents/{documentID}/attachments
|
||||
*
|
||||
* @param documentId - The document ID
|
||||
* @returns Array of attachment IDs
|
||||
*/
|
||||
async getAttachments(documentId: string): Promise<string[]> {
|
||||
return this.http.request<string[]>({
|
||||
method: 'GET',
|
||||
path: `/documents/${encodeURIComponent(documentId)}/attachments`,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an attachment to a document.
|
||||
* POST /documents/{documentID}/attachments
|
||||
*
|
||||
* @param documentId - The document ID
|
||||
* @param attachmentId - The attachment ID to add
|
||||
*/
|
||||
async addAttachment(documentId: string, attachmentId: string): Promise<void> {
|
||||
await this.http.request<void>({
|
||||
method: 'POST',
|
||||
path: `/documents/${encodeURIComponent(documentId)}/attachments`,
|
||||
body: { attachmentId },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update attachments for a document (replace all).
|
||||
* PATCH /documents/{documentID}/attachments
|
||||
*
|
||||
* @param documentId - The document ID
|
||||
* @param attachmentIds - Array of attachment IDs
|
||||
*/
|
||||
async updateAttachments(documentId: string, attachmentIds: string[]): Promise<void> {
|
||||
await this.http.request<void>({
|
||||
method: 'PATCH',
|
||||
path: `/documents/${encodeURIComponent(documentId)}/attachments`,
|
||||
body: { attachmentIds },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all attachments from a document.
|
||||
* DELETE /documents/{documentID}/attachments
|
||||
*
|
||||
* @param documentId - The document ID
|
||||
*/
|
||||
async removeAttachments(documentId: string): Promise<void> {
|
||||
await this.http.request<void>({
|
||||
method: 'DELETE',
|
||||
path: `/documents/${encodeURIComponent(documentId)}/attachments`,
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user