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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@flotiq/flotiq-api-sdk

v1.0.0-alpha.12

Published

Dedicated js/ts client for Flotiq API which focuses on type safety and IDE autocompletion of user data types.

Readme

Flotiq API Javascript/Typescript SDK

Dedicated js/ts client for Flotiq Headless CMS API which focuses on type safety and IDE autocompletion of user data types.

With types generated using our typegen command, it enables fast and typesafe development with Flotiq as a data backend.

Generated flotiq-api.d.ts types can be either committed with your code, or .gitignore-d and generated during development and CI/CD.

You can still use all the API features without type generation. TypeScript user types can be added or removed at any point in development without code changes required.

Note: This SDK is stable and actively maintained. It is production-ready as of version 1.0.0.
New features and improvements are still planned — see Development Status for more.

Table of contents:

Features

| | JavaScript | Typescript | | ---------------------------------------------------------------------------- | ---------- | ---------- | | Fetch and update Flotiq content | ✅ | ✅ | | Search API | ✅ | ✅ | | TS/JS types for content definitions in data | ✅* | ✅** | | TS/JS types for content definitions in data with hydrated relations | ✅* | ✅** | | TS/JS types for content definitions in filters | ✅* | ✅** | | Discriminating between data types in any type relations and search responses | ✅*** | ✅*** | | Custom Middleware (e.g. to add next cache to each fetch) | ✅ | ✅ | | Generating URL to uploaded Media | ✅ | ✅ | | CTD operations | ❌ | ❌ |

  • * Requires typegen types and <reference path="./flotiq-api.d.ts" /> annotation
  • ** Requires typegen types
  • *** Requires typegen types, only with api.helpers.instanceOf helper

Installation from npm

  1. run npm install @flotiq/flotiq-api-sdk
  2. (optional) Generate typescript types for your data definitions
    1. Create .env file and add FLOTIQ_API_KEY env variable inside
    2. Run npm exec flotiq-api-typegen to generate account type definitions

Installation from yarn

  1. run yarn add @flotiq/flotiq-api-sdk
  2. (optional) Generate typescript types for your data definitions
  3. Create .env file and add FLOTIQ_API_KEY env variable inside
  4. Run yarn exec flotiq-api-typegen to generate account type definitions

Usage examples

In JS (CommonJS)

// Only if types were generated:
/// <reference path="./flotiq-api.d.ts" />

const { Flotiq } = require("@flotiq/flotiq-api-sdk");

const api = new Flotiq(); // read api key automatically from process.env.FLOTIQ_API_KEY
// or
const api = new Flotiq({
  apiKey: "<YOUR API KEY>",
});

await api.content._media.list().then((response) => {
  console.log("media > list", response);
});

In Typescript

import { Flotiq } from "@flotiq/flotiq-api-sdk";

const api = new Flotiq(); // read api key automatically from process.env.FLOTIQ_API_KEY
// or
const api = new Flotiq({
  apiKey: "<YOUR API KEY>",
});

await api.content._media.list().then((response) => {
  console.log("media > list", response);
});

List objects

api.content._media.list().then((response) => {
  console.log("media > list", response);
});

api.content._media
  .list({
    page: 1,
    limit: 100,
    orderBy: "fileName",
    orderDirection: "asc",
  })
  .then((response) => {
    console.log(
      "media > list (limit=100, page=1, orderBy=fileName,asc)",
      response
    );
  });

Get object

api.content._media.get("_media-xyz-id").then((response) => {
  console.log("media > get by id", response);
});

Hydrate objects

// works also on list()
api.content._media.get("_media-xyz-id", { hydrate: 1 }).then((response) => {
  console.log("media > get", response.tags);
});

Hydrate objects to second level

// works also on list()
api.content._media.get("_media-xyz-id", { hydrate: 2 }).then((response) => {
  console.log("media > get", response.tags);
});

Generate media url

// works also on list()
api.content._media.get("_media-xyz-id").then((response) => {
  console.log(
    "media > url",
    api.helpers.getMediaUrl(response, {
      width: 200,
      height: 200,
    })
  );
});

Filter Objects

api.content.blogpost
  .list({
    filters: {
      image: {
        type: "contains",
        filter: "_media",
      },
    },
  })
  .then((response) => {
    console.log("only blogposts with image", response);
  });

Create objects

api.content.blogpost
  .create({
    title: "New post 2",
  })
  .then((newPost) => console.log(newPost.id));

Batch create objects

api.content.blogpost
  .batchCreate([
    {title: "New post 2"},
    {title: "New post 3"}
  ])
  .then(({ batch_success_count }) => console.log(batch_success_count));

Batch delete objects

api.content.blogpost
  .batchDelete(["post-1", "post-2"])
  .then(({ deletedCount }) => console.log(deletedCount));

Iterate all pages

