
Research
/Security News
Laravel Lang Compromised with RCE Backdoor Across 700+ Versions
Laravel Lang packages were compromised with an RCE backdoor across hundreds of versions, exposing cloud, CI/CD, and developer secrets.
@syncagent/vue
Advanced tools
Vue 3 SDK for SyncAgent — composables for AI database chat in Vue apps.
Works with MongoDB, PostgreSQL, MySQL, SQLite, SQL Server, and Supabase.
sa_)Every new project gets a 14-day trial with 500 free requests — no credit card required. After the trial, you get 100 free requests/month on the Free plan.
npm install @syncagent/vue @syncagent/js
<script setup lang="ts">
import { ref } from "vue";
import { SyncAgentClient } from "@syncagent/js";
import { useSyncAgent } from "@syncagent/vue";
const client = new SyncAgentClient({
apiKey: import.meta.env.VITE_SYNCAGENT_KEY,
connectionString: import.meta.env.VITE_DATABASE_URL,
});
const { messages, isLoading, error, status, sendMessage, stop, reset } = useSyncAgent({ client });
const input = ref("");
function send() {
if (!input.value.trim()) return;
sendMessage(input.value);
input.value = "";
}
</script>
<template>
<div class="chat">
<div v-if="status" class="status">⏳ {{ status.label }}</div>
<div class="messages">
<div v-for="(msg, i) in messages" :key="i" :class="['message', msg.role]">
{{ msg.content }}
</div>
</div>
<div v-if="error" class="error">⚠️ {{ error.message }}</div>
<div class="input-row">
<input v-model="input" @keydown.enter="send" placeholder="Ask about your data..." :disabled="isLoading" />
<button @click="send" :disabled="isLoading || !input.trim()">Send</button>
<button v-if="isLoading" @click="stop">Stop</button>
<button @click="reset">Clear</button>
</div>
</div>
</template>
# .env (Vite)
VITE_SYNCAGENT_KEY=sa_your_api_key
VITE_DATABASE_URL=mongodb+srv://user:pass@cluster/db
⚠️ Security note: In production, pass the connection string from your server/API route instead of exposing it in client-side env vars.
<script setup lang="ts">
import { computed } from "vue";
import { SyncAgentClient } from "@syncagent/js";
import { useSyncAgent } from "@syncagent/vue";
import { useAuth } from "@/composables/auth";
const { user } = useAuth();
const client = computed(() => new SyncAgentClient({
apiKey: import.meta.env.VITE_SYNCAGENT_KEY,
connectionString: import.meta.env.VITE_DATABASE_URL,
filter: { organizationId: user.value.orgId },
operations: user.value.isAdmin
? ["read", "create", "update", "delete"]
: ["read"],
}));
const { messages, isLoading, sendMessage } = useSyncAgent({
client: client.value,
context: { userId: user.value.id, page: "dashboard" },
});
</script>
<script setup lang="ts">
import { SyncAgentClient } from "@syncagent/js";
import { useSyncAgent } from "@syncagent/vue";
const client = new SyncAgentClient({
apiKey: import.meta.env.VITE_SYNCAGENT_KEY,
connectionString: import.meta.env.VITE_DATABASE_URL,
tools: {
sendNotification: {
description: "Send a push notification to a user",
inputSchema: {
userId: { type: "string", description: "User ID" },
message: { type: "string", description: "Notification message" },
},
execute: async ({ userId, message }) => {
await pushService.send(userId, message);
return { sent: true };
},
},
},
});
const { messages, sendMessage } = useSyncAgent({ client });
</script>
Use toolsOnly: true when you want the agent to only call your custom tools — no database access:
<script setup lang="ts">
import { SyncAgentClient } from "@syncagent/js";
import { useSyncAgent } from "@syncagent/vue";
const client = new SyncAgentClient({
apiKey: import.meta.env.VITE_SYNCAGENT_KEY,
toolsOnly: true,
tools: {
searchProducts: {
description: "Search products by name",
inputSchema: { query: { type: "string" } },
execute: async ({ query }) => {
const res = await fetch(`/api/products?q=${query}`);
return res.json();
},
},
},
});
const { messages, sendMessage } = useSyncAgent({ client });
</script>
Use useCustomerChat to build customer support interfaces with Vue reactive state. This composable wraps the JS SDK's customerChat method, managing conversation state, escalation, and resolution as Vue Ref values.
<script setup lang="ts">
import { ref } from "vue";
import { SyncAgentClient } from "@syncagent/js";
import { useCustomerChat } from "@syncagent/vue";
const client = new SyncAgentClient({
apiKey: import.meta.env.VITE_SYNCAGENT_KEY,
connectionString: import.meta.env.VITE_DATABASE_URL,
externalUserId: "user_abc123",
});
const {
messages,
conversationId,
isLoading,
isEscalated,
isResolved,
error,
welcomeMessage,
sendMessage,
rateConversation,
reset,
} = useCustomerChat({
client,
onEscalated: () => {
console.log("Conversation escalated to a human agent");
},
onResolved: (id) => {
console.log(`Conversation ${id} resolved`);
},
});
const input = ref("");
function send() {
if (!input.value.trim()) return;
sendMessage(input.value);
input.value = "";
}
</script>
<template>
<div class="customer-chat">
<div v-if="welcomeMessage" class="welcome">{{ welcomeMessage }}</div>
<div class="messages">
<div v-for="(msg, i) in messages" :key="i" :class="['message', msg.role]">
{{ msg.content }}
</div>
</div>
<div v-if="isEscalated" class="notice">🙋 You've been connected to a human agent.</div>
<div v-if="isResolved" class="notice">
✅ Conversation resolved.
<button @click="rateConversation(5)">Rate ⭐⭐⭐⭐⭐</button>
</div>
<div v-if="error" class="error">⚠️ {{ error.message }}</div>
<div class="input-row">
<input v-model="input" @keydown.enter="send" placeholder="Ask a question..." :disabled="isLoading" />
<button @click="send" :disabled="isLoading || !input.trim()">Send</button>
<button @click="reset">Clear</button>
</div>
</div>
</template>
| Name | Type | Description |
|---|---|---|
messages | Ref<Message[]> | Conversation message history |
conversationId | Ref<string | null> | Current conversation ID |
isLoading | Ref<boolean> | True while awaiting a response |
isEscalated | Ref<boolean> | True when escalated to a human agent |
isResolved | Ref<boolean> | True when the conversation is resolved |
error | Ref<Error | null> | Last error, if any |
welcomeMessage | Ref<string | null> | Welcome message (first interaction only) |
sendMessage | (content: string, metadata?: Record<string, any>) => Promise<void> | Send a customer message |
rateConversation | (rating: number) => Promise<void> | Rate the conversation (1-5) |
reset | () => void | Clear all state and start fresh |
UseCustomerChatOptions| Option | Type | Description |
|---|---|---|
client | SyncAgentClient | Required. Must be configured with externalUserId |
onEscalated | () => void | Called when the conversation is escalated to a human agent |
onResolved | (conversationId: string) => void | Called when the conversation is resolved |
When no externalUserId is provided, the composable activates a guest identification flow. Guests must identify themselves before sending messages. The composable exposes reactive refs and a method for managing this flow.
useCustomerChat| Name | Type | Description |
|---|---|---|
isIdentified | Ref<boolean> | true when the guest has been identified (via form or stored identity) |
guestIdentity | Ref<GuestIdentity | null> | The current guest identity object, or null if not yet identified |
identifyGuest | (data: { name: string; email: string; phone?: string }) => void | Submit guest identification data — validates, generates ID, persists, and transitions state |
GuestIdentificationForm ComponentThe GuestIdentificationForm SFC provides a ready-made form with built-in validation. It emits a submit event with the complete GuestIdentity when the guest provides valid data.
<script setup lang="ts">
import { SyncAgentClient } from "@syncagent/js";
import { useCustomerChat, GuestIdentificationForm } from "@syncagent/vue";
import type { GuestIdentity, GuestFormConfig } from "@syncagent/vue";
const client = new SyncAgentClient({
apiKey: import.meta.env.VITE_SYNCAGENT_KEY,
});
const { messages, isIdentified, sendMessage, identifyGuest } = useCustomerChat({
client,
onGuestIdentified: (identity) => {
console.log("Guest identified:", identity.name, identity.email);
},
});
const formConfig: GuestFormConfig = {
title: "Welcome!",
subtitle: "Tell us a bit about yourself to get started.",
submitButtonText: "Start Chat",
namePlaceholder: "Your name",
emailPlaceholder: "you@example.com",
};
function handleGuestSubmit(identity: GuestIdentity) {
identifyGuest(identity);
}
</script>
<template>
<div class="chat">
<GuestIdentificationForm
v-if="!isIdentified"
:config="formConfig"
class-name="guest-form"
@submit="handleGuestSubmit"
/>
<div v-else>
<div v-for="(msg, i) in messages" :key="i" :class="msg.role">
{{ msg.content }}
</div>
<!-- chat input here -->
</div>
</div>
</template>
You can build your own form and call identifyGuest directly:
<script setup lang="ts">
import { ref } from "vue";
import { SyncAgentClient } from "@syncagent/js";
import { useCustomerChat } from "@syncagent/vue";
const client = new SyncAgentClient({
apiKey: import.meta.env.VITE_SYNCAGENT_KEY,
});
const { isIdentified, guestIdentity, identifyGuest, error, messages, sendMessage } = useCustomerChat({
client,
onGuestIdentified: (identity) => {
console.log("Guest identified:", identity.guestId);
},
});
const name = ref("");
const email = ref("");
const phone = ref("");
function submitGuestForm() {
identifyGuest({
name: name.value,
email: email.value,
phone: phone.value || undefined,
});
}
</script>
<template>
<div>
<form v-if="!isIdentified" @submit.prevent="submitGuestForm">
<input v-model="name" placeholder="Name" required />
<input v-model="email" type="email" placeholder="Email" required />
<input v-model="phone" type="tel" placeholder="Phone (optional)" />
<button type="submit">Start Chat</button>
<p v-if="error" class="error">{{ error.message }}</p>
</form>
<div v-else>
<p>Welcome, {{ guestIdentity?.name }}!</p>
<div v-for="(msg, i) in messages" :key="i" :class="msg.role">
{{ msg.content }}
</div>
<!-- chat input here -->
</div>
</div>
</template>
Note: If
identifyGuestis called with invalid data (empty name or invalid email), theerrorref is set with a validation message andisIdentifiedremainsfalse. Messages cannot be sent until the guest is identified.
⚠️ Deprecated:
createDual()will be removed in a future major version. UseuseDualChat()instead — passexternalUserIddirectly to enable both modes on a single instance.
Legacy pattern (deprecated):
<script setup lang="ts">
import { SyncAgentClient } from "@syncagent/js";
import { useSyncAgent, useCustomerChat } from "@syncagent/vue";
const { db, support } = SyncAgentClient.createDual({
apiKey: import.meta.env.VITE_SYNCAGENT_KEY,
connectionString: import.meta.env.VITE_DATABASE_URL,
externalUserId: "customer_123",
});
// Database agent for admin queries
const { messages: adminMessages, sendMessage: adminSend } = useSyncAgent({ client: db });
// Customer agent for support
const { messages: supportMessages, sendMessage: supportSend } = useCustomerChat({ client: support });
</script>
Before (deprecated):
<script setup lang="ts">
import { SyncAgentClient } from "@syncagent/js";
import { useSyncAgent, useCustomerChat } from "@syncagent/vue";
const { db, support } = SyncAgentClient.createDual({
apiKey: import.meta.env.VITE_SYNCAGENT_KEY,
connectionString: import.meta.env.VITE_DATABASE_URL,
externalUserId: "customer_123",
});
const { messages: adminMessages, sendMessage: adminSend } = useSyncAgent({ client: db });
const { messages: supportMessages, sendMessage: supportSend } = useCustomerChat({ client: support });
</script>
After (recommended):
<script setup lang="ts">
import { SyncAgentClient } from "@syncagent/js";
import { useDualChat } from "@syncagent/vue";
const dualClient = SyncAgentClient.createDual({
apiKey: import.meta.env.VITE_SYNCAGENT_KEY,
connectionString: import.meta.env.VITE_DATABASE_URL,
externalUserId: "customer_123",
});
const { db, support } = useDualChat({ client: dualClient });
</script>
The useDualChat() composable provides a single reactive interface for both database and customer chat on the same client instance. Pass externalUserId to a DualClient to enable both db (database agent) and support (customer agent) namespaces from one setup.
<script setup lang="ts">
import { ref } from "vue";
import { SyncAgentClient } from "@syncagent/js";
import { useDualChat } from "@syncagent/vue";
const dualClient = SyncAgentClient.createDual({
apiKey: import.meta.env.VITE_SYNCAGENT_KEY,
connectionString: import.meta.env.VITE_DATABASE_URL,
externalUserId: "user_abc123",
});
const { db, support } = useDualChat({ client: dualClient });
const dbInput = ref("");
const supportInput = ref("");
function sendDbMessage() {
if (!dbInput.value.trim()) return;
db.sendMessage(dbInput.value);
dbInput.value = "";
}
function sendSupportMessage() {
if (!supportInput.value.trim()) return;
support.sendMessage(supportInput.value);
supportInput.value = "";
}
</script>
<template>
<div class="dual-chat">
<!-- Database Agent -->
<div class="panel">
<h3>Database Agent</h3>
<div v-for="(msg, i) in db.messages" :key="'db-' + i" :class="msg.role">
{{ msg.content }}
</div>
<input v-model="dbInput" @keydown.enter="sendDbMessage" placeholder="Query your data..." />
<button @click="sendDbMessage" :disabled="db.isLoading">Send</button>
</div>
<!-- Customer Support -->
<div class="panel">
<h3>Customer Support</h3>
<div v-for="(msg, i) in support.messages" :key="'support-' + i" :class="msg.role">
{{ msg.content }}
</div>
<input v-model="supportInput" @keydown.enter="sendSupportMessage" placeholder="Ask support..." />
<button @click="sendSupportMessage" :disabled="support.isLoading">Send</button>
</div>
</div>
</template>
DualChatReturnAll properties are Vue reactive refs.
db namespace| Name | Type | Description |
|---|---|---|
db.messages | Ref<Message[]> | Database agent conversation history |
db.isLoading | Ref<boolean> | True while the database agent is streaming |
db.error | Ref<Error | null> | Last error from the database agent |
db.status | Ref<{ step: string; label: string } | null> | Live status (connecting, querying, thinking, done) |
db.lastData | Ref<ToolData | null> | Last DB query result |
db.sendMessage | (content: string) => Promise<void> | Send a message to the database agent |
db.stop | () => void | Abort the current database agent stream |
db.reset | () => void | Clear database agent messages |
support namespace| Name | Type | Description |
|---|---|---|
support.messages | Ref<Message[]> | Customer support conversation history |
support.conversationId | Ref<string | null> | Current support conversation ID |
support.isLoading | Ref<boolean> | True while awaiting a support response |
support.isEscalated | Ref<boolean> | True when escalated to a human agent |
support.isResolved | Ref<boolean> | True when the conversation is resolved |
support.error | Ref<Error | null> | Last error from the support agent |
support.welcomeMessage | Ref<string | null> | Welcome message (first interaction only) |
support.sendMessage | (content: string, metadata?: Record<string, any>) => Promise<void> | Send a message to customer support |
support.rateConversation | (rating: number) => Promise<void> | Rate the support conversation (1-5) |
support.reset | () => void | Clear support state and start fresh |
UseDualChatOptions| Option | Type | Required | Description |
|---|---|---|---|
client | DualClient | Yes | A client created via SyncAgentClient.createDual() with externalUserId |
context | Record<string, any> | No | Extra context injected into every message for both agents |
onData | (data: ToolData) => void | No | Called when the database agent tool returns data |
onEscalated | () => void | No | Called when the support conversation is escalated to a human agent |
onResolved | (conversationId: string) => void | No | Called when the support conversation is resolved |
If useDualChat() is called without a valid DualClient instance, it throws:
useDualChat: a valid DualClient instance is required
Ensure you pass a client created via SyncAgentClient.createDual() with a valid externalUserId.
The <SyncAgentCustomerChat> component is a pre-built, drop-in customer support chat widget. It handles the full conversation lifecycle: guest identification, messaging, escalation to human agents, real-time Pusher messages, satisfaction rating, and theming — all with zero custom UI required.
<script setup lang="ts">
import { SyncAgentCustomerChat } from "@syncagent/vue";
</script>
<template>
<SyncAgentCustomerChat
api-key="sa_your_api_key"
connection-string="your_connection_string"
/>
</template>
A floating chat button appears in the bottom-right corner. Anonymous visitors see a guest identification form before chatting.
| Prop | Type | Default | Description |
|---|---|---|---|
config | SyncAgentConfig | — | Pre-built configuration object. Takes priority over individual props. |
apiKey | string | — | API key (required if no config). |
connectionString | string | — | Database connection string (required if no config). |
externalUserId | string | — | Authenticated user ID. Skips guest form when provided. |
mode | "floating" | "inline" | "floating" | Floating toggle button or embedded inline panel. |
position | "bottom-right" | "bottom-left" | "bottom-right" | Position of the floating widget (floating mode only). |
defaultOpen | boolean | false | Whether the floating panel starts open (floating mode only). |
title | string | "Customer Support" | Header title text (max 100 chars). |
subtitle | string | "How can we help you?" | Header subtitle text (max 200 chars). |
placeholder | string | "Type your message..." | Input placeholder text (max 150 chars). |
welcomeMessage | string | — | Initial welcome message displayed before any interaction. |
accentColor | string | "#6366f1" | Primary accent color (hex, rgb, or hsl). |
darkMode | boolean | false | Enable dark mode color scheme. |
className | string | — | Additional CSS class on the root container. |
guestForm | GuestFormConfig | — | Custom guest form configuration (title, subtitle, placeholders, button text). |
pusherKey | string | — | Pusher app key for real-time human agent messages. |
pusherCluster | string | "us2" | Pusher cluster. |
metadata | Record<string, any> | — | Extra metadata sent with every message. |
| Event | Payload | Description |
|---|---|---|
escalated | — | Fired when the conversation is escalated to a human agent. |
resolved | conversationId: string | Fired when the conversation is resolved. |
guest-identified | identity: GuestIdentity | Fired when a guest completes identification. |
<script setup lang="ts">
import { SyncAgentCustomerChat } from "@syncagent/vue";
const config = {
apiKey: "sa_your_api_key",
connectionString: import.meta.env.VITE_DATABASE_URL,
customerMode: true,
externalUserId: "user_abc123",
};
</script>
<template>
<SyncAgentCustomerChat :config="config" />
</template>
<template>
<SyncAgentCustomerChat
api-key="sa_your_api_key"
connection-string="your_connection_string"
position="bottom-left"
:default-open="true"
title="Need Help?"
subtitle="We're here for you"
/>
</template>
Embed the chat inside your layout instead of a floating button:
<template>
<div style="height: 600px">
<SyncAgentCustomerChat
api-key="sa_your_api_key"
connection-string="your_connection_string"
mode="inline"
/>
</div>
</template>
<template>
<SyncAgentCustomerChat
api-key="sa_your_api_key"
connection-string="your_connection_string"
:dark-mode="true"
accent-color="#8b5cf6"
/>
</template>
<script setup lang="ts">
import { SyncAgentCustomerChat } from "@syncagent/vue";
import type { GuestIdentity } from "@syncagent/vue";
function onEscalated() {
console.log("Conversation escalated to a human agent");
}
function onResolved(conversationId: string) {
console.log("Conversation resolved:", conversationId);
}
function onGuestIdentified(identity: GuestIdentity) {
console.log("Guest identified:", identity.name, identity.email);
}
</script>
<template>
<SyncAgentCustomerChat
api-key="sa_your_api_key"
connection-string="your_connection_string"
@escalated="onEscalated"
@resolved="onResolved"
@guest-identified="onGuestIdentified"
/>
</template>
useCustomerChat ComposableFor developers who want to build a fully custom chat UI, the useCustomerChat composable provides all the reactive state and methods without any pre-built UI.
| Option | Type | Required | Description |
|---|---|---|---|
client | SyncAgentClient | Yes | Client instance (configure with customerMode: true). |
externalUserId | string | No | Authenticated user ID. Bypasses guest flow when provided. |
onEscalated | () => void | No | Called when the conversation is escalated to a human agent. |
onResolved | (conversationId: string) => void | No | Called when the conversation is resolved. |
onGuestIdentified | (identity: GuestIdentity) => void | No | Called when a guest completes identification. |
| Name | Type | Description |
|---|---|---|
messages | Ref<Message[]> | Conversation message history. |
conversationId | Ref<string | null> | Current conversation ID (set after first message). |
isLoading | Ref<boolean> | true while awaiting a response. |
isEscalated | Ref<boolean> | true when escalated to a human agent. |
isResolved | Ref<boolean> | true when the conversation is resolved. |
error | Ref<Error | null> | Last error, or null. |
welcomeMessage | Ref<string | null> | Welcome message (first interaction only). |
isIdentified | Ref<boolean> | true when the user is identified (has externalUserId or completed guest form). |
guestIdentity | Ref<GuestIdentity | null> | The stored guest identity, or null. |
sendMessage | (content: string, metadata?: Record<string, any>) => Promise<void> | Send a message to the customer agent. |
rateConversation | (rating: number) => Promise<void> | Rate the conversation (1–5). |
identifyGuest | (data: { name: string; email: string; phone?: string }) => void | Submit guest identification data. |
reset | () => void | Clear all state and start fresh. |
<script setup lang="ts">
import { ref } from "vue";
import { SyncAgentClient } from "@syncagent/js";
import { useCustomerChat } from "@syncagent/vue";
const client = new SyncAgentClient({
apiKey: import.meta.env.VITE_SYNCAGENT_KEY,
connectionString: import.meta.env.VITE_DATABASE_URL,
customerMode: true,
externalUserId: "user_abc123",
});
const {
messages,
isLoading,
isEscalated,
isResolved,
error,
sendMessage,
rateConversation,
} = useCustomerChat({ client });
const input = ref("");
function send() {
if (!input.value.trim()) return;
sendMessage(input.value);
input.value = "";
}
</script>
<template>
<div class="my-custom-chat">
<div v-for="(msg, i) in messages" :key="i" :class="msg.role">
{{ msg.content }}
</div>
<p v-if="isEscalated">You're connected to a human agent.</p>
<div v-if="isResolved">
<p>Conversation resolved!</p>
<button @click="rateConversation(5)">⭐ Rate 5/5</button>
</div>
<p v-if="error" class="error">{{ error.message }}</p>
<form @submit.prevent="send">
<input v-model="input" placeholder="Ask a question..." :disabled="isLoading" />
<button type="submit" :disabled="isLoading || !input.trim()">Send</button>
</form>
</div>
</template>
The <SyncAgentCustomerChat> component uses the shared theme engine (computeTheme from @syncagent/js) to generate a complete WCAG-compliant color palette from two inputs:
accentColor — Any valid CSS color string (hex, rgb, hsl). Used for buttons, user message bubbles, focus outlines, and the header background. Defaults to #6366f1.darkMode — When true, generates a dark color scheme. All text-on-background pairs maintain a minimum 4.5:1 contrast ratio.All styles are applied inline, so no external CSS is required and no styles leak to or from your application. You can pass a className prop to add your own class for additional positioning or layout styles, and use the :style binding on a wrapper element for further customization.
<template>
<!-- Custom accent + dark mode -->
<SyncAgentCustomerChat
api-key="sa_your_api_key"
connection-string="your_connection_string"
accent-color="#ec4899"
:dark-mode="true"
class-name="my-chat-widget"
/>
</template>
<style>
.my-chat-widget {
/* Additional layout styles — component colors are handled internally */
margin: 16px;
}
</style>
The <SyncAgentCustomerChat> component is built to meet WCAG 2.1 AA standards:
role="region" with an aria-label. The message list uses role="log" to convey its purpose to assistive technologies.aria-live="polite" with aria-relevant="additions", so screen readers announce incoming messages without interrupting the user.useSyncAgent(options)| Option | Type | Description |
|---|---|---|
client | SyncAgentClient | Required. Create with new SyncAgentClient(config) |
context | Record<string,any> | Extra context injected into every message |
onData | (data: ToolData) => void | Called when a DB tool returns data |
| Name | Type | Description |
|---|---|---|
messages | Readonly<Ref<Message[]>> | Conversation history |
isLoading | Readonly<Ref<boolean>> | True while streaming |
error | Readonly<Ref<Error|null>> | Last error |
status | Readonly<Ref<{step,label}|null>> | Live status (connecting, querying, thinking, done) |
lastData | Readonly<Ref<ToolData|null>> | Last DB query result |
sendMessage | (content: string) => Promise<void> | Send a message |
stop | () => void | Abort current stream |
reset | () => void | Clear all messages |
| Database | Connection String Format |
|---|---|
| MongoDB | mongodb+srv://user:pass@cluster.mongodb.net/mydb |
| PostgreSQL | postgresql://user:pass@host:5432/mydb |
| MySQL | mysql://user:pass@host:3306/mydb |
| SQLite | /absolute/path/to/database.sqlite |
| SQL Server | Server=host,1433;Database=mydb;User Id=user;Password=pass;Encrypt=true; |
| Supabase | https://xxx.supabase.co|your-anon-key |
| Plan | Requests/mo | Collections | Price |
|---|---|---|---|
| Free (+ 14-day trial) | 100 (500 during trial) | 5 | GH₵0 |
| Starter | 5,000 | 20 | GH₵150/mo |
| Pro | 50,000 | Unlimited | GH₵500/mo |
| Enterprise | Unlimited | Unlimited | Custom |
MIT
FAQs
SyncAgent Vue 3 SDK — composables and chat component
We found that @syncagent/vue 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
Laravel Lang packages were compromised with an RCE backdoor across hundreds of versions, exposing cloud, CI/CD, and developer secrets.

Security News
Socket found a malicious postinstall hook across 700+ GitHub repos, including PHP packages on Packagist and Node.js project repositories.

Security News
Vibe coding at scale is reshaping how packages are created, contributed, and selected across the software supply chain