Typescript SDK

TypeScript SDK Quick Start — WowSQL Docs

TypeScript / JavaScript Quick Start

WowSQL TypeScript SDK — Get started in minutes

Get your API key: Use the WowSQL project dashboard to create or copy your API key. The same key works for database, auth, and storage (unified API key).

Installation

Official package: View on npm →

npm install @wowsql/sdk
# or: yarn add @wowsql/sdk
# or: pnpm add @wowsql/sdk

Initialize Client

import WowSQLClient from '@wowsql/sdk';

// Initialize client with your API key
// Note: The same key works for database, auth, and storage operations
const client = new WowSQLClient({
  projectUrl: 'myproject',  // Your project subdomain
  apiKey: 'your_api_key_here'  // Single key for all operations
});

// Or with full URL
const clientFull = new WowSQLClient({
  projectUrl: 'https://myproject.wowsqlconnect.com',
  apiKey: 'your_api_key'
});

// CORRECT: Use .select() before .get()
const users = await client.table('users').select('*').get();

Example API Call (REST)

You can also call the API directly with fetch:

const response = await fetch(`${API_URL}/api/v1/db/tables/users/query`, {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    select: ['id', 'email', 'name'],
    filters: [{ column: 'status', operator: 'eq', value: 'active' }],
    order_by: [{ column: 'created_at', direction: 'desc' }],
    limit: 10
  })
});
const data = await response.json();
console.log(data);

Query Data

Basic Queries

// Get all records - use .select() before .get()
const users = await client.table('users').select('*').get();

// With filters - use .filter() or helper methods
const adults = await client.table('users')
  .select('*')
  .filter({ column: 'age', operator: 'gte', value: 18 })
  .get();

// Or using filter(column, operator, value)
const adults2 = await client.table('users')
  .select('*')
  .filter('age', 'gte', 18)
  .get();

// Select specific columns
const names = await client.table('users')
  .select(['id', 'name'])
  .get();

Advanced Queries

// Multiple filters with sorting
const activeUsers = await client.table('users')
  .filter({ column: 'status', operator: 'eq', value: 'active' })
  .filter({ column: 'age', operator: 'gt', value: 18 })
  .order('created_at', 'desc')
  .limit(20)
  .offset(0)
  .get();

console.log(`Found ${activeUsers.count} users`);
activeUsers.data.forEach(user => console.log(user.name));

Filter Helper Methods

// Using helper methods (more readable)
const users = await client.table('users')
  .eq('status', 'active')
  .gt('age', 18)
  .like('email', '%@gmail.com')
  .isNotNull('email_verified_at')
  .in('role', ['admin', 'moderator'])
  .between('created_at', '2024-01-01', '2024-12-31')
  .get();

// OR conditions
const usersOr = await client.table('users')
  .eq('status', 'active')
  .or('role', 'eq', 'admin')
  .get();

GROUP BY and Aggregates

Basic GROUP BY

// Group by category with counts
const result = await client.table('products')
  .select('category', 'COUNT(*) as count', 'AVG(price) as avg_price')
  .groupBy('category')
  .get();

// Group by date
const result2 = await client.table('orders')
  .select('DATE(created_at) as date', 'COUNT(*) as orders', 'SUM(total) as revenue')
  .groupBy('DATE(created_at)')
  .orderBy('date', 'desc')
  .get();

// Multiple GROUP BY columns
const result3 = await client.table('sales')
  .select('region', 'category', 'SUM(amount) as total')
  .groupBy(['region', 'category'])
  .get();

HAVING Clause

// Filter aggregated results
const result = await client.table('products')
  .select('category', 'COUNT(*) as count')
  .groupBy('category')
  .having('COUNT(*)', 'gt', 10)
  .get();

// Multiple HAVING conditions
const result2 = await client.table('orders')
  .select('DATE(created_at) as date', 'SUM(total) as revenue')
  .groupBy('DATE(created_at)')
  .having('SUM(total)', 'gt', 1000)
  .having('COUNT(*)', 'gte', 5)
  .get();

Multiple ORDER BY

// Order by multiple columns
const result = await client.table('products')
  .select('*')
  .orderByMultiple([
    { column: 'category', direction: 'asc' },
    { column: 'price', direction: 'desc' },
    { column: 'created_at', direction: 'desc' }
  ])
  .get();

CRUD Operations

Create Record

const result = await client.table('users').create({
  name: 'John Doe',
  email: 'john@example.com',
  age: 30
});

console.log(`Created user with ID: ${result.id}`);

Update Record

await client.table('users').update(123, {
  email: 'newemail@example.com'
});

console.log('User updated successfully');

Delete Record

await client.table('users').delete(123);
console.log('User deleted successfully');

Get Single Record by ID

const user = await client.table('users').getById(123);
console.log(`User: ${user.name}`);

Get First Record

// Get first matching record
const user = await client.table('users')
  .filter({ column: 'status', operator: 'eq', value: 'active' })
  .first();

if (user) {
  console.log(`First active user: ${user.name}`);
}

Type-safe Queries

Use generics for full type safety and autocomplete:

import { WowSQLClient, QueryResponse } from '@wowsql/sdk';

interface User {
  id: number;
  name: string;
  email: string;
  age: number;
}

const client = new WowSQLClient({ projectUrl: 'myproject', apiKey: 'key' });

// Type-safe table access
const users: QueryResponse<User> = await client.table<User>('users').get();

// Full type safety and autocomplete
users.data.forEach((user: User) => {
  console.log(user.name);  // TypeScript knows this is a string
});

Error Handling

import { WowSQLError } from '@wowsql/sdk';

try {
  const users = await client.table('users').select('*').get();
  console.log(`Success: ${users.data.length} users`);
} catch (error) {
  if (error instanceof WowSQLError) {
    if (error.statusCode === 401) console.error('Authentication failed — check your API key');
    else if (error.statusCode === 404) console.error('Table or resource not found');
    else console.error(`Error (${error.statusCode}): ${error.message}`);
  } else throw error;
}

Filter Operators

Available operators for filtering data:

OperatorDescriptionExample (TypeScript)
eqEquals.filter({ column: 'status', operator: 'eq', value: 'active' })
neqNot equals.filter({ column: 'status', operator: 'neq', value: 'deleted' })
gtGreater than.filter({ column: 'age', operator: 'gt', value: 18 })
gteGreater than or equal.filter({ column: 'age', operator: 'gte', value: 18 })
ltLess than.filter({ column: 'price', operator: 'lt', value: 100 })
lteLess than or equal.filter({ column: 'price', operator: 'lte', value: 100 })
likePattern matching.filter({ column: 'name', operator: 'like', value: 'john' })
isIS NULL / IS NOT NULL.filter({ column: 'deleted_at', operator: 'is', value: null })
inIN operator.filter('category', 'in', ['electronics', 'books'])
not_inNOT IN.filter('status', 'not_in', ['deleted', 'archived'])
betweenBETWEEN.filter('price', 'between', [10, 100])
not_betweenNOT BETWEEN.filter('age', 'not_between', [18, 65])

Authentication

Use the same API key for authentication operations. The unified key system means one key works for both database and auth.

Sign Up & Sign In

import { ProjectAuthClient } from '@wowsql/sdk';

const auth = new ProjectAuthClient({
  projectUrl: 'myproject',
  apiKey: 'your_api_key'  // Same key as database client
});

// Sign up
const result = await auth.signUp({
  email: 'user@example.com',
  password: 'SecurePassword123',
  full_name: 'John Doe'
});
console.log(`Access token: ${result.session.accessToken}`);

// Sign in
const login = await auth.signIn({
  email: 'user@example.com',
  password: 'SecurePassword123'
});
console.log(`User ID: ${login.user?.id}`);

Password Reset

// Request password reset
await auth.forgotPassword('user@example.com');

// Reset password with token from email
await auth.resetPassword('reset_token_from_email', 'NewSecurePassword123');

OTP Authentication

// Send OTP for login
await auth.sendOtp({ email: 'user@example.com', purpose: 'login' });

// Verify OTP and login
const result = await auth.verifyOtp({
  email: 'user@example.com',
  otp: '123456',
  purpose: 'login'
});
console.log(`Logged in: ${result.user?.id}`);

Magic Link & Email Verification

// Send magic link
await auth.sendMagicLink({ email: 'user@example.com', purpose: 'login' });

// Verify email with token
await auth.verifyEmail('verification_token_from_email');

// Resend verification email
await auth.resendVerification('user@example.com');

OAuth Authentication

Setup checklist — do this once per provider, per project:
1. In your WowSQL dashboard → Project → Auth → Providers, enable the provider (e.g. Google) and paste the Client ID and Client Secret from your provider's developer console.
2. Copy the Redirect URI shown in the dashboard (https://<project-slug>.wowsqlconnect.com/api/auth/oauth/<provider>/callback) and add it to your provider's list of Authorised redirect URIs (Google: Cloud Console → Credentials → OAuth 2.0 client → Authorised redirect URIs).
3. Make sure the Client ID / Secret are pasted without leading or trailing spaces.

How the callback works: The OAuth callback URL (/api/auth/oauth/<provider>/callback) is handled entirely by the WowSQL backend — your application does not need to send an API key on that URL. The backend exchanges the code for tokens, creates/updates the user record, and then redirects to your frontend_redirect_uri with the session tokens as query parameters. You only need to handle the final redirect in your frontend.

// ── Step 1: Server-side — get the Google authorization URL ──────────────────
// Call from a server-side route (Next.js API route, Express handler, etc.).
// Never call from the browser directly — your API key must stay server-side.
import { ProjectAuthClient } from '@wowsql/sdk';

const auth = new ProjectAuthClient({
  projectUrl: process.env.WOWSQL_PROJECT_URL!, // e.g. https://<slug>.wowsqlconnect.com
  apiKey:     process.env.WOWSQL_ANON_KEY!,    // wowsql_anon_...
});

// frontend_redirect_uri: where YOUR app should land after the OAuth flow finishes
const { authorizationUrl } = await auth.getOAuthAuthorizationUrl(
  'google',
  'https://yourapp.com/auth/callback'   // must be an allowed origin in your app
);
// Redirect the browser to authorizationUrl — Google handles login from here.
// Google will call: https://<slug>.wowsqlconnect.com/api/auth/oauth/google/callback
// WowSQL backend exchanges the code and redirects to your frontend_redirect_uri.


// ── Step 2: Frontend — handle the redirect from WowSQL ──────────────────────
// WowSQL redirects to https://yourapp.com/auth/callback?access_token=...&refresh_token=...
// Read the tokens from the URL and store them.
// Example (Next.js page / React component):
import { useEffect } from 'react';
import { useRouter } from 'next/navigation';

export default function AuthCallbackPage() {
  const router = useRouter();

  useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    const accessToken  = params.get('access_token');
    const refreshToken = params.get('refresh_token');
    const error        = params.get('error');

    if (error) {
      console.error('OAuth error:', error);
      router.replace('/auth/login?error=' + error);
      return;
    }
    if (accessToken) {
      // Persist tokens however your app manages session (cookie, localStorage, etc.)
      sessionStorage.setItem('wowsql_access_token',  accessToken);
      sessionStorage.setItem('wowsql_refresh_token', refreshToken ?? '');
      router.replace('/dashboard');
    }
  }, []);

  return <p>Signing you in…</p>;
}


// ── (Advanced) Manual code exchange — only if you handle the callback yourself
const result = await auth.exchangeOAuthCallback(
  'google',
  'authorization_code_from_callback',
  'https://yourapp.com/auth/callback'  // must exactly match the redirect_uri used in step 1
);
console.log(`OAuth login successful: ${result.user?.id}`);

Storage Operations

Initialize Storage

import { WowSQLStorage } from '@wowsql/sdk';

const storage = new WowSQLStorage({
  projectUrl: 'myproject',
  apiKey: 'your_api_key'  // Same key for all operations
});

File Operations

// Upload file (from Buffer/Blob/File)
const result = await storage.upload(file, 'uploads/document.pdf', {
  folder: 'documents'
});
console.log(`Uploaded: ${result.file_key}`);

// Get file URL (with metadata)
const urlData = await storage.getFileUrl('uploads/document.pdf', { expiresIn: 3600 });
console.log(`Download URL: ${urlData.file_url}`);
console.log(`Expires at: ${urlData.expires_at}`);

// Get presigned URL
const presignedUrl = await storage.getPresignedUrl({
  objectKey: 'uploads/document.pdf',
  expiresIn: 3600,
  operation: 'get_object'
});
console.log(`URL: ${presignedUrl}`);

// List files
const files = await storage.listFiles({ prefix: 'uploads/' });
files.forEach(file => console.log(`${file.key}: ${file.size_mb?.toFixed(2)} MB`));

// Delete file
await storage.deleteFile('uploads/document.pdf');

// Check quota
const quota = await storage.getQuota();
console.log(`Used: ${quota.used_gb?.toFixed(2)} GB / ${quota.quota_gb?.toFixed(2)} GB`);

Download or View File

Via REST: use GET .../files/{file_key}/download for attachment download, or GET .../files/{file_key}/view to view inline in the browser.

Schema DDL (WowSQLSchema)

UUID primary key: POST /api/v2/schema/tables requires a primaryKey column with type UUID. Use auto_increment: true on that column for DEFAULT gen_random_uuid(). Raw CREATE TABLE via /api/v2/schema/execute cannot use SERIAL PRIMARY KEY (or similar integer PK). Existing tables are unchanged.

import { WowSQLSchema } from '@wowsql/sdk';

const schema = new WowSQLSchema({ projectUrl: 'myproject', serviceKey: 'wowsql_service_...' });
await schema.createTable({
  tableName: 'items',
  columns: [
    { name: 'id', type: 'UUID', auto_increment: true },
    { name: 'title', type: 'TEXT' },
  ],
  primaryKey: 'id',
});