const params = {
  page: 1,
  limit: 100,
  orderBy: "fileName" as keyof InternalMedia,
  orderDirection: "asc" as "asc" | "desc",
};

let result: ListResponse<InternalMedia>;
do {
  result = await api.content._media.list(params);
  console.log(result.data[0].fileName);
  params.page++;
} while (result.total_pages > result.current_page);

Search API

api.search.query({ q: "asd" }).then((response) => {
  console.log(
    "search score for item 0",
    response.data[0].score,
    response.data[0].item.id
  );
});

Search API with type checking

api.search
  .query({ q: "The name of the thing" })
  // note added response type below:
  .then((response: SearchResponse<Blogpost | Product>) => {
    for (const searchResult of response.data) {
      if (api.helpers.instanceOf(searchResult.item, "blogpost")) {
        // firstResult.item is now Blogpost
        console.log("Found blogpost!", searchResult.item.title);
      } else if (api.helpers.instanceOf(searchResult.item, "product")) {
        // firstResult.item is now Product
        console.log("Found product!", searchResult.item.name);
      } else {
        // firstResult.item is neither Blogpost or Product
        // do nothing
      }
    }
  });

CTD Scoped Search API

api.content.blogpost.search({ q: "Product updates" }).then((response) => {
  const blogpost = response.data[0].item; // Typed as Blogpost!
  console.log("Typed search result", blogpost.title);
});

Middleware Intercepting all requests that go to flotiq api:

const api = new Flotiq({
  apiKey: "<YOUR API KEY>",
  middleware: [
    {
      beforeRequest: async (requestContext) => {
        console.log("Requesting:", requestContext.url);

        return {
          ...requestContext,
          init: {
            ...requestContext.init,
            headers: {
              ...requestContext.init.headers,
              "User-Agent": "My cool app",
            },
          },
        };
      },
    },
  ],
});

SDK API - Flotiq class

constructor

import { Flotiq } from "@flotiq/flotiq-api-sdk";

const api = new Flotiq(); 
//or
const api = new Flotiq(options); 

options argument can contain the following properties:

  • apiKey: string - your Flotiq api key. If none provided, process.env.FLOTIQ_API_KEY will be used.
  • apiUrl: string - Flotiq API url. By default, it points to https://api.flotiq.com. You'll need to change it only if you are Flotiq Enterprise client, with self-hosted Flotiq instance.
  • middleware: Array - an array of middleware objects intercepting all requests. If multiple middlewares are used, they will be executed in order provided in the array.
    • middleware[].beforeRequest - a callback intercepting each request before it happens. It can override all fetch options (including url) and fetch method itself. It must return new (or modified) context.
       {
         beforeRequest: (requestContext: {
           url: string;
           init: RequestInit;
           fetch: typeof fetch;
         }) => Promise<{
           url: string;
           init: RequestInit;
           fetch: typeof fetch;
         }>
       }

api.content.<content_definition_api_name>

You can access each content type data api using its api name.

Content api provides following methods:

  • list(listOptions) - used to list mulitple objects. For more infe see Flotiq Docs - Listing content through the API. listOptions can contain following properties:

    • hydrate: 0 | 1 | 2 - hydration level for relations. 0 will not include related objects, 1 will join data from related objects, 2 will join data from related objects and from their relations. Default value is 0.
    • filters: Object - object containing filtering rules
    • orderBy: string - which Content Type Definition property determines the order
    • orderDirection: "asc" | "desc" - order direction
    • limit: number - how many results should be returned in the result
    • page: number - page number. With limit: 10, page: 1 will return first 10 results, page: 2 - results 11-20 and so on.
  • get(id: string, options) - find single object by its id. options is an object with following properties:

    • hydrate: 0 | 1 | 2 - hydration level (see above)
  • update(id: string, data: Object) - Perform PUT operation on Content Type Object with provided data.

  • patch(id: string, data: Object) - Perform PATCH operation on Content Type Object with partial data.

  • delete(id: string) - remove single object.

  • create(data: Object) - create new object

  • search(searchParams) - search through all objects of given type with Full-text search API endpoint. (see detailed parameters below)

    Results are scoped to selected Content Type Definition, therefore the two following search queries are performing the same API call:

      api.content.<content_definition_api_name>.search({
        q: 'search string'
      })
       api.search.query({ 
         contentType: ["<content_definition_api_name>"], 
         q: 'search string' 
       })

api.search.query(searchParams)

Performs Full-text search operation with provided parameters. For more details see Flotiq docs - Search API.

searchParams accepts the following parameters:

  • orderBy: string - which field determines order of results
  • orderDirection: "asc" | "desc" - ordering direction
  • limit: number - number of results per page
  • page: number - page number
  • q: string - query string (required)
  • contentType: string[] - Limits results to provided content types. If not provided, Search API will search through all Content Type Definitions.

