@vicaniddouglas/js_aide
v1.13.0
Published
A versatile collection of modular JavaScript utility helpers designed to streamline single-page application (SPA) development and general web programming tasks.
Maintainers
Readme
@vicaniddouglas/js_aide
A versatile collection of modular JavaScript utility helpers designed to streamline single-page application (SPA) development and general web programming tasks. This library provides a set of independent modules for common functionalities such as routing, input handling, validation, and more.
Description
@vicaniddouglas/js_aide bundles frequently needed JavaScript functionalities into a cohesive, easy-to-use package. Each module is designed to be independent, allowing you to import only what you need, reducing bundle size and improving application performance. From dynamic client-side routing to robust input validation and DOM manipulation, this library aims to accelerate your development workflow.
Features
🎮 Live Playground
Explore all library features—including the new Asynchronous Handshaking system—directly in our interactive sandbox.
Access via Repository:
- Clone the repository:
git clone https://gitlab.com/vicaniddouglas/js_aide.git - Open
demo/index.htmlin any modern browser.
Access via NPM: If you have the package installed locally, you can run the playground using:
npm explore @vicaniddouglas/js_aide -- npm run serve:demoRouter
A modern, feature-rich client-side router for Single-Page Applications (SPAs).
- History API-based navigation.
- Supports dynamic route segments (e.g.,
/users/:id). - Automatic interception of internal
<a>tags for seamless SPA navigation. - Configurable route guards (
beforeNavigate) with support for redirects. - View lifecycle hooks (
beforeEnter,beforeLeave) directly on DOM elements for managing view transitions and data loading. - Parses and exposes URL query parameters and hash fragments.
- Efficient view toggling, only hiding the previously active view.
validator
A module offering various input validation utilities (e.g., email, number, custom regex).
inputHandlers
Utilities for enhanced DOM element interaction, such as restricting input to numbers, formatting number inputs, or providing custom select options.
requests
Helper functions for making HTTP requests (e.g., fetch wrappers for common patterns).
dates
Convenience functions for common date and time manipulation tasks.
fileManager
Utilities for browser-side file handling (e.g., file uploads, local storage, file type checks).
camera
Functions for interacting with device cameras, capturing images or video streams (requires browser API support).
figures
Utilities for number formatting, currency (including UGX defaults), and percentages.
dependencyManager
A robust manager for dynamically loading CDN-based libraries (like SheetJS or jsPDF) with retry logic and dependency tracking.
WebSocketClient
A professional-grade WebSocket client featuring automatic reconnection, heartbeat/health monitoring, and a built-in instance registry to prevent duplicate connections. Supports namespaces, rooms, and message acknowledgements.
Installation
Install the package via npm:
npm install @vicaniddouglas/js_aideOr via yarn:
yarn add @vicaniddouglas/js_aideUsage
Ensure your project is configured to use ES Modules (e.g., by adding "type": "module" to your project's package.json or using a bundler).
Importing Modules
You can import specific modules or all of them:
// Import specific modules
import { Router, validator } from "@vicaniddouglas/js_aide";
// Or import all, though generally not recommended for tree-shaking
// import * => JSAide from '@vicaniddouglas/js_aide';Example: Using the Router
// main.js
import { Router } from "@vicaniddouglas/js_aide";
// Define your routes, mapping paths to DOM element IDs
const appRoutes = {
"/": "home-view",
"/products": "products-list-view",
"/products/:id": "product-detail-view", // Dynamic segment
"/profile": "user-profile-view",
};
const router = new Router(appRoutes, "/");
// --- Optional: Add a route guard ---
router.beforeNavigate = async (toPath, navigationContext) => {
console.log(
`Attempting to navigate from ${navigationContext.from} to ${toPath}`,
);
// Example: Protect the profile route
if (toPath.startsWith("/profile")) {
const isAuthenticated = await checkUserAuthentication(); // Your auth logic
if (!isAuthenticated) {
console.warn(
"Access denied: User not authenticated. Redirecting to login.",
);
return "/login"; // Redirect to a login page
}
}
return true; // Allow navigation
};
// --- Optional: Listen for navigation events ---
window.addEventListener("router:navigated", (event) => {
const { path, pathname, params, query, hash } = event.detail;
console.log(`Navigated to: ${path}`);
console.log("Params:", params); // e.g., { id: '123' } for /products/123
console.log("Query:", query); // e.g., { search: 'item' } for /search?search=item
console.log("Hash:", hash); // e.g., '#section1' for /page#section1
});
// --- Example: Define view lifecycle hooks on your DOM elements ---
// Assuming you have a <div id="product-detail-view"> in your HTML
const productDetailView = document.getElementById("product-detail-view");
if (productDetailView) {
productDetailView.beforeEnter = async (routeParams) => {
console.log(`Entering product detail view for ID: ${routeParams.id}`);
// Fetch product data based on routeParams.id
const product = await fetchProductData(routeParams.id);
// Render product details into the view
renderProductDetails(productDetailView, product);
};
productDetailView.beforeLeave = () => {
console.log("Leaving product detail view. Cleaning up...");
// Dispose of any event listeners or resources specific to this view
cleanupProductDetailResources();
};
}
// Manually navigate (or click an <a> tag)
router.navigate("/products/123?utm_source=email#overview");Example: Using the WebSocket Client
The WebSocketClient is designed to be "Zero-Touch," handling connection lifecycles and resource management automatically.
import { WebSocketClient, ConnectionEvent } from "@vicaniddouglas/js_aide";
// The constructor automatically reuses instances for the same URL (Registry Pattern)
const ws = new WebSocketClient("ws://localhost:8000");
// Listen for connection events
ws.on("open", () => {
console.log("Connected to server!");
});
// Register a handler for a specific event
ws.onMessage("user_update", (data) => {
console.log("Profile updated:", data);
});
ws.connect();ws.send(event, data) vs ws.sendWithAck(event, data)
ws.send(): A "fire and forget" method. It sends the data and returns immediately. Use this for non-critical updates like typing indicators.ws.sendWithAck(): Returns a Promise that resolves when the server confirms receipt. Use this for critical actions like saving a profile or processing a payment.
// Critical action with Acknowledgement
try {
const response = await ws.sendWithAck("save_profile", { bio: "Hello world" });
console.log("Profile saved successfully:", response);
} catch (error) {
console.error("Failed to save profile (timed out):", error.message);
}The Backend Contract (Implementing Acknowledgements)
To support sendWithAck(), your backend (e.g., Python/FastAPI, Node.js, Go) must follow the @vicaniddouglas framework standard:
- The client sends a message containing an
idandack: true. - The server must respond with a message containing:
event: "ack"id: The exact same ID sent by the client.success:trueorfalse.data(optional): Any response data to return to the client.
Example Server Response (JSON):
{
"event": "ack",
"id": "1712065432123-0",
"success": true,
"data": { "status": "saved" }
}Example: Using the Requests Module
The sendRequest function is a proactive HTTP client that standardizes all responses into a single dictionary format. It automatically handles error popups and callbacks, eliminating the need for try-catch blocks.
Standardized Response
Every call returns a Promise that always resolves to this structure:
{
status: boolean, // true if Success, false if Error (Network or Business)
log: string, // Error message on failure, or "" on success
data: any, // The actual payload from the server
httpCode: number // The raw HTTP status code
}New Proactive Options
| Option | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| onSuccess | Function | null | Runs automatically if status is true. Strictly awaited. |
| onError | Function | null | Runs automatically if status is false. Strictly awaited. |
| showLoading | Function | null | Called with true/false. Strictly awaited. |
| silent | Boolean | false | If true, disables the automatic Red Popup on error. |
Usage Patterns
1. The "Sequential Async Flow" (Awaiting Callbacks)
Because sendRequest strictly awaits your callbacks, you can safely use async/await inside them without worrying about race conditions or premature page reloads.
import { sendRequest, popup } from "@vicaniddouglas/js_aide";
await sendRequest({
endpoint: '/api/save',
onSuccess: async (data) => {
// This popup is BEAUTIFUL and BLOCKING.
// sendRequest will NOT finish until the user clicks OK.
await popup.success("Settings Saved!");
}
});
// This reload is GUARANTEED to happen only after the popup is closed.
window.location.reload(); 2. The "Fire and Forget" (Proactive Success) No need to check status if you only care about success. If it fails, the user gets a popup automatically.
import { sendRequest } from "@vicaniddouglas/js_aide";
sendRequest({
endpoint: '/api/settings',
onSuccess: (data) => console.log("Profile updated!", data)
});2. The "Sequential Chain" (Linear Await)
Since the promise never rejects, you can write linear logic without try-catch.
const res = await sendRequest({ endpoint: '/profile' });
if (res.status) {
// Since status is true, we know data is safe to use
const stats = await sendRequest({ endpoint: `/stats/${res.data.id}` });
if (stats.status) render(stats.data);
}3. Silent Background Tasks
Use silent: true for background checks where a popup would be annoying.
sendRequest({
endpoint: '/api/poll-notifications',
silent: true,
onSuccess: (count) => updateBadge(count)
});Example: Using the Popup System
The popup module provides a Promise-based modal system for showing professional alerts. It is fully accessible (supports the Escape key) and highly customizable.
import { popup, icons } from "@vicaniddouglas/js_aide";
// Basic success alert (auto-closes in 2.5s)
await popup.success("Profile saved!");Configuration Reference
Every popup method (.success(), .error(), .info()) accepts an optional options object as the second argument.
| Option | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| duration | Number | 2500ms - 4000ms | Time before the modal closes automatically. |
| persistent| Boolean| false | If true, the modal will stay on screen until manually closed. |
| closable | Boolean| true | If false, hides the close button and disables Esc/backdrop clicks. |
| icon | String | Theme default | A custom SVG string to override the default icon. |
| color | String | Theme default | A custom hex or CSS color for the icon and background tint. |
Common Usage Patterns
1. Sticky Info (Requires Acknowledgment)
await popup.info("Maintenance scheduled for midnight.", { persistent: true });2. Process Lock (Interaction Block) Use this to prevent users from navigating away during critical operations.
// Shows a modal with no close buttons
popup.info("Deleting account data...", { persistent: true, closable: false });
await api.deleteAccount();
popup.close(); // Programmatically remove the modal
await popup.success("Account deleted.");3. Custom Branding Override the icon and color to match specific visual needs.
popup.success("Photo Uploaded!", {
icon: icons.cameraIcon(),
color: "#3b82f6"
});4. Asynchronous Handshaking (Zero-Alert)
The popup system provides replacements for native confirm() and prompt() that are fully asynchronous, themeable, and non-blocking in the developer's logic (via await).
Confirmation Dialogs
Returns true on confirm, false on cancel/close.
const confirmed = await popup.confirm("Are you sure you want to delete this?");
if (confirmed) {
await deleteRecord();
await popup.success("Deleted!");
}Data-Entry Prompts
Returns the input value as a string on submit, or null if cancelled.
const name = await popup.prompt("Enter your display name:", {
placeholder: "e.g., Douglas",
inputType: "text" // Options: text, number, currency, password
});
if (name) {
console.log("Hello", name);
}| Prompt Option | Description |
| :--- | :--- |
| inputType | Controls input behavior (text, number, currency, password). |
| defaultValue| Initial text inside the input. |
| submitText | Text for the action button (default: "Submit"). |
| cancelText | Text for the dismiss button (default: "Cancel"). |
Development
Running Tests
We use Vitest for unit testing. The library has over 80+ verified tests covering all core modules (Routing, Validation, WebSocket, Dates, etc.).
npm testBuilding for Production
Generates minified ESM, IIFE, and CJS bundles in the dist folder using esbuild.
npm run buildLicense
This project is licensed under the MIT License.
