@hotmeshio/hotmesh
Version:
Permanent-Memory Workflows & AI Agents
191 lines (190 loc) • 9.44 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.VALSEP = exports.WEBSEP = exports.TYPSEP = exports.KEYSEP = exports.HMNS = exports.KeyType = exports.KeyService = void 0;
const hotmesh_1 = require("../types/hotmesh");
Object.defineProperty(exports, "KeyType", { enumerable: true, get: function () { return hotmesh_1.KeyType; } });
/**
* Keys
*
* hmsh -> {hash} hotmesh config {version: "0.0.1", namespace: "hmsh"}
* hmsh:a:<appid> -> {hash} app profile { "id": "appid", "version": "2", "versions/1": "GMT", "versions/2": "GMT"}
* hmsh:<appid>:r: -> {hash} throttle rates {':': '23', 'topic.thing': '555'} => {':i': 'all', 'topic.thing': '555seconds'}
* hmsh:<appid>:w: -> {zset} work items/tasks an engine must do like garbage collect or hook a set of matching records (hookAll)
* hmsh:<appid>:t: -> {zset} an ordered set of list (work lists) ids
* hmsh:<appid>:t:<timeValue?> -> {list} a worklist of `jobId+activityId` items that should be awakened
* hmsh:<appid>:q: -> {hash} quorum-wide messages
* hmsh:<appid>:q:<ngnid> -> {hash} engine-targeted messages (targeted quorum-oriented message)
* hmsh:<appid>:j:<jobid> -> {hash} job data
* hmsh:<appid>:s:<jobkey>:<dateTime> -> {hash} job stats (general)
* hmsh:<appid>:s:<jobkey>:<dateTime>:mdn:<field/path>:<fieldvalue> -> {zset} job stats (median)
* hmsh:<appid>:s:<jobkey>:<dateTime>:index:<field/path>:<fieldvalue> -> {list} job stats (index of jobid[])
* hmsh:<appid>:v:<version>:activities -> {hash} schemas [cache]
* hmsh:<appid>:v:<version>:transitions -> {hash} transitions [cache]
* hmsh:<appid>:v:<version>:subscriptions -> {hash} subscriptions [cache]
* hmsh:<appid>:x: -> {xstream} when an engine is sent or reads a buffered task (engines read from their custom topic)
* hmsh:<appid>:x:<topic> -> {xstream} when a worker is sent or reads a buffered task (workers read from their custom topic)
* hmsh:<appid>:hooks -> {hash} hook patterns/rules; set at compile time
* hmsh:<appid>:signals -> {string} dynamic hook signals (hget/hdel); expirable
* hmsh:<appid>:sym:keys: -> {hash} list of symbol ranges and :cursor assigned at version deploy time for job keys
* hmsh:<appid>:sym:keys:<activityid|$subscribes> -> {hash} list of symbols based upon schema enums (initially) and adaptively optimized (later) during runtime; if '$subscribes' is used as the activityid, it is a top-level `job` symbol set (for job keys)
* hmsh:<appid>:sym:vals: -> {hash} list of symbols for job values across all app versions
*/
const HMNS = 'hmsh';
exports.HMNS = HMNS;
const KEYSEP = ':'; // default delimiter for keys
exports.KEYSEP = KEYSEP;
const VALSEP = '::'; // default delimiter for vals
exports.VALSEP = VALSEP;
const WEBSEP = '::'; // default delimiter for webhook vals
exports.WEBSEP = WEBSEP;
const TYPSEP = '::'; // delimiter for ZSET task typing (how should a list be used?)
exports.TYPSEP = TYPSEP;
class KeyService {
/**
* Returns a key that can be used to access a value in the key/value store
* appropriate for the given key type; the keys have an implicit hierarchy
* and are used to organize data in the store in a tree-like structure
* via the use of colons as separators.
* @param namespace
* @param keyType
* @param params
* @returns {string}
*/
static mintKey(namespace, keyType, params) {
switch (keyType) {
case hotmesh_1.KeyType.HOTMESH:
return namespace;
case hotmesh_1.KeyType.THROTTLE_RATE:
return `${namespace}:${params.appId}:r:`;
case hotmesh_1.KeyType.WORK_ITEMS:
return `${namespace}:${params.appId}:w:${params.scoutType || ''}`;
case hotmesh_1.KeyType.TIME_RANGE:
return `${namespace}:${params.appId}:t:${params.timeValue || ''}`;
case hotmesh_1.KeyType.APP:
return `${namespace}:a:${params.appId || ''}`;
case hotmesh_1.KeyType.QUORUM:
return `${namespace}:${params.appId}:q:${params.engineId || ''}`;
case hotmesh_1.KeyType.JOB_STATE:
return `${namespace}:${params.appId}:j:${params.jobId}`;
case hotmesh_1.KeyType.JOB_DEPENDENTS:
return `${namespace}:${params.appId}:d:${params.jobId}`;
case hotmesh_1.KeyType.JOB_STATS_GENERAL:
return `${namespace}:${params.appId}:s:${params.jobKey}:${params.dateTime}`;
case hotmesh_1.KeyType.JOB_STATS_MEDIAN:
return `${namespace}:${params.appId}:s:${params.jobKey}:${params.dateTime}:${params.facet}`;
case hotmesh_1.KeyType.JOB_STATS_INDEX:
return `${namespace}:${params.appId}:s:${params.jobKey}:${params.dateTime}:${params.facet}`;
case hotmesh_1.KeyType.SCHEMAS:
return `${namespace}:${params.appId}:v:${params.appVersion}:schemas`;
case hotmesh_1.KeyType.SUBSCRIPTIONS:
return `${namespace}:${params.appId}:v:${params.appVersion}:subscriptions`;
case hotmesh_1.KeyType.SUBSCRIPTION_PATTERNS:
return `${namespace}:${params.appId}:v:${params.appVersion}:transitions`;
case hotmesh_1.KeyType.HOOKS:
return `${namespace}:${params.appId}:hooks`;
case hotmesh_1.KeyType.SIGNALS:
return `${namespace}:${params.appId}:signals`;
case hotmesh_1.KeyType.SYMKEYS:
return `${namespace}:${params.appId}:sym:keys:${params.activityId || ''}`;
case hotmesh_1.KeyType.SYMVALS:
return `${namespace}:${params.appId}:sym:vals:`;
case hotmesh_1.KeyType.STREAMS:
return `${namespace}:${params.appId || ''}:x:${params.topic || ''}`;
default:
throw new Error('Invalid key type.');
}
}
/**
* Extracts the parts of a given key string, safely handling cases where
* the 'id' portion may contain additional colons.
* @param key - The key to parse.
* @returns An object with the parsed key parts.
*/
static parseKey(key) {
const [namespace, appId, entity, ...rest] = key.split(KEYSEP);
const id = rest.join(KEYSEP) || ''; // Join remaining parts to reconstruct the id
return {
namespace,
app: entity === 'a' ? appId : undefined,
entity,
id,
};
}
/**
* Reconstructs a key string from its parts.
* @param parts - An object with the key parts.
* @returns The reconstructed key string.
*/
static reconstituteKey(parts) {
const { namespace, app, entity, id } = parts;
return `${namespace}${KEYSEP}${app}${KEYSEP}${entity}${KEYSEP}${id || ''}`;
}
/**
* Resolves an entity type abbreviation to a table-friendly name.
* @param abbreviation - The abbreviated entity type.
* @returns The long-form entity name.
*/
static resolveEntityType(abbreviation, id = '') {
switch (abbreviation) {
case 'a':
return 'applications';
case 'r':
return 'throttles';
case 'w':
return id === '' ? 'task_priorities' : 'roles';
case 't':
return id === '' ? 'task_schedules' : 'task_lists';
case 'q':
return 'events';
case 'j':
return 'jobs';
case 's':
return 'stats';
case 'v':
return 'versions';
case 'x':
return id === '' ? 'streams' : 'stream_topics';
case 'hooks':
return 'signal_patterns';
case 'signals':
return 'signal_registry';
case 'sym':
return 'symbols';
default:
return 'unknown_entity';
}
}
static resolveAbbreviation(entity) {
switch (entity) {
case 'applications':
return 'a';
case 'throttles':
return 'r';
case 'roles':
return 'w';
case 'task_schedules':
return 't';
case 'task_lists':
return 't';
case 'events':
return 'q';
case 'jobs':
return 'j';
case 'stats':
return 's';
case 'versions':
return 'v';
case 'streams':
return 'x';
case 'signal_patterns':
return 'hooks';
case 'signal_registry':
return 'signals';
case 'symbols':
return 'sym';
default:
return 'unknown_entity';
}
}
}
exports.KeyService = KeyService;