first commit
This commit is contained in:
78
src/client.ts
Normal file
78
src/client.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { ValidationError } from "./types/errors.ts";
|
||||
import { DEFAULT_CONFIG, ENDPOINTS } from "./constants.ts";
|
||||
import { handleResponse, toBlob } from "./utils.ts";
|
||||
import { ClientConfig } from "./types/config.ts";
|
||||
import { FileContent, ValidationResult } from "./types/validation.ts";
|
||||
|
||||
export class CaballoClient {
|
||||
private readonly config: ClientConfig;
|
||||
|
||||
constructor(config: ClientConfig) {
|
||||
this.config = {
|
||||
...DEFAULT_CONFIG,
|
||||
...config,
|
||||
};
|
||||
|
||||
if (!this.config.baseUrl) {
|
||||
throw new Error("baseUrl is required");
|
||||
}
|
||||
}
|
||||
|
||||
async validateXml(content: FileContent): Promise<ValidationResult> {
|
||||
try {
|
||||
const blob = toBlob(content);
|
||||
|
||||
if (blob.size === 0) {
|
||||
throw new ValidationError("Empty file content");
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("file", blob);
|
||||
|
||||
const response = await fetch(
|
||||
`${this.config.baseUrl}${ENDPOINTS.validateXml}`,
|
||||
{
|
||||
method: "POST",
|
||||
body: formData,
|
||||
signal: AbortSignal.timeout(this.config.timeout!),
|
||||
},
|
||||
);
|
||||
|
||||
return handleResponse(response);
|
||||
} catch (error) {
|
||||
if (error instanceof TypeError) {
|
||||
throw new ValidationError("Network error or invalid URL");
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async validatePdf(content: FileContent): Promise<ValidationResult> {
|
||||
try {
|
||||
const blob = toBlob(content);
|
||||
|
||||
if (blob.size === 0) {
|
||||
throw new ValidationError("Empty file content");
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("file", blob);
|
||||
|
||||
const response = await fetch(
|
||||
`${this.config.baseUrl}${ENDPOINTS.validatePdf}`,
|
||||
{
|
||||
method: "POST",
|
||||
body: formData,
|
||||
signal: AbortSignal.timeout(this.config.timeout!),
|
||||
},
|
||||
);
|
||||
|
||||
return handleResponse(response);
|
||||
} catch (error) {
|
||||
if (error instanceof TypeError) {
|
||||
throw new ValidationError("Network error or invalid URL");
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
src/constants.ts
Normal file
11
src/constants.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { ClientConfig } from "./types/config.ts";
|
||||
|
||||
export const DEFAULT_CONFIG: Partial<ClientConfig> = {
|
||||
timeout: 30000,
|
||||
retries: 3,
|
||||
};
|
||||
|
||||
export const ENDPOINTS = {
|
||||
validateXml: "/api/v1/e-invoice/validate/xml",
|
||||
validatePdf: "/api/v1/e-invoice/validate/pdf",
|
||||
} as const;
|
||||
4
src/mod.ts
Normal file
4
src/mod.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from "./client.ts";
|
||||
export * from "./types/config.ts";
|
||||
export * from "./types/errors.ts";
|
||||
export * from "./types/validation.ts";
|
||||
5
src/types/config.ts
Normal file
5
src/types/config.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface ClientConfig {
|
||||
baseUrl: string;
|
||||
timeout?: number;
|
||||
retries?: number;
|
||||
}
|
||||
12
src/types/errors.ts
Normal file
12
src/types/errors.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export class ValidationError extends Error {
|
||||
constructor(message: string, public statusCode?: number) {
|
||||
super(message);
|
||||
this.name = "ValidationError";
|
||||
}
|
||||
}
|
||||
|
||||
export interface ApiError {
|
||||
status: string;
|
||||
message: string;
|
||||
details?: string;
|
||||
}
|
||||
8
src/types/validation.ts
Normal file
8
src/types/validation.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export interface ValidationResult {
|
||||
valid: boolean;
|
||||
conformanceLevel?: string;
|
||||
structureErrors?: string[];
|
||||
pdfErrors?: string[];
|
||||
}
|
||||
|
||||
export type FileContent = Uint8Array | Blob | File;
|
||||
24
src/utils.ts
Normal file
24
src/utils.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { ApiError, ValidationError } from "./types/errors.ts";
|
||||
import { FileContent, ValidationResult } from "./types/validation.ts";
|
||||
|
||||
export function toBlob(content: FileContent): Blob {
|
||||
if (content instanceof Blob) return content;
|
||||
return new Blob([content]);
|
||||
}
|
||||
|
||||
export async function handleResponse(
|
||||
response: Response,
|
||||
): Promise<ValidationResult> {
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({
|
||||
message: response.statusText,
|
||||
status: `${response.status}`,
|
||||
})) as ApiError;
|
||||
throw new ValidationError(
|
||||
errorData.message || "Unknown error",
|
||||
response.status,
|
||||
);
|
||||
}
|
||||
const data = await response.json();
|
||||
return data as ValidationResult;
|
||||
}
|
||||
Reference in New Issue
Block a user