api.helpers

Helper methods to work with API and SDK itself. These are:

  • api.helpers.getMediaUrl(media: InternalMedia, options) - generate url to media file uploaded to Flotiq. options can contain:

    • width: number, height: number - for images, Flotiq will return resized image. If one of the dimensions is omitted, resize operation will preserve original image proportions.
    • variantName: string - for images, Flotiq will return variant of the image. Can be also resized. If variant is not present url fallbacks to original image
    • type: 'image'| 'file' - default: 'image', use it to change the url behaviour and return urls with '/file/' instead of '/image/widthxheight/'.
    • omitFileName: boolean - default: false, use it to change the url behaviour and return urls with '/ID.extension' instead of '/ID/fileName'.
  • api.helpers.instanceOf(data: object, ctdName: string) - checks if object belongs to provided CTD.

    When using generated Typescript types, it will determine which Content Type Definition interface is the object typed with. See Search API with type checking example for more detailed use case. It will also help determine hydrated relation data type.

  • api.helpers.hydrate(contentObject, options) - virtually hydrate content object with its relations. This method allows you to hydrate objects after they have been fetched, which is useful when you need different hydration levels for different use cases or when you need to hydrate only selected types.

    options can contain:

    • level?: number - hydration level, determines how deep the relations should be hydrated
    • failMode?: "throw" | "insertNull" | "ignore" - how to handle failed hydration attempts - default: throw
      • throw - if any relation is not found, throw an error
      • insertNull - replace data link object with null if relation was not found
      • ignore - leave data link object if relation was not found
    • hydratedTypes?: string[] - array of content type names to hydrate (if not provided, all relations will be hydrated)

    Example:

    const blogPost = await api.content.blogPost.get("id");
    const blogPostHydratedTwice = await api.helpers.hydrate(blogPost, { 
      failMode: "insertNull", 
      hydratedTypes: ["category"], 
      level: 2,
    });
    if (api.helpers.instanceOf(blogPostHydratedTwice.category, "category")) {
      // category is now typed as Category
      console.log(blogPostHydratedTwice.category.name);
    }

flotiq-api-typegen

flotiq-api-typegen

Generates types for Flotiq API based on the content type definitions on your account

Options

| Option | Description | Default | | ------ | ----------- | ------- | | --flotiq-key | Flotiq API key with read only access | | | --flotiq-api-url | Url to the Flotiq API | https://api.flotiq.com | | --output | Path to target filename | ./flotiq-api.d.ts | | --watch | Watch for changes in the content type definitions and regenerate types | false |

Development

See CONTRIBUTING.md

Development Status

Features that might appear in the future (not necessarily before v1):

  • JS flavour support

    • [x] Typescript - ts files
    • [x] CommonJS - js with require
    • [ ] ECMAScript - js with import (esm build needs to be added, for now it may not work in all projects)
  • [x] typegen based on CTDs

    • [x] filter knows what filter flotiq have
    • [x] (partial) filter knows what fields user have (were missing internals for the moment, but own fields are listed)
    • [x] hydrate knows what are results for different hydration levels
    • [x] crud operations know param and result types
    • [x] filter knows it can only list
    • [x] hydrate knows it can only list and get
  • [x] basic get/list/update/create/delete objects

  • [x] filter

    • [x] smart filter types that know if they require filter and filter2 params
  • [x] hydration

    • [ ] default hydration: export const flotiq = new Flotiq({ hydrate: 1 })
  • [ ] search (wip)

    • [x] content type scoped search
    • [ ] all search params
    • [x] result type recognition
  • [ ] virtual hydration (e.g. after search)

  • [x] batch operations

  • [x] ordering

  • [x] pagination parameters

  • [x] middlewares (e.g. for next)

    • [x] fetch override
  • [ ] CTD operations (list/create/get/update) - flotiq.definitions.list() etc

  • [x] api key autoloading from .env when creating Flotiq

  • [x] getMediaUrl

  • [ ] upload media api

  • [x] changelog

  • [ ] contributing guide (in progress)

  • [x] CLI params, help text and other DX features (yargs)

  • [ ] Namespace support for multiple spaces used

    • proposed api:

      const defaultApi = new Flotiq(); // Based on key provided as FLOTIQ_API_KEY
      const blogApi = new Flotiq.ns.Blog(); // Based on space name or provided alias && FLOTIQ_BLOG_API_KEY
      const pageApi = new Flotiq.ns.Page(); // Based on space name or provided alias && FLOTIQ_PAGE_API_KEY
      
      blogApi.content.blogpost... // typed ctds from blog space
      pageApi.content.menu...  // Typed ctds from page space
      
      pageApi.content.blogpost... // Not existing ctds in given space will not provide typing and throw an error 404 from backend
    • example data migration

    • example - cross space usage (e.g. next implementation of https://flotiq.com/blog/)