@hotmeshio/hotmesh
Version:
Permanent-Memory Workflows & AI Agents
283 lines (282 loc) • 9.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SerializerService = exports.MDATA_SYMBOLS = void 0;
const utils_1 = require("../../modules/utils");
const dateReg = /^"\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z)?"$/;
exports.MDATA_SYMBOLS = {
SLOTS: 26,
ACTIVITY: {
KEYS: ['aid', 'dad', 'as', 'atp', 'stp', 'ac', 'au', 'err', 'l1s', 'l2s'],
},
ACTIVITY_UPDATE: {
KEYS: ['au', 'err', 'l2s'],
},
JOB: {
KEYS: [
'ngn',
'tpc',
'pj',
'pg',
'pd',
'px',
'pa',
'key',
'app',
'vrs',
'jid',
'gid',
'aid',
'ts',
'jc',
'ju',
'js',
'err',
'trc',
],
},
JOB_UPDATE: {
KEYS: ['ju', 'err'],
},
};
class SerializerService {
constructor() {
this.resetSymbols({}, {}, {});
}
abbreviate(consumes, symbolNames, fields = []) {
for (const symbolName of symbolNames) {
const symbolSet = this.symKeys.get(symbolName);
const symbolPaths = consumes[symbolName];
for (const symbolPath of symbolPaths) {
const abbreviation = symbolSet.get(symbolPath);
if (abbreviation) {
const dimensionalIndex = this.resolveDimensionalIndex(symbolPath);
fields.push(`${abbreviation}${dimensionalIndex}`);
}
else {
fields.push(symbolPath);
}
}
}
return fields;
}
resolveDimensionalIndex(path) {
if (this.isJobPath(path)) {
return '';
}
else {
const [activityId] = path.split('/');
if (activityId in this.dIds) {
return this.dIds[activityId];
}
else if ('$ADJACENT' in this.dIds) {
//else=> pre-authorizing adjacent activity entry
return this.dIds['$ADJACENT'];
}
return ',0';
}
}
isJobPath(path) {
return path.startsWith('data/') || path.startsWith('metadata/');
}
resetSymbols(symKeys, symVals, dIds) {
this.symKeys = new Map();
this.symReverseKeys = new Map();
for (const id in symKeys) {
this.symKeys.set(id, new Map(Object.entries(symKeys[id])));
}
this.symValMaps = new Map(Object.entries(symVals));
this.symValReverseMaps = this.getReverseValueMap(this.symValMaps);
this.dIds = dIds;
}
getReverseKeyMap(keyMap, id) {
let map = this.symReverseKeys.get(id);
if (!map) {
map = new Map();
for (const [key, val] of keyMap.entries()) {
map.set(val, key);
}
this.symReverseKeys.set(id, map);
}
return map;
}
getReverseValueMap(valueMap) {
const map = new Map();
for (const [key, val] of valueMap.entries()) {
map.set(val, key);
}
return map;
}
static filterSymVals(startIndex, maxIndex, existingSymbolValues, proposedValues) {
const newSymbolValues = {};
const currentSymbolValues = { ...existingSymbolValues };
const currentValuesSet = new Set(Object.values(currentSymbolValues));
for (const value of proposedValues) {
if (!currentValuesSet.has(value)) {
if (startIndex > maxIndex) {
return newSymbolValues;
}
const symbol = (0, utils_1.getSymVal)(startIndex);
startIndex++;
newSymbolValues[symbol] = value;
currentValuesSet.add(value);
}
}
return newSymbolValues;
}
compress(document, ids) {
if (this.symKeys.size === 0) {
return document;
}
const source = { ...document };
const result = {};
const compressWithMap = (abbreviationMap, id) => {
for (const key in source) {
if (key.startsWith(`${id}/`) ||
id.startsWith('$') &&
['data', 'metadata'].includes(key.split('/')[0])) {
const dimensionalIndex = this.resolveDimensionalIndex(key);
const shortKey = abbreviationMap.get(key) || key;
const shortDimensionalKey = `${shortKey}${dimensionalIndex}`;
result[shortDimensionalKey] = source[key];
}
else if (!(key in result) && this.isLiteralKeyType(key)) {
//mark (-) and search (_)
result[key] = source[key];
}
}
};
for (const id of ids) {
const abbreviationMap = this.symKeys.get(id);
if (abbreviationMap) {
compressWithMap(abbreviationMap, id);
}
}
return result;
}
isLiteralKeyType(key) {
return key.startsWith('-') || key.startsWith('_');
}
decompress(document, ids) {
if (this.symKeys.size === 0) {
return document;
}
const result = { ...document };
const inflateWithMap = (abbreviationMap, id) => {
const reversedAbbreviationMap = this.getReverseKeyMap(abbreviationMap, id);
for (const key in result) {
//strip dimensional index from key
const shortKey = key.split(',')[0];
const longKey = reversedAbbreviationMap.get(shortKey);
if (longKey) {
result[longKey] = result[key];
delete result[key];
}
}
};
for (const id of ids) {
const abbreviationMap = this.symKeys.get(id);
if (abbreviationMap) {
inflateWithMap(abbreviationMap, id);
}
}
return result;
}
//stringify: convert a n-dimensional document to a 2-d hash
stringify(document) {
const result = {};
for (const key in document) {
const value = SerializerService.toString(document[key]);
if (value) {
// if (/^:*[a-zA-Z]{2}$/.test(value)) {
// value = ':' + value;
// } else if (this.symValReverseMaps.has(value)) {
// value = this.symValReverseMaps.get(value);
// }
result[key] = value;
}
}
return result;
}
//parse: convert a 2-d hash to a n-dimensional document
parse(document) {
const result = {};
for (const [key, value] of Object.entries(document)) {
if (value === undefined || value === null)
continue;
// if (/^:+[a-zA-Z]{2}$/.test(value)) {
// result[key] = value.slice(1);
// } else {
// if (value?.length === 2 && this.symValMaps.has(value)) {
// value = this.symValMaps.get(value);
// }
result[key] = SerializerService.fromString(value);
// }
}
return result;
}
static toString(value) {
switch (typeof value) {
case 'string':
break;
case 'boolean':
value = value ? '/t' : '/f';
break;
case 'number':
value = '/d' + value.toString();
break;
case 'undefined':
return undefined;
case 'object':
if (value === null) {
value = '/n';
}
else {
value = '/s' + JSON.stringify(value);
}
break;
}
return value;
}
static fromString(value) {
if (typeof value !== 'string')
return undefined;
const prefix = value.slice(0, 2);
const rest = value.slice(2);
switch (prefix) {
case '/t': // boolean true
return true;
case '/f': // boolean false
return false;
case '/d': // number
return Number(rest);
case '/n': // null
return null;
case '/s': // object (JSON string)
if (dateReg.exec(rest)) {
return new Date(JSON.parse(rest));
}
return JSON.parse(rest);
default: // string
return value;
}
}
package(multiDimensionalDocument, ids) {
const flatDocument = this.stringify(multiDimensionalDocument);
return this.compress(flatDocument, ids);
}
unpackage(document, ids) {
const multiDimensionalDocument = this.decompress(document, ids);
return this.parse(multiDimensionalDocument);
}
export() {
const obj = {};
for (const [id, map] of this.symKeys.entries()) {
obj[id] = {};
for (const [key, value] of map.entries()) {
obj[id][key] = value;
}
}
return obj;
}
}
exports.SerializerService = SerializerService;