npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

lekana-gemini

v1.0.0

Published

A shared TypeScript library for Lekana microservices that provides AI-powered document processing, validation, and workflow automation using Google's Gemini API

Readme

hw# @lekana/gemini

A shared TypeScript library for Lekana microservices that provides AI-powered document processing, validation, and workflow automation using Google's Gemini API.

Features

Clean API – Simple, typed functions for extraction, validation, and workflows
Secure – No API keys stored; inject at runtime from environment variables
Reusable Prompts – Centralized prompt templates shared across services
TypeScript Native – Full type definitions and strict mode enabled
Production Ready – Error handling, JSON sanitization, and CommonJS output


Table of Contents


Installation

npm install @lekana/gemini

Requirements:

Setup environment variable:

export GEMINI_API_KEY="your-api-key-here"

Or in your .env file:

GEMINI_API_KEY=your-api-key-here

Quick Start

import { extractFields } from "@lekana/gemini";

async function processInvoice() {
  const result = await extractFields(
    { documentText: "Invoice #12345\nTotal: $1,500.00\nDate: Dec 10, 2025" },
    process.env.GEMINI_API_KEY!
  );

  console.log(result.fields);
  // Output: { invoiceNumber: "12345", total: 1500, date: "2025-12-10" }
}

processInvoice();

API Reference

1. GeminiClient

Low-level wrapper for direct Gemini API access. Use this when you need custom prompts beyond the helper functions.

Constructor

import { GeminiClient } from "@lekana/gemini";

const client = new GeminiClient({
  apiKey: process.env.GEMINI_API_KEY!,
  model: "gemini-1.5-pro", // optional, defaults to "gemini-1.5-pro"
});

Options:

  • apiKey (required): Your Gemini API key
  • model (optional): Model name (default: "gemini-1.5-pro")

Methods

generateText(prompt: string): Promise<string>

Sends a prompt to Gemini and returns the AI-generated response.

const response = await client.generateText(
  "Summarize the following invoice in one sentence: Invoice #789, Total $2,300"
);

console.log(response);
// "Invoice #789 has a total amount of $2,300."

Throws:

  • If API key is missing
  • If prompt is empty
  • If Gemini API request fails

2. extractFields

Extracts structured data from unstructured document text using AI. Returns parsed JSON.

Function Signature

extractFields(
  input: { documentText: string },
  apiKey: string
): Promise<{ fields: any }>

Example

import { extractFields } from "@lekana/gemini";

const result = await extractFields(
  {
    documentText: `
      INVOICE
      Invoice Number: INV-2025-001
      Customer: Acme Corp
      Total Amount: $5,000.00
      Due Date: January 15, 2026
      Items:
      - Widget A (qty: 10) - $3,000
      - Service B - $2,000
    `,
  },
  process.env.GEMINI_API_KEY!
);

console.log(result.fields);

Output:

{
  "invoiceNumber": "INV-2025-001",
  "customer": "Acme Corp",
  "totalAmount": 5000,
  "dueDate": "2026-01-15",
  "items": [
    { "name": "Widget A", "quantity": 10, "price": 3000 },
    { "name": "Service B", "price": 2000 }
  ]
}

Uses Prompt: src/prompts/extract.txt

Throws:

  • If API key is missing
  • If documentText is empty
  • If JSON parsing fails

3. validateDocument

Validates a JSON object and returns validation status with error messages.

Function Signature

validateDocument(
  input: { json: any },
  apiKey: string
): Promise<{ isValid: boolean; errors: string[] }>

Example

import { validateDocument } from "@lekana/gemini";

const validation = await validateDocument(
  {
    json: {
      invoiceNumber: "INV-001",
      customerEmail: "invalid-email", // Invalid format
      totalAmount: -500, // Invalid: negative
      items: [], // Invalid: empty array
    },
  },
  process.env.GEMINI_API_KEY!
);

console.log(validation);

Output:

{
  "isValid": false,
  "errors": [
    "customerEmail must be a valid email address",
    "totalAmount cannot be negative",
    "items array cannot be empty"
  ]
}

Valid example:

const validation = await validateDocument(
  {
    json: {
      invoiceNumber: "INV-001",
      customerEmail: "[email protected]",
      totalAmount: 500,
    },
  },
  process.env.GEMINI_API_KEY!
);

console.log(validation);
// { isValid: true, errors: [] }

Uses Prompt: src/prompts/validate.txt

Throws:

  • If API key is missing
  • If json is undefined
  • If JSON parsing fails

4. runWorkflowStep

Executes a generic workflow step with custom logic defined by the step metadata.

Function Signature

runWorkflowStep(
  step: { id: string; prompt?: string },
  data: Record<string, unknown>,
  apiKey: string
): Promise<{ stepId: string; output: any }>

Example

import { runWorkflowStep } from "@lekana/gemini";

const result = await runWorkflowStep(
  {
    id: "calculate-tax",
    prompt: "Calculate 10% tax on the total amount and return the result",
  },
  {
    invoiceNumber: "INV-001",
    totalAmount: 1000,
    items: ["Widget A", "Widget B"],
  },
  process.env.GEMINI_API_KEY!
);

console.log(result);

Output:

{
  "stepId": "calculate-tax",
  "output": {
    "totalAmount": 1000,
    "taxRate": 0.1,
    "taxAmount": 100,
    "totalWithTax": 1100
  }
}

Uses Prompt: src/prompts/workflow.txt

Throws:

  • If API key is missing
  • If step doesn't have an id
  • If JSON parsing fails

Complete Examples

Example 1: Invoice Processing Pipeline

import {
  extractFields,
  validateDocument,
  runWorkflowStep,
} from "@lekana/gemini";

async function processInvoice(rawText: string) {
  const apiKey = process.env.GEMINI_API_KEY!;

  try {
    // Step 1: Extract structured data
    console.log("📄 Extracting fields...");
    const extraction = await extractFields({ documentText: rawText }, apiKey);
    console.log("Extracted:", extraction.fields);

    // Step 2: Validate extracted data
    console.log("✅ Validating data...");
    const validation = await validateDocument(
      { json: extraction.fields },
      apiKey
    );

    if (!validation.isValid) {
      console.error("❌ Validation failed:", validation.errors);
      throw new Error(`Invalid data: ${validation.errors.join(", ")}`);
    }
    console.log("✅ Data is valid");

    // Step 3: Calculate totals with tax
    console.log("🧮 Calculating tax...");
    const taxCalculation = await runWorkflowStep(
      {
        id: "calculate-tax",
        prompt: "Calculate 15% tax and grand total",
      },
      extraction.fields,
      apiKey
    );
    console.log("Tax calculation:", taxCalculation.output);

    // Step 4: Generate summary
    console.log("📝 Generating summary...");
    const summary = await runWorkflowStep(
      {
        id: "generate-summary",
        prompt: "Create a one-sentence summary of this invoice",
      },
      { ...extraction.fields, ...taxCalculation.output },
      apiKey
    );

    return {
      extractedData: extraction.fields,
      taxDetails: taxCalculation.output,
      summary: summary.output,
    };
  } catch (error) {
    console.error("Error processing invoice:", error);
    throw error;
  }
}

// Usage
const invoiceText = `
  INVOICE #INV-2025-123
  Bill To: XYZ Company
  Amount: $10,000
  Date: December 10, 2025
`;

processInvoice(invoiceText)
  .then((result) => console.log("✅ Processing complete:", result))
  .catch((err) => console.error("❌ Failed:", err.message));

Example 2: Express.js Microservice

import express from "express";
import { extractFields, validateDocument } from "@lekana/gemini";

const app = express();
app.use(express.json());

// Extract endpoint
app.post("/api/extract", async (req, res) => {
  try {
    const { documentText } = req.body;

    if (!documentText) {
      return res.status(400).json({ error: "documentText is required" });
    }

    const result = await extractFields(
      { documentText },
      process.env.GEMINI_API_KEY!
    );

    res.json({ success: true, data: result.fields });
  } catch (error) {
    console.error("Extraction error:", error);
    res.status(500).json({
      error: "Extraction failed",
      message: error.message,
    });
  }
});

// Validate endpoint
app.post("/api/validate", async (req, res) => {
  try {
    const { json } = req.body;

    if (!json) {
      return res.status(400).json({ error: "json payload is required" });
    }

    const validation = await validateDocument(
      { json },
      process.env.GEMINI_API_KEY!
    );

    res.json({
      success: true,
      isValid: validation.isValid,
      errors: validation.errors,
    });
  } catch (error) {
    console.error("Validation error:", error);
    res.status(500).json({
      error: "Validation failed",
      message: error.message,
    });
  }
});

app.listen(3000, () => {
  console.log("🚀 Microservice running on http://localhost:3000");
});

Usage:

# Extract fields
curl -X POST http://localhost:3000/api/extract \
  -H "Content-Type: application/json" \
  -d '{"documentText": "Invoice #123, Total: $500"}'

# Validate data
curl -X POST http://localhost:3000/api/validate \
  -H "Content-Type: application/json" \
  -d '{"json": {"invoiceNumber": "123", "total": 500}}'

Example 3: Custom Gemini Client Usage

import { GeminiClient } from "@lekana/gemini";

async function customAITask() {
  const client = new GeminiClient({
    apiKey: process.env.GEMINI_API_KEY!,
    model: "gemini-1.5-pro",
  });

  // Custom classification
  const classification = await client.generateText(`
    Classify this document type and return only JSON:
    { "type": "invoice" | "receipt" | "contract" | "other" }
    
    Document: "RECEIPT - Coffee Shop - $4.50"
  `);
  console.log(classification);

  // Custom entity extraction
  const entities = await client.generateText(`
    Extract all company names from this text as JSON array:
    "Acme Corp signed a contract with XYZ Ltd and Beta Industries"
  `);
  console.log(entities);
}

customAITask();

Error Handling

All library functions throw errors for:

  • Missing/empty API keys
  • Missing required parameters
  • Gemini API failures
  • JSON parsing failures

Best Practice: Always use try/catch

import { extractFields } from "@lekana/gemini";

async function safeExtraction(text: string) {
  try {
    const result = await extractFields(
      { documentText: text },
      process.env.GEMINI_API_KEY!
    );
    return { success: true, data: result.fields };
  } catch (error) {
    console.error("Extraction failed:", error.message);
    return {
      success: false,
      error: error.message,
      fallback: {},
    };
  }
}

Common Error Messages:

  • "Gemini API key is required to initialize the client."
  • "API key is required for extractFields."
  • "extractFields requires non-empty documentText."
  • "Failed to parse JSON from Gemini response: ..."
  • "Gemini generateText failed: ..."

TypeScript Types

Full type definitions for better IDE support and type safety:

import type {
  // Client options
  GeminiClientOptions,

  // Extract function types
  ExtractInput,
  ExtractResult,

  // Validate function types
  ValidateInput,
  ValidateResult,

  // Workflow function types
  WorkflowStep,
  WorkflowData,
  WorkflowResult,
} from "@lekana/gemini";

// Example usage
const extractInput: ExtractInput = {
  documentText: "Invoice...",
};

const validateInput: ValidateInput = {
  json: { amount: 100 },
};

const workflowStep: WorkflowStep = {
  id: "step-1",
  prompt: "Process this data",
};

Development

Project Structure

zybbera-gemini/
├── package.json
├── tsconfig.json
├── README.md
├── src/
│   ├── index.ts              # Public API exports
│   ├── types.ts              # TypeScript type definitions
│   ├── geminiClient.ts       # GeminiClient class
│   ├── extract.ts            # extractFields function
│   ├── validate.ts           # validateDocument function
│   ├── workflow.ts           # runWorkflowStep function
│   └── prompts/
│       ├── extract.txt       # Extraction prompt template
│       ├── validate.txt      # Validation prompt template
│       └── workflow.txt      # Workflow prompt template
└── dist/                     # Compiled output (generated)

Build from Source

# Install dependencies
npm install

# Compile TypeScript
npm run build

# Output will be in dist/

Customizing Prompts

Edit the prompt files in src/prompts/ to customize AI behavior:

  • extract.txt – Controls how data is extracted from documents
  • validate.txt – Defines validation rules and error messages
  • workflow.txt – Sets behavior for workflow step execution

After editing, rebuild:

npm run build

Configuration

Package Details

  • Name: @lekana/gemini
  • Version: 1.0.0
  • Target: ES2020, CommonJS
  • Main: dist/index.js
  • Types: dist/index.d.ts
  • Access: Restricted (private NPM package)

Dependencies

  • @google/generative-ai – Official Google Gemini SDK
  • @types/node (dev) – Node.js type definitions
  • typescript (dev) – TypeScript compiler

Security Notes

⚠️ Never commit API keys to version control

  • Always inject GEMINI_API_KEY from environment variables
  • Use .env files (and add to .gitignore)
  • For production: use secret management (AWS Secrets Manager, Azure Key Vault, etc.)

This library does not store or log API keys


Support

For issues or questions:

  1. Check the examples above
  2. Review error handling patterns
  3. Verify your GEMINI_API_KEY is set correctly

License

Private package for Lekana microservices. #� �l�e�k�a�n�a�-�g�e�m�i�n�i� � �#� �l�e�k�a�n�a�-�g�e�m�i�n�i� � �