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 🙏

© 2024 – Pkg Stats / Ryan Hefner

jamaibase

v0.3.0

Published

JamAIBase Client SDK (JS/TS). JamAI Base: Let Your Database Orchestrate LLMs and RAG

Downloads

77

Readme

JamAI Base

Overview

Welcome to JamAI Base – the real-time database that orchestrates Large Language Models (LLMs) for you. Designed to simplify AI integration, JamAI Base offers a Backend as a Service (BaaS) platform with an intuitive, spreadsheet-like interface. Focus on defining your data requirements through natural language prompts, and let us handle the complexities of RAG, LLMOps, conversation histories, and LLM orchestration.

Key Benefits

Ease of Use

  • Interface: Simple, intuitive spreadsheet-like interface.
  • Focus: Define data requirements through natural language prompts.

Scalability

  • Foundation: Built on LanceDB, an open-source vector database designed for AI workloads.
  • Performance: Serverless design ensures optimal performance and seamless scalability.

Flexibility

  • LLM Support: Supports any LLMs, including OpenAI GPT-4, Anthropic Claude 3, and Meta Llama3.
  • Capabilities: Leverage state-of-the-art AI capabilities effortlessly.

Declarative Paradigm

  • Approach: Define the "what" rather than the "how."
  • Simplification: Simplifies complex data operations, making them accessible to users with varying levels of technical expertise.

Innovative RAG Techniques

  • Effortless RAG: Built-in RAG features, no need to build the RAG pipeline yourself.
  • Query Rewriting: Boosts the accuracy and relevance of your search queries.
  • Hybrid Search & Reranking: Combines keyword-based search, structured search, and vector search for the best results.
  • Structured RAG Content Management: Organizes and manages your structured content seamlessly.
  • Adaptive Chunking: Automatically determines the best way to chunk your data.
  • BGE M3-Embedding: Leverages multi-lingual, multi-functional, and multi-granular text embeddings for free.

Key Features

Generative Tables

Transform static database tables into dynamic, AI-enhanced entities.

  • Dynamic Data Generation: Automatically populate columns with relevant data generated by LLMs.
  • Built-in REST API Endpoint: Streamline the process of integrating AI capabilities into applications.

Action Tables

Facilitate real-time interactions between the application frontend and the LLM backend.

  • Real-Time Responsiveness: Provide a responsive AI interaction layer for applications.
  • Automated Backend Management: Eliminate the need for manual backend management of user inputs and outputs.
  • Complex Workflow Orchestration: Enable the creation of sophisticated LLM workflows.

Knowledge Tables

Act as repositories for structured data and documents, enhancing the LLM’s contextual understanding.

  • Rich Contextual Backdrop: Provide a rich contextual backdrop for LLM operations.
  • Enhanced Data Retrieval: Support other generative tables by supplying detailed, structured contextual information.
  • Efficient Document Management: Enable uploading and synchronization of documents and data.

Chat Tables

Simplify the creation and management of intelligent chatbot applications.

  • Intelligent Chatbot Development: Simplify the development and operational management of chatbots.
  • Context-Aware Interactions: Enhance user engagement through intelligent and context-aware interactions.
  • Seamless Integration: Integrate with Retrieval-Augmented Generation (RAG) to utilize content from any Knowledge Table.

LanceDB Integration

Efficient management and querying of large-scale multi-modal data.

  • Optimized Data Handling: Store, manage, query, and retrieve embeddings on large-scale multi-modal data efficiently.
  • Scalability: Ensure optimal performance and seamless scalability.

Declarative Paradigm

Focus on defining "what" you want to achieve rather than "how" to achieve it.

  • Simplified Development: Allow users to define relationships and desired outcomes.
  • Non-Procedural Approach: Eliminate the need to write procedures.
  • Functional Flexibility: Support functional programming through LLMs.

Installation

npm install jamaibase@latest

Usage

Create API Client

Create an API client with baseURL:

import JamAI from "jamaibase";

const jamai = new JamAI({ baseURL: "http://localhost:5173/" });

