Global

Members

Class

# constant BaseService

Export BaseService with observability mixin applied.

This demonstrates the mixin composition pattern. RawBaseService provides core CRUD operations, while withObservable wraps it to add automatic:

  • Timing (operation duration tracking)
  • Logging (structured logs for all operations)
  • Metrics (success/failure counts, duration stats)
  • Event emission (observability.service events)

How Mixins Work: withObservable() is a higher-order function that:

  1. Takes a service class (RawBaseService)
  2. Returns a new class that extends it
  3. Wraps key methods (getById, create, update, etc.)
  4. Adds pre/post hooks for timing and logging
  5. Emits events for monitoring

What This Means for Your Code:

const iconService = new IconService();
const icon = await iconService.getById(123);

// Automatically logged:
// "icon-service.getById success 45ms { id: 123 }"

// Automatically emitted:
// Event: observability.service
//   { service: 'icon', operation: 'getById', phase: 'success', durationMs: 45 }

// Automatically tracked:
// Metric: operation_duration_ms=45 operation=getById service=icon result=success

In Production: The full composition would include more mixins:

const BaseService =
  withObservable(
  withCacheable(
  withPluggable(
  withAccessControl(
  withSoftDeletable(
  withActivatable(
    RawBaseService
  ))))));
See:
  • withObservable For observability mixin documentation

View Source src/common/BaseService.js, line 601

# constant BaseService

CartService

  • Extends BaseService so all the standard CRUD flows are consistent.
  • Uses CartRepository for carts persistence.
  • Uses CartItemRepository for cart_items persistence (same module boundary).
  • Uses other modules via their initService() for product reads.

View Source src/carts/bak-CartService.js, line 12

# constant IconRepository

Icon repository with cursor pagination support.

Extends RawIconRepository with withCursorPagination mixin to provide efficient keyset-based pagination for large icon datasets (750K+ icons).

View Source src/products/icons/IconRepository.js, line 234

Examples
// Cursor paginate icons
const result = await iconRepo.cursorPaginate({
  filters: {
    price: 'free',
    tagIds: [1, 2, 3],
    styleId: 5
  },
  cursor: null,
  limit: 20,
  sortBy: 'createdAt',
  sortOrder: 'desc'
});
// Next page (using cursor from previous page)
const page2 = await iconRepo.cursorPaginate({
  filters: { price: 'free' },
  cursor: 'eyJpZCI6MTAyMCwiY3JlYXRlZEF0IjoiMjAyNC0wMS0xNVQxMDowMDowMFoifQ==',
  limit: 20
});

# categoriesPlugin

Categories Plugin Provides CRUD endpoints for managing categories. Routes:

  • GET /category/:page/:pageSize
  • GET /category/
  • GET /category/:id
  • POST /category
  • PATCH /category/:id
  • DELETE /category/:id Each route supports appropriate query parameters and request bodies as defined in the schemas.

View Source http/src/plugins/categories.plugin.js, line 14

# familiesPlugin

Families Plugin Provides CRUD endpoints for managing families. Routes:

  • GET /family/:userId/:page/:pageSize
  • GET /family/:page/:pageSize
  • GET /family/
  • GET /family/:id
  • POST /family
  • PATCH /family/:id
  • DELETE /family/:id Each route supports appropriate query parameters and request bodies as defined in the schemas.

View Source http/src/plugins/families.plugin.js, line 13

# iconsPlugin

Icons Plugin Provides CRUD endpoints for managing icons. Routes:

  • GET /icon/:userId/:page/:pageSize
  • GET /icon/:page/:pageSize
  • GET /icon
  • GET /icon/:id
  • POST /icon
  • PATCH /icon/:id
  • DELETE /icon/:id Each route supports appropriate query parameters and request bodies as defined in the schemas.

View Source http/src/plugins/icons.plugin.js, line 7

# imagesPlugin

Images Plugin Provides CRUD endpoints for managing images. Routes:

  • GET /image/:entityType/:entityId/:page/:pageSize
  • GET /image/:page/:pageSize
  • GET /image/:id
  • POST /image
  • PATCH /image/:id
  • DELETE /image/:id Each route supports appropriate query parameters and request bodies as defined in the schemas.

View Source http/src/plugins/images.plugin.js, line 13

number

# constant kDEFAULT_MAX_LIMIT

Maximum limit for pagination to prevent excessive data transfer.

View Source http/src/factory.js, line 37

# setsPlugin

Sets Plugin Provides CRUD endpoints for managing sets. Routes:

  • GET /set/:userId/:page/:pageSize
  • GET /set/:page/:pageSize
  • GET /set/
  • GET /set/:id
  • POST /set
  • PATCH /set/:id
  • DELETE /set/:id Each route supports appropriate query parameters and request bodies as defined in the schemas.

View Source http/src/plugins/sets.plugin.js, line 13

# tagsPlugin

Tags Plugin Provides CRUD endpoints for managing tags. Routes:

  • GET /tag/:page/:pageSize
  • GET /tag
  • GET /tag/:id
  • POST /tag
  • PATCH /tag/:id
  • DELETE /tag/:id Each route supports appropriate query parameters and request bodies as defined in the schemas.

View Source http/src/plugins/tags.plugin.js, line 5

Methods

# protected _applyArrayPositionCursor(query, cursorData, iconIdsOrder, sortOrder) → {Object}

Apply array position cursor condition (for Elasticsearch relevance sorting).

When sorting by Elasticsearch relevance, results are ordered by their position in the iconIdsOrder array. The cursor contains the array position, and we need to filter for items that come after that position.

Parameters:
Name Type Description
query Object

Objection.js query builder

cursorData Object

Decoded cursor data with arrayPosition

iconIdsOrder Array.<number>

Ordered array of icon IDs from Elasticsearch

sortOrder string

'asc' or 'desc'

View Source src/common/mixins/repository/withCursorPagination.js, line 494

Modified query

Object
Example
// Cursor: { arrayPosition: 20, id: 5005 }
// iconIdsOrder: [1001, 2003, 5005, 3002] (from Elasticsearch)
// Query: WHERE array_position(ARRAY[iconIdsOrder], id) > 20

# protected _applyArrayPositionSort(query, iconIdsOrder, sortOrder) → {Object}

Apply array position sorting (for Elasticsearch relevance).

Orders results by their position in the iconIdsOrder array, which preserves the relevance ranking from Elasticsearch.

Parameters:
Name Type Description
query Object

Objection.js query builder

iconIdsOrder Array.<number>

Ordered array of icon IDs from Elasticsearch

sortOrder string

'asc' or 'desc'

View Source src/common/mixins/repository/withCursorPagination.js, line 530

Modified query

Object
Example
// iconIdsOrder: [1001, 2003, 5005, 3002] (from Elasticsearch)
// ORDER BY array_position(ARRAY[iconIdsOrder], id) ASC

# protected _applyCursorCondition(query, cursorData, sortField, sortOrder) → {Object}

Apply cursor condition to query (keyset WHERE clause).

Builds the keyset condition for efficient pagination:

  • For DESC: WHERE (sort_field, id) < (cursor_value, cursor_id)
  • For ASC: WHERE (sort_field, id) > (cursor_value, cursor_id)

This uses composite index and is O(log n) instead of O(n).

Parameters:
Name Type Description
query Object

Objection.js query builder

cursorData Object

Decoded cursor data

sortField string

Database field to sort by (snake_case)

sortOrder string

'asc' or 'desc'

View Source src/common/mixins/repository/withCursorPagination.js, line 456

Modified query

Object

# protected _applyFilters(query, filters) → {Object}

Apply filters to query.

This is meant to be overridden in subclasses to handle domain-specific filters. The base implementation does nothing.

Subclasses should apply filters like:

  • price (free, premium, all)
  • tagIds (array of tag IDs)
  • styleId (design style)
  • userId (creator)
  • searchTerm (text search)
  • etc.
Parameters:
Name Type Description
query Object

Objection.js query builder

filters Object

Filter criteria

View Source src/common/mixins/repository/withCursorPagination.js, line 419

Modified query

Object
Example
// Override in IconRepository
_applyFilters(query, filters) {
  if (filters.price) {
    query.where('price', filters.price);
  }
  if (filters.tagIds && filters.tagIds.length > 0) {
    query.whereIn('tags.id', filters.tagIds);
  }
  return query;
}

# protected _createArrayPositionCursor(entity, iconIdsOrder) → {string}

Create cursor from entity for array position sorting.

For array position sorting, the cursor contains:

  • arrayPosition: Position in the iconIdsOrder array
  • id: Icon ID (for validation)
  • sortType: 'arrayPosition' (to distinguish from field-based cursors)
Parameters:
Name Type Description
entity Object

Entity instance or plain object

iconIdsOrder Array.<number>

Ordered array of icon IDs

View Source src/common/mixins/repository/withCursorPagination.js, line 562

Encoded cursor token

string
Example
// Entity: { id: 5005, name: 'home-icon' }
// iconIdsOrder: [1001, 2003, 5005, 3002] (from Elasticsearch)
// Cursor: { arrayPosition: 3, id: 5005, sortType: 'arrayPosition' }

# protected _toCamelCase(str) → {string}

Convert snake_case to camelCase.

Parameters:
Name Type Description
str string

snake_case string

View Source src/common/mixins/repository/withCursorPagination.js, line 598

camelCase string

string

# protected _toSnakeCase(str) → {string}

Convert camelCase to snake_case.

Parameters:
Name Type Description
str string

camelCase string

View Source src/common/mixins/repository/withCursorPagination.js, line 587

snake_case string

string

# assertService()

Tiny guard to make missing service configs fail loudly & clearly.

View Source src/carts/bak-CartService.js, line 378

# buildSchemas(entityClass) → {Object}

Build JSON schemas for common response types from an entity class.

Generates schemas for single entities, arrays of entities, paginated responses, and delete confirmations. These schemas are used for Fastify route response validation.

Parameters:
Name Type Description
entityClass function

Entity class with static getJsonSchema() method

View Source http/src/factory.js, line 56

Object containing:

  • entitySchema: Schema for single entity
  • listSchema: Schema for array of entities
  • paginatedSchema: Schema for paginated response with metadata
  • deletedSchema: Schema for delete confirmation { deleted: boolean }
Object
Example
const schemas = buildSchemas(IconEntity);
// schemas.paginatedSchema can be used in route response validation

# createEntityFromModel(ModelClass, extraMethodsopt, optionsopt) → {function}

Factory function to create an immutable Entity class from an Objection.js Model.

This is the primary way to define entities in the system. It automatically:

  • Converts snake_case database columns to camelCase entity properties
  • Derives a JSON schema from the Model's jsonSchema
  • Filters hidden fields (passwords, tokens, etc.)
  • Materializes related entities (lazy-loaded to avoid circular dependencies)
  • Freezes instances for immutability
  • Validates data against the derived schema

Why This Pattern?

  • Separation of Concerns: Database models (Objection) vs. domain entities (business logic)
  • Immutability: Frozen entities prevent accidental mutations
  • Type Safety: JSON schema provides runtime validation
  • Security: Hidden fields prevent sensitive data leakage
  • Flexibility: Related entities can be included/excluded dynamically
Parameters:
Name Type Attributes Default Description
ModelClass Object

Objection.js Model class with jsonSchema

extraMethods Object <optional>
{}

Additional methods to add to entity instances

options Object <optional>
{}

Entity configuration options

hiddenFields Array.<string> <optional>
[]

Fields to hide (e.g., ['password', 'resetToken'])

allowedColumns Array.<string> <optional>
[]

If provided, only these fields are included (whitelist)

relatedEntities Object.<string, function()> <optional>
{}

Related entity loaders (lazy functions)

freeze boolean <optional>
true

Whether to freeze instances (default: true)

View Source src/common/BaseEntity.js, line 267

Entity class extending BaseEntity with derived schema

function
Examples
// Basic entity
const IconEntity = createEntityFromModel(IconModel, {}, {
  hiddenFields: ['internalId']
});

const icon = new IconEntity({ id: 1, name: 'home', internal_id: 'secret' });
console.log(icon.name); // 'home' (camelCase)
console.log(icon.internalId); // undefined (hidden)
Object.isFrozen(icon); // true
// Entity with related entities (lazy-loaded to avoid circular deps)
const IconEntity = createEntityFromModel(IconModel, {
  // Extra methods
  isPublished() {
    return this.isActive && !this.isDeleted;
  }
}, {
  hiddenFields: ['secretKey'],
  relatedEntities: {
    set: () => require('./SetEntity'),      // Lazy load
    images: () => require('./ImageEntity')
  }
});

const iconData = {
  id: 1,
  name: 'home',
  set: { id: 10, name: 'Material' },
  images: [{ id: 100, url: '/img.png' }]
};

const icon = new IconEntity(iconData);
console.log(icon.set instanceof SetEntity); // true
console.log(icon.images[0] instanceof ImageEntity); // true
console.log(icon.isPublished()); // true (custom method)
// Entity with allowedColumns (whitelist)
const PublicIconEntity = createEntityFromModel(IconModel, {}, {
  allowedColumns: ['id', 'name', 'svgPath', 'isActive']
  // Only these fields will be included, all others dropped
});

# createItem(config) → {function}

Factory function to generate a create (POST) route.

Creates a POST route that accepts JSON body, validates it, and creates a new item. Request body is passed directly to service.create().

Parameters:
Name Type Attributes Default Description
config Object

Route configuration

path string <optional>
'/'

Route path

service Object

Service instance with create() method

schema Object

Fastify route schema for validation

entityClass function <optional>

Entity class (not currently used)

name string <optional>
'resource'

Resource name for error messages

preHandler Array | function <optional>
[]

Fastify preHandler hooks

View Source http/src/factory.js, line 304

Async function that registers the route with Fastify

function
Example
await createItem({
  route: '/',
  service: iconService,
  schema: schemas.CreateSchema,
  name: 'icon'
})(fastify);

# async cursorPaginate(options) → {Promise.<Object>|Array|Object|boolean|boolean|string|null|string|null|number}

Paginate using cursor-based keyset pagination.

Builds a query with:

  1. Apply all filters FIRST (WHERE clauses)
  2. Apply cursor condition (keyset WHERE)
  3. Sort by specified fields + id for uniqueness
  4. Limit results
  5. Generate cursors for next/prev pages

Keyset Condition: For sortBy='createdAt', sortOrder='desc':

WHERE (created_at, id) < (cursor.createdAt, cursor.id)

This uses a composite index and is O(log n) instead of O(n) like OFFSET.

Parameters:
Name Type Attributes Default Description
options Object

Pagination options

filters Object <optional>
{}

Filter criteria

cursor string <optional>
null

Cursor token from previous page

limit number <optional>
20

Page size (max 100)

sortBy string <optional>
'createdAt'

Field to sort by

sortOrder string <optional>
'desc'

'asc' or 'desc'

includeTotalCount boolean <optional>
false

Whether to count total (expensive!)

entityClass function <optional>

Entity class for results

entityOptions Object <optional>
{}

Entity construction options

trx Object <optional>

Knex transaction

View Source src/common/mixins/repository/withCursorPagination.js, line 232

Pagination result

Promise.<Object>

result.results - Entity instances for current page

Array

result.pageInfo - Pagination metadata

Object

result.pageInfo.hasNextPage - True if more results exist

boolean

result.pageInfo.hasPreviousPage - True if previous page exists

boolean

result.pageInfo.startCursor - Cursor for first item

string | null

result.pageInfo.endCursor - Cursor for last item

string | null

[result.pageInfo.totalCount] - Total count (if includeTotalCount=true)

number
Examples
// First page (newest icons)
const page1 = await repo.cursorPaginate({
  filters: { price: 'free' },
  cursor: null,
  limit: 20,
  sortBy: 'createdAt',
  sortOrder: 'desc'
});
// Next page (using cursor from previous page)
const page2 = await repo.cursorPaginate({
  filters: { price: 'free' },
  cursor: 'eyJpZCI6MTAyMCwiY3JlYXRlZEF0IjoiMjAyNC0wMS0xNVQxMDowMDowMFoifQ==',
  limit: 20,
  sortBy: 'createdAt',
  sortOrder: 'desc'
});
// With multiple filters (search facets)
const results = await repo.cursorPaginate({
  filters: {
    price: 'free',
    tagIds: [1, 2, 3],
    styleId: 5,
    userId: 123,
    searchTerm: 'home'
  },
  cursor: null,
  limit: 20
});
// Ascending sort (oldest first)
const oldestFirst = await repo.cursorPaginate({
  filters: {},
  cursor: null,
  limit: 20,
  sortBy: 'createdAt',
  sortOrder: 'asc'
});

# deleteItem(config) → {function}

Factory function to generate a delete (DELETE) route.

Creates a DELETE route that removes an item by ID. Returns 404 if not found. Returns { deleted: true } on success, { deleted: false } if deletion failed.

Parameters:
Name Type Attributes Default Description
config Object

Route configuration

path string <optional>
'/:id'

Route path with ID parameter

idParam string <optional>
'id'

Name of ID parameter in path

parseId function <optional>

Function to parse ID from string (default: Number)

service Object

Service instance with getById() and delete() methods

schema Object

Fastify route schema for validation

entityClass function <optional>

Entity class (not currently used)

name string <optional>
'resource'

Resource name for error messages

preHandler Array | function <optional>
[]

Fastify preHandler hooks

View Source http/src/factory.js, line 409

Async function that registers the route with Fastify

function
Example
await deleteItem({
  route: '/:id',
  service: iconService,
  schema: schemas.DeleteSchema,
  name: 'icon'
})(fastify);

# ensureTrailingSlash(path) → {string}

Ensure a path ends with a trailing slash.

Parameters:
Name Type Description
path string

View Source http/src/factory.js, line 88

string

# getItem(config) → {function}

Factory function to generate a get-by-ID route.

Creates a GET route that fetches a single item by ID. Returns 404 if not found. Supports custom ID parameter names and parsing functions.

Parameters:
Name Type Attributes Default Description
config Object

Route configuration

path string <optional>
'/:id'

Route path with ID parameter

idParam string <optional>
'id'

Name of ID parameter in path

parseId function <optional>

Function to parse ID from string (default: Number)

service Object

Service instance with getById() method

schema Object

Fastify route schema for validation

entityClass function <optional>

Entity class (not currently used)

name string <optional>
'resource'

Resource name for error messages

preHandler Array | function <optional>
[]

Fastify preHandler hooks

View Source http/src/factory.js, line 254

Async function that registers the route with Fastify

function
Examples
await getItem({
  route: '/:id',
  service: iconService,
  schema: schemas.GetItemSchema,
  name: 'icon'
})(fastify);
// With UUID parsing
await getItem({
  route: '/:uuid',
  idParam: 'uuid',
  parseId: (v) => v.toString(),
  service: userService,
  schema: schemas.GetUserSchema,
  name: 'user'
})(fastify);

# getPaginatedSchema()

Build schema for pagination.

View Source http/src/factory.js, line 93

# initCartItemService() → {CartItemService}

Initialize the cart item service

View Source src/carts/cart-items/index.js, line 10

  • If the initialization fails
Error
  • The initialized cart item service

# initCartService() → {CartService}

Initializes the CartService with injected dependencies.

View Source src/carts/index.js, line 11

CartService

# initCategoryService() → {CategoryService}

Initializes the CategoryService with injected dependencies.

View Source src/products/categories/index.js, line 11

# initDownloadService() → {DownloadService}

Initializes the DownloadService with injected dependencies.

View Source src/downloads/index.js, line 11

# initEntityToCategoriesService() → {EntityToCategoriesService}

Initializes the EntityToCategoriesService with injected dependencies.

View Source src/products/entity-to-categories/index.js, line 11

EntityToCategoriesService

# initEntityToTagsService() → {EntityToTagsService}

Initializes the EntityToTagsService with injected dependencies.

View Source src/products/entity-to-tags/index.js, line 11

EntityToTagsService

# initFavoriteService() → {FavoriteService}

Initializes the FavoriteService with injected dependencies.

View Source src/favorites/index.js, line 10

# initIconService() → {IconService}

Initializes the IconService with injected dependencies.

View Source src/products/icons/index.js, line 12

IconService

# initImageService() → {ImageService}

Initializes the ImageService with injected dependencies.

View Source src/images/index.js, line 10

ImageService

# initImageTypeService() → {ImageTypeService}

Initializes the ImageTypeService with injected dependencies.

View Source src/images/image-types/index.js, line 10

ImageTypeService

# initPaymentTypeService() → {PaymentTypeService}

Initializes the PaymentTypeService with injected dependencies.

View Source src/transactions/payment-types/index.js, line 11

PaymentTypeService

# initProductTypeService() → {ProductTypeService}

Initializes the ProductTypeService with injected dependencies.

View Source src/products/product-types/index.js, line 9

# initPurchasedItemService() → {PurchasedItemService}

Initializes the PurchasedItemService with injected dependencies.

View Source src/products/purchased-items/index.js, line 11

PurchasedItemService

# initStyleService() → {StyleService}

Initializes the StyleService with injected dependencies.

View Source src/products/styles/index.js, line 11

StyleService

# initTagService() → {TagService}

Initializes the TagService with injected dependencies.

View Source src/products/tags/index.js, line 11

TagService

# initTransactionCategoryService() → {TransactionCategoryService}

Initializes the TransactionCategoryService with injected dependencies.

View Source src/transactions/transaction-categories/index.js, line 11

# initTransactionItemService() → {TransactionItemService}

Initializes the TransactionItemService with injected dependencies.

View Source src/transactions/transaction-items/index.js, line 11

# initTransactionService(params) → {TransactionService}

Initialize the transaction service

Parameters:
Name Type Description
params Object
DB Object

The database instance

ModelsRegistry Object

The models registry instance

couponCode string

The coupon code to be used

View Source src/transactions/index.js, line 21

  • If the coupon code is invalid
Error
  • The initialized transaction service

# initTransactionTypeService() → {TransactionTypeService}

Initializes the TransactionTypeService with injected dependencies.

View Source src/transactions/transaction-types/index.js, line 10

# initTransactionsViewService() → {TransactionsViewService}

Initializes the TransactionsViewService with injected dependencies.

View Source src/transactions/transactions-view/index.js, line 11

# list(config) → {function}

Factory function to generate a paginated list route with filtering.

Creates a GET route that returns paginated results with filtering support. The route delegates to service.paginate() and supports dynamic WHERE clauses via the getWhere function.

Parameters:
Name Type Attributes Default Description
config Object

Route configuration

route string

Route path (e.g., '/:page/:pageSize')

service Object

Service instance with paginate() method

schema Object

Fastify route schema for validation

getWhere function <optional>

Function to build WHERE clause from request Receives (req) and returns object of filter conditions

page number <optional>
1

Default page number

pageSize number <optional>
100

Default page size

preHandler Array | function <optional>
[]

Fastify preHandler hooks (e.g., authentication, authorization)

View Source http/src/factory.js, line 197

Async function that registers the route with Fastify

function
Examples
// Generate a list route with filtering
await list({
  route: '/:page/:pageSize',
  service: iconService,
  schema: schemas.IconPaginatedSchema,
  getWhere: (req) => {
    const filters = {};
    if (req.query.setId) filters.setId = Number(req.query.setId);
    if (req.query.isActive !== undefined) filters.isActive = req.query.isActive;
    return filters;
  }
})(fastify);
// With authentication
await list({
  route: '/:page/:pageSize',
  service: iconService,
  schema: schemas.IconPaginatedSchema,
  preHandler: [authenticate, authorize([UserRoles.Admin])]
})(fastify);

# makeCrudPlugin(config) → {function}

Higher-level factory to create a complete CRUD plugin from route definitions.

Generates multiple CRUD routes (list, getItem, createItem, patchItem, deleteItem) from an array of route configurations. Simplifies plugin creation by providing common service and entity once and defining multiple routes declaratively.

Parameters:
Name Type Description
config Object

Plugin configuration

service Object

Service instance shared across all routes

entityClass function

Entity class shared across all routes

name string

Resource name for error messages (e.g., 'icon')

routes Array.<Object>

Array of route configurations

routes[].kind string

Route type: 'list', 'getItem', 'createItem', 'patchItem', 'deleteItem'

routes[ Object

Additional route-specific config (merged with common config)

View Source http/src/factory.js, line 488

If service, entityClass, or name is missing

Error

If unsupported route kind is specified

Error

Async Fastify plugin function

function
Example
const iconCrudPlugin = makeCrudPlugin({
  service: iconService,
  entityClass: IconEntity,
  name: 'icon',
  routes: [
    {
      kind: 'list',
      route: '/:page/:pageSize',
      schema: schemas.IconPaginatedSchema,
      getWhere: (req) => ({ setId: req.query.setId })
    },
    {
      kind: 'getItem',
      path: '/:id',
      schema: schemas.GetItemSchema
    },
    {
      kind: 'createItem',
      path: '/',
      schema: schemas.CreateSchema,
      preHandler: [authenticate]
    }
  ]
});

// Register plugin with Fastify
await fastify.register(iconCrudPlugin, { prefix: '/icons' });

# mapKeys(obj, fn) → {Object}

Map an object's keys using a transform function.

Parameters:
Name Type Description
obj Object
fn function

View Source src/common/BaseEntity.js, line 472

Object

# paginate()

Paginate items with offset/limit parameters.

View Source http/src/factory.js, line 126

# patchItem(config) → {function}

Factory function to generate a patch (PATCH/update) route.

Creates a PATCH route that updates an existing item by ID. Returns 404 if not found. Fetches the item before and after update to ensure existence and return fresh data.

Parameters:
Name Type Attributes Default Description
config Object

Route configuration

path string <optional>
'/:id'

Route path with ID parameter

idParam string <optional>
'id'

Name of ID parameter in path

parseId function <optional>

Function to parse ID from string (default: Number)

service Object

Service instance with getById() and update() methods

schema Object

Fastify route schema for validation

entityClass function <optional>

Entity class (not currently used)

name string <optional>
'resource'

Resource name for error messages

preHandler Array | function <optional>
[]

Fastify preHandler hooks

View Source http/src/factory.js, line 350

Async function that registers the route with Fastify

function
Example
await patchItem({
  route: '/:id',
  service: iconService,
  schema: schemas.UpdateSchema,
  name: 'icon'
})(fastify);

# withCursorPagination(BaseClass) → {function}

Mixin to add cursor pagination to a repository class.

Adds cursorPaginate() method that implements keyset pagination with:

  • Multi-field sort support (e.g., created_at DESC, id DESC)
  • Filter application before cursor (search facets)
  • Cursor encoding/decoding
  • Metadata (hasNext, hasPrev, cursors)
  • Forward and backward paging

Method Added:

async cursorPaginate(options)

Options:

  • filters - Object with filter criteria (price, tagIds, styleId, etc.)
  • cursor - Encoded cursor token from previous page
  • limit - Page size (default: 20, max: 100)
  • sortBy - Field to sort by (default: 'createdAt')
  • sortOrder - 'asc' or 'desc' (default: 'desc')
  • includeTotalCount - Whether to count total matches (expensive!)
  • entityClass - Entity class for results
  • entityOptions - Options for entity construction
  • trx - Knex transaction

Performance:

  • First page (no cursor): O(log n + limit)
  • Subsequent pages (with cursor): O(log n + limit)
  • Total count (if requested): O(n) - use sparingly!
Parameters:
Name Type Description
BaseClass function

Repository class to extend

View Source src/common/mixins/repository/withCursorPagination.js, line 147

Enhanced repository class with cursor pagination

function
Examples
// Create repository with cursor pagination
class RawIconRepository {
  constructor(opts) {
    this.model = IconModel;
  }
}

const IconRepository = withCursorPagination(RawIconRepository);
// Use in service
const result = await iconRepo.cursorPaginate({
  filters: {
    price: 'free',
    tagIds: [1, 2, 3]
  },
  cursor: null,  // First page
  limit: 20,
  sortBy: 'createdAt',
  sortOrder: 'desc'
});

Type Definitions

Object

# CategoryDeletedSchema

Properties:
Name Type Description
deleted boolean

View Source http/src/schemas/categories.js, line 54

Object

# CategoryListSchema

Properties:
Name Type Description
results Array.<CategorySchema>

View Source http/src/schemas/categories.js, line 22

Object

# CategoryPaginatedSchema

Properties:
Name Type Attributes Description
results Array.<CategorySchema>
total number
page number
pageSize number
totalPages number
cacheHit boolean <optional>

View Source http/src/schemas/categories.js, line 31

Object

# CategorySchema

Properties:
Name Type Description
id number
name string
isActive boolean
createdAt string

(date-time)

updatedAt string

(date-time)

View Source http/src/schemas/categories.js, line 1

Object

# CreateCategorySchema

Properties:
Name Type Description
name string
isActive boolean

View Source http/src/schemas/categories.js, line 64

Object

# CreateFamilySchema

Properties:
Name Type Description
name string
price number
description string
licenseId number
teamId number
uniqueId string
userId number
sort number
isActive boolean

View Source http/src/schemas/families.js, line 93

Object

# CreateIconSchema

Properties:
Name Type Description
name string
price number
width number
height number
setId number
styleId number
teamId number
userId number
uniqueId string
licenseId number
isActive boolean

View Source http/src/schemas/icons.js, line 99

Object

# CreateImageSchema

Properties:
Name Type Description
entityId number
entityType string
imageTypeId number
imageHash string
visibility string
access string
name string
fileType string
url string
uniqueId string

View Source http/src/schemas/images.js, line 103

Object

# CreateSetSchema

Properties:
Name Type Description
name string
price number
familyId number
licenseId number
typeId number
styleId number
teamId number
uniqueId string
userId number
description string
sort number
isActive boolean

View Source http/src/schemas/sets.js, line 102

Object

# CreateTagSchema

Properties:
Name Type Description
name string
isActive boolean

View Source http/src/schemas/tags.js, line 65

Object

# DeleteCategorySchema

Properties:
Name Type Description
id number
200 CategoryDeletedSchema
404 Object

View Source http/src/schemas/categories.js, line 160

Object

# FamilyDeletedSchema

Properties:
Name Type Description
deleted boolean

View Source http/src/schemas/families.js, line 83

Object

# FamilyListSchema

Properties:
Name Type Description
results Array.<FamilySchema>

View Source http/src/schemas/families.js, line 51

Object

# FamilyPaginatedSchema

Properties:
Name Type Description
results Array.<FamilySchema>
total number
page number
pageSize number
totalPages number
cacheHit boolean

View Source http/src/schemas/families.js, line 60

Object

# FamilySchema

Properties:
Name Type Description
id number
name string
price number
description string
licenseId number
teamId number
uniqueId string
userId number
sort number
isActive boolean
createdAt string

(date-time)

updatedAt string

(date-time)

isDeleted boolean

View Source http/src/schemas/families.js, line 1

Object

# GetCategorySchema

Properties:
Name Type Description
id number
200 CategorySchema
404 Object

View Source http/src/schemas/categories.js, line 107

Object

# GetFamilySchema

Properties:
Name Type Description
id number
200 FamilySchema
404 Object

View Source http/src/schemas/families.js, line 168

Object

# GetIconSchema

Properties:
Name Type Description
id number
200 IconSchema
404 Object

View Source http/src/schemas/icons.js, line 182

Object

# GetImageSchema

Properties:
Name Type Description
id number
200 ImageSchema
404 Object

View Source http/src/schemas/images.js, line 177

Object

# GetSetSchema

Properties:
Name Type Description
id number
200 SetSchema
404 Object

View Source http/src/schemas/sets.js, line 180

Object

# GetTagSchema

Properties:
Name Type Description
id number
200 TagSchema
404 Object

View Source http/src/schemas/tags.js, line 108

Object

# IconDeletedSchema

Properties:
Name Type Description
deleted boolean

View Source http/src/schemas/icons.js, line 89

Object

# IconListSchema

Properties:
Name Type Description
results Array.<IconSchema>

View Source http/src/schemas/icons.js, line 57

Object

# IconPaginatedSchema

Properties:
Name Type Description
results Array.<IconSchema>
total number
page number
pageSize number
totalPages number
cacheHit boolean

View Source http/src/schemas/icons.js, line 66

Object

# IconSchema

Properties:
Name Type Description
id number
name string
price number
width number
height number
setId number
styleId number
teamId number
userId number
uniqueId string
licenseId number
isActive boolean
createdAt string

(date-time)

updatedAt string

(date-time)

isDeleted boolean

View Source http/src/schemas/icons.js, line 1

Object

# ImageDeletedSchema

Properties:
Name Type Description
deleted boolean

View Source http/src/schemas/images.js, line 93

Object

# ImageListSchema

Properties:
Name Type Description
results Array.<ImageSchema>

View Source http/src/schemas/images.js, line 61

Object

# ImagePaginatedSchema

Properties:
Name Type Description
results Array.<ImageSchema>
total number
page number
pageSize number
totalPages number
cacheHit boolean

View Source http/src/schemas/images.js, line 70

Object

# ImageSchema

Properties:
Name Type Description
id number
entityId number
entityType string
imageTypeId number
imageHash string
visibility string
access string
name string
fileType string
url string
uniqueId string
createdAt string

(date-time)

updatedAt string

(date-time)

isDeleted boolean

View Source http/src/schemas/images.js, line 8

Object

# ListCategoriesSchema

Properties:
Name Type Attributes Description
page number <optional>
pageSize number <optional>
isActive boolean <optional>
200 Array.<CategorySchema>

View Source http/src/schemas/categories.js, line 82

Object

# ListFamiliesSchema

Properties:
Name Type Attributes Description
page number <optional>
pageSize number <optional>
userId number <optional>
teamId number <optional>
licenseId number <optional>
isActive boolean <optional>
isDeleted boolean <optional>
200 Array.<FamilySchema>

View Source http/src/schemas/families.js, line 135

Object

# ListIconsSchema

Properties:
Name Type Attributes Description
page number <optional>
pageSize number <optional>
setId number <optional>
styleId number <optional>
teamId number <optional>
userId number <optional>
isActive boolean <optional>
isDeleted boolean <optional>
200 Array.<IconSchema>

View Source http/src/schemas/icons.js, line 147

Object

# ListImagesSchema

Properties:
Name Type Attributes Description
page number <optional>
pageSize number <optional>
entityType string <optional>
entityId number <optional>
isDeleted boolean <optional>
200 Array.<ImageSchema>

View Source http/src/schemas/images.js, line 148

Object

# ListSetsSchema

Properties:
Name Type Attributes Description
page number <optional>
pageSize number <optional>
familyId number <optional>
isActive boolean <optional>
200 Array.<SetSchema>

View Source http/src/schemas/sets.js, line 153

Object

# ListTagsSchema

Properties:
Name Type Attributes Description
page number <optional>
pageSize number <optional>
isActive boolean <optional>
200 Array.<TagSchema>

View Source http/src/schemas/tags.js, line 83

Object

# SetDeletedSchema

Properties:
Name Type Description
deleted boolean

View Source http/src/schemas/sets.js, line 92

Object

# SetListSchema

Properties:
Name Type Description
results Array.<SetSchema>

View Source http/src/schemas/sets.js, line 60

Object

# SetPaginatedSchema

Properties:
Name Type Description
results Array.<SetSchema>
total number
page number
pageSize number
totalPages number
cacheHit boolean

View Source http/src/schemas/sets.js, line 69

Object

# SetSchema

Properties:
Name Type Description
id number
name string
price number
familyId number
licenseId number
typeId number
styleId number
teamId number
uniqueId string
userId number
description string
sort number
isActive boolean
createdAt string

(date-time)

updatedAt string

(date-time)

isDeleted boolean

View Source http/src/schemas/sets.js, line 1

Object

# TagDeletedSchema

Properties:
Name Type Description
deleted boolean

View Source http/src/schemas/tags.js, line 54

Object

# TagListSchema

Properties:
Name Type Description
results Array.<TagSchema>

View Source http/src/schemas/tags.js, line 22

Object

# TagPaginatedSchema

Properties:
Name Type Description
results Array.<TagSchema>
total number
page number
pageSize number
totalPages number
cacheHit boolean

View Source http/src/schemas/tags.js, line 31

Object

# TagSchema

Properties:
Name Type Description
id number
name string
isActive boolean
createdAt string

(date-time)

updatedAt string

(date-time)

View Source http/src/schemas/tags.js, line 1

Object

# UpdateCategorySchema

Properties:
Name Type Description
id number
body Object
200 CategorySchema
404 Object

View Source http/src/schemas/categories.js, line 129