Skip to main content

Helper Functions

The framework provides various helper functions for common operations.

Key Helpers​

Functions for working with DynamoDB keys.

addSortKeyVersion(sk: string, version: number): string​

Adds a version suffix to a sort key.

import { addSortKeyVersion } from '@mbc-cqrs-serverless/core';

const versionedSk = addSortKeyVersion('CAT#001', 1);
// Result: 'CAT#001@1'

getSortKeyVersion(sk: string): number​

Extracts the version number from a sort key. Returns VERSION_LATEST if no version suffix exists.

import { getSortKeyVersion } from '@mbc-cqrs-serverless/core';

const version = getSortKeyVersion('CAT#001@3');
// Result: 3

const latestVersion = getSortKeyVersion('CAT#001');
// Result: VERSION_LATEST (-1)

removeSortKeyVersion(sk: string): string​

Removes the version suffix from a sort key.

import { removeSortKeyVersion } from '@mbc-cqrs-serverless/core';

const sk = removeSortKeyVersion('CAT#001@3');
// Result: 'CAT#001'

generateId(pk: string, sk: string): string​

Generates a unique ID by combining partition key and sort key (without version).

import { generateId } from '@mbc-cqrs-serverless/core';

const id = generateId('TENANT#mbc', 'CAT#001@3');
// Result: 'TENANT#mbc#CAT#001'

sortKeyBaseFromId(pk: string, itemId: string): string | undefined​

The inverse of generateId: extracts the base sort key from a composite ID. Returns undefined if the ID does not start with the given partition key.

import { sortKeyBaseFromId } from '@mbc-cqrs-serverless/core';

const skBase = sortKeyBaseFromId('TENANT#mbc', 'TENANT#mbc#CAT#001');
// Result: 'CAT#001'

parseTwoSegmentPkSkFromId(itemId: string): { pk: string; skBase: string } | undefined​

Splits a composite ID back into its partition key and base sort key, assuming the partition key has two segments (type and tenant code). Returns undefined if the ID has fewer than three segments.

import { parseTwoSegmentPkSkFromId } from '@mbc-cqrs-serverless/core';

const result = parseTwoSegmentPkSkFromId('TENANT#mbc#CAT#001');
// result.pk is 'TENANT#mbc' and result.skBase is 'CAT#001'

getTenantCode(pk: string): string | undefined​

Extracts the tenant code from a partition key.

import { getTenantCode } from '@mbc-cqrs-serverless/core';

const tenantCode = getTenantCode('TENANT#mbc');
// Result: 'mbc'

masterPk(tenantCode?: string): string​

Generates a partition key for master data.

import { masterPk } from '@mbc-cqrs-serverless/core';

const pk = masterPk('mbc');
// Result: 'MASTER#mbc'

const commonPk = masterPk();
// Result: 'MASTER#single' (DEFAULT_TENANT_CODE)

seqPk(tenantCode?: string): string​

Generates a partition key for sequences.

import { seqPk } from '@mbc-cqrs-serverless/core';

const pk = seqPk('mbc');
// Result: 'SEQ#mbc'

ttlSk(tableName: string): string​

Generates a TTL sort key for a table. Used to identify TTL-related records.

import { ttlSk } from '@mbc-cqrs-serverless/core';

const sk = ttlSk('my-table');
// Result: 'TTL#my-table'

S3 Attribute Helpers​

Functions for working with S3 URI attributes.

isS3AttributeKey(attributes: any): boolean​

Checks if an attribute value is an S3 URI.

import { isS3AttributeKey } from '@mbc-cqrs-serverless/core';

const isS3 = isS3AttributeKey('s3://my-bucket/path/to/file.pdf');
// Result: true

const isNotS3 = isS3AttributeKey('regular string');
// Result: false

toS3AttributeKey(bucket: string, key: string): string​

Creates an S3 URI from bucket and key.

import { toS3AttributeKey } from '@mbc-cqrs-serverless/core';

const s3Uri = toS3AttributeKey('my-bucket', 'path/to/file.pdf');
// Result: 's3://my-bucket/path/to/file.pdf'

parseS3AttributeKey(s3Uri: string): { bucket: string; key: string }​

Parses an S3 URI into bucket and key components.

import { parseS3AttributeKey } from '@mbc-cqrs-serverless/core';

const { bucket, key } = parseS3AttributeKey('s3://my-bucket/path/to/file.pdf');
// bucket: 'my-bucket', key: 'path/to/file.pdf'

Context Helpers​

Functions for working with invocation context and user information.

getUserContext(ctx: IInvoke | ExecutionContext): UserContext​

Extracts user context from the invocation context. Returns userId, tenantCode, tenantRole, tenantRoles, and tenantGroupIds.

import { getUserContext } from '@mbc-cqrs-serverless/core';

const userContext = getUserContext(invokeContext);
// Returns: { userId: '...', tenantCode: 'mbc', tenantRole: 'admin', tenantRoles: ['admin'], tenantGroupIds: [] }

extractInvokeContext(ctx?: ExecutionContext): IInvoke​

Extracts the invocation context from a NestJS execution context. Supports both Lambda and local development environments.

import { extractInvokeContext } from '@mbc-cqrs-serverless/core';
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';

@Injectable()
export class MyGuard implements CanActivate {
canActivate(ctx: ExecutionContext) {
const invokeContext = extractInvokeContext(ctx);
// Use ctx for further operations
return true;
}
}

getAuthorizerClaims(ctx: IInvoke): JwtClaims​

Extracts JWT claims from the authorizer in the invocation context.

import { getAuthorizerClaims } from '@mbc-cqrs-serverless/core';

const claims = getAuthorizerClaims(invokeContext);
// Returns JWT claims including sub, email, custom:tenant, etc.

UserContext Class​

class UserContext {
userId: string; // User's unique identifier (sub claim)
tenantCode: string; // Current tenant code
tenantRole: string; // User's role in the current tenant
tenantRoles: string[]; // Direct roles for the active tenant (excludes group-derived roles)
tenantGroupIds: string[]; // Group IDs from custom:groups for the active tenant

constructor(partial: Partial<UserContext>);
}
Version Note

tenantRoles and tenantGroupIds were added to UserContext in version 1.3.1 as part of group-based role authorization. tenantRole (singular) is kept for backward compatibility. See Authentication — Group-Based Roles for usage.

JwtClaims Interface​

interface JwtClaims {
sub: string; // User's unique identifier
iss: string; // Token issuer URL
username?: string; // Username
'cognito:groups'?: string[]; // Cognito user groups
'cognito:username': string; // Cognito username
origin_jti?: string; // Original JWT ID
client_id?: string; // OAuth client ID
scope?: string; // OAuth scopes
aud: string; // Token audience
event_id: string; // Cognito event ID
token_use: string; // Token type (access/id)
auth_time: number; // Authentication timestamp
name: string; // User's name
'custom:tenant'?: string; // User's default tenant code
'custom:roles'?: string; // JSON array of tenant roles
'custom:groups'?: string; // JSON array of TenantGroupMembership
exp: number; // Expiration timestamp
email: string; // User's email address
email_verified?: boolean; // Email verification status
iat: number; // Issued at timestamp
jti: string; // JWT ID
}

DateTime Helpers​

Functions for working with dates and ISO strings.

toISOString(date: Date): string | undefined​

Converts a Date to ISO string format. Returns undefined if date is null/undefined.

import { toISOString } from '@mbc-cqrs-serverless/core';

const isoString = toISOString(new Date('2024-01-15T10:30:00Z'));
// Result: '2024-01-15T10:30:00.000Z'

toISOStringWithTimezone(date: Date): string | undefined​

Converts a Date to ISO string format with timezone offset. Returns undefined if date is null/undefined.

import { toISOStringWithTimezone } from '@mbc-cqrs-serverless/core';

const isoString = toISOStringWithTimezone(new Date('2024-01-15T10:30:00'));
// Result: '2024-01-15T10:30:00+09:00' (in JST timezone)

isISOString(val: string): boolean​

Checks if a string is a valid ISO date string.

import { isISOString } from '@mbc-cqrs-serverless/core';

isISOString('2024-01-15T10:30:00.000Z'); // true
isISOString('2024-01-15'); // false
isISOString('invalid'); // false

isISOStringWithTimezone(val: string): boolean​

Checks if a string is a valid ISO date string with timezone.

import { isISOStringWithTimezone } from '@mbc-cqrs-serverless/core';

isISOStringWithTimezone('2024-01-15T10:30:00+09:00'); // true
isISOStringWithTimezone('2024-01-15T10:30:00.000Z'); // false

Event-Type Helpers​

Functions for working with AWS event source ARNs.

getEventTypeFromArn(source: string): string | null​

Extracts the event type from an AWS ARN. Returns 'sqs', 'sns', 'dynamodb', 'event-bridge', or null.

import { getEventTypeFromArn } from '@mbc-cqrs-serverless/core';

const eventType = getEventTypeFromArn('arn:aws:dynamodb:ap-northeast-1:123456789:table/my-table/stream/...');
// Result: 'dynamodb'

const sqsType = getEventTypeFromArn('arn:aws:sqs:ap-northeast-1:123456789:my-queue');
// Result: 'sqs'

getResourceNameFromArn(source: string): string​

Extracts the resource name from an AWS ARN.

import { getResourceNameFromArn } from '@mbc-cqrs-serverless/core';

const tableName = getResourceNameFromArn('arn:aws:dynamodb:ap-northeast-1:123456789:table/my-table/stream/...');
// Result: 'my-table'

const queueName = getResourceNameFromArn('arn:aws:sqs:ap-northeast-1:123456789:my-queue');
// Result: 'my-queue'

Object Helpers​

Functions for working with objects.

isObject(item: any): boolean​

Checks if the value is a plain object (not array, not null).

import { isObject } from '@mbc-cqrs-serverless/core';

isObject({ key: 'value' }); // true
isObject([1, 2, 3]); // false
isObject(null); // false
isObject('string'); // false

mergeDeep(target: any, ...sources: any[]): any​

Deep merges objects without mutating the original objects.

import { mergeDeep } from '@mbc-cqrs-serverless/core';

const result = mergeDeep(
{ a: 1, b: { c: 2 } },
{ b: { d: 3 }, e: 4 }
);
// Result: { a: 1, b: { c: 2, d: 3 }, e: 4 }

objectBytes(obj: any): number​

Calculates the byte size of a JSON-serialized object.

import { objectBytes } from '@mbc-cqrs-serverless/core';

const size = objectBytes({ name: 'test', value: 123 });
// Result: byte size of JSON string

pickKeys(obj: any, keys: string[]): object​

Creates a new object with only the specified keys.

import { pickKeys } from '@mbc-cqrs-serverless/core';

const result = pickKeys({ a: 1, b: 2, c: 3 }, ['a', 'c']);
// Result: { a: 1, c: 3 }

omitKeys(obj: any, keys: string[]): object​

Creates a new object without the specified keys.

import { omitKeys } from '@mbc-cqrs-serverless/core';

const result = omitKeys({ a: 1, b: 2, c: 3 }, ['b']);
// Result: { a: 1, c: 3 }

Serializer Helpers​

Functions for converting between internal DynamoDB structure and external flat structure.

SerializerOptions Interface​

interface SerializerOptions {
keepAttributes?: boolean; // Reserved for future use
flattenDepth?: number; // Reserved for future use
}
note

The SerializerOptions interface is defined for future extensibility but is not currently used by the function. The function always flattens attributes to the top level.

serializeToExternal<T extends CommandEntity | DataEntity>(item: T | null | undefined, options?: SerializerOptions): Record<string, any> | null​

Converts internal DynamoDB entity to external flat structure. Flattens the attributes object into the root level. Returns null if input is null or undefined.

import { serializeToExternal } from '@mbc-cqrs-serverless/core';

const entity = {
pk: 'TENANT#mbc',
sk: 'CAT#001',
id: 'TENANT#mbc#CAT#001',
code: '001',
name: 'Category 1',
version: 1,
tenantCode: 'mbc',
type: 'CAT',
isDeleted: false,
attributes: { color: 'red', size: 'large' }
};

const external = serializeToExternal(entity);
// Result:
// {
// id: 'TENANT#mbc#CAT#001',
// pk: 'TENANT#mbc',
// sk: 'CAT#001',
// code: '001',
// name: 'Category 1',
// version: 1,
// tenantCode: 'mbc',
// type: 'CAT',
// isDeleted: false,
// color: 'red', // Flattened from attributes
// size: 'large' // Flattened from attributes
// }

deserializeToInternal<T extends CommandEntity | DataEntity>(data: Record<string, any> | null | undefined, EntityClass: new () => T): T | null​

Converts external flat structure back to internal DynamoDB entity structure. Returns null if input is null or undefined.

import { deserializeToInternal, DataEntity } from '@mbc-cqrs-serverless/core';

const external = {
id: 'TENANT#mbc#CAT#001',
name: 'Category 1',
color: 'red',
size: 'large'
};

const entity = deserializeToInternal(external, DataEntity);
// Result: DataEntity with pk, sk, name, and attributes: { color, size }

Source Helper​

Function for generating command source identifiers.

getCommandSource(moduleName: string, controllerName: string, method: string): string​

Generates a standardized source string for commands.

import { getCommandSource } from '@mbc-cqrs-serverless/core';

const source = getCommandSource('CatalogModule', 'CatalogController', 'create');
// Result: '[CatalogModule]:CatalogController.create'

Constants​

VERSION_FIRST: number​

A constant equal to 0. Use as the version field when creating a new entity for the first time.

import { VERSION_FIRST } from '@mbc-cqrs-serverless/core';

const command = {
pk,
sk,
name: dto.name,
version: VERSION_FIRST, // New entity: version starts at 0
};

VERSION_LATEST: number​

A constant equal to -1. Use as the version field to bypass optimistic locking (always overwrites). Returned by getSortKeyVersion() when no version suffix is present.

import { VERSION_LATEST } from '@mbc-cqrs-serverless/core';

const command = {
pk,
sk,
name: dto.name,
version: VERSION_LATEST, // Bypass optimistic locking
};
caution

Using VERSION_LATEST bypasses optimistic locking, so concurrent writes from multiple clients will silently overwrite each other. Only use it when concurrent writes to the same entity are impossible (e.g., system-only background jobs, TTL-managed records, or initial seeding).

IS_LAMBDA_RUNNING: boolean​

A constant that indicates whether the code is running in an AWS Lambda environment.

import { IS_LAMBDA_RUNNING } from '@mbc-cqrs-serverless/core';

if (IS_LAMBDA_RUNNING) {
// Lambda-specific logic
} else {
// Local development logic
}