Create an API client with api key and project id:

import JamAI from "jamaibase";

const jamai = new JamAI({ apiKey: "jamai_apikey", projectId: "proj_id" });

Create an API client with custom HTTP client:

import axios from "axios";
import JamAI from "jamaibase";

const username = "user";
const password = "password";

const credentials = Buffer.from(`${username}:${password}`).toString("base64");

const httpClient = axios.create({
    headers: {
        Authorization: `Basic ${credentials}`,
        "Content-Type": "application/json"
    }
});

const jamai = new JamAI({
    baseURL: "https://api.jamaibase.com",
    httpClient: httpClient
});

Create an API client with maxretry and timeout:

import JamAI from "jamaibase";

const jamai = new JamAI({
    baseURL: "https://api.jamaibase.com",
    maxRetries: 3,
    timeout: 500
});

Configure httpAgent/ httpsAgent:

import JamAI from "jamaibase";

const jamai = new JamAI({
    baseURL: "https://api.jamaibase.com"
});

jamai.setHttpagentConfig({
    maxSockets: 100,
    maxFreeSockets: 10,
    freeSocketTimeout: 30000 // free socket keepalive for 30 seconds
});

Can be imported from different modules depending on the need:

import JamAI from "jamaibase/index.umd.js";

Types

Types can be imported from resources:

import { ChatRequest } from "jamaibase/dist/resources/llm/chat";

let response: ChatRequest;

Use client object to call the methods

Example of adding a row to action table:

try {
    const response = await jamai.table.addRow({
        table_type: "action",
        table_id: "workout-suggestion",
        data: [
            {
                age: 30,
                height_in_centimeters: 170,
                weight_in_kg: 60
            }
        ],
        reindex: null,
        concurrent: false
    });
    console.log("response: ", response);
} catch (err) {
    console.error(err.message);
}

Example of adding row with streaming output

try {
    const stream = await jamai.table.addRowStream({
        table_type: "action",
        table_id: "action-table-example-1",
        data: [
            {
                Name: "Albert Eistein"
            }
        ],
        reindex: null,
        concurrent: false
    });

    const reader = stream.getReader();

    while (true) {
        const { done, value } = await reader.read();
        if (done) {
            console.log("Done");
            break;
        }
        console.log(value);
        if (value) {
            console.log(value?.choices[0]?.message.content);
        }
    }
} catch (err) {}

Constructor Parameters for APIClient Configuration

| Parameter | Type | Description | Default Value | Required / Optional | | --- | --- | --- | --- | --- | | baseURL | string | Base URL for the API requests. | https://api.jamaibase.com | optional | | maxRetries | number | Maximum number of retries for failed requests. | 0 | Optional | | httpClient | AxiosInstance | Axios instance for making HTTP requests. | AxiosInstance | Optional | | timeout | number \| undefined | Timeout for the requests. | undefined | Optional | | apiKey | string \| undefined | apiKey. | undefined | Rqruired if accessing cloud | | projectId | string \| undefined | projectId. | undefined | Optional if accessing cloud | | dangerouslyAllowBrowser | boolean | Allowing the insecure usage of JamAI API Key on client side. | false | Optional if accessing cloud |

Quick Start Guide

React JS

To integrate JamAI into a React application, follow these steps:

  1. Install React and Create a New Project
    npx create-react-app my-app
    cd my-app
  1. Install jamai
    npm install jamaibase
  1. Create and Use the JamAI Client in your React component
// App.tsx

import { useEffect, useState } from "react";
import JamAI from "jamaibase";
import { PageListTableMetaResponse } from "jamaibase/dist/resources/gen_tables/tables";

