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

fql-toolkit

v4.2.5

Published

Fql Toolkit

Readme

fql-toolkit

TypeScript client library for FQL (Form Query Language). Wraps the CL-FQL REST API with a typed, chainable interface so frontends don't have to hand-craft FQL strings or manage fql_token manually.

Installation

npm install fql-toolkit

Quick Start

import FQLClient from 'fql-toolkit';
import { AuthManager } from 'fql-toolkit/auth';

// 1. Create an AuthManager (handles login, guest sessions, storage)
const auth = new AuthManager({
  baseURL: 'http://localhost:7645',
  storage: localStorage,
});

await auth.login('[email protected]', 'password');

// 2. Create a client that reads the token from auth automatically
const client = new FQLClient({
  baseURL: 'http://localhost:7645',
  auth,
});

// 3. Use it
const res = await client.form('Employees')
  .labels('name', 'salary')
  .with('salary', '>', 50000)
  .get();

if (res.ok) {
  console.log(res.data);
} else {
  console.error(res.error);
}

Auth module

fql-toolkit/auth exports AuthManager — a pure TypeScript class that handles all CL-FQL auth operations, persists state to configurable storage, and notifies subscribers on changes.

Import paths

import { AuthManager }                          from 'fql-toolkit/auth';
import { useAuth }                               from 'fql-toolkit/auth/react';
import type { AuthUser, AuthState, AuthResult }  from 'fql-toolkit/auth';

new AuthManager(options)

| Option | Type | Description | |-----------|---------------------------|-------------| | baseURL | string | Backend base URL, e.g. http://localhost:7645 | | storage | AuthStorage \| null | Where to persist auth state. Pass localStorage, sessionStorage, or null for memory-only. |

AuthStorage is any object with getItem / setItem / removeItemlocalStorage and sessionStorage both qualify.

Auth state is persisted under the key "fql-auth". On construction, AuthManager hydrates from storage automatically — no extra init() call needed.

Auth operations

All async methods return Promise<AuthResult> and never throw. On network or HTTP error they return { ok: false, error: '...' }.

const auth = new AuthManager({ baseURL: 'http://localhost:7645', storage: localStorage });

// Guest session (always available, even before login)
await auth.enterAsGuest();

// Login
const result = await auth.login('[email protected]', 'password');
if (!result.ok) console.error(result.error);

// Logout — clears state and automatically re-enters as guest
await auth.logout();

// Registration (sends activation email; result.user is absent)
await auth.register('[email protected]', { activationURL: 'https://myapp.com/activate?token=' });

// Account activation (does not set user state — call login() after)
await auth.activateAccount('nickname', activationToken, 'password');

// Password reset
await auth.requestPasswordReset('[email protected]', { resetPasswordURL: 'https://myapp.com/reset?token=' });
await auth.resetPassword(token, 'newpassword');

State access

auth.getToken();   // string | null
auth.getState();   // { user: AuthUser | null, token: string | null, loggedIn: boolean }

loggedIn is true only when the authenticated user has role !== 'GUEST'.

AuthUser type

type AuthUser =
  | { id: number; token: string; role: 'GUEST' }
  | { id: number; email: string; nickname: string; token: string; role: 'SUPERADMIN' | 'ADMIN' | 'USER' }

useAuth(manager) — React hook

import { useAuth } from 'fql-toolkit/auth/react';

function MyComponent() {
  const { user, token, loggedIn } = useAuth(auth);
  // Re-renders on every auth state change
}

Requires React 18+. Uses useSyncExternalStore internally — SSR-safe.

Observer (non-React)

const unsubscribe = auth.subscribe(() => {
  console.log('auth state changed:', auth.getState());
});

unsubscribe(); // stop listening

CL-FQL endpoints called

| Operation | Endpoint | |-----------|----------| | enterAsGuest | POST /api/auth/register/guest | | login | POST /api/auth/login | | register | POST /api/auth/register | | activateAccount | POST /api/auth/activate | | requestPasswordReset | POST /api/auth/request-password-reset | | resetPassword | POST /api/auth/reset-password |


new FQLClient(config)

Accepts either a static token or an AuthManager:

// Static token (simple scripts, server-side)
const client = new FQLClient({ baseURL: 'http://localhost:7645', token: 'jwt-token' });

// AuthManager (recommended for frontends — token is read dynamically on every request)
const client = new FQLClient({ baseURL: 'http://localhost:7645', auth: authManager });

| Option | Type | Description | |-----------|-----------------|-------------| | baseURL | string | Backend base URL | | token | string | Static JWT. Use when auth is not provided. | | auth | AuthManager | Auth manager. Token is read on every request — stays current after login/logout. |


client.forms — Form management (DDL)

client.forms.create(input)

Creates a new form. dataSpecs defines scalar fields; dataRefs defines reference fields.

await client.forms.create({
  name: 'Orders',
  dataSpecs: [
    { name: 'amount',   type: 'number', notNull: true },
    { name: 'note',     type: 'text' },
    { name: 'approved', type: 'boolean' },
  ],
  dataRefs: [
    { name: 'customer', cardinality: [1, 1],      path: 'Customers.id' },
    { name: 'items',    cardinality: [0, 'many'],  path: 'Products.id' },
  ],
});

Type aliases accepted for type: stringtext, int / integer / float / doublenumber, boolboolean.

client.forms.show(formNames?)

await client.forms.show();                        // all forms
await client.forms.show(['Orders', 'Customers']); // specific forms

client.forms.modify(formName, changes)

await client.forms.modify('Orders', {
  add:    [{ name: 'discount', type: 'number' }],
  remove: ['note'],
});

client.forms.remove(formNameOrNames)

await client.forms.remove('Orders');
await client.forms.remove(['Orders', 'Customers']);

client.form(name) — Record management (DML)

.create(data)

await client.form('Orders').create({ amount: 150, approved: true });

.get() / .labels(...fields).get()

// All records, all fields
await client.form('Orders').get();

// Specific fields
await client.form('Orders').labels('amount', 'approved').get();

// With filter
await client.form('Orders')
  .labels('amount')
  .with('approved', '=', true)
  .get();

.with(field, operator, value)

Adds a filter condition. Multiple calls are ANDed together.

await client.form('Orders')
  .with('amount', '>', 100)
  .with('approved', '=', true)
  .get();

Dot notation for reference fields:

.with('customer.name', '=', 'Acme Corp')

Supported operators: = != <> < > <= >=

.modify(newValues)

Updates matching records. At least one .with() required. Fetches fql_token automatically.

await client.form('Orders')
  .with('amount', '=', 150)
  .modify({ amount: 200, approved: false });

.remove()

Removes matching records. At least one .with() required. Fetches fql_token automatically.

await client.form('Orders')
  .with('approved', '=', false)
  .remove();

client.execute(fqlString, fqlToken?)

Escape hatch for raw FQL commands not covered by the builder API.

await client.execute('show forms');
await client.execute('get Employees with salary > 50000');

// Pass fql_token manually for raw modify/remove:
const getRes = await client.execute('get Orders with amount = 150');
await client.execute('remove Orders with amount = 150', getRes.fqlToken);

Response shape

All methods return Promise<FQLResult<T>>:

interface FQLResult<T = unknown[]> {
  ok:       boolean;       // false on error
  data:     T | null;      // null when ok === false
  error:    string | null; // non-null when ok === false
  message:  string;        // backend message (always present)
  fqlToken: FQLToken | null;
}
const res = await client.form('Orders').get();

if (!res.ok) {
  console.error(res.error);
} else {
  const orders = res.data; // unknown[] by default, cast as needed
}

Error handling

Validation errors (missing name, unknown type, missing .with() condition) throw FQLError synchronously before any network call.

import { FQLError } from 'fql-toolkit';

try {
  await client.form('Orders').remove(); // no .with() → throws
} catch (err) {
  if (err instanceof FQLError) console.error(err.message);
}

Network and backend errors are returned as FQLResult with ok: false — they do not throw.


Testing

# Unit tests (no backend needed)
npm run test:unit

# Integration tests (requires a running CL-FQL backend)
# 1. Copy .env.example → .env and fill in FQL_URL and FQL_API_KEY
# 2. Run:
npm run test:integration