
Research
/Security News
Popular Go Decimal Library Targeted by Long-Running Typosquat with DNS Backdoor
A long-running Go typosquat impersonated the popular shopspring/decimal library and used DNS TXT records to execute commands.
@gofranz/formshive-submit
Advanced tools
JavaScript library for submitting forms to Formshive with retry logic, file support, and flexible HTTP client options
A robust JavaScript/TypeScript library for submitting forms to Formshive with advanced features including retry logic, file uploads, progress tracking, and flexible HTTP client support.
npm install @gofranz/formshive-submit
# or
yarn add @gofranz/formshive-submit
# or
pnpm add @gofranz/formshive-submit
For browser usage via CDN:
<script src="https://unpkg.com/@gofranz/formshive-submit/dist/formshive-submit.min.js"></script>
import { submitFormSimple } from '@gofranz/formshive-submit';
// Simple form submission
const response = await submitFormSimple('your-form-id', {
name: 'John Doe',
email: 'john@example.com',
message: 'Hello from Formshive Submit!'
});
console.log('Form submitted successfully:', response);
import { submitForm } from '@gofranz/formshive-submit';
try {
const response = await submitForm({
formId: 'your-form-id',
data: {
name: 'Jane Smith',
email: 'jane@example.com',
subject: 'Contact Form',
message: 'This is a test message.'
},
callbacks: {
onSuccess: (response) => {
console.log('Success!', response);
},
onError: (error) => {
console.error('Submission failed:', error);
},
onRetry: (attempt, maxAttempts) => {
console.log(`Retrying... ${attempt}/${maxAttempts}`);
}
}
});
} catch (error) {
console.error('Final error:', error);
}
import { submitForm } from '@gofranz/formshive-submit';
const fileInput = document.getElementById('fileInput');
const formData = new FormData();
formData.append('name', 'John Doe');
formData.append('file', fileInput.files[0]);
const response = await submitForm({
formId: 'file-upload-form',
data: formData,
callbacks: {
onProgress: (percent, loaded, total) => {
console.log(`Upload progress: ${percent}%`);
document.getElementById('progress').style.width = percent + '%';
}
}
});
import { submitForm } from '@gofranz/formshive-submit';
const files = document.getElementById('multipleFiles').files;
const formData = new FormData();
formData.append('title', 'Multiple File Upload');
for (let i = 0; i < files.length; i++) {
formData.append(`file_${i}`, files[i]);
}
const response = await submitForm({
formId: 'multi-file-form',
data: formData,
files: {
maxFileSize: 10 * 1024 * 1024, // 10MB per file
allowedTypes: ['image/jpeg', 'image/png', 'application/pdf'],
trackProgress: true
},
callbacks: {
onProgress: (percent) => updateProgressBar(percent)
}
});
import { submitForm, RetryPresets } from '@gofranz/formshive-submit';
const response = await submitForm({
formId: 'your-form-id',
data: { message: 'Hello' },
retry: {
maxAttempts: 5,
baseDelay: 2000, // 2 seconds
maxDelay: 30000, // 30 seconds max
enableJitter: true, // Add randomness to delays
backoffMultiplier: 2 // Exponential backoff factor
}
});
// Or use presets
const response2 = await submitForm({
formId: 'your-form-id',
data: { message: 'Hello' },
retry: RetryPresets.patient() // More retries, longer delays
});
import axios from 'axios';
import { submitForm } from '@gofranz/formshive-submit';
// Option 1: Use string identifier
const response = await submitForm({
formId: 'your-form-id',
data: { message: 'Hello' },
httpClient: 'axios' // Requires axios to be installed
});
// Option 2: Use custom axios instance
const customAxios = axios.create({
timeout: 10000,
headers: {
'Custom-Header': 'value'
}
});
const response2 = await submitForm({
formId: 'your-form-id',
data: { message: 'Hello' },
httpClient: customAxios
});
const response = await submitForm({
formId: 'your-form-id',
data: { message: 'Hello' },
endpoint: 'https://your-custom-domain.com/api/v1',
headers: {
'Authorization': 'Bearer your-token',
'Custom-Header': 'custom-value'
},
timeout: 15000 // 15 seconds
});
import { validateFormData, submitForm } from '@gofranz/formshive-submit';
const data = {
name: '',
email: 'invalid-email',
message: 'Hello'
};
const validation = validateFormData(data);
if (!validation.isValid) {
console.log('Validation errors:', validation.errors);
console.log('Warnings:', validation.warnings);
return;
}
const response = await submitForm({
formId: 'validated-form',
data: data
});
import { FormSubmitter } from '@gofranz/formshive-submit';
// Create a submitter with default configuration
const submitter = new FormSubmitter({
endpoint: 'https://api.myapp.com/v1',
retry: {
maxAttempts: 5,
baseDelay: 1000
},
debug: true
});
// Submit multiple forms using the same configuration
const response1 = await submitter.submit('contact-form', {
name: 'John',
email: 'john@example.com'
});
const response2 = await submitter.submit('feedback-form', {
rating: 5,
comment: 'Great service!'
});
// Test connection
const isConnected = await submitter.testConnection();
console.log('API is reachable:', isConnected);
import { submitForm, formatFileSize } from '@gofranz/formshive-submit';
const response = await submitForm({
formId: 'upload-form',
data: formData,
callbacks: {
onStart: () => {
console.log('Upload starting...');
showProgressBar(true);
},
onProgress: (percent, loaded, total) => {
const loadedSize = formatFileSize(loaded);
const totalSize = formatFileSize(total);
console.log(`${percent}% - ${loadedSize}/${totalSize}`);
updateProgress(percent);
},
onSuccess: (response) => {
console.log('Upload complete!');
hideProgressBar();
},
onError: (error) => {
console.error('Upload failed:', error);
showError(error.message);
}
}
});
<!DOCTYPE html>
<html>
<head>
<title>Formshive Submit Example</title>
</head>
<body>
<form id="myForm">
<input type="text" name="name" placeholder="Name" required>
<input type="email" name="email" placeholder="Email" required>
<textarea name="message" placeholder="Message"></textarea>
<input type="file" name="file" multiple>
<button type="submit">Submit</button>
</form>
<script src="https://unpkg.com/@gofranz/formshive-submit/dist/formshive-submit.min.js"></script>
<script>
document.getElementById('myForm').addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
try {
const response = await FormshiveSubmit.submitForm({
formId: 'my-form-id',
data: formData,
callbacks: {
onSuccess: (response) => {
alert('Form submitted successfully!');
},
onError: (error) => {
alert('Error: ' + error.message);
}
}
});
} catch (error) {
console.error('Submission error:', error);
}
});
</script>
</body>
</html>
submitForm(options: FormshiveSubmitOptions): Promise<SubmitResponse>Main form submission function with full configuration options.
submitFormSimple(formId: string, data: Record<string, any> | FormData, options?: Partial<FormshiveSubmitOptions>): Promise<SubmitResponse>Simplified submission function for basic use cases.
validateFormData(data: Record<string, any> | FormData): ValidationResultValidates form data before submission.
FormSubmitterReusable form submitter with configurable defaults.
const submitter = new FormSubmitter(defaultOptions);
await submitter.submit(formId, data, overrideOptions);
FormshiveSubmitOptionsinterface FormshiveSubmitOptions {
formId: string; // Required: Formshive form ID
data: Record<string, any> | FormData; // Required: Form data
endpoint?: string; // API endpoint (default: api.formshive.com)
httpClient?: HttpClient; // 'fetch', 'axios', or axios instance
retry?: RetryConfig; // Retry configuration
files?: FileConfig; // File upload configuration
callbacks?: FormshiveCallbacks; // Success/error/progress callbacks
headers?: Record<string, string>; // Additional HTTP headers
timeout?: number; // Request timeout in milliseconds
debug?: boolean; // Enable debug logging
}
SubmitResponseinterface SubmitResponse {
success: boolean;
data?: any;
statusCode: number;
headers?: Record<string, string>;
redirectUrl?: string;
attempt: number;
duration: number;
}
SubmitErrorinterface SubmitError extends Error {
code: string;
statusCode?: number;
response?: any;
attempt: number;
isRetryable: boolean;
originalError?: Error;
fieldErrors?: FieldValidationError[];
validationResponse?: FieldValidationErrorResponse;
}
The library provides detailed error information with specific error codes:
NETWORK_ERROR - Network connectivity issuesTIMEOUT_ERROR - Request timeoutVALIDATION_ERROR - Form validation failedFILE_TOO_LARGE - File exceeds size limitINVALID_FILE_TYPE - File type not allowedFORM_NOT_FOUND - Form ID not foundSERVER_ERROR - Server-side error (5xx)RATE_LIMITED - Too many requests (429)try {
const response = await submitForm(options);
} catch (error) {
switch (error.code) {
case 'FORM_NOT_FOUND':
console.error('Form not found. Check your form ID.');
break;
case 'FILE_TOO_LARGE':
console.error('File is too large. Please choose a smaller file.');
break;
case 'NETWORK_ERROR':
console.error('Network error. Please check your connection.');
break;
default:
console.error('Unexpected error:', error.message);
}
}
When form validation fails (400 Bad Request), Formshive returns structured field-level validation errors that you can use to display specific error messages for each form field.
import { submitForm, isFieldValidationError, getFieldErrors } from '@gofranz/formshive-submit';
try {
const response = await submitForm({
formId: 'contact-form',
data: {
name: '', // Missing required field
email: 'invalid-email', // Invalid format
message: 'Hello'
}
});
} catch (error) {
if (isFieldValidationError(error)) {
console.log('Form has validation errors');
const fieldErrors = getFieldErrors(error);
fieldErrors.forEach(fieldError => {
console.log(`Field: ${fieldError.field}`);
console.log(`Error: ${fieldError.message}`);
console.log(`Code: ${fieldError.code}`);
});
} else {
console.error('Non-validation error:', error.message);
}
}
The library provides helper functions to make it easy to display field errors in your forms:
import { createFieldErrorHelpers, submitForm } from '@gofranz/formshive-submit';
let currentError = null;
// Create helpers for easy UI integration
const errorHelpers = createFieldErrorHelpers(currentError);
// Check if a field has an error
if (errorHelpers.hasError('email')) {
document.getElementById('email').classList.add('input-error');
}
// Get error message for a field
const emailErrorMsg = errorHelpers.getMessage('email');
if (emailErrorMsg) {
document.getElementById('email-error').textContent = emailErrorMsg;
}
// Get CSS class for field error state
const fieldClass = errorHelpers.getFieldClass('email', 'has-error');
document.getElementById('email').className = fieldClass;
import {
submitForm,
isFieldValidationError,
createFieldErrorHelpers,
getValidationErrorSummary
} from '@gofranz/formshive-submit';
async function handleFormSubmit(formData) {
let currentError = null;
try {
const response = await submitForm({
formId: 'registration-form',
data: formData
});
// Success - clear any previous errors
clearFieldErrors();
showSuccessMessage();
} catch (error) {
currentError = error;
if (isFieldValidationError(error)) {
// Handle field-specific validation errors
displayFieldErrors(error);
// Show general validation summary
const summary = getValidationErrorSummary(error);
showErrorMessage(summary);
} else {
// Handle other types of errors
showErrorMessage(error.message || 'An unexpected error occurred');
}
}
}
function displayFieldErrors(error) {
const helpers = createFieldErrorHelpers(error, 'field-error');
const fieldNames = ['name', 'email', 'phone', 'message'];
fieldNames.forEach(fieldName => {
const input = document.getElementById(fieldName);
const errorDiv = document.getElementById(`${fieldName}-error`);
if (helpers.hasError(fieldName)) {
// Add error styling
input.classList.add('field-error');
// Show error message
errorDiv.textContent = helpers.getMessage(fieldName);
errorDiv.style.display = 'block';
} else {
// Clear error state
input.classList.remove('field-error');
errorDiv.style.display = 'none';
}
});
}
interface FieldValidationError {
field: string; // Field name (e.g., 'email')
code: string; // Error code (e.g., 'required', 'invalid_format')
message: string; // User-friendly error message
params: Record<string, any>; // Additional error parameters
}
interface FieldValidationErrorResponse {
error: string; // Always 'validation_error'
action?: string; // Optional action hint
message: string; // General validation error message
errors: FieldValidationError[]; // Array of field-specific errors
}
The library exports many utility functions for working with field validation errors:
isFieldValidationError(error) - Check if error contains field validation errorsgetFieldErrors(error) - Get array of all field validation errorsgetFieldError(error, fieldName) - Get validation error for specific fieldhasFieldError(error, fieldName) - Check if specific field has errorgetErrorFieldNames(error) - Get names of all fields with errorsformatFieldErrors(error) - Get simple object mapping field names to error messagescreateFieldErrorHelpers(error) - Create helper object for UI integrationgetValidationErrorSummary(error) - Get human-readable error summaryhasErrorCode(error, code) - Check if any field has specific error codegetErrorsByCode(error, code) - Get all errors with specific codeContributions are welcome! Please read our contributing guidelines and submit pull requests for any improvements.
MIT License - see LICENSE file for details.
For issues and questions, please visit our GitHub repository or contact support at support@formshive.com.
Formshive Submit - Making form submissions robust and reliable. ✨
FAQs
JavaScript library for submitting forms to Formshive with retry logic, file support, and flexible HTTP client options
The npm package @gofranz/formshive-submit receives a total of 11 weekly downloads. As such, @gofranz/formshive-submit popularity was classified as not popular.
We found that @gofranz/formshive-submit demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
/Security News
A long-running Go typosquat impersonated the popular shopspring/decimal library and used DNS TXT records to execute commands.

Research
Active npm supply chain attack compromises @antv packages in a fast-moving malicious publish wave tied to Mini Shai-Hulud.

Security News
/Research
Socket detected malicious node-ipc versions with obfuscated stealer/backdoor behavior in a developing npm supply chain attack.