export default function Home() {
    const [tableData, setTableData] = useState<PageListTableMetaResponse>();

    useEffect(() => {
        const fetchData = async () => {
            const jamai = new JamAI({
                baseURL: process.env.NEXT_PUBLIC_JAMAI_BASEURL!,
                apiKey: process.env.JAMAI_API_KEY,
                projectId: process.env.JAMAI_PROJECT_ID,
            });
            try {
                const response = await jamai.table.listTables({
                    table_type: "action",
                });
                setTableData(response);
            } catch (err: any) {
                console.error(err.message);
            }
            fetchData();
        };
    }, []);

    return (
        <div>
            <h1>List of Tables</h1>
            <ul>
                {tableData?.items.map((table) => (
                    <li key={table.id}>
                        <h2>Table ID: {table.id}</h2>
                        <h3>Columns:</h3>
                        <ul>
                            {table.cols.map((column) => (
                                <li key={column.id}>
                                    <p>ID: {column.id}</p>
                                    <p>Data Type: {column.dtype}</p>
                                    {/* Render other properties as needed */}
                                </li>
                            ))}
                        </ul>
                    </li>
                ))}
            </ul>
        </div>
    );
}

Next JS

To integrate JamAI into a Next.js application, follow these steps:

  1. Install Next.js and Create a New Project
    npx create-next-app@latest
    cd (path/to/your/app)
  1. Install jamaibase
    npm install jamaibase
  1. Generate API Key -> Go to cloud.jamaibase.com/organization/secrets and collect API Key

  2. Collect Project ID -> Go to cloud.jamaibase.com/project and copy the project id.

  3. Create .env.local file at the root of your project and add the keys:

NEXT_PUBLIC_JAMAI_BASEURL=http://api.jamaibase.com/
JAMAI_API_KEY=your_jamai_sk_api_key
JAMAI_PROJECT_ID=your_proj_id
  1. Create a route handler to fetch data.
// src/app/api/list-tables/route.ts
import JamAI from "jamaibase";
import {
    PageListTableMetaResponse,
    TableTypes,
} from "jamaibase/resources/gen_tables/tables";
import { NextRequest, NextResponse } from "next/server";

const jamai = new JamAI({
    baseURL: process.env.NEXT_PUBLIC_JAMAI_BASEURL!,
    apiKey: process.env.JAMAI_API_KEY,
    projectId: process.env.JAMAI_PROJECT_ID,
});

export async function GET(request: NextRequest) {
    const searchParams = request.nextUrl.searchParams;
    const tableType = (searchParams.get("type") || "action") as TableTypes;

    try {
        let data: PageListTableMetaResponse = await jamai.table.listTables({
            table_type: tableType,
        });
        return NextResponse.json(data);
    } catch (error: any) {
        console.error("Error fetching tables:", error.response);
        return NextResponse.json(
            { message: "Internal server error" },
            { status: 500 }
        );
    }
}
  1. Then, in your Next.js component, you can fetch this data from the API route and render it:
// src/app/page.tsx

"use client";

import { PageListTableMetaResponse } from "jamaibase/dist/resources/gen_tables/tables";
import { ChangeEvent, useEffect, useState } from "react";

export default function Home() {
    const [tableData, setTableData] = useState<PageListTableMetaResponse>();
    const [tableType, setTableType] = useState("action");

    const handleTableTypeChange = (e: ChangeEvent<HTMLSelectElement>) => {
        setTableType(e.target.value);
    };

    useEffect(() => {
        const fetchData = async () => {
            console.log("fetch data");
            const response = await fetch(`/api/list-tables?type=${tableType}`);
            if (response.ok) {
                const data: PageListTableMetaResponse = await response.json();
                setTableData(data);
            } else {
                console.error("Failed to fetch data:", response.statusText);
            }
        };
        fetchData();
    }, [tableType]);
    return (
        <main className="flex min-h-screen flex-col  p-24">
            <div className="max-w-sm mx-auto my-10 p-5 bg-white rounded-lg shadow-md">
                <label className="block text-sm font-medium text-gray-700 mb-2">
                    Choose Table Type:
                </label>
                <select
                    value={tableType}
                    onChange={handleTableTypeChange}
                    className="block w-full py-2 px-3 border border-gray-300 bg-white rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm text-black"
                >
                    <option value="action">Action</option>
                    <option value="chat">Chat</option>
                    <option value="knowledge">Knowledge</option>
                </select>
            </div>

            <div className="space-y-6">
                <h1 className="text-4xl">List of Tables</h1>
                <table className="min-w-full divide-y divide-gray-200">
                    <thead className="bg-gray-50">
                        <tr>
                            <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
                                Table ID
                            </th>
                            <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
                                Columns
                            </th>
                            <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
                                Column Type
                            </th>
                            <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
                                Number of Rows
                            </th>
                        </tr>
                    </thead>
                    <tbody className="bg-white divide-y divide-gray-300 text-black">
                        {tableData?.items.map((table) => (
                            <tr key={table.id}>
                                <td className="px-6 py-4 whitespace-nowrap">
                                    {table.id}
                                </td>
                                <td className="px-6 py-4 whitespace-nowrap">
                                    <ul className="space-y-2">
                                        {table.cols.map((column) => (
                                            <li className="" key={column.id}>
                                                <span>{column.id}: </span>
                                                <span>{column.dtype}</span>
                                            </li>
                                        ))}
                                    </ul>
                                </td>
                                <td className="px-6 py-4 whitespace-nowrap">
                                    <ul className="space-y-2">
                                        {table.cols.map((column) => (
                                            <li className="" key={column.id}>
                                                <span>
                                                    {column.gen_config
                                                        ? "Output"
                                                        : "Input"}
                                                </span>
                                            </li>
                                        ))}
                                    </ul>
                                </td>
                                <td className="px-6 py-4 whitespace-nowrap">
                                    {table.num_rows}
                                </td>
                            </tr>
                        ))}
                    </tbody>
                </table>
            </div>
        </main>
    );
}
  1. Start the app
npm run dev

SvelteKit

  1. Setup SvelteKit Project
npm create svelte@latest jamai-example-app
cd jamai-example-app
npm install
  1. Install JamAI
npm i jamaibase
  1. Generate API Key -> Go to cloud.jamaibase.com/organization/secrets and collect API Key

  2. Collect Project ID -> Go to cloud.jamaibase.com/project and copy the project id.

  3. Create .env file at the root of your project and add the keys:

PUBLIC_JAMAI_BASEURL=http://api.jamaibase.com/
JAMAI_API_KEY=your_jamai_sk_api_key
JAMAI_PROJECT_ID=your_proj_id
  1. reate a new file src/routes/create-table/+page.svelte and add the following code:
<script>
   <script lang="ts">
    export let form;
</script>

<main>
    <h1>Create Action Table</h1>

    {#if form?.success}
        <!-- this message is ephemeral; it exists because the page was rendered in
		   response to a form submission. it will vanish if the user reloads -->
        <p>Successfully created the table.</p>
    {/if}
    {#if !form?.success}
        <!-- this message is ephemeral; it exists because the page was rendered in
		   response to a form submission. it will vanish if the user reloads -->
        <p>Sorry, something went wrong!</p>
    {/if}

    <form method="POST" action="/create-table">
        <label>
            Table ID
            <input name="table_id" />
        </label>
        <label>
            Column Name
            <input name="column_name" />
        </label>
        <label>
            Columng Data Type
            <select name="column_d_type">
                <option value="str">str</option>
                <option value="int">int</option>
                <option value="float">float</option>
                <option value="bool">bool</option>
            </select>
        </label>
        <button type="submit">Create</button>
    </form>
</main>
  1. Create a form action in the +page.server.ts file in the same path to accept post data from the form.
import JamAI from "jamaibase";
import { fail } from "@sveltejs/kit";
import { PUBLIC_JAMAI_URL } from "$env/static/public";
import { JAMAI_API_KEY, JAMAI_PROJECT_ID } from "$env/static/private";

const jamai = new JamAI({
    baseURL: PUBLIC_JAMAI_URL,
    apiKey: JAMAI_API_KEY,
    projectId: JAMAI_PROJECT_ID,
});

export const actions = {
    default: async ({ request }) => {

        type DTypes = "float" | "int" | "bool" | "str" | undefined;

        const data = await request.formData();
        const tableId = data.get("table_id")?.toString();
        const columnName = data.get("column_name")?.toString();
        const columnDType = data.get("column_d_type")?.toString() as DTypes;

        console.log("data: ", data);
        try {
            const response = await jamai.table.createActionTable({
                id: tableId!,
                cols: [{ id: columnName!, dtype: columnDType! }],
            });

            return { success: true, data: response };
        } catch (error) {
            console.error(error);
            fail(500, { message: "Something went wrong!" });
        }
    },
};
  1. Start the app
npm run dev

Nuxt

  1. Setup Nuxt Project
npx nuxi init jamai-example-app
cd jamai-example-app
npm install
  1. Install JamAI
npm i jamaibase
  1. Collect the secrets:
  1. Create .env file at the root of your project and add the keys:
PUBLIC_JAMAI_BASEURL=http://api.jamaibase.com/
JAMAI_API_KEY=your_jamai_sk_api_key
JAMAI_PROJECT_ID=your_proj_id
  1. In the nuxt.config.ts file, add runtimeConfig to use the environment variables:
runtimeConfig: {
        JAMAI_API_KEY: process.env.JAMAI_API_KEY,
        public: {
            JAMAI_BASEURL: process.env.JAMAI_BASEURL,
            JAMAI_PROJECT_ID: process.env.JAMAI_PROJECT_ID,
        },
    },
  1. create a new file /pages/index.vue and add the following code:
<template>
    <main>
        <div class="container">
            <label>Choose Table Type:</label>
            <select v-model="tableType" @change="fetchTables">
                <option value="action">Action</option>
                <option value="chat">Chat</option>
                <option value="knowledge">Knowledge</option>
            </select>
        </div>

        <div class="container">
            <h1>List of Tables</h1>
            <table>
                <thead>
                    <tr>
                        <th>Table ID</th>
                        <th>Columns</th>
                        <th>Column Type</th>
                        <th>Number of Rows</th>
                    </tr>
                </thead>
                <tbody>
                    <tr v-for="table in tableData.items" :key="table.id">
                        <td>{{ table.id }}</td>
                        <td>
                            <ul>
                                <li v-for="column in table.cols" :key="column.id">{{ column.id }}: {{ column.dtype }}</li>
                            </ul>
                        </td>
                        <td>
                            <ul>
                                <li v-for="column in table.cols" :key="column.id">{{ column.gen_config ? "Output" : "Input" }}</li>
                            </ul>
                        </td>
                        <td>{{ table.num_rows }}</td>
                    </tr>
                </tbody>
            </table>
        </div>
    </main>
</template>

<script setup>
    import { ref, onMounted } from "vue";

    const tableType = ref("action");
    const tableData = ref({ items: [] });

    async function fetchTables() {
        const response = await $fetch(`/api/list-tables?type=${tableType.value}`);

        if (response.success) {
            tableData.value = response.data;
        } else {
            console.error("Failed to fetch data");
        }
    }

    onMounted(() => {
        fetchTables();
    });
</script>
  1. Add the following CSS to make the table look better:

<style scoped>
/* Main layout styling */
main {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    padding: 24px;
}

/* Container styling */
.container {
    max-width: 600px;
    margin: 40px auto;
    padding: 20px;
    background-color: #fff;
    border-radius: 8px;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

/* Label and select input styling */
label {
    display: block;
    margin-bottom: 8px;
    font-size: 14px;
    font-weight: 500;
    color: #333;
}

select {
    display: block;
    width: 100%;
    padding: 8px;
    border: 1px solid #ccc;
    border-radius: 4px;
    background-color: #fff;
    margin-bottom: 20px;
    font-size: 14px;
}

/* Table styling */
table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 20px;
}

th,
td {
    padding: 12px;
    border: 1px solid #ddd;
    text-align: left;
}

th {
    background-color: #f4f4f4;
    font-weight: 600;
}

tr:nth-child(even) {
    background-color: #f9f9f9;
}

tr:hover {
    background-color: #f1f1f1;
}

/* Responsive styling */
@media (max-width: 600px) {
    .container {
        padding: 10px;
    }

    table,
    th,
    td {
        font-size: 12px;
    }

    th,
    td {
        padding: 8px;
    }
}
</style>
  1. create a server handler at server/api/list-tables.js and add the following code:
import JamAI from "jamaibase";

const {
    JAMAI_API_KEY,
    public: { JAMAI_BASEURL, JAMAI_PROJECT_ID }
} = useRuntimeConfig();

const jamai = new JamAI({
    baseURL: JAMAI_BASEURL,
    apiKey: JAMAI_API_KEY,
    projectId: JAMAI_PROJECT_ID
});

export default defineEventHandler(async (event) => {
    const { type = "action" } = getQuery(event);

    try {
        const data = await jamai.table.listTables({ table_type: type });
        return { success: true, data: data };
    } catch (error) {
        console.error("Error fetching tables:", error);
        return { success: false, data: "Something went wrong" };
    }
});
  1. Now, create another page (server/api/create-table.js) to create new action table:
<template>
    <main>
        <h1>Create Action Table</h1>

        <div v-if="form.success">
            <p>Successfully created the table.</p>
        </div>
        <div v-else-if="form.error">
            <p>Sorry, something went wrong!</p>
        </div>

        <form @submit.prevent="submitForm">
            <label>
                Table ID
                <input v-model="tableId" />
            </label>
            <label>
                Column Name
                <input v-model="columnName" />
            </label>
            <label>
                Column Data Type
                <select v-model="columnDType">
                    <option value="str">str</option>
                    <option value="int">int</option>
                    <option value="float">float</option>
                    <option value="bool">bool</option>
                </select>
            </label>
            <button type="submit">Create</button>
        </form>
    </main>
</template>

<script setup>
    import { ref } from "vue";
    import { useRouter } from "vue-router";

    const tableId = ref("");
    const columnName = ref("");
    const columnDType = ref("str");
    const form = ref({ success: false, error: false });
    const router = useRouter();

    async function submitForm() {
        const { data } = useFetch("/api/create-table", {
            method: "post",
            headers: {
                "Content-Type": "application/json"
            },
            body: {
                table_id: tableId.value,
                column_name: columnName.value,
                column_d_type: columnDType.value
            }
        });

        if (data.value?.success) {
            form.value.success = true;
            form.value.error = false;
        } else {
            form.value.success = false;
            form.value.error = true;
        }
    }
</script>
  1. Create a server handler at server/api/create-table.js to accept the request and create a new table:
import JamAI from "jamaibase";

const {
    JAMAI_API_KEY,
    public: { JAMAI_BASEURL, JAMAI_PROJECT_ID }
} = useRuntimeConfig();

const jamai = new JamAI({
    baseURL: JAMAI_BASEURL,
    apiKey: JAMAI_API_KEY,
    projectId: JAMAI_PROJECT_ID
});

export default defineEventHandler(async (event) => {
    const { table_id, column_name, column_d_type } = await readBody(event);

    try {
        const response = await jamai.table.createActionTable({
            id: table_id,
            cols: [{ id: column_name, dtype: column_d_type }]
        });

        return { success: true, data: response };
    } catch (error) {
        console.error("error: ", error.response);
        return { success: false, message: "Something went wrong!" };
    }
});
  1. Finally, create a defalut layout (layouts/defalut.vue) to navigate between pages:
<template>
    <div>
        <nav>
            <ul>
                <li><NuxtLink to="/">Home</NuxtLink></li>
                <li><NuxtLink to="/create-table">Create Table</NuxtLink></li>
            </ul>
        </nav>
        <slot />
    </div>
</template>

<script setup></script>

<style scoped>
    nav {
        background-color: #f8f9fa;
        padding: 10px;
    }

    nav ul {
        list-style: none;
        padding: 0;
        margin: 0;
        display: flex;
        gap: 20px;
    }

    nav ul li {
        display: inline;
    }

    nav a {
        text-decoration: none;
        color: #007bff;
    }

    nav a:hover {
        text-decoration: underline;
    }
</style>
  1. Start the app
npm run dev