npm package: @logic-joe/logicforms-api
Description: API client for LogicForms - TypeScript client for the LogicForms REST API
Author: logic-joe
Latest version: 0.0.35

# @logic-joe/logicforms-api

[![npm version](https://img.shields.io/npm/v/@logic-joe/logicforms-api.svg)](https://www.npmjs.com/package/@logic-joe/logicforms-api)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)

TypeScript API client for the LogicForms REST API. A lightweight, fetch-based client with full type safety.

## Installation

```bash
npm install @logic-joe/logicforms-api
# or
pnpm add @logic-joe/logicforms-api
# or
yarn add @logic-joe/logicforms-api
```

## Quick Start

```typescript
import { createFormServiceClient } from "@logic-joe/logicforms-api";

// Create a client
const client = createFormServiceClient({
  baseUrl: "https://logicforms.onrender.com",
  apiKey: "your-api-key",
});

// Get a published form
const form = await client.getFormPublic({ id: "form_abc123" });
console.log(form.name, form.fields);

// Submit form data
const result = await client.submitForm({
  formId: "form_abc123",
  data: {
    email: "user@example.com",
    name: "John Doe",
  },
});
console.log("Submission ID:", result.submissionId);
```

## API Reference

### `createFormServiceClient(options)`

Creates a new API client instance.

```typescript
interface CreateClientOptions {
  baseUrl?: string; // Default: "https://logicforms.onrender.com"
  apiKey?: string; // Your API key
  credentials?: RequestCredentials; // Default: "omit"
}
```

### Client Methods

#### `getFormPublic({ id, locale? })`

Fetches a published form by ID.

```typescript
const form = await client.getFormPublic({
  id: "form_abc123",
  locale: "de", // Optional: request specific language
});

// Response
interface GetFormPublicResponse {
  id: string;
  name: string;
  description: string;
  fields: FormField[];
  layout: FormBlock[];
  settings: FormSettings;
  customCss: string;
  locale?: string; // Current locale
  sourceLocale?: string; // Original language
  availableLocales?: string[]; // All available translations
}
```

#### `submitForm({ formId, data })`

Submits form data.

```typescript
const result = await client.submitForm({
  formId: "form_abc123",
  data: { email: "user@example.com" },
});

// Response
interface SubmitFormResponse {
  success: boolean;
  submissionId: string;
}
```

#### `getUploadUrl(params)`

Gets a presigned URL for file upload (quarantine bucket).

```typescript
const upload = await client.getUploadUrl({
  formId: "form_abc123",
  fieldId: "field_xyz",
  filename: "document.pdf",
  contentType: "application/pdf",
  fileSize: 1024000,
});

// Response
interface GetUploadUrlResponse {
  fileId: string;
  uploadUrl: string;
}
```

#### `confirmUploadComplete({ fileId })`

Confirms file upload and triggers antivirus scan.

```typescript
await client.confirmUploadComplete({ fileId: "file_123" });
```

#### `getFileStatus({ fileId })`

Gets current file scan status.

```typescript
const status = await client.getFileStatus({ fileId: "file_123" });

// Response
interface FileStatusResponse {
  fileId: string;
  status: FileStatus; // "pending_upload" | "pending_scan" | "scanning" | "clean" | "infected" | "scan_failed"
  filename?: string;
}
```

#### `getDownloadUrl({ fileId })`

Gets a presigned download URL (only for clean files).

```typescript
const download = await client.getDownloadUrl({ fileId: "file_123" });

// Response
interface GetDownloadUrlResponse {
  downloadUrl: string;
  filename: string;
}
```

## File Upload Flow

Complete example of uploading a file with virus scanning:

```typescript
import { createFormServiceClient } from "@logic-joe/logicforms-api";

const client = createFormServiceClient({ apiKey: "your-key" });

async function uploadFile(file: File, formId: string, fieldId: string) {
  // 1. Get presigned upload URL
  const { fileId, uploadUrl } = await client.getUploadUrl({
    formId,
    fieldId,
    filename: file.name,
    contentType: file.type,
    fileSize: file.size,
  });

  // 2. Upload file directly to S3 (quarantine bucket)
  await fetch(uploadUrl, {
    method: "PUT",
    body: file,
    headers: { "Content-Type": file.type },
  });

  // 3. Confirm upload and trigger AV scan
  await client.confirmUploadComplete({ fileId });

  // 4. Poll for scan result
  let status = await client.getFileStatus({ fileId });
  while (status.status === "pending_scan" || status.status === "scanning") {
    await new Promise((r) => setTimeout(r, 1000));
    status = await client.getFileStatus({ fileId });
  }

  if (status.status === "clean") {
    console.log("File is safe:", fileId);
    return fileId;
  } else {
    throw new Error(`File scan failed: ${status.status}`);
  }
}
```

## Types & Constants

### Field Types

```typescript
import { FieldType } from "@logic-joe/logicforms-api";

FieldType.TEXT; // "TEXT"
FieldType.EMAIL; // "EMAIL"
FieldType.NUMBER; // "NUMBER"
FieldType.TEXTAREA; // "TEXTAREA"
FieldType.SELECT; // "SELECT"
FieldType.CHECKBOX; // "CHECKBOX"
FieldType.RADIO; // "RADIO"
FieldType.DATE; // "DATE"
FieldType.FILE; // "FILE"
```

### Block Types

```typescript
import { BlockType } from "@logic-joe/logicforms-api";

BlockType.FIELD; // "FIELD"
BlockType.HEADING; // "HEADING"
BlockType.TEXT; // "TEXT"
BlockType.DIVIDER; // "DIVIDER"
BlockType.ROW; // "ROW"
```

### Core Interfaces

```typescript
interface FormField {
  id: string;
  name: string;
  label: string;
  type: FieldType;
  required: boolean;
  placeholder: string;
  defaultValue: string;
  options: FieldOption[];
  validation: Record<string, string>;
  order: number;
}

interface FormBlock {
  id: string;
  type: BlockType;
  fieldId?: string;
  content?: string;
  level?: number;
  columns?: number;
  children?: FormBlock[];
}

interface FormSettings {
  submitButtonText: string;
  successMessage: string;
  redirectUrl: string;
  submitAction?: "message" | "redirect";
  theme?: ThemeSettings;
  honeypotEnabled?: boolean;
  recaptcha?: RecaptchaSettings;
  turnstile?: TurnstileSettings;
}
```

## Utility Modules

### Date Format Utilities

```typescript
import {
  toISO,
  fromISO,
  parseDate,
  isValidFormat,
  DATE_FORMATS,
} from "@logic-joe/logicforms-api/dateFormat";

// Convert custom format to ISO
toISO("25/12/2024", "DD/MM/YYYY"); // "2024-12-25"

// Convert ISO to custom format
fromISO("2024-12-25", "DD.MM.YYYY"); // "25.12.2024"

// Parse date string
parseDate("25/12/2024", "DD/MM/YYYY"); // Date object

// Available formats
DATE_FORMATS; // Array of { value, label } options
```

### HTML Sanitization

```typescript
import { sanitizeHtml, stripHtml } from "@logic-joe/logicforms-api/sanitize";

// Sanitize HTML (keeps safe tags)
sanitizeHtml("<p>Hello <script>bad</script></p>"); // "<p>Hello </p>"

// Strip all HTML tags
stripHtml("<p>Hello <strong>World</strong></p>"); // "Hello World"
```

## Error Handling

```typescript
import {
  createFormServiceClient,
  ApiClientError,
} from "@logic-joe/logicforms-api";

const client = createFormServiceClient({ apiKey: "your-key" });

try {
  const form = await client.getFormPublic({ id: "invalid" });
} catch (error) {
  if (error instanceof ApiClientError) {
    console.log("Status:", error.statusCode);
    console.log("Message:", error.message);
  }
}
```

## TypeScript Support

This package is written in TypeScript and provides full type definitions. All types are exported:

```typescript
import type {
  FormField,
  FormBlock,
  FormSettings,
  FieldType,
  BlockType,
  GetFormPublicResponse,
  SubmitFormResponse,
  GetUploadUrlResponse,
  FileStatusResponse,
  ThemeSettings,
  RecaptchaSettings,
  TurnstileSettings,
} from "@logic-joe/logicforms-api";
```

## License

MIT