UNPKG

@fjell/lib

Version:

Server-side Library for Fjell

1,449 lines (1,417 loc) 50.6 kB
var __defProp = Object.defineProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; // src/errors.ts import { abbrevIK, isComKey, isPriKey } from "@fjell/core"; var LibError = class _LibError extends Error { operation; coordinate; constructor(message, operation, coordinate, options) { super(`${message} - ${coordinate} - ${operation}`, options); this.operation = operation; this.coordinate = coordinate; if (Error.captureStackTrace) { Error.captureStackTrace(this, _LibError); } } }; var NotFoundError = class extends LibError { key; constructor(operation, coordinate, key, options) { const keyTypeArray = coordinate.kta; const isCompositeLibrary = keyTypeArray.length > 1; const keyType = isComKey(key) ? "ComKey" : "PriKey"; const message = [ `Item not found for key: ${abbrevIK(key)}`, ``, `Note: If you believe this item should exist, verify:`, `1. The key values are correct: ${abbrevIK(key)}`, `2. The item was created in the expected location`, isCompositeLibrary ? `3. This is a composite item library - keys should have both parent and location components` : `3. This is a primary item library - keys should only have a primary key`, ``, `Expected key type: ${keyType}` ].join("\n"); super(message, operation, coordinate, options); this.key = key; } }; var InvalidKeyTypeError = class extends LibError { key; expectedFormat; receivedFormat; constructor(operation, coordinate, key, expectedIsComposite, options) { const keyTypeArray = coordinate.kta; let expectedFormat; let receivedFormat; if (expectedIsComposite) { const locationTypes = keyTypeArray.slice(1).join(", "); expectedFormat = `ComKey with format: { kt: '${keyTypeArray[0]}', pk: string|number, loc: [${locationTypes.split(", ").map((kt) => `{ kt: '${kt}', lk: string|number }`).join(", ")}] }`; } else { expectedFormat = `PriKey with format: { kt: '${keyTypeArray[0]}', pk: string|number }`; } if (typeof key === "string" || typeof key === "number") { receivedFormat = `a ${typeof key} value: ${JSON.stringify(key)}`; } else if (key && typeof key === "object") { if (isPriKey(key)) { receivedFormat = `PriKey: ${abbrevIK(key)}`; } else if (isComKey(key)) { receivedFormat = `ComKey: ${abbrevIK(key)}`; } else { receivedFormat = `an object: ${JSON.stringify(key)}`; } } else { receivedFormat = `${typeof key}: ${JSON.stringify(key)}`; } const message = [ `Invalid key type for ${operation} operation.`, `Expected: ${expectedFormat}`, `Received: ${receivedFormat}`, ``, expectedIsComposite ? `This is a composite item library. You must provide both the parent key and location keys.` : `This is a primary item library. You should provide just the primary key.`, ``, `Example correct usage:`, expectedIsComposite ? ` library.operations.${operation}({ kt: '${keyTypeArray[0]}', pk: 'parent-id', loc: [{ kt: '${keyTypeArray[1]}', lk: 'child-id' }] })` : ` library.operations.${operation}({ kt: '${keyTypeArray[0]}', pk: 'item-id' })` ].join("\n"); super(message, operation, coordinate, options); this.key = key; this.expectedFormat = expectedFormat; this.receivedFormat = receivedFormat; } }; var NotUpdatedError = class extends LibError { key; constructor(operation, coordinate, key, options) { super(`Item not updated for key ${abbrevIK(key)}`, operation, coordinate, options); this.key = key; } }; var ValidationError = class extends LibError { constructor(message, operation, coordinate, options) { super(`Validation failed: ${message}`, operation, coordinate, options); } }; var CreateValidationError = class extends ValidationError { constructor(parameters, coordinate, options) { super( `Create Validation Failed: ${JSON.stringify(parameters)}`, "create", coordinate, options ); } }; var UpdateValidationError = class extends ValidationError { constructor(parameters, coordinate, options) { super( `Update Validation Failed: ${JSON.stringify(parameters)}`, "update", coordinate, options ); } }; var RemoveValidationError = class extends ValidationError { constructor(parameters, coordinate, options) { const keyInfo = parameters.key ? `key: ${abbrevIK(parameters.key)}` : "key: undefined"; super( `Remove Validation Failed: ${keyInfo}`, "remove", coordinate, options ); } }; var UpdateError = class extends LibError { constructor(parameters, coordinate, options) { const keyInfo = parameters.key ? `key: ${abbrevIK(parameters.key)}` : "key: undefined"; super( `Update Failed: ${keyInfo}`, "update", coordinate, options ); } }; var RemoveError = class extends LibError { constructor(parameters, coordinate, options) { const keyInfo = parameters.key ? `key: ${abbrevIK(parameters.key)}` : "key: undefined"; super( `Remove Failed: ${keyInfo}`, "remove", coordinate, options ); } }; var HookError = class extends LibError { constructor(message, operation, coordinate, options) { super(`${message}`, operation, coordinate, options); } }; var LocationKeyOrderError = class extends LibError { key; constructor(operation, coordinate, key, options) { const keyTypeArray = coordinate.kta; const expectedLocationTypes = keyTypeArray.slice(1); const actualLocationTypes = key.loc.map((loc) => loc.kt); const expectedOrder = expectedLocationTypes.map( (kt, i) => ` [${i}] { kt: '${kt}', lk: <value> }` ).join("\n"); const actualOrder = key.loc.map( (loc, i) => ` [${i}] { kt: '${loc.kt}', lk: ${JSON.stringify(loc.lk)} }` ).join("\n"); const mismatches = []; for (let i = 0; i < Math.max(expectedLocationTypes.length, actualLocationTypes.length); i++) { if (i >= expectedLocationTypes.length) { mismatches.push(` \u2022 Position ${i}: Unexpected location key with type '${actualLocationTypes[i]}'`); } else if (i >= actualLocationTypes.length) { mismatches.push(` \u2022 Position ${i}: Missing location key with type '${expectedLocationTypes[i]}'`); } else if (expectedLocationTypes[i] !== actualLocationTypes[i]) { mismatches.push(` \u2022 Position ${i}: Expected '${expectedLocationTypes[i]}' but got '${actualLocationTypes[i]}'`); } } const message = [ `Location key array order mismatch for ${operation} operation.`, ``, `The location keys in your ComKey must match the hierarchy defined by the library.`, ``, `Expected location key order for '${keyTypeArray[0]}':`, expectedOrder, ``, `Received location key order:`, actualOrder, ``, `Issues found:`, ...mismatches, ``, `Understanding the hierarchy:`, ` The key type array [${keyTypeArray.map((kt) => `'${kt}'`).join(", ")}] defines the containment hierarchy.`, ` - '${keyTypeArray[0]}' is the primary item type`, expectedLocationTypes.length > 0 ? ` - '${keyTypeArray[0]}' items are contained in '${expectedLocationTypes[0]}'` : "", expectedLocationTypes.length > 1 ? ` - '${expectedLocationTypes[0]}' items are contained in '${expectedLocationTypes[1]}'` : "", expectedLocationTypes.length > 2 ? ` - '${expectedLocationTypes[1]}' items are contained in '${expectedLocationTypes[2]}'` : "", ``, `Correct example:`, ` library.operations.${operation}({`, ` kt: '${keyTypeArray[0]}',`, ` pk: 'item-id',`, ` loc: [`, expectedLocationTypes.map((kt) => ` { kt: '${kt}', lk: 'parent-id' }`).join(",\n"), ` ]`, ` })` ].filter((line) => line !== "").join("\n"); super(message, operation, coordinate, options); this.key = key; } }; // src/logger.ts import Logging from "@fjell/logging"; var LibLogger = Logging.getLogger("@fjell/lib"); var logger_default = LibLogger; // src/Library.ts import { createInstance as createBaseInstance } from "@fjell/registry"; var logger = logger_default.get("Library"); var createLibrary = (registry, coordinate, operations, options) => { logger.debug("createLibrary", { coordinate, operations, registry, options }); const baseInstance = createBaseInstance(registry, coordinate); return { ...baseInstance, operations, options: options || {} }; }; var isLibrary = (library) => { return library !== null && typeof library !== "undefined" && typeof library.coordinate !== "undefined" && typeof library.operations !== "undefined" && typeof library.options !== "undefined" && typeof library.registry !== "undefined"; }; // src/LibraryFactory.ts var logger2 = logger_default.get("InstanceFactory"); var createLibraryFactory = (operations, options) => { return (coordinate, context) => { logger2.debug("Creating lib instance", { coordinate, registry: context.registry, operations, options }); return createLibrary(context.registry, coordinate, operations, options); }; }; // src/Operations.ts import { isComKey as isComKey2, isPriKey as isPriKey2 } from "@fjell/core"; // src/ops/all.ts import { executeWithContext } from "@fjell/core"; import { validateLocations } from "@fjell/validation"; var logger3 = logger_default.get("library", "ops", "all"); var wrapAllOperation = (toWrap, options, coordinate, registry) => { const all = async (query, locations, allOptions) => { const locs = locations ?? []; logger3.debug("all", { query, locations: locs, options: allOptions }); if (locs.length > 0) { validateLocations(locs, coordinate, "all"); } const context = { itemType: coordinate.kta[0], operationType: "all", operationName: "all", params: { query, locations: locs, options: allOptions }, locations: locs }; return executeWithContext( () => toWrap.all(query, locs, allOptions), context ); }; return all; }; // src/ops/create.ts import { executeWithContext as executeWithContext2 } from "@fjell/core"; import { validateKey, validateLocations as validateLocations2, validateSchema } from "@fjell/validation"; var logger4 = logger_default.get("library", "ops", "create"); var wrapCreateOperation = (toWrap, options, coordinate, registry) => { const libOptions = options; const create = async (item, createOptions3) => { try { logger4.debug("create", { item, createOptions: createOptions3 }); if (createOptions3) { if ("key" in createOptions3 && createOptions3.key) { validateKey(createOptions3.key, coordinate, "create"); } if ("locations" in createOptions3 && createOptions3.locations) { validateLocations2(createOptions3.locations, coordinate, "create"); } } let itemToCreate = item; itemToCreate = await runPreCreateHook(itemToCreate, createOptions3); await validateCreate(itemToCreate, createOptions3); const context = { itemType: coordinate.kta[0], operationType: "create", operationName: "create", params: { item: itemToCreate, options: createOptions3 }, locations: createOptions3?.locations }; let createdItem = await executeWithContext2( () => toWrap.create(itemToCreate, createOptions3), context ); createdItem = await runPostCreateHook(createdItem); logger4.debug("Create operation completed successfully", { createdItem }); return createdItem; } catch (error) { if (error instanceof CreateValidationError) { throw error; } logger4.error("Create operation failed", { component: "lib", operation: "create", itemType: coordinate.kta[0], itemData: JSON.stringify(item), createOptions: JSON.stringify(createOptions3), errorType: error?.constructor?.name || typeof error, errorMessage: error?.message, errorCode: error?.errorInfo?.code || error?.code, suggestion: "Check validation rules, required fields, unique constraints, and hooks implementation", coordinate: JSON.stringify(coordinate), stack: error?.stack }); throw new Error(error.message, { cause: error }); } }; return create; async function runPreCreateHook(item, options2) { let itemToCreate = item; if (libOptions?.hooks?.preCreate) { try { itemToCreate = await libOptions.hooks.preCreate(itemToCreate, options2); } catch (error) { logger4.error("preCreate hook failed", { component: "lib", operation: "create", hook: "preCreate", itemType: coordinate.kta[0], itemData: JSON.stringify(item), errorType: error?.constructor?.name, errorMessage: error?.message, suggestion: "Check preCreate hook implementation for errors", coordinate: JSON.stringify(coordinate), stack: error?.stack }); throw new HookError( "Error in preCreate", "create", coordinate, { cause: error } ); } } else { } return itemToCreate; } async function runPostCreateHook(createdItem) { if (libOptions?.hooks?.postCreate) { try { createdItem = await libOptions.hooks.postCreate(createdItem); } catch (error) { throw new HookError( "Error in postCreate", "create", coordinate, { cause: error } ); } } else { } return createdItem; } async function validateCreate(item, options2) { if (libOptions?.validation?.schema) { try { await validateSchema(item, libOptions.validation.schema); } catch (error) { throw new CreateValidationError( { item, options: options2 }, coordinate, { cause: error } ); } } if (!libOptions?.validators?.onCreate) { return; } try { const isValid = await libOptions.validators.onCreate(item, options2); if (!isValid) { throw new CreateValidationError( { item, options: options2 }, coordinate, { cause: new Error("Invalid item") } ); } } catch (error) { if (error instanceof CreateValidationError) throw error; throw new CreateValidationError( { item, options: options2 }, coordinate, { cause: error } ); } } }; // src/ops/find.ts import { executeWithContext as executeWithContext3, ValidationError as ValidationError2 } from "@fjell/core"; var logger5 = logger_default.get("library", "ops", "find"); var wrapFindOperation = (toWrap, options, coordinate, registry) => { const { finders } = options || {}; const find = async (finder, params, locations, findOptions) => { const locs = locations ?? []; logger5.debug("find", { finder, params, locations: locs, findOptions }); if (!finders?.[finder]) { const availableFinders = finders ? Object.keys(finders) : []; throw new ValidationError2( `Finder "${finder}" not found`, availableFinders, "Use one of the available finders" ); } const context = { itemType: coordinate.kta[0], operationType: "find", operationName: finder, params, locations: locs }; return executeWithContext3( () => toWrap.find(finder, params, locs, findOptions), context ); }; return find; }; // src/ops/findOne.ts import { executeWithContext as executeWithContext4, ValidationError as ValidationError3 } from "@fjell/core"; var logger6 = logger_default.get("library", "ops", "findOne"); var wrapFindOneOperation = (toWrap, options, coordinate, registry) => { const { finders } = options || {}; const findOne = async (finder, params, locations) => { const locs = locations ?? []; logger6.debug("findOne", { finder, params, locations: locs }); if (!finders?.[finder]) { const availableFinders = finders ? Object.keys(finders) : []; throw new ValidationError3( `Finder "${finder}" not found`, availableFinders, "Use one of the available finders" ); } const context = { itemType: coordinate.kta[0], operationType: "findOne", operationName: finder, params, locations: locs }; return executeWithContext4( () => toWrap.findOne(finder, params, locs), context ); }; return findOne; }; // src/ops/get.ts import { executeWithContext as executeWithContext5 } from "@fjell/core"; import { validateKey as validateKey2 } from "@fjell/validation"; var logger7 = logger_default.get("library", "ops", "get"); var wrapGetOperation = (toWrap, options, coordinate, registry) => { const get = async (key) => { logger7.debug("get", { key }); validateKey2(key, coordinate, "get"); const context = { itemType: coordinate.kta[0], operationType: "get", operationName: "get", params: { key }, key }; return executeWithContext5( () => toWrap.get(key), context ); }; return get; }; // src/ops/one.ts import { executeWithContext as executeWithContext6 } from "@fjell/core"; var logger8 = logger_default.get("library", "ops", "one"); var wrapOneOperation = (toWrap, options, coordinate, registry) => { const one = async (query, locations) => { const locs = locations ?? []; logger8.debug("one", { query, locations: locs }); const context = { itemType: coordinate.kta[0], operationType: "one", operationName: "one", params: { query, locations: locs }, locations: locs }; return executeWithContext6( () => toWrap.one(query, locs), context ); }; return one; }; // src/ops/remove.ts import { executeWithContext as executeWithContext7 } from "@fjell/core"; var logger9 = logger_default.get("library", "ops", "remove"); var wrapRemoveOperation = (toWrap, options, coordinate, registry) => { const remove = async (key) => { try { logger9.debug("remove", { key }); await runPreRemoveHook(key); await validateRemove(key); const context = { itemType: coordinate.kta[0], operationType: "remove", operationName: "remove", params: { key }, key }; const item = await executeWithContext7( () => toWrap.remove(key), context ); if (!item) { logger9.error("Remove operation failed - no item returned", { key }); throw new RemoveError({ key }, coordinate); } await runPostRemoveHook(item); logger9.debug("Remove operation completed successfully", { item }); return item; } catch (error) { throw new Error(error.message, { cause: error }); } }; return remove; async function runPreRemoveHook(key) { if (options?.hooks?.preRemove) { try { await options.hooks.preRemove(key); } catch (error) { throw new HookError("preRemove", "remove", coordinate, { cause: error }); } } else { } } async function runPostRemoveHook(item) { if (options?.hooks?.postRemove) { try { await options.hooks.postRemove(item); } catch (error) { throw new HookError("postRemove", "remove", coordinate, { cause: error }); } } else { } } async function validateRemove(key) { if (!options?.validators?.onRemove) { return; } try { const isValid = await options.validators.onRemove(key); if (!isValid) { throw new RemoveValidationError( { key }, coordinate, { cause: new Error("Error validating remove") } ); } } catch (error) { throw new RemoveValidationError( { key }, coordinate, { cause: error } ); } } }; // src/ops/update.ts import { executeWithContext as executeWithContext8 } from "@fjell/core"; import { validateSchema as validateSchema2 } from "@fjell/validation"; var logger10 = logger_default.get("library", "ops", "update"); var wrapUpdateOperation = (toWrap, options, coordinate, registry) => { const update = async (key, item) => { try { logger10.debug("update", { key, item }); let originalItem; if (options?.hooks?.onChange) { try { originalItem = await toWrap.get(key); } catch (error) { logger10.warning("Failed to fetch original item for onChange hook", { component: "lib", operation: "update", phase: "fetch-for-onChange", key: JSON.stringify(key), itemType: coordinate.kta[0], errorType: error?.constructor?.name || typeof error, errorMessage: error?.message, note: "Update will continue without onChange hook", coordinate: JSON.stringify(coordinate) }); } } let itemToUpdate = item; itemToUpdate = await runPreUpdateHook(key, itemToUpdate); await validateUpdate(key, itemToUpdate); const context = { itemType: coordinate.kta[0], operationType: "update", operationName: "update", params: { key, updates: itemToUpdate }, key }; let updatedItem; try { updatedItem = await executeWithContext8( () => toWrap.update(key, itemToUpdate), context ); } catch (updateError) { throw new UpdateError({ key, item: itemToUpdate }, coordinate, { cause: updateError }); } try { updatedItem = await runPostUpdateHook(updatedItem); } catch (hookError) { throw new UpdateError({ key, item: itemToUpdate }, coordinate, { cause: hookError }); } if (options?.hooks?.onChange && originalItem != null) { try { await options.hooks.onChange(originalItem, updatedItem); } catch (error) { throw new HookError( "Error in onChange", "update", coordinate, { cause: error } ); } } logger10.debug("Update operation completed successfully", { updatedItem }); return updatedItem; } catch (error) { if (error instanceof UpdateValidationError) { throw error; } throw new Error(error.message, { cause: error }); } }; return update; async function runPreUpdateHook(key, itemToUpdate) { if (options?.hooks?.preUpdate) { try { itemToUpdate = await options.hooks.preUpdate(key, itemToUpdate); } catch (error) { throw new HookError( "Error in preUpdate", "update", coordinate, { cause: error } ); } } else { } return itemToUpdate; } async function runPostUpdateHook(updatedItem) { if (options?.hooks?.postUpdate) { try { updatedItem = await options.hooks.postUpdate(updatedItem); } catch (error) { throw new HookError( "Error in postUpdate", "update", coordinate, { cause: error } ); } } else { } return updatedItem; } async function validateUpdate(key, itemToUpdate) { if (options?.validation) { try { if (options.validation.updateSchema) { await validateSchema2(itemToUpdate, options.validation.updateSchema); } } catch (error) { throw new UpdateValidationError( { key, item: itemToUpdate }, coordinate, { cause: error } ); } } if (!options?.validators?.onUpdate) { return; } try { const isValid = await options.validators.onUpdate(key, itemToUpdate); if (!isValid) { throw new UpdateValidationError( { key, item: itemToUpdate }, coordinate, { cause: new Error("Invalid item") } ); } } catch (error) { if (error instanceof UpdateValidationError) throw error; throw new UpdateValidationError( { key, item: itemToUpdate }, coordinate, { cause: error } ); } } }; // src/ops/upsert.ts import { executeWithContext as executeWithContext9 } from "@fjell/core"; var logger11 = logger_default.get("ops", "upsert"); var wrapUpsertOperation = (ops, coordinate, registry) => { const upsert = async (key, itemProperties, locations, options) => { logger11.debug("upsert", { key, itemProperties }); const context = { itemType: coordinate.kta[0], operationType: "upsert", operationName: "upsert", params: { key, item: itemProperties }, key }; return executeWithContext9( async () => { let item = null; try { logger11.debug("Retrieving item by key", { key }); item = await ops.get(key); } catch (error) { const isNotFound = error instanceof NotFoundError || error?.name === "NotFoundError" || error?.errorInfo?.code === "NOT_FOUND"; if (isNotFound) { logger11.debug("Item not found, creating new item", { key, errorType: error?.name, errorCode: error?.errorInfo?.code }); const createOptions3 = locations ? { locations } : { key }; item = await ops.create(itemProperties, createOptions3); } else { logger11.error("Unexpected error during upsert get operation", { component: "lib", operation: "upsert", phase: "get-existing", key: JSON.stringify(key), itemType: coordinate.kta[0], errorType: error?.constructor?.name || typeof error, errorMessage: error?.message, errorName: error?.name, errorCode: error?.errorInfo?.code, suggestion: "Check database connectivity, permissions, and key validity", coordinate: JSON.stringify(coordinate) }); throw error; } } if (!item) { logger11.error("Failed to retrieve or create item during upsert", { component: "lib", operation: "upsert", key: JSON.stringify(key), itemType: coordinate.kta[0], suggestion: "This should not happen. Check create operation implementation and error handling.", coordinate: JSON.stringify(coordinate) }); throw new Error(`Failed to retrieve or create item for upsert with key: ${JSON.stringify(key)}`); } logger11.debug("Updating item", { key: item.key, itemProperties }); item = await ops.update(item.key, itemProperties, options); logger11.debug("Item updated successfully", { item }); return item; }, context ); }; return upsert; }; // src/ops/action.ts import { executeWithContext as executeWithContext10, ValidationError as ValidationError4 } from "@fjell/core"; var logger12 = logger_default.get("library", "ops", "action"); var wrapActionOperation = (toWrap, options, coordinate) => { const { actions } = options || {}; const action = async (key, actionKey, actionParams) => { logger12.debug("Action operation started", { key, actionKey, actionParams }); if (!actions?.[actionKey]) { const availableActions = actions ? Object.keys(actions) : []; logger12.error("Action not found", { component: "lib", operation: "action", requestedAction: actionKey, availableActions, key: JSON.stringify(key), itemType: coordinate.kta[0], suggestion: availableActions.length > 0 ? `Use one of the available actions: ${availableActions.join(", ")}` : "Define actions in your library configuration", coordinate: JSON.stringify(coordinate) }); throw new ValidationError4( `Action "${actionKey}" not found`, availableActions, availableActions.length > 0 ? `Use one of the available actions: ${availableActions.join(", ")}` : "Define actions in your library configuration" ); } const context = { itemType: coordinate.kta[0], operationType: "action", operationName: actionKey, params: actionParams || {}, key }; try { return await executeWithContext10( async () => { const actionMethod = actions[actionKey]; const item = await toWrap.get(key); if (!item) { logger12.error("Item not found for action", { component: "lib", operation: "action", action: actionKey, key: JSON.stringify(key), itemType: coordinate.kta[0], suggestion: "Verify the item exists before calling actions. Check if the key is correct or if the item was deleted.", coordinate: JSON.stringify(coordinate) }); throw new Error(`Item not found for action "${actionKey}" with key: ${JSON.stringify(key)}`); } const result = await actionMethod(item, actionParams || {}); logger12.debug("Action operation completed", { actionKey, result }); return result; }, context ); } catch (error) { const errorDetails = { operation: "action", actionKey, coordinate: coordinate.kta, key: JSON.stringify(key) }; if (typeof error.message === "string") { errorDetails.message = error.message; } if (typeof error.name === "string") { errorDetails.name = error.name; } if (typeof error.code === "string" || typeof error.code === "number") { errorDetails.code = error.code; } if (typeof error.stack === "string") { errorDetails.stack = error.stack; } if (typeof error.constraint === "string") { errorDetails.constraint = error.constraint; } if (typeof error.detail === "string") { errorDetails.detail = error.detail; } if (error.errors && Array.isArray(error.errors)) { errorDetails.validationErrors = error.errors.map((e) => ({ message: e.message, type: e.type, path: e.path })); } logger12.error(`Action "${actionKey}" failed`, errorDetails); throw error; } }; return action; }; // src/ops/facet.ts import { executeWithContext as executeWithContext11, ValidationError as ValidationError5 } from "@fjell/core"; var logger13 = logger_default.get("library", "ops", "facet"); var wrapFacetOperation = (toWrap, options, coordinate, registry) => { const { facets } = options || {}; const facet = async (key, facetKey, facetParams) => { logger13.debug("Facet operation started", { key, facetKey, facetParams }); if (!facets?.[facetKey]) { const availableFacets = facets ? Object.keys(facets) : []; throw new ValidationError5( `Facet "${facetKey}" not found`, availableFacets, "Use one of the available facets" ); } const context = { itemType: coordinate.kta[0], operationType: "facet", operationName: facetKey, params: facetParams || {}, key }; return executeWithContext11( async () => { const facetMethod = facets[facetKey]; logger13.debug("Getting item for facet", { key }); const item = await toWrap.get(key); if (!item) { throw new Error(`Item not found for key: ${JSON.stringify(key)}`); } const result = facetMethod(item, facetParams || {}); logger13.debug("Facet operation completed", { facetKey, result }); return result; }, context ); }; return facet; }; // src/ops/allAction.ts import { executeWithContext as executeWithContext12, ValidationError as ValidationError6 } from "@fjell/core"; var logger14 = logger_default.get("library", "ops", "allAction"); var wrapAllActionOperation = (toWrap, options, coordinate) => { const { allActions } = options || {}; const allAction = async (allActionKey, allActionParams, locations) => { const locs = locations ?? []; logger14.debug("AllAction operation started", { allActionKey, allActionParams, locations: locs }); if (!allActions?.[allActionKey]) { const availableActions = allActions ? Object.keys(allActions) : []; throw new ValidationError6( `AllAction "${allActionKey}" not found`, availableActions, "Use one of the available actions" ); } const context = { itemType: coordinate.kta[0], operationType: "allAction", operationName: allActionKey, params: allActionParams || {}, locations: locs }; try { return await executeWithContext12( async () => { const allActionMethod = allActions[allActionKey]; const result = await allActionMethod(allActionParams || {}, locs); logger14.debug("AllAction operation completed", { allActionKey, result }); return result; }, context ); } catch (error) { const errorDetails = { operation: "allAction", actionKey: allActionKey, coordinate: coordinate.kta, locations: locs }; if (typeof error.message === "string") { errorDetails.message = error.message; } if (typeof error.name === "string") { errorDetails.name = error.name; } if (typeof error.code === "string" || typeof error.code === "number") { errorDetails.code = error.code; } if (typeof error.stack === "string") { errorDetails.stack = error.stack; } if (typeof error.constraint === "string") { errorDetails.constraint = error.constraint; } if (typeof error.detail === "string") { errorDetails.detail = error.detail; } if (error.errors && Array.isArray(error.errors)) { errorDetails.validationErrors = error.errors.map((e) => ({ message: e.message, type: e.type, path: e.path })); } logger14.error(`AllAction "${allActionKey}" failed`, errorDetails); throw error; } }; return allAction; }; // src/ops/allFacet.ts import { executeWithContext as executeWithContext13, ValidationError as ValidationError7 } from "@fjell/core"; var logger15 = logger_default.get("library", "ops", "allFacet"); var wrapAllFacetOperation = (toWrap, options, coordinate, registry) => { const { allFacets } = options || {}; const allFacet = async (allFacetKey, allFacetParams, locations) => { const locs = locations ?? []; logger15.debug("AllFacet operation started", { allFacetKey, allFacetParams, locations: locs }); if (!allFacets?.[allFacetKey]) { const availableFacets = allFacets ? Object.keys(allFacets) : []; throw new ValidationError7( `AllFacet "${allFacetKey}" not found`, availableFacets, "Use one of the available facets" ); } const context = { itemType: coordinate.kta[0], operationType: "allFacet", operationName: allFacetKey, params: allFacetParams || {}, locations: locs }; return executeWithContext13( () => { const allFacetMethod = allFacets[allFacetKey]; const result = allFacetMethod(allFacetParams || {}, locs); logger15.debug("AllFacet operation completed", { allFacetKey, result }); return result; }, context ); }; return allFacet; }; // src/Operations.ts var logger16 = logger_default.get("Operations"); var wrapOperations = (toWrap, options, coordinate, registry) => { logger16.default("\u{1F517} [LIB] Wrapping operations with hooks and validation", { coordinate: coordinate.kta, hasHooks: !!options.hooks, hasValidators: !!options.validators, toWrapType: toWrap.constructor?.name || "Unknown" }); const operations = {}; logger16.default("\u{1F517} [LIB] Wrapping create operation"); operations.create = wrapCreateOperation(toWrap, options, coordinate, registry); logger16.default("\u{1F517} [LIB] Wrapping update operation"); operations.update = wrapUpdateOperation(toWrap, options, coordinate, registry); logger16.default("\u{1F517} [LIB] Wrapping remove operation"); operations.remove = wrapRemoveOperation(toWrap, options, coordinate, registry); logger16.default("\u{1F517} [LIB] Wrapping other operations"); operations.all = wrapAllOperation(toWrap, options, coordinate, registry); operations.one = wrapOneOperation(toWrap, options, coordinate, registry); operations.get = wrapGetOperation(toWrap, options, coordinate, registry); operations.find = wrapFindOperation(toWrap, options, coordinate, registry); operations.findOne = wrapFindOneOperation(toWrap, options, coordinate, registry); operations.upsert = wrapUpsertOperation(operations, coordinate, registry); operations.action = wrapActionOperation(toWrap, options, coordinate); operations.facet = wrapFacetOperation(toWrap, options, coordinate, registry); operations.allAction = wrapAllActionOperation(toWrap, options, coordinate); operations.allFacet = wrapAllFacetOperation(toWrap, options, coordinate, registry); operations.finders = { ...toWrap.finders || {}, ...options.finders || {} }; operations.actions = { ...toWrap.actions || {}, ...options.actions || {} }; operations.facets = { ...toWrap.facets || {}, ...options.facets || {} }; operations.allActions = { ...toWrap.allActions || {}, ...options.allActions || {} }; operations.allFacets = { ...toWrap.allFacets || {}, ...options.allFacets || {} }; logger16.default("\u{1F517} [LIB] Operations wrapping completed", { coordinate: coordinate.kta, wrappedOperations: Object.keys(operations) }); return operations; }; var createReadOnlyOperations = (toWrap) => { logger16.debug("createReadOnlyOperations", { toWrap }); const create = async (item, options) => { logger16.warning("create", "Cannot Create in a ReadOnly Library, Returning Empty Item"); return {}; }; const update = async (key, item) => { logger16.warning("update", "Cannot Update in a ReadOnly Library, Returning Empty Item"); return {}; }; const upsert = async (key, itemProperties, locations) => { logger16.warning("upsert", "Cannot Upsert in a ReadOnly Library, Returning Empty Item"); return {}; }; const remove = async (key) => { logger16.warning("remove", "Cannot Remove in a ReadOnly Library, Returning Empty Item"); return {}; }; return { ...toWrap, create, update, upsert, remove }; }; // src/Options.ts import deepmerge from "deepmerge"; var logger17 = logger_default.get("Options"); var createDefaultOptions = () => { logger17.debug("createDefaultOptions"); function clearAggs(item) { delete item.aggs; return item; } return { hooks: { // TODO: "We need to figure out how to make this an array of hooks..." preCreate: async (item, options) => { const retItem = clearAggs(item); return retItem; }, // TODO: "We need to figure out how to make this an array of hooks..." preUpdate: async (key, item) => { const retItem = clearAggs(item); return retItem; } } }; }; var createOptions = (options) => { const defaultOptions = createDefaultOptions(); return deepmerge(defaultOptions, options ?? {}); }; // src/Registry.ts import { createRegistry as createBaseRegistry } from "@fjell/registry"; var logger18 = logger_default.get("LibRegistry"); var createRegistryFactory = () => { return (type, registryHub) => { if (type !== "lib") { throw new Error(`LibRegistryFactory can only create 'lib' type registries, got: ${type}`); } logger18.debug("Creating lib registry", { type, registryHub }); const baseRegistry = createBaseRegistry(type, registryHub); return baseRegistry; }; }; var createRegistry = (registryHub) => { const baseRegistry = createBaseRegistry("lib", registryHub); return { ...baseRegistry }; }; // src/processing/OperationContext.ts import { AsyncLocalStorage } from "async_hooks"; var serializeKey = (key) => { if (key && "pk" in key && "kt" in key && !("loc" in key)) { return `${key.kt}:${key.pk}`; } else if (key && "pk" in key && "kt" in key && "loc" in key && key.loc) { const locStr = key.loc.map((l) => `${l.kt}:${l.lk}`).join(","); return `${key.kt}:${key.pk}|${locStr}`; } throw new Error(`Unsupported key type: ${JSON.stringify(key)}`); }; var createOperationContext = () => { const inProgress = /* @__PURE__ */ new Set(); const cache = /* @__PURE__ */ new Map(); return { inProgress, cache, markInProgress(key) { const serialized = serializeKey(key); logger_default.debug("Marking key as in progress", { key, serialized }); inProgress.add(serialized); }, markComplete(key) { const serialized = serializeKey(key); logger_default.debug("Marking key as complete", { key, serialized }); inProgress.delete(serialized); }, isInProgress(key) { const serialized = serializeKey(key); const result = inProgress.has(serialized); logger_default.debug("Checking if key is in progress", { key, serialized, result }); return result; }, getCached(key) { const serialized = serializeKey(key); const result = cache.get(serialized); logger_default.debug("Getting cached item", { key, serialized, found: !!result }); return result; }, setCached(key, item) { const serialized = serializeKey(key); logger_default.debug("Caching item", { key, serialized }); cache.set(serialized, item); }, isCached(key) { const serialized = serializeKey(key); const result = cache.has(serialized); logger_default.debug("Checking if key is cached", { key, serialized, result }); return result; } }; }; var createProcessingContext = createOperationContext; var ContextManager = class { asyncLocalStorage = new AsyncLocalStorage(); /** * Get the current context if one is set */ getCurrentContext() { const context = this.asyncLocalStorage.getStore(); if (context) { logger_default.debug("Got current context from AsyncLocalStorage"); } return context; } /** * Execute a function with a specific context set as current * The context will be available to all async operations within the function */ async withContext(context, fn) { logger_default.debug("Running with context in AsyncLocalStorage"); return this.asyncLocalStorage.run(context, fn); } }; var contextManager = new ContextManager(); // src/processing/AggregationBuilder.ts import { ikToLKA, isComKey as isComKey3 } from "@fjell/core"; var logger19 = logger_default.get("lib", "processing", "AggregationBuilder"); var buildAggregation = async (item, aggregationDefinition, registry, context) => { logger19.debug("\u{1F50D} AggregationBuilder START", { itemKeyType: item.key.kt, itemKeyPk: item.key.pk, itemKeyFull: JSON.stringify(item.key), targetKta: aggregationDefinition.kta, aggregationProperty: aggregationDefinition.property, cardinality: aggregationDefinition.cardinality }); const currentItemType = item.key.kt; const targetKta = aggregationDefinition.kta; const targetKtaSliced = targetKta.slice(1); const isChildAggregation = targetKta.length > 1 && targetKtaSliced.includes(currentItemType); logger19.debug("\u{1F50D} AggregationBuilder DETECTION", { currentItemType, targetKta, targetKtaSliced, includesCurrentItem: targetKtaSliced.includes(currentItemType), isChildAggregation, isComKeyResult: isComKey3(item.key) }); let location; if (isComKey3(item.key)) { const comKey = item.key; logger19.debug("\u{1F50D} AggregationBuilder COMKEY", { comKeyKt: comKey.kt, comKeyPk: comKey.pk, comKeyLoc: JSON.stringify(comKey.loc), comKeyLocLength: comKey.loc?.length || 0 }); if (isChildAggregation) { const currentItemLocKey = { kt: comKey.kt, lk: comKey.pk }; location = [currentItemLocKey, ...comKey.loc]; logger19.debug("\u{1F50D} AggregationBuilder CHILD AGGREGATION", { currentItemLocKey, parentLocs: JSON.stringify(comKey.loc), constructedLocation: JSON.stringify(location), locationLength: location.length }); } else { location = ikToLKA(comKey); logger19.debug("\u{1F50D} AggregationBuilder SIBLING AGGREGATION", { ikToLKAResult: JSON.stringify(location), locationLength: location.length }); } } else { location = ikToLKA(item.key); logger19.debug("\u{1F50D} AggregationBuilder PRIMARY KEY", { ikToLKAResult: JSON.stringify(location), locationLength: location.length }); } logger19.debug("\u{1F50D} AggregationBuilder FINAL LOCATION", { finalLocation: JSON.stringify(location), finalLocationLength: location.length, operationType: aggregationDefinition.cardinality, targetLibraryKta: aggregationDefinition.kta }); const libraryInstance = registry.get(aggregationDefinition.kta); if (!libraryInstance) { throw new Error(`Library instance not found for key type array: ${aggregationDefinition.kta.join(", ")}`); } const aggregationCacheKey = `${aggregationDefinition.kta.join(".")}_${aggregationDefinition.cardinality}_${serializeKey(item.key)}`; if (context) { if (context.cache.has(aggregationCacheKey)) { const cachedResult = context.cache.get(aggregationCacheKey); logger19.debug("Using cached aggregation result", { aggregationCacheKey, property: aggregationDefinition.property }); item[aggregationDefinition.property] = cachedResult; return item; } } return contextManager.withContext(context || contextManager.getCurrentContext() || createOperationContext(), async () => { if (aggregationDefinition.cardinality === "one") { return libraryInstance.operations.one({}, location).then((result) => { if (context) { context.cache.set(aggregationCacheKey, result); } item[aggregationDefinition.property] = result; return item; }); } else { return libraryInstance.operations.all({}, location).then((results) => { if (context) { context.cache.set(aggregationCacheKey, results); } item[aggregationDefinition.property] = results; return item; }); } }); }; // src/processing/ReferenceBuilder.ts var buildReference = async (item, referenceDefinition, registry, context) => { throw new Error( "buildReference() from @fjell/lib is deprecated and no longer functional. Use implementation-specific builders instead:\n- buildSequelizeReference from @fjell/lib-sequelize for SQL databases\n- buildFirestoreReference from @fjell/lib-firestore for Firestore" ); }; // src/wrapImplementationOperations.ts function wrapImplementationOperations(implOps, options) { return { // Spread the implementation operations ...implOps, // Add stub implementations for extended operations // These return "no-op" values since they're not implemented by default facet: async () => null, allFacet: async () => null, action: async () => [{}, []], allAction: async () => [[], []], // Add metadata dictionaries from options finders: { ...options.finders || {} }, actions: { ...options.actions || {} }, facets: { ...options.facets || {} }, allActions: { ...options.allActions || {} }, allFacets: { ...options.allFacets || {} } }; } // src/primary/index.ts var primary_exports = {}; __export(primary_exports, { createLibrary: () => createLibrary2, wrapOperations: () => wrapOperations2 }); // src/primary/Library.ts var logger20 = logger_default.get("primary", "Instance"); var createLibrary2 = (registry, coordinate, operations, options) => { logger20.debug("createLibrary", { coordinate, operations, registry, options }); const library = createLibrary(registry, coordinate, operations, options); if (!library) { return library; } return { ...library, operations }; }; // src/primary/Operations.ts var logger21 = logger_default.get("primary", "Operations"); var wrapOperations2 = (toWrap, options, coordinate, registry) => { logger21.debug("wrapOperations", { toWrap, options, coordinate, registry }); const operations = wrapOperations(toWrap, options, coordinate, registry); return operations; }; // src/contained/index.ts var contained_exports = {}; __export(contained_exports, { createLibrary: () => createLibrary3, createOptions: () => createOptions2, wrapOperations: () => wrapOperations3 }); // src/contained/Library.ts var createLibrary3 = (parent, registry, coordinate, operations, options) => { const library = createLibrary(registry, coordinate, operations, options); return { ...library, parent }; }; // src/contained/Operations.ts var wrapOperations3 = (toWrap, options, coordinate, registry) => { logger_default.debug("wrapOperations", { toWrap, options, coordinate, registry }); const operations = wrapOperations(toWrap, options, coordinate, registry); return operations; }; // src/contained/Options.ts var createOptions2 = (libOptions) => { const options = createOptions(libOptions); return { ...options }; }; export { contained_exports as Contained, CreateValidationError, HookError, InvalidKeyTypeError, LibError, LocationKeyOrderErr