@autofleet/sadot 1.4.20 → 1.4.21-beta-e58014c3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- const e=require(`../repository/definition.cjs`),t=require(`../repository/value.cjs`),n=require(`../repository/entries.cjs`),r=require(`../utils/scopeAttributes.cjs`),i=[`id`,`name`,`entityId`,`fieldType`,`displayName`,`validation`,`entityType`,`modelType`,`required`,`disabled`,`defaultValue`],a=async({instancesIds:e,options:t,sadotOptions:r})=>{if(!r.useCustomFieldsEntries)return{};let i=await n.findEntriesByModelIds(e,t??{}),a=Object.fromEntries(i.map(e=>{let{modelId:t,customFields:n}=e?.dataValues??{};if(t)return[t,n]}).filter(e=>e!==void 0));return e.forEach(e=>{a[e]??={}}),a},o=async({instancesIds:e,options:n,sadotOptions:r})=>r.useCustomFieldsEntries?{}:(await t.findValuesByModelIds(e,n??{})).reduce((e,t)=>{let{modelId:n}=t;return e[n]??=[],e[n].push(t),e},{}),s=(e,t)=>e.reduce((e,n)=>({...e,...t[n.customFieldDefinitionId]&&{[t[n.customFieldDefinitionId].name]:n.value}}),{}),c=(t,n,c,l={},u={useCustomFieldsEntries:!1,hasTypeId:!1})=>async(d,f)=>{if(f.originalAttributes?.length>0&&!f.originalAttributes?.includes?.(`customFields`))return;let p=Array.isArray(d)?d:[d];p=p.filter(Boolean);let m=r.default(p,n),h=[...new Set(m)].filter(Boolean),g=h.reduce((e,t)=>({...e,[t]:[]}),{}),_,v;f.transaction&&(f.transaction.definitionCache??=new Map,v=`${t}:${h.slice().sort().join(`,`)}`,_=f.transaction.definitionCache.get(v));let y;if(!_)if(u.hasTypeId&&p.length>0&&p[0].typeId){let n=[...new Set(p.map(e=>e.typeId).filter(Boolean))];y=new Map,n.forEach(e=>y.set(e,new Set));let r=(await Promise.all(n.map(async n=>{let r=await e.findByModelTypeId(n,{withDisabled:!1,entityIds:h,modelType:t,modelOptions:l,transaction:f.transaction});return r.forEach(e=>y.get(n).add(e.id)),r}))).flat(),i=new Map;r.forEach(e=>{i.set(e.id,e)}),_=Promise.resolve(Array.from(i.values()))}else _=e.findByEntityIds(t,h,{transaction:f.transaction,modelOptions:l,attributes:i}),f.transaction?.definitionCache?.set(v,_);let b=await _;if(b.length===0){p.forEach(e=>{e.customFields={}});return}l?.include&&l.useEntityIdFromInclude&&l.include(m).forEach(({model:e})=>{b.forEach(t=>{let n=t[e.name]?.entityId||t[`${e.name}.entityId`];n&&!g[n]&&(g[n]=[])})});let x=b.reduce((e,t)=>({...e,[t.id]:t}),{});b.forEach(e=>{let t=e.entityId;if(l?.useEntityIdFromInclude&&l.include){let n=l.include(m);for(let{model:r}of n){let n=e[r.name]?.entityId||e[`${r.name}.entityId`];if(n){t=n;break}}}g[t]&&g[t].push(e)});let S=p.map(e=>e.id),[C,w]=await Promise.all([o({instancesIds:S,options:f,sadotOptions:u}),a({instancesIds:S,options:f,sadotOptions:u})]);p.forEach(e=>{let{id:t}=e,r=C[t],i=r?s(r,x):{},a=u.useCustomFieldsEntries?w[t]:i;n.forEach(t=>{let n=g[e[t]];n&&n.length>0&&n.forEach(t=>{y&&!y.get(e.typeId)?.has(t.id)||a[t.name]===void 0&&(a[t.name]=null)})}),e.customFields=a,f.attributesToRemove?.forEach?.(t=>{delete e.dataValues?.[t],delete e?.[t]}),c===`afterFind`&&e?.changed?.(`customFields`,!1)})};var l=c;exports.default=l;
1
+ const e=require(`../repository/definition.cjs`),t=require(`../repository/value.cjs`),n=require(`../repository/entries.cjs`),r=require(`../utils/scopeAttributes.cjs`),i=[`id`,`name`,`entityId`,`fieldType`,`displayName`,`validation`,`entityType`,`modelType`,`required`,`disabled`,`defaultValue`],a=async({instancesIds:e,options:t,sadotOptions:r})=>{if(!r.useCustomFieldsEntries)return{};let i=await n.findEntriesByModelIds(e,t??{}),a=Object.fromEntries(i.map(e=>{let{modelId:t,customFields:n}=e?.dataValues??{};if(t)return[t,n]}).filter(e=>e!==void 0));return e.forEach(e=>{a[e]??={}}),a},o=async({instancesIds:e,options:n,sadotOptions:r})=>r.useCustomFieldsEntries?{}:(await t.findValuesByModelIds(e,n??{})).reduce((e,t)=>{let{modelId:n}=t;return e[n]??=[],e[n].push(t),e},{}),s=(e,t)=>e.reduce((e,n)=>({...e,...t[n.customFieldDefinitionId]&&{[t[n.customFieldDefinitionId].name]:n.value}}),{}),c=(t,n,c,l={},u={useCustomFieldsEntries:!1,hasTypeId:!1})=>async(d,f)=>{if(f.originalAttributes?.length>0&&!f.originalAttributes?.includes?.(`customFields`))return;let p=Array.isArray(d)?d:[d];p=p.filter(Boolean);let m=r.default(p,n),h=[...new Set(m)].filter(Boolean),g=h.reduce((e,t)=>({...e,[t]:[]}),{}),_,v;f.transaction&&(f.transaction.definitionCache??=new Map,v=`${t}:${h.slice().sort().join(`,`)}`,_=f.transaction.definitionCache.get(v));let y;if(!_){let n=u.hasTypeId&&p.length>0&&p[0].typeId,r=async(r=f.transaction)=>{if(n){let n=[...new Set(p.map(e=>e.typeId).filter(Boolean))];y=new Map,n.forEach(e=>y.set(e,new Set));let i=(await Promise.all(n.map(async n=>{let i=await e.findByModelTypeId(n,{withDisabled:!1,entityIds:h,modelType:t,modelOptions:l,transaction:r});return i.forEach(e=>y.get(n).add(e.id)),i}))).flat(),a=new Map;return i.forEach(e=>{a.set(e.id,e)}),Array.from(a.values())}return e.findByEntityIds(t,h,{transaction:r,modelOptions:l,attributes:i})};_=u.matPathManager&&u.isMatPathActive?.()?u.matPathManager.withPaths(e=>r(e),{transaction:f.transaction}):r(),n||f.transaction?.definitionCache?.set(v,_)}let b=await _;if(b.length===0){p.forEach(e=>{e.customFields={}});return}l?.include&&l.useEntityIdFromInclude&&l.include(m).forEach(({model:e})=>{b.forEach(t=>{let n=t[e.name]?.entityId||t[`${e.name}.entityId`];n&&!g[n]&&(g[n]=[])})});let x=b.reduce((e,t)=>({...e,[t.id]:t}),{});b.forEach(e=>{let t=e.entityId;if(l?.useEntityIdFromInclude&&l.include){let n=l.include(m);for(let{model:r}of n){let n=e[r.name]?.entityId||e[`${r.name}.entityId`];if(n){t=n;break}}}g[t]&&g[t].push(e)});let S=p.map(e=>e.id),[C,w]=await Promise.all([o({instancesIds:S,options:f,sadotOptions:u}),a({instancesIds:S,options:f,sadotOptions:u})]);p.forEach(e=>{let{id:t}=e,r=C[t],i=r?s(r,x):{},a=u.useCustomFieldsEntries?w[t]:i;n.forEach(t=>{let n=g[e[t]];n&&n.length>0&&n.forEach(t=>{y&&!y.get(e.typeId)?.has(t.id)||a[t.name]===void 0&&(a[t.name]=null)})}),e.customFields=a,f.attributesToRemove?.forEach?.(t=>{delete e.dataValues?.[t],delete e?.[t]}),c===`afterFind`&&e?.changed?.(`customFields`,!1)})};var l=c;exports.default=l;
2
2
  //# sourceMappingURL=enrich.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"enrich.cjs","names":["applyScopeToInstance","cacheKey: string | undefined","modelTypeDefinitionsMap: Map<string, Set<string>> | undefined"],"sources":["../../src/hooks/enrich.ts"],"sourcesContent":["import * as ValueRepo from '../repository/value';\nimport * as DefinitionRepo from '../repository/definition';\nimport * as EntriesRepo from '../repository/entries';\nimport type CustomFieldValue from '../models/CustomFieldValue';\nimport type CustomFieldDefinition from '../models/CustomFieldDefinition';\nimport type { SerializedCustomFields } from '../types/definition';\nimport type { CustomFieldOptions, ModelOptions, TransactionOptions } from '../types';\nimport applyScopeToInstance from '../utils/scopeAttributes';\n\n// Include all required fields for proper functioning\nconst CUSTOM_FIELD_DEFINITION_ATTRIBUTES_TO_PULL = [\n 'id',\n 'name',\n 'entityId',\n 'fieldType',\n 'displayName',\n 'validation',\n 'entityType',\n 'modelType',\n 'required',\n 'disabled',\n 'defaultValue',\n];\n\ntype SupportedHookTypes = 'afterFind' | 'afterCreate' | 'afterUpdate';\n\ntype CustomFieldEntries = Record<string, any>;\n\n// eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style\ninterface GetValuesGroupByInstanceResponse {\n [modelId: string]: CustomFieldValue[];\n}\n\n// eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style\ninterface GetCustomFieldEntriesByInstanceIdResponse {\n [modelId: string]: CustomFieldEntries;\n}\n\nexport const getCustomFieldEntriesByInstanceId = async ({\n instancesIds,\n options,\n sadotOptions,\n}: {\n instancesIds: string[];\n options?: TransactionOptions;\n sadotOptions: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>;\n}): Promise<GetCustomFieldEntriesByInstanceIdResponse> => {\n if (!sadotOptions.useCustomFieldsEntries) {\n return {};\n }\n\n const customFieldEntries = await EntriesRepo.findEntriesByModelIds(\n instancesIds,\n options ?? {},\n );\n\n const customFieldEntriesByInstanceId = Object.fromEntries(customFieldEntries.map((instanceEntries) => {\n const { modelId, customFields } = instanceEntries?.dataValues ?? {};\n if (!modelId) {\n return undefined;\n }\n return [modelId, customFields];\n }).filter(v => v !== undefined));\n\n instancesIds.forEach((instanceId) => {\n customFieldEntriesByInstanceId[instanceId] ??= {};\n });\n\n return customFieldEntriesByInstanceId;\n};\n\nexport const getValuesGroupByInstance = async ({\n instancesIds,\n options,\n sadotOptions,\n}: {\n instancesIds: string[];\n options?: TransactionOptions;\n sadotOptions: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>;\n}): Promise<GetValuesGroupByInstanceResponse> => {\n if (sadotOptions.useCustomFieldsEntries) {\n return {};\n }\n\n const customFieldValues = await ValueRepo.findValuesByModelIds(\n instancesIds,\n options ?? {},\n );\n\n // Group fields by modelId\n return customFieldValues.reduce<Record<string, CustomFieldValue[]>>((acc, v) => {\n const { modelId } = v;\n acc[modelId] ??= [];\n acc[modelId].push(v);\n return acc;\n }, {});\n};\n\n/**\n * Serialize custom fields value into the format of {[name] -> [fieldData]}\n */\nconst serializeCustomFields = (\n customFieldValues: CustomFieldValue[],\n customFieldDefinitionsHash: Record<string, CustomFieldDefinition>,\n): SerializedCustomFields => {\n const customFields = customFieldValues.reduce((acc, cfv) => ({\n ...acc,\n ...(\n customFieldDefinitionsHash[cfv.customFieldDefinitionId]\n && { [customFieldDefinitionsHash[cfv.customFieldDefinitionId].name]: cfv.value }\n ),\n }), {});\n return customFields;\n};\n/**\n * A hook to attach the custom fields when fetching a model instances.\n */\nconst enrichResults = (\n modelType: string,\n scopeAttributes: string[],\n hookType?: SupportedHookTypes,\n modelOptions: ModelOptions = {},\n sadotOptions: Pick<CustomFieldOptions, 'useCustomFieldsEntries' | 'hasTypeId'> = { useCustomFieldsEntries: false, hasTypeId: false },\n) => async (\n instancesOrInstance: any | any[],\n options: TransactionOptions,\n): Promise<void> => {\n if (options.originalAttributes?.length > 0 && !options.originalAttributes?.includes?.('customFields')) {\n return;\n }\n\n const primaryKey = 'id';\n let instances = Array.isArray(instancesOrInstance)\n ? instancesOrInstance\n : [instancesOrInstance];\n\n instances = instances.filter(Boolean);\n\n const identifiers = applyScopeToInstance(instances, scopeAttributes);\n\n const uniqueIdentifiers = [...new Set(identifiers)].filter(Boolean);\n\n const identifierCustomFieldDefinitionsMapping = uniqueIdentifiers.reduce((map, identifier) => ({\n ...map,\n [identifier]: [],\n }), {});\n\n // Cache for definitions by model type and transaction to avoid redundant DB queries\n let customFieldDefinitionsPromise;\n let cacheKey: string | undefined;\n\n if (options.transaction) {\n // Initialize definition cache Map if not already present directly on the transaction object\n options.transaction.definitionCache ??= new Map();\n cacheKey = `${modelType}:${uniqueIdentifiers.slice().sort().join(',')}`;\n customFieldDefinitionsPromise = options.transaction.definitionCache.get(cacheKey);\n }\n\n let modelTypeDefinitionsMap: Map<string, Set<string>> | undefined;\n\n // Fetch from database (either first time in this transaction or no transaction)\n if (!customFieldDefinitionsPromise) {\n const shouldApplyTypeFiltering = sadotOptions.hasTypeId && instances.length > 0 && instances[0].typeId;\n\n if (shouldApplyTypeFiltering) {\n const uniqueTypeIds = [...new Set(instances.map(instance => instance.typeId).filter(Boolean))];\n\n modelTypeDefinitionsMap = new Map<string, Set<string>>();\n uniqueTypeIds.forEach(typeId => modelTypeDefinitionsMap!.set(typeId, new Set()));\n\n const definitionsResults = await Promise.all(\n uniqueTypeIds.map(async (typeId) => {\n const defs = await DefinitionRepo.findByModelTypeId(typeId, { withDisabled: false, entityIds: uniqueIdentifiers, modelType, modelOptions, transaction: options.transaction });\n defs.forEach(def => modelTypeDefinitionsMap!.get(typeId)!.add(def.id));\n return defs;\n }),\n );\n\n const allDefinitions = definitionsResults.flat();\n const uniqueDefinitionsMap = new Map();\n allDefinitions.forEach((def) => {\n uniqueDefinitionsMap.set(def.id, def);\n });\n customFieldDefinitionsPromise = Promise.resolve(Array.from(uniqueDefinitionsMap.values()));\n } else {\n customFieldDefinitionsPromise = DefinitionRepo.findByEntityIds(\n modelType,\n uniqueIdentifiers,\n { transaction: options.transaction, modelOptions, attributes: CUSTOM_FIELD_DEFINITION_ATTRIBUTES_TO_PULL },\n );\n\n options.transaction?.definitionCache?.set(cacheKey!, customFieldDefinitionsPromise);\n }\n }\n const customFieldDefinitions = await customFieldDefinitionsPromise;\n\n if (customFieldDefinitions.length === 0) {\n // if no custom fields, we can return\n instances.forEach((instance) => {\n instance.customFields = {};\n });\n return;\n }\n\n if (modelOptions?.include && modelOptions.useEntityIdFromInclude) {\n // if we pass useEntityIdFromInclude,\n // map the entity from the options to the identifierCustomFieldDefinitionsMapping\n modelOptions.include(identifiers).forEach(({ model }) => {\n customFieldDefinitions.forEach((cfd: any) => {\n // try 2 ways to get the entityId from the joined model - for raw and non-raw\n const entityId = cfd[model!.name]?.entityId || cfd[`${model!.name}.entityId` as keyof CustomFieldDefinition];\n if (entityId && !identifierCustomFieldDefinitionsMapping[entityId]) {\n identifierCustomFieldDefinitionsMapping[entityId] = [];\n }\n });\n });\n }\n\n const definitionsMap = customFieldDefinitions.reduce((map, definition) => ({\n ...map,\n [definition.id]: definition,\n }), {});\n\n customFieldDefinitions.forEach((cfd: any) => {\n let entityIdToUse = cfd.entityId;\n\n if (modelOptions?.useEntityIdFromInclude && modelOptions.include) {\n const contextIncludes = modelOptions.include(identifiers);\n for (const { model } of contextIncludes) {\n const joinedEntityId = cfd[model!.name]?.entityId || cfd[`${model!.name}.entityId` as keyof CustomFieldDefinition];\n if (joinedEntityId) {\n entityIdToUse = joinedEntityId;\n break;\n }\n }\n }\n\n if (identifierCustomFieldDefinitionsMapping[entityIdToUse]) {\n identifierCustomFieldDefinitionsMapping[entityIdToUse].push(cfd);\n }\n });\n\n // Get the values per instates ids:\n const instancesIds = instances.map(i => i[primaryKey]);\n\n // Group fields by modelId\n const [valuesGroupByInstance, customFieldEntriesByInstanceId] = await Promise.all([\n getValuesGroupByInstance({\n instancesIds,\n options,\n sadotOptions,\n }),\n getCustomFieldEntriesByInstanceId({\n instancesIds,\n options,\n sadotOptions,\n }),\n ]);\n\n // Attach custom fields to the instances\n instances.forEach((instance) => {\n const { id } = instance;\n\n const instanceValues = valuesGroupByInstance[id];\n const serializedCustomFieldsValues = instanceValues ? serializeCustomFields(instanceValues, definitionsMap) : {};\n\n const customFields = sadotOptions.useCustomFieldsEntries\n ? customFieldEntriesByInstanceId[id]\n : serializedCustomFieldsValues;\n\n scopeAttributes.forEach((attribute) => {\n const identifier = instance[attribute];\n\n const entityCustomFieldDefinitions = identifierCustomFieldDefinitionsMapping[identifier] as CustomFieldDefinition[] | undefined;\n if (entityCustomFieldDefinitions && entityCustomFieldDefinitions.length > 0) {\n entityCustomFieldDefinitions.forEach((customFieldDefinition) => {\n if (modelTypeDefinitionsMap) {\n const applicableDefinitionIds = modelTypeDefinitionsMap.get(instance.typeId);\n if (!applicableDefinitionIds?.has(customFieldDefinition.id)) {\n return;\n }\n }\n\n if (customFields[customFieldDefinition.name] === undefined) {\n customFields[customFieldDefinition.name] = null;\n }\n });\n }\n });\n instance.customFields = customFields;\n (options.attributesToRemove as string[] | undefined)?.forEach?.((attribute) => {\n delete instance.dataValues?.[attribute];\n // if raw:\n delete instance?.[attribute];\n });\n // sequelize will think customFields changed also in 'find', so we need to mark it as unchanged\n if (hookType === 'afterFind') {\n // changed() could be undefined, i.e in raw: true\n instance?.changed?.('customFields', false);\n }\n });\n};\n\nexport default enrichResults;\n"],"mappings":"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"}
1
+ {"version":3,"file":"enrich.cjs","names":["applyScopeToInstance","cacheKey: string | undefined","modelTypeDefinitionsMap: Map<string, Set<string>> | undefined"],"sources":["../../src/hooks/enrich.ts"],"sourcesContent":["import * as ValueRepo from '../repository/value';\nimport * as DefinitionRepo from '../repository/definition';\nimport * as EntriesRepo from '../repository/entries';\nimport type CustomFieldValue from '../models/CustomFieldValue';\nimport type CustomFieldDefinition from '../models/CustomFieldDefinition';\nimport type { SerializedCustomFields } from '../types/definition';\nimport type { CustomFieldOptions, ModelOptions, TransactionOptions } from '../types';\nimport applyScopeToInstance from '../utils/scopeAttributes';\n\n// Include all required fields for proper functioning\nconst CUSTOM_FIELD_DEFINITION_ATTRIBUTES_TO_PULL = [\n 'id',\n 'name',\n 'entityId',\n 'fieldType',\n 'displayName',\n 'validation',\n 'entityType',\n 'modelType',\n 'required',\n 'disabled',\n 'defaultValue',\n];\n\ntype SupportedHookTypes = 'afterFind' | 'afterCreate' | 'afterUpdate';\n\ntype CustomFieldEntries = Record<string, any>;\n\n// eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style\ninterface GetValuesGroupByInstanceResponse {\n [modelId: string]: CustomFieldValue[];\n}\n\n// eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style\ninterface GetCustomFieldEntriesByInstanceIdResponse {\n [modelId: string]: CustomFieldEntries;\n}\n\nexport const getCustomFieldEntriesByInstanceId = async ({\n instancesIds,\n options,\n sadotOptions,\n}: {\n instancesIds: string[];\n options?: TransactionOptions;\n sadotOptions: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>;\n}): Promise<GetCustomFieldEntriesByInstanceIdResponse> => {\n if (!sadotOptions.useCustomFieldsEntries) {\n return {};\n }\n\n const customFieldEntries = await EntriesRepo.findEntriesByModelIds(\n instancesIds,\n options ?? {},\n );\n\n const customFieldEntriesByInstanceId = Object.fromEntries(customFieldEntries.map((instanceEntries) => {\n const { modelId, customFields } = instanceEntries?.dataValues ?? {};\n if (!modelId) {\n return undefined;\n }\n return [modelId, customFields];\n }).filter(v => v !== undefined));\n\n instancesIds.forEach((instanceId) => {\n customFieldEntriesByInstanceId[instanceId] ??= {};\n });\n\n return customFieldEntriesByInstanceId;\n};\n\nexport const getValuesGroupByInstance = async ({\n instancesIds,\n options,\n sadotOptions,\n}: {\n instancesIds: string[];\n options?: TransactionOptions;\n sadotOptions: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>;\n}): Promise<GetValuesGroupByInstanceResponse> => {\n if (sadotOptions.useCustomFieldsEntries) {\n return {};\n }\n\n const customFieldValues = await ValueRepo.findValuesByModelIds(\n instancesIds,\n options ?? {},\n );\n\n // Group fields by modelId\n return customFieldValues.reduce<Record<string, CustomFieldValue[]>>((acc, v) => {\n const { modelId } = v;\n acc[modelId] ??= [];\n acc[modelId].push(v);\n return acc;\n }, {});\n};\n\n/**\n * Serialize custom fields value into the format of {[name] -> [fieldData]}\n */\nconst serializeCustomFields = (\n customFieldValues: CustomFieldValue[],\n customFieldDefinitionsHash: Record<string, CustomFieldDefinition>,\n): SerializedCustomFields => {\n const customFields = customFieldValues.reduce((acc, cfv) => ({\n ...acc,\n ...(\n customFieldDefinitionsHash[cfv.customFieldDefinitionId]\n && { [customFieldDefinitionsHash[cfv.customFieldDefinitionId].name]: cfv.value }\n ),\n }), {});\n return customFields;\n};\n/**\n * A hook to attach the custom fields when fetching a model instances.\n */\nconst enrichResults = (\n modelType: string,\n scopeAttributes: string[],\n hookType?: SupportedHookTypes,\n modelOptions: ModelOptions = {},\n sadotOptions: Pick<CustomFieldOptions, 'useCustomFieldsEntries' | 'hasTypeId' | 'matPathManager' | 'isMatPathActive'> = { useCustomFieldsEntries: false, hasTypeId: false },\n) => async (\n instancesOrInstance: any | any[],\n options: TransactionOptions,\n): Promise<void> => {\n if (options.originalAttributes?.length > 0 && !options.originalAttributes?.includes?.('customFields')) {\n return;\n }\n\n const primaryKey = 'id';\n let instances = Array.isArray(instancesOrInstance)\n ? instancesOrInstance\n : [instancesOrInstance];\n\n instances = instances.filter(Boolean);\n\n const identifiers = applyScopeToInstance(instances, scopeAttributes);\n\n const uniqueIdentifiers = [...new Set(identifiers)].filter(Boolean);\n\n const identifierCustomFieldDefinitionsMapping = uniqueIdentifiers.reduce((map, identifier) => ({\n ...map,\n [identifier]: [],\n }), {});\n\n // Cache for definitions by model type and transaction to avoid redundant DB queries\n let customFieldDefinitionsPromise;\n let cacheKey: string | undefined;\n\n if (options.transaction) {\n // Initialize definition cache Map if not already present directly on the transaction object\n options.transaction.definitionCache ??= new Map();\n cacheKey = `${modelType}:${uniqueIdentifiers.slice().sort().join(',')}`;\n customFieldDefinitionsPromise = options.transaction.definitionCache.get(cacheKey);\n }\n\n let modelTypeDefinitionsMap: Map<string, Set<string>> | undefined;\n\n // Fetch from database (either first time in this transaction or no transaction).\n // When mat-path is active, run inside withPaths(ANCESTORS) so RLS on joined tables\n // (e.g. Context) filters CFDs to those visible at the caller's path + its ancestors.\n if (!customFieldDefinitionsPromise) {\n const shouldApplyTypeFiltering = sadotOptions.hasTypeId && instances.length > 0 && instances[0].typeId;\n\n const fetchDefinitions = async (transaction = options.transaction) => {\n if (shouldApplyTypeFiltering) {\n const uniqueTypeIds = [...new Set(instances.map(instance => instance.typeId).filter(Boolean))];\n\n modelTypeDefinitionsMap = new Map<string, Set<string>>();\n uniqueTypeIds.forEach(typeId => modelTypeDefinitionsMap!.set(typeId, new Set()));\n\n const definitionsResults = await Promise.all(\n uniqueTypeIds.map(async (typeId) => {\n const defs = await DefinitionRepo.findByModelTypeId(typeId, { withDisabled: false, entityIds: uniqueIdentifiers, modelType, modelOptions, transaction });\n defs.forEach(def => modelTypeDefinitionsMap!.get(typeId)!.add(def.id));\n return defs;\n }),\n );\n\n const allDefinitions = definitionsResults.flat();\n const uniqueDefinitionsMap = new Map();\n allDefinitions.forEach((def) => {\n uniqueDefinitionsMap.set(def.id, def);\n });\n return Array.from(uniqueDefinitionsMap.values());\n }\n return DefinitionRepo.findByEntityIds(\n modelType,\n uniqueIdentifiers,\n { transaction, modelOptions, attributes: CUSTOM_FIELD_DEFINITION_ATTRIBUTES_TO_PULL },\n );\n };\n\n customFieldDefinitionsPromise = sadotOptions.matPathManager && sadotOptions.isMatPathActive?.()\n ? sadotOptions.matPathManager.withPaths(\n transaction => fetchDefinitions(transaction),\n { transaction: options.transaction },\n )\n : fetchDefinitions();\n\n if (!shouldApplyTypeFiltering) {\n options.transaction?.definitionCache?.set(cacheKey!, customFieldDefinitionsPromise);\n }\n }\n const customFieldDefinitions = await customFieldDefinitionsPromise;\n\n if (customFieldDefinitions.length === 0) {\n // if no custom fields, we can return\n instances.forEach((instance) => {\n instance.customFields = {};\n });\n return;\n }\n\n if (modelOptions?.include && modelOptions.useEntityIdFromInclude) {\n // if we pass useEntityIdFromInclude,\n // map the entity from the options to the identifierCustomFieldDefinitionsMapping\n modelOptions.include(identifiers).forEach(({ model }) => {\n customFieldDefinitions.forEach((cfd: any) => {\n // try 2 ways to get the entityId from the joined model - for raw and non-raw\n const entityId = cfd[model!.name]?.entityId || cfd[`${model!.name}.entityId` as keyof CustomFieldDefinition];\n if (entityId && !identifierCustomFieldDefinitionsMapping[entityId]) {\n identifierCustomFieldDefinitionsMapping[entityId] = [];\n }\n });\n });\n }\n\n const definitionsMap = customFieldDefinitions.reduce((map, definition) => ({\n ...map,\n [definition.id]: definition,\n }), {});\n\n customFieldDefinitions.forEach((cfd: any) => {\n let entityIdToUse = cfd.entityId;\n\n if (modelOptions?.useEntityIdFromInclude && modelOptions.include) {\n const contextIncludes = modelOptions.include(identifiers);\n for (const { model } of contextIncludes) {\n const joinedEntityId = cfd[model!.name]?.entityId || cfd[`${model!.name}.entityId` as keyof CustomFieldDefinition];\n if (joinedEntityId) {\n entityIdToUse = joinedEntityId;\n break;\n }\n }\n }\n\n if (identifierCustomFieldDefinitionsMapping[entityIdToUse]) {\n identifierCustomFieldDefinitionsMapping[entityIdToUse].push(cfd);\n }\n });\n\n // Get the values per instates ids:\n const instancesIds = instances.map(i => i[primaryKey]);\n\n // Group fields by modelId\n const [valuesGroupByInstance, customFieldEntriesByInstanceId] = await Promise.all([\n getValuesGroupByInstance({\n instancesIds,\n options,\n sadotOptions,\n }),\n getCustomFieldEntriesByInstanceId({\n instancesIds,\n options,\n sadotOptions,\n }),\n ]);\n\n // Attach custom fields to the instances\n instances.forEach((instance) => {\n const { id } = instance;\n\n const instanceValues = valuesGroupByInstance[id];\n const serializedCustomFieldsValues = instanceValues ? serializeCustomFields(instanceValues, definitionsMap) : {};\n\n const customFields = sadotOptions.useCustomFieldsEntries\n ? customFieldEntriesByInstanceId[id]\n : serializedCustomFieldsValues;\n\n scopeAttributes.forEach((attribute) => {\n const identifier = instance[attribute];\n\n const entityCustomFieldDefinitions = identifierCustomFieldDefinitionsMapping[identifier] as CustomFieldDefinition[] | undefined;\n if (entityCustomFieldDefinitions && entityCustomFieldDefinitions.length > 0) {\n entityCustomFieldDefinitions.forEach((customFieldDefinition) => {\n if (modelTypeDefinitionsMap) {\n const applicableDefinitionIds = modelTypeDefinitionsMap.get(instance.typeId);\n if (!applicableDefinitionIds?.has(customFieldDefinition.id)) {\n return;\n }\n }\n\n if (customFields[customFieldDefinition.name] === undefined) {\n customFields[customFieldDefinition.name] = null;\n }\n });\n }\n });\n instance.customFields = customFields;\n (options.attributesToRemove as string[] | undefined)?.forEach?.((attribute) => {\n delete instance.dataValues?.[attribute];\n // if raw:\n delete instance?.[attribute];\n });\n // sequelize will think customFields changed also in 'find', so we need to mark it as unchanged\n if (hookType === 'afterFind') {\n // changed() could be undefined, i.e in raw: true\n instance?.changed?.('customFields', false);\n }\n });\n};\n\nexport default enrichResults;\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{findByEntityIds as e,findByModelTypeId as t}from"../repository/definition.js";import{findValuesByModelIds as n}from"../repository/value.js";import{findEntriesByModelIds as r}from"../repository/entries.js";import i from"../utils/scopeAttributes.js";const a=[`id`,`name`,`entityId`,`fieldType`,`displayName`,`validation`,`entityType`,`modelType`,`required`,`disabled`,`defaultValue`],o=async({instancesIds:e,options:t,sadotOptions:n})=>{if(!n.useCustomFieldsEntries)return{};let i=await r(e,t??{}),a=Object.fromEntries(i.map(e=>{let{modelId:t,customFields:n}=e?.dataValues??{};if(t)return[t,n]}).filter(e=>e!==void 0));return e.forEach(e=>{a[e]??={}}),a},s=async({instancesIds:e,options:t,sadotOptions:r})=>r.useCustomFieldsEntries?{}:(await n(e,t??{})).reduce((e,t)=>{let{modelId:n}=t;return e[n]??=[],e[n].push(t),e},{}),c=(e,t)=>e.reduce((e,n)=>({...e,...t[n.customFieldDefinitionId]&&{[t[n.customFieldDefinitionId].name]:n.value}}),{});var l=(n,r,l,u={},d={useCustomFieldsEntries:!1,hasTypeId:!1})=>async(f,p)=>{if(p.originalAttributes?.length>0&&!p.originalAttributes?.includes?.(`customFields`))return;let m=Array.isArray(f)?f:[f];m=m.filter(Boolean);let h=i(m,r),g=[...new Set(h)].filter(Boolean),_=g.reduce((e,t)=>({...e,[t]:[]}),{}),v,y;p.transaction&&(p.transaction.definitionCache??=new Map,y=`${n}:${g.slice().sort().join(`,`)}`,v=p.transaction.definitionCache.get(y));let b;if(!v)if(d.hasTypeId&&m.length>0&&m[0].typeId){let e=[...new Set(m.map(e=>e.typeId).filter(Boolean))];b=new Map,e.forEach(e=>b.set(e,new Set));let r=(await Promise.all(e.map(async e=>{let r=await t(e,{withDisabled:!1,entityIds:g,modelType:n,modelOptions:u,transaction:p.transaction});return r.forEach(t=>b.get(e).add(t.id)),r}))).flat(),i=new Map;r.forEach(e=>{i.set(e.id,e)}),v=Promise.resolve(Array.from(i.values()))}else v=e(n,g,{transaction:p.transaction,modelOptions:u,attributes:a}),p.transaction?.definitionCache?.set(y,v);let x=await v;if(x.length===0){m.forEach(e=>{e.customFields={}});return}u?.include&&u.useEntityIdFromInclude&&u.include(h).forEach(({model:e})=>{x.forEach(t=>{let n=t[e.name]?.entityId||t[`${e.name}.entityId`];n&&!_[n]&&(_[n]=[])})});let S=x.reduce((e,t)=>({...e,[t.id]:t}),{});x.forEach(e=>{let t=e.entityId;if(u?.useEntityIdFromInclude&&u.include){let n=u.include(h);for(let{model:r}of n){let n=e[r.name]?.entityId||e[`${r.name}.entityId`];if(n){t=n;break}}}_[t]&&_[t].push(e)});let C=m.map(e=>e.id),[w,T]=await Promise.all([s({instancesIds:C,options:p,sadotOptions:d}),o({instancesIds:C,options:p,sadotOptions:d})]);m.forEach(e=>{let{id:t}=e,n=w[t],i=n?c(n,S):{},a=d.useCustomFieldsEntries?T[t]:i;r.forEach(t=>{let n=_[e[t]];n&&n.length>0&&n.forEach(t=>{b&&!b.get(e.typeId)?.has(t.id)||a[t.name]===void 0&&(a[t.name]=null)})}),e.customFields=a,p.attributesToRemove?.forEach?.(t=>{delete e.dataValues?.[t],delete e?.[t]}),l===`afterFind`&&e?.changed?.(`customFields`,!1)})};export{l as default};
1
+ import{findByEntityIds as e,findByModelTypeId as t}from"../repository/definition.js";import{findValuesByModelIds as n}from"../repository/value.js";import{findEntriesByModelIds as r}from"../repository/entries.js";import i from"../utils/scopeAttributes.js";const a=[`id`,`name`,`entityId`,`fieldType`,`displayName`,`validation`,`entityType`,`modelType`,`required`,`disabled`,`defaultValue`],o=async({instancesIds:e,options:t,sadotOptions:n})=>{if(!n.useCustomFieldsEntries)return{};let i=await r(e,t??{}),a=Object.fromEntries(i.map(e=>{let{modelId:t,customFields:n}=e?.dataValues??{};if(t)return[t,n]}).filter(e=>e!==void 0));return e.forEach(e=>{a[e]??={}}),a},s=async({instancesIds:e,options:t,sadotOptions:r})=>r.useCustomFieldsEntries?{}:(await n(e,t??{})).reduce((e,t)=>{let{modelId:n}=t;return e[n]??=[],e[n].push(t),e},{}),c=(e,t)=>e.reduce((e,n)=>({...e,...t[n.customFieldDefinitionId]&&{[t[n.customFieldDefinitionId].name]:n.value}}),{});var l=(n,r,l,u={},d={useCustomFieldsEntries:!1,hasTypeId:!1})=>async(f,p)=>{if(p.originalAttributes?.length>0&&!p.originalAttributes?.includes?.(`customFields`))return;let m=Array.isArray(f)?f:[f];m=m.filter(Boolean);let h=i(m,r),g=[...new Set(h)].filter(Boolean),_=g.reduce((e,t)=>({...e,[t]:[]}),{}),v,y;p.transaction&&(p.transaction.definitionCache??=new Map,y=`${n}:${g.slice().sort().join(`,`)}`,v=p.transaction.definitionCache.get(y));let b;if(!v){let r=d.hasTypeId&&m.length>0&&m[0].typeId,i=async(i=p.transaction)=>{if(r){let e=[...new Set(m.map(e=>e.typeId).filter(Boolean))];b=new Map,e.forEach(e=>b.set(e,new Set));let r=(await Promise.all(e.map(async e=>{let r=await t(e,{withDisabled:!1,entityIds:g,modelType:n,modelOptions:u,transaction:i});return r.forEach(t=>b.get(e).add(t.id)),r}))).flat(),a=new Map;return r.forEach(e=>{a.set(e.id,e)}),Array.from(a.values())}return e(n,g,{transaction:i,modelOptions:u,attributes:a})};v=d.matPathManager&&d.isMatPathActive?.()?d.matPathManager.withPaths(e=>i(e),{transaction:p.transaction}):i(),r||p.transaction?.definitionCache?.set(y,v)}let x=await v;if(x.length===0){m.forEach(e=>{e.customFields={}});return}u?.include&&u.useEntityIdFromInclude&&u.include(h).forEach(({model:e})=>{x.forEach(t=>{let n=t[e.name]?.entityId||t[`${e.name}.entityId`];n&&!_[n]&&(_[n]=[])})});let S=x.reduce((e,t)=>({...e,[t.id]:t}),{});x.forEach(e=>{let t=e.entityId;if(u?.useEntityIdFromInclude&&u.include){let n=u.include(h);for(let{model:r}of n){let n=e[r.name]?.entityId||e[`${r.name}.entityId`];if(n){t=n;break}}}_[t]&&_[t].push(e)});let C=m.map(e=>e.id),[w,T]=await Promise.all([s({instancesIds:C,options:p,sadotOptions:d}),o({instancesIds:C,options:p,sadotOptions:d})]);m.forEach(e=>{let{id:t}=e,n=w[t],i=n?c(n,S):{},a=d.useCustomFieldsEntries?T[t]:i;r.forEach(t=>{let n=_[e[t]];n&&n.length>0&&n.forEach(t=>{b&&!b.get(e.typeId)?.has(t.id)||a[t.name]===void 0&&(a[t.name]=null)})}),e.customFields=a,p.attributesToRemove?.forEach?.(t=>{delete e.dataValues?.[t],delete e?.[t]}),l===`afterFind`&&e?.changed?.(`customFields`,!1)})};export{l as default};
2
2
  //# sourceMappingURL=enrich.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"enrich.js","names":["EntriesRepo.findEntriesByModelIds","ValueRepo.findValuesByModelIds","applyScopeToInstance","cacheKey: string | undefined","modelTypeDefinitionsMap: Map<string, Set<string>> | undefined","DefinitionRepo.findByModelTypeId","DefinitionRepo.findByEntityIds"],"sources":["../../src/hooks/enrich.ts"],"sourcesContent":["import * as ValueRepo from '../repository/value';\nimport * as DefinitionRepo from '../repository/definition';\nimport * as EntriesRepo from '../repository/entries';\nimport type CustomFieldValue from '../models/CustomFieldValue';\nimport type CustomFieldDefinition from '../models/CustomFieldDefinition';\nimport type { SerializedCustomFields } from '../types/definition';\nimport type { CustomFieldOptions, ModelOptions, TransactionOptions } from '../types';\nimport applyScopeToInstance from '../utils/scopeAttributes';\n\n// Include all required fields for proper functioning\nconst CUSTOM_FIELD_DEFINITION_ATTRIBUTES_TO_PULL = [\n 'id',\n 'name',\n 'entityId',\n 'fieldType',\n 'displayName',\n 'validation',\n 'entityType',\n 'modelType',\n 'required',\n 'disabled',\n 'defaultValue',\n];\n\ntype SupportedHookTypes = 'afterFind' | 'afterCreate' | 'afterUpdate';\n\ntype CustomFieldEntries = Record<string, any>;\n\n// eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style\ninterface GetValuesGroupByInstanceResponse {\n [modelId: string]: CustomFieldValue[];\n}\n\n// eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style\ninterface GetCustomFieldEntriesByInstanceIdResponse {\n [modelId: string]: CustomFieldEntries;\n}\n\nexport const getCustomFieldEntriesByInstanceId = async ({\n instancesIds,\n options,\n sadotOptions,\n}: {\n instancesIds: string[];\n options?: TransactionOptions;\n sadotOptions: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>;\n}): Promise<GetCustomFieldEntriesByInstanceIdResponse> => {\n if (!sadotOptions.useCustomFieldsEntries) {\n return {};\n }\n\n const customFieldEntries = await EntriesRepo.findEntriesByModelIds(\n instancesIds,\n options ?? {},\n );\n\n const customFieldEntriesByInstanceId = Object.fromEntries(customFieldEntries.map((instanceEntries) => {\n const { modelId, customFields } = instanceEntries?.dataValues ?? {};\n if (!modelId) {\n return undefined;\n }\n return [modelId, customFields];\n }).filter(v => v !== undefined));\n\n instancesIds.forEach((instanceId) => {\n customFieldEntriesByInstanceId[instanceId] ??= {};\n });\n\n return customFieldEntriesByInstanceId;\n};\n\nexport const getValuesGroupByInstance = async ({\n instancesIds,\n options,\n sadotOptions,\n}: {\n instancesIds: string[];\n options?: TransactionOptions;\n sadotOptions: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>;\n}): Promise<GetValuesGroupByInstanceResponse> => {\n if (sadotOptions.useCustomFieldsEntries) {\n return {};\n }\n\n const customFieldValues = await ValueRepo.findValuesByModelIds(\n instancesIds,\n options ?? {},\n );\n\n // Group fields by modelId\n return customFieldValues.reduce<Record<string, CustomFieldValue[]>>((acc, v) => {\n const { modelId } = v;\n acc[modelId] ??= [];\n acc[modelId].push(v);\n return acc;\n }, {});\n};\n\n/**\n * Serialize custom fields value into the format of {[name] -> [fieldData]}\n */\nconst serializeCustomFields = (\n customFieldValues: CustomFieldValue[],\n customFieldDefinitionsHash: Record<string, CustomFieldDefinition>,\n): SerializedCustomFields => {\n const customFields = customFieldValues.reduce((acc, cfv) => ({\n ...acc,\n ...(\n customFieldDefinitionsHash[cfv.customFieldDefinitionId]\n && { [customFieldDefinitionsHash[cfv.customFieldDefinitionId].name]: cfv.value }\n ),\n }), {});\n return customFields;\n};\n/**\n * A hook to attach the custom fields when fetching a model instances.\n */\nconst enrichResults = (\n modelType: string,\n scopeAttributes: string[],\n hookType?: SupportedHookTypes,\n modelOptions: ModelOptions = {},\n sadotOptions: Pick<CustomFieldOptions, 'useCustomFieldsEntries' | 'hasTypeId'> = { useCustomFieldsEntries: false, hasTypeId: false },\n) => async (\n instancesOrInstance: any | any[],\n options: TransactionOptions,\n): Promise<void> => {\n if (options.originalAttributes?.length > 0 && !options.originalAttributes?.includes?.('customFields')) {\n return;\n }\n\n const primaryKey = 'id';\n let instances = Array.isArray(instancesOrInstance)\n ? instancesOrInstance\n : [instancesOrInstance];\n\n instances = instances.filter(Boolean);\n\n const identifiers = applyScopeToInstance(instances, scopeAttributes);\n\n const uniqueIdentifiers = [...new Set(identifiers)].filter(Boolean);\n\n const identifierCustomFieldDefinitionsMapping = uniqueIdentifiers.reduce((map, identifier) => ({\n ...map,\n [identifier]: [],\n }), {});\n\n // Cache for definitions by model type and transaction to avoid redundant DB queries\n let customFieldDefinitionsPromise;\n let cacheKey: string | undefined;\n\n if (options.transaction) {\n // Initialize definition cache Map if not already present directly on the transaction object\n options.transaction.definitionCache ??= new Map();\n cacheKey = `${modelType}:${uniqueIdentifiers.slice().sort().join(',')}`;\n customFieldDefinitionsPromise = options.transaction.definitionCache.get(cacheKey);\n }\n\n let modelTypeDefinitionsMap: Map<string, Set<string>> | undefined;\n\n // Fetch from database (either first time in this transaction or no transaction)\n if (!customFieldDefinitionsPromise) {\n const shouldApplyTypeFiltering = sadotOptions.hasTypeId && instances.length > 0 && instances[0].typeId;\n\n if (shouldApplyTypeFiltering) {\n const uniqueTypeIds = [...new Set(instances.map(instance => instance.typeId).filter(Boolean))];\n\n modelTypeDefinitionsMap = new Map<string, Set<string>>();\n uniqueTypeIds.forEach(typeId => modelTypeDefinitionsMap!.set(typeId, new Set()));\n\n const definitionsResults = await Promise.all(\n uniqueTypeIds.map(async (typeId) => {\n const defs = await DefinitionRepo.findByModelTypeId(typeId, { withDisabled: false, entityIds: uniqueIdentifiers, modelType, modelOptions, transaction: options.transaction });\n defs.forEach(def => modelTypeDefinitionsMap!.get(typeId)!.add(def.id));\n return defs;\n }),\n );\n\n const allDefinitions = definitionsResults.flat();\n const uniqueDefinitionsMap = new Map();\n allDefinitions.forEach((def) => {\n uniqueDefinitionsMap.set(def.id, def);\n });\n customFieldDefinitionsPromise = Promise.resolve(Array.from(uniqueDefinitionsMap.values()));\n } else {\n customFieldDefinitionsPromise = DefinitionRepo.findByEntityIds(\n modelType,\n uniqueIdentifiers,\n { transaction: options.transaction, modelOptions, attributes: CUSTOM_FIELD_DEFINITION_ATTRIBUTES_TO_PULL },\n );\n\n options.transaction?.definitionCache?.set(cacheKey!, customFieldDefinitionsPromise);\n }\n }\n const customFieldDefinitions = await customFieldDefinitionsPromise;\n\n if (customFieldDefinitions.length === 0) {\n // if no custom fields, we can return\n instances.forEach((instance) => {\n instance.customFields = {};\n });\n return;\n }\n\n if (modelOptions?.include && modelOptions.useEntityIdFromInclude) {\n // if we pass useEntityIdFromInclude,\n // map the entity from the options to the identifierCustomFieldDefinitionsMapping\n modelOptions.include(identifiers).forEach(({ model }) => {\n customFieldDefinitions.forEach((cfd: any) => {\n // try 2 ways to get the entityId from the joined model - for raw and non-raw\n const entityId = cfd[model!.name]?.entityId || cfd[`${model!.name}.entityId` as keyof CustomFieldDefinition];\n if (entityId && !identifierCustomFieldDefinitionsMapping[entityId]) {\n identifierCustomFieldDefinitionsMapping[entityId] = [];\n }\n });\n });\n }\n\n const definitionsMap = customFieldDefinitions.reduce((map, definition) => ({\n ...map,\n [definition.id]: definition,\n }), {});\n\n customFieldDefinitions.forEach((cfd: any) => {\n let entityIdToUse = cfd.entityId;\n\n if (modelOptions?.useEntityIdFromInclude && modelOptions.include) {\n const contextIncludes = modelOptions.include(identifiers);\n for (const { model } of contextIncludes) {\n const joinedEntityId = cfd[model!.name]?.entityId || cfd[`${model!.name}.entityId` as keyof CustomFieldDefinition];\n if (joinedEntityId) {\n entityIdToUse = joinedEntityId;\n break;\n }\n }\n }\n\n if (identifierCustomFieldDefinitionsMapping[entityIdToUse]) {\n identifierCustomFieldDefinitionsMapping[entityIdToUse].push(cfd);\n }\n });\n\n // Get the values per instates ids:\n const instancesIds = instances.map(i => i[primaryKey]);\n\n // Group fields by modelId\n const [valuesGroupByInstance, customFieldEntriesByInstanceId] = await Promise.all([\n getValuesGroupByInstance({\n instancesIds,\n options,\n sadotOptions,\n }),\n getCustomFieldEntriesByInstanceId({\n instancesIds,\n options,\n sadotOptions,\n }),\n ]);\n\n // Attach custom fields to the instances\n instances.forEach((instance) => {\n const { id } = instance;\n\n const instanceValues = valuesGroupByInstance[id];\n const serializedCustomFieldsValues = instanceValues ? serializeCustomFields(instanceValues, definitionsMap) : {};\n\n const customFields = sadotOptions.useCustomFieldsEntries\n ? customFieldEntriesByInstanceId[id]\n : serializedCustomFieldsValues;\n\n scopeAttributes.forEach((attribute) => {\n const identifier = instance[attribute];\n\n const entityCustomFieldDefinitions = identifierCustomFieldDefinitionsMapping[identifier] as CustomFieldDefinition[] | undefined;\n if (entityCustomFieldDefinitions && entityCustomFieldDefinitions.length > 0) {\n entityCustomFieldDefinitions.forEach((customFieldDefinition) => {\n if (modelTypeDefinitionsMap) {\n const applicableDefinitionIds = modelTypeDefinitionsMap.get(instance.typeId);\n if (!applicableDefinitionIds?.has(customFieldDefinition.id)) {\n return;\n }\n }\n\n if (customFields[customFieldDefinition.name] === undefined) {\n customFields[customFieldDefinition.name] = null;\n }\n });\n }\n });\n instance.customFields = customFields;\n (options.attributesToRemove as string[] | undefined)?.forEach?.((attribute) => {\n delete instance.dataValues?.[attribute];\n // if raw:\n delete instance?.[attribute];\n });\n // sequelize will think customFields changed also in 'find', so we need to mark it as unchanged\n if (hookType === 'afterFind') {\n // changed() could be undefined, i.e in raw: true\n instance?.changed?.('customFields', false);\n }\n });\n};\n\nexport default enrichResults;\n"],"mappings":"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"}
1
+ {"version":3,"file":"enrich.js","names":["EntriesRepo.findEntriesByModelIds","ValueRepo.findValuesByModelIds","applyScopeToInstance","cacheKey: string | undefined","modelTypeDefinitionsMap: Map<string, Set<string>> | undefined","DefinitionRepo.findByModelTypeId","DefinitionRepo.findByEntityIds"],"sources":["../../src/hooks/enrich.ts"],"sourcesContent":["import * as ValueRepo from '../repository/value';\nimport * as DefinitionRepo from '../repository/definition';\nimport * as EntriesRepo from '../repository/entries';\nimport type CustomFieldValue from '../models/CustomFieldValue';\nimport type CustomFieldDefinition from '../models/CustomFieldDefinition';\nimport type { SerializedCustomFields } from '../types/definition';\nimport type { CustomFieldOptions, ModelOptions, TransactionOptions } from '../types';\nimport applyScopeToInstance from '../utils/scopeAttributes';\n\n// Include all required fields for proper functioning\nconst CUSTOM_FIELD_DEFINITION_ATTRIBUTES_TO_PULL = [\n 'id',\n 'name',\n 'entityId',\n 'fieldType',\n 'displayName',\n 'validation',\n 'entityType',\n 'modelType',\n 'required',\n 'disabled',\n 'defaultValue',\n];\n\ntype SupportedHookTypes = 'afterFind' | 'afterCreate' | 'afterUpdate';\n\ntype CustomFieldEntries = Record<string, any>;\n\n// eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style\ninterface GetValuesGroupByInstanceResponse {\n [modelId: string]: CustomFieldValue[];\n}\n\n// eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style\ninterface GetCustomFieldEntriesByInstanceIdResponse {\n [modelId: string]: CustomFieldEntries;\n}\n\nexport const getCustomFieldEntriesByInstanceId = async ({\n instancesIds,\n options,\n sadotOptions,\n}: {\n instancesIds: string[];\n options?: TransactionOptions;\n sadotOptions: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>;\n}): Promise<GetCustomFieldEntriesByInstanceIdResponse> => {\n if (!sadotOptions.useCustomFieldsEntries) {\n return {};\n }\n\n const customFieldEntries = await EntriesRepo.findEntriesByModelIds(\n instancesIds,\n options ?? {},\n );\n\n const customFieldEntriesByInstanceId = Object.fromEntries(customFieldEntries.map((instanceEntries) => {\n const { modelId, customFields } = instanceEntries?.dataValues ?? {};\n if (!modelId) {\n return undefined;\n }\n return [modelId, customFields];\n }).filter(v => v !== undefined));\n\n instancesIds.forEach((instanceId) => {\n customFieldEntriesByInstanceId[instanceId] ??= {};\n });\n\n return customFieldEntriesByInstanceId;\n};\n\nexport const getValuesGroupByInstance = async ({\n instancesIds,\n options,\n sadotOptions,\n}: {\n instancesIds: string[];\n options?: TransactionOptions;\n sadotOptions: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>;\n}): Promise<GetValuesGroupByInstanceResponse> => {\n if (sadotOptions.useCustomFieldsEntries) {\n return {};\n }\n\n const customFieldValues = await ValueRepo.findValuesByModelIds(\n instancesIds,\n options ?? {},\n );\n\n // Group fields by modelId\n return customFieldValues.reduce<Record<string, CustomFieldValue[]>>((acc, v) => {\n const { modelId } = v;\n acc[modelId] ??= [];\n acc[modelId].push(v);\n return acc;\n }, {});\n};\n\n/**\n * Serialize custom fields value into the format of {[name] -> [fieldData]}\n */\nconst serializeCustomFields = (\n customFieldValues: CustomFieldValue[],\n customFieldDefinitionsHash: Record<string, CustomFieldDefinition>,\n): SerializedCustomFields => {\n const customFields = customFieldValues.reduce((acc, cfv) => ({\n ...acc,\n ...(\n customFieldDefinitionsHash[cfv.customFieldDefinitionId]\n && { [customFieldDefinitionsHash[cfv.customFieldDefinitionId].name]: cfv.value }\n ),\n }), {});\n return customFields;\n};\n/**\n * A hook to attach the custom fields when fetching a model instances.\n */\nconst enrichResults = (\n modelType: string,\n scopeAttributes: string[],\n hookType?: SupportedHookTypes,\n modelOptions: ModelOptions = {},\n sadotOptions: Pick<CustomFieldOptions, 'useCustomFieldsEntries' | 'hasTypeId' | 'matPathManager' | 'isMatPathActive'> = { useCustomFieldsEntries: false, hasTypeId: false },\n) => async (\n instancesOrInstance: any | any[],\n options: TransactionOptions,\n): Promise<void> => {\n if (options.originalAttributes?.length > 0 && !options.originalAttributes?.includes?.('customFields')) {\n return;\n }\n\n const primaryKey = 'id';\n let instances = Array.isArray(instancesOrInstance)\n ? instancesOrInstance\n : [instancesOrInstance];\n\n instances = instances.filter(Boolean);\n\n const identifiers = applyScopeToInstance(instances, scopeAttributes);\n\n const uniqueIdentifiers = [...new Set(identifiers)].filter(Boolean);\n\n const identifierCustomFieldDefinitionsMapping = uniqueIdentifiers.reduce((map, identifier) => ({\n ...map,\n [identifier]: [],\n }), {});\n\n // Cache for definitions by model type and transaction to avoid redundant DB queries\n let customFieldDefinitionsPromise;\n let cacheKey: string | undefined;\n\n if (options.transaction) {\n // Initialize definition cache Map if not already present directly on the transaction object\n options.transaction.definitionCache ??= new Map();\n cacheKey = `${modelType}:${uniqueIdentifiers.slice().sort().join(',')}`;\n customFieldDefinitionsPromise = options.transaction.definitionCache.get(cacheKey);\n }\n\n let modelTypeDefinitionsMap: Map<string, Set<string>> | undefined;\n\n // Fetch from database (either first time in this transaction or no transaction).\n // When mat-path is active, run inside withPaths(ANCESTORS) so RLS on joined tables\n // (e.g. Context) filters CFDs to those visible at the caller's path + its ancestors.\n if (!customFieldDefinitionsPromise) {\n const shouldApplyTypeFiltering = sadotOptions.hasTypeId && instances.length > 0 && instances[0].typeId;\n\n const fetchDefinitions = async (transaction = options.transaction) => {\n if (shouldApplyTypeFiltering) {\n const uniqueTypeIds = [...new Set(instances.map(instance => instance.typeId).filter(Boolean))];\n\n modelTypeDefinitionsMap = new Map<string, Set<string>>();\n uniqueTypeIds.forEach(typeId => modelTypeDefinitionsMap!.set(typeId, new Set()));\n\n const definitionsResults = await Promise.all(\n uniqueTypeIds.map(async (typeId) => {\n const defs = await DefinitionRepo.findByModelTypeId(typeId, { withDisabled: false, entityIds: uniqueIdentifiers, modelType, modelOptions, transaction });\n defs.forEach(def => modelTypeDefinitionsMap!.get(typeId)!.add(def.id));\n return defs;\n }),\n );\n\n const allDefinitions = definitionsResults.flat();\n const uniqueDefinitionsMap = new Map();\n allDefinitions.forEach((def) => {\n uniqueDefinitionsMap.set(def.id, def);\n });\n return Array.from(uniqueDefinitionsMap.values());\n }\n return DefinitionRepo.findByEntityIds(\n modelType,\n uniqueIdentifiers,\n { transaction, modelOptions, attributes: CUSTOM_FIELD_DEFINITION_ATTRIBUTES_TO_PULL },\n );\n };\n\n customFieldDefinitionsPromise = sadotOptions.matPathManager && sadotOptions.isMatPathActive?.()\n ? sadotOptions.matPathManager.withPaths(\n transaction => fetchDefinitions(transaction),\n { transaction: options.transaction },\n )\n : fetchDefinitions();\n\n if (!shouldApplyTypeFiltering) {\n options.transaction?.definitionCache?.set(cacheKey!, customFieldDefinitionsPromise);\n }\n }\n const customFieldDefinitions = await customFieldDefinitionsPromise;\n\n if (customFieldDefinitions.length === 0) {\n // if no custom fields, we can return\n instances.forEach((instance) => {\n instance.customFields = {};\n });\n return;\n }\n\n if (modelOptions?.include && modelOptions.useEntityIdFromInclude) {\n // if we pass useEntityIdFromInclude,\n // map the entity from the options to the identifierCustomFieldDefinitionsMapping\n modelOptions.include(identifiers).forEach(({ model }) => {\n customFieldDefinitions.forEach((cfd: any) => {\n // try 2 ways to get the entityId from the joined model - for raw and non-raw\n const entityId = cfd[model!.name]?.entityId || cfd[`${model!.name}.entityId` as keyof CustomFieldDefinition];\n if (entityId && !identifierCustomFieldDefinitionsMapping[entityId]) {\n identifierCustomFieldDefinitionsMapping[entityId] = [];\n }\n });\n });\n }\n\n const definitionsMap = customFieldDefinitions.reduce((map, definition) => ({\n ...map,\n [definition.id]: definition,\n }), {});\n\n customFieldDefinitions.forEach((cfd: any) => {\n let entityIdToUse = cfd.entityId;\n\n if (modelOptions?.useEntityIdFromInclude && modelOptions.include) {\n const contextIncludes = modelOptions.include(identifiers);\n for (const { model } of contextIncludes) {\n const joinedEntityId = cfd[model!.name]?.entityId || cfd[`${model!.name}.entityId` as keyof CustomFieldDefinition];\n if (joinedEntityId) {\n entityIdToUse = joinedEntityId;\n break;\n }\n }\n }\n\n if (identifierCustomFieldDefinitionsMapping[entityIdToUse]) {\n identifierCustomFieldDefinitionsMapping[entityIdToUse].push(cfd);\n }\n });\n\n // Get the values per instates ids:\n const instancesIds = instances.map(i => i[primaryKey]);\n\n // Group fields by modelId\n const [valuesGroupByInstance, customFieldEntriesByInstanceId] = await Promise.all([\n getValuesGroupByInstance({\n instancesIds,\n options,\n sadotOptions,\n }),\n getCustomFieldEntriesByInstanceId({\n instancesIds,\n options,\n sadotOptions,\n }),\n ]);\n\n // Attach custom fields to the instances\n instances.forEach((instance) => {\n const { id } = instance;\n\n const instanceValues = valuesGroupByInstance[id];\n const serializedCustomFieldsValues = instanceValues ? serializeCustomFields(instanceValues, definitionsMap) : {};\n\n const customFields = sadotOptions.useCustomFieldsEntries\n ? customFieldEntriesByInstanceId[id]\n : serializedCustomFieldsValues;\n\n scopeAttributes.forEach((attribute) => {\n const identifier = instance[attribute];\n\n const entityCustomFieldDefinitions = identifierCustomFieldDefinitionsMapping[identifier] as CustomFieldDefinition[] | undefined;\n if (entityCustomFieldDefinitions && entityCustomFieldDefinitions.length > 0) {\n entityCustomFieldDefinitions.forEach((customFieldDefinition) => {\n if (modelTypeDefinitionsMap) {\n const applicableDefinitionIds = modelTypeDefinitionsMap.get(instance.typeId);\n if (!applicableDefinitionIds?.has(customFieldDefinition.id)) {\n return;\n }\n }\n\n if (customFields[customFieldDefinition.name] === undefined) {\n customFields[customFieldDefinition.name] = null;\n }\n });\n }\n });\n instance.customFields = customFields;\n (options.attributesToRemove as string[] | undefined)?.forEach?.((attribute) => {\n delete instance.dataValues?.[attribute];\n // if raw:\n delete instance?.[attribute];\n });\n // sequelize will think customFields changed also in 'find', so we need to mark it as unchanged\n if (hookType === 'afterFind') {\n // changed() could be undefined, i.e in raw: true\n instance?.changed?.('customFields', false);\n }\n });\n};\n\nexport default enrichResults;\n"],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,`__esModule`,{value:!0});const e=require(`./utils/logger/index.cjs`),t=require(`./utils/constants/index.cjs`),n=require(`./models/CustomFieldValue.cjs`),r=require(`./models/CustomFieldDefinition.cjs`),i=require(`./models/CustomFieldEntries.cjs`),a=require(`./models/CustomValidator.cjs`),o=require(`./models/index.cjs`),s=require(`./api/index.cjs`),c=require(`./utils/db/index.cjs`),l=require(`./utils/helpers/index.cjs`),u=require(`./scopes/filter.cjs`),d=require(`./utils/init.cjs`),f=require(`./init-state.cjs`),p=require(`./utils/validations/schema/custom-fields.cjs`),m=new f.SadotInitializationState,h=async(t,n,r)=>{e.tryAddingTraceIdMiddleware();let{models:i,useCustomFieldsEntries:a,useModelTypeMapping:l}=r;t&&t.use(`/api`,s.default);let u=r.sequelize??c.default(r.databaseConfig);return process.env.NODE_ENV===`test`&&await o.initTestModels(u),d.addHooks(i,n,{useCustomFieldsEntries:a}),await o.initTables(u,r.getUser,{useCustomFieldsEntries:a,useModelTypeMapping:l}),d.addScopes(i,n,{useCustomFieldsEntries:a}),d.applyCustomAssociation(i),e.default.debug(`sadot - custom fields finished initializing with models`,i),u},g=async(e,t,n)=>{let r=h(e,t,n);return m.setInitPromise(r,!n.sequelize),await r};var _=g;const v=(e,t)=>{d.removeHooks(e,t)};exports.CUSTOM_FIELDS_FILTER_SCOPE=t.CUSTOM_FIELDS_FILTER_SCOPE,exports.CustomFieldDefinition=r.default,exports.CustomFieldDefinitionType=t.CustomFieldDefinitionType,exports.CustomFieldEntries=i.default,exports.CustomFieldValue=n.default,exports.CustomFieldsSchema=p.CustomFieldsSchema,exports.CustomValidator=a.default,exports.customFieldsSortScope=u.customFieldsSortScope,exports.default=_,exports.disableCustomFields=v,exports.generateCustomFieldSearchQueryPayload=l.generateCustomFieldSearchQueryPayload,exports.generateRandomString=l.generateRandomString,exports.sadotInitState=m,exports.supportedEntities=t.supportedEntities;
1
+ Object.defineProperty(exports,`__esModule`,{value:!0});const e=require(`./utils/logger/index.cjs`),t=require(`./utils/constants/index.cjs`),n=require(`./models/CustomFieldValue.cjs`),r=require(`./models/CustomFieldDefinition.cjs`),i=require(`./models/CustomFieldEntries.cjs`),a=require(`./models/CustomValidator.cjs`),o=require(`./models/index.cjs`),s=require(`./api/index.cjs`),c=require(`./utils/db/index.cjs`),l=require(`./utils/helpers/index.cjs`),u=require(`./scopes/filter.cjs`),d=require(`./utils/init.cjs`),f=require(`./init-state.cjs`),p=require(`./utils/validations/schema/custom-fields.cjs`),m=new f.SadotInitializationState,h=async(t,n,r)=>{e.tryAddingTraceIdMiddleware();let{models:i,useCustomFieldsEntries:a,useModelTypeMapping:l,matPathManager:u,isMatPathActive:f}=r;t&&t.use(`/api`,s.default);let p=r.sequelize??c.default(r.databaseConfig);return process.env.NODE_ENV===`test`&&await o.initTestModels(p),d.addHooks(i,n,{useCustomFieldsEntries:a,matPathManager:u,isMatPathActive:f}),await o.initTables(p,r.getUser,{useCustomFieldsEntries:a,useModelTypeMapping:l}),d.addScopes(i,n,{useCustomFieldsEntries:a}),d.applyCustomAssociation(i),e.default.debug(`sadot - custom fields finished initializing with models`,i),p},g=async(e,t,n)=>{let r=h(e,t,n);return m.setInitPromise(r,!n.sequelize),await r};var _=g;const v=(e,t)=>{d.removeHooks(e,t)};exports.CUSTOM_FIELDS_FILTER_SCOPE=t.CUSTOM_FIELDS_FILTER_SCOPE,exports.CustomFieldDefinition=r.default,exports.CustomFieldDefinitionType=t.CustomFieldDefinitionType,exports.CustomFieldEntries=i.default,exports.CustomFieldValue=n.default,exports.CustomFieldsSchema=p.CustomFieldsSchema,exports.CustomValidator=a.default,exports.customFieldsSortScope=u.customFieldsSortScope,exports.default=_,exports.disableCustomFields=v,exports.generateCustomFieldSearchQueryPayload=l.generateCustomFieldSearchQueryPayload,exports.generateRandomString=l.generateRandomString,exports.sadotInitState=m,exports.supportedEntities=t.supportedEntities;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["sadotInitState: SadotInitializationState","SadotInitializationState","api","initDB","initTestModels","initTables"],"sources":["../src/index.ts"],"sourcesContent":["import type { Application } from 'express';\nimport type { Sequelize } from 'sequelize-typescript';\nimport {\n initTables, initTestModels,\n} from './models';\nimport api from './api';\nimport initDB from './utils/db';\nimport logger, { tryAddingTraceIdMiddleware } from './utils/logger';\nimport type { CustomFieldOptions, ModelFetcher, Models } from './types';\nimport {\n addHooks, addScopes, applyCustomAssociation, removeHooks,\n} from './utils/init';\nimport { SadotInitializationState } from './init-state';\n\nexport * from './utils/validations/schema/custom-fields';\n\nexport * from './utils/constants';\n\nexport * from './utils/helpers';\n\nexport { customFieldsSortScope } from './scopes/filter';\nexport {\n CustomFieldDefinition,\n CustomFieldEntries,\n CustomFieldValue,\n CustomValidator,\n} from './models';\n\nexport const sadotInitState: SadotInitializationState = new SadotInitializationState();\n\n/**\n * Internal implementation of custom fields initialization\n * Contains all the business logic without state tracking\n */\nconst internalUseCustomFields = async (\n app: Pick<Application, 'use'> | null,\n getModel: ModelFetcher,\n options: CustomFieldOptions,\n): Promise<Sequelize> => {\n tryAddingTraceIdMiddleware();\n const { models, useCustomFieldsEntries, useModelTypeMapping } = options;\n if (app) {\n app.use('/api', api);\n }\n const sequelize = options.sequelize ?? initDB(options.databaseConfig);\n if (process.env.NODE_ENV === 'test') {\n await initTestModels(sequelize);\n }\n // The order is important\n addHooks(models, getModel, { useCustomFieldsEntries });\n await initTables(sequelize, options.getUser, { useCustomFieldsEntries, useModelTypeMapping });\n addScopes(models, getModel, { useCustomFieldsEntries });\n applyCustomAssociation(models);\n\n logger.debug('sadot - custom fields finished initializing with models', models);\n return sequelize;\n};\n\n/**\n * Adding custom fields enrichment to the models inside the MODELS_FILE_NAME json file\n * @see {@link 'custom-fields/config'} for configurations\n */\nconst useCustomFields = async (\n app: Pick<Application, 'use'> | null,\n getModel: ModelFetcher,\n options: CustomFieldOptions,\n): Promise<Sequelize> => {\n const initPromise = internalUseCustomFields(app, getModel, options);\n\n sadotInitState.setInitPromise(initPromise, !options.sequelize);\n\n return await initPromise;\n};\n\nexport default useCustomFields;\n\nexport const disableCustomFields = (models: Models[], getModel: ModelFetcher): void => {\n removeHooks(models, getModel);\n};\n"],"mappings":"2lBA4BaA,EAA2C,IAAIC,EAAAA,yBAMtD,EAA0B,MAC9B,EACA,EACA,IACuB,CACvB,EAAA,4BAA4B,CAC5B,GAAM,CAAE,SAAQ,yBAAwB,uBAAwB,EAC5D,GACF,EAAI,IAAI,OAAQC,EAAAA,QAAI,CAEtB,IAAM,EAAY,EAAQ,WAAaC,EAAAA,QAAO,EAAQ,eAAe,CAWrE,OAVI,QAAQ,IAAI,WAAa,QAC3B,MAAMC,EAAAA,eAAe,EAAU,CAGjC,EAAA,SAAS,EAAQ,EAAU,CAAE,yBAAwB,CAAC,CACtD,MAAMC,EAAAA,WAAW,EAAW,EAAQ,QAAS,CAAE,yBAAwB,sBAAqB,CAAC,CAC7F,EAAA,UAAU,EAAQ,EAAU,CAAE,yBAAwB,CAAC,CACvD,EAAA,uBAAuB,EAAO,CAE9B,EAAA,QAAO,MAAM,0DAA2D,EAAO,CACxE,GAOH,EAAkB,MACtB,EACA,EACA,IACuB,CACvB,IAAM,EAAc,EAAwB,EAAK,EAAU,EAAQ,CAInE,OAFA,EAAe,eAAe,EAAa,CAAC,EAAQ,UAAU,CAEvD,MAAM,GAGf,IAAA,EAAe,EAEf,MAAa,GAAuB,EAAkB,IAAiC,CACrF,EAAA,YAAY,EAAQ,EAAS"}
1
+ {"version":3,"file":"index.cjs","names":["sadotInitState: SadotInitializationState","SadotInitializationState","api","initDB","initTestModels","initTables"],"sources":["../src/index.ts"],"sourcesContent":["import type { Application } from 'express';\nimport type { Sequelize } from 'sequelize-typescript';\nimport {\n initTables, initTestModels,\n} from './models';\nimport api from './api';\nimport initDB from './utils/db';\nimport logger, { tryAddingTraceIdMiddleware } from './utils/logger';\nimport type { CustomFieldOptions, ModelFetcher, Models } from './types';\nimport {\n addHooks, addScopes, applyCustomAssociation, removeHooks,\n} from './utils/init';\nimport { SadotInitializationState } from './init-state';\n\nexport * from './utils/validations/schema/custom-fields';\n\nexport * from './utils/constants';\n\nexport * from './utils/helpers';\n\nexport { customFieldsSortScope } from './scopes/filter';\nexport {\n CustomFieldDefinition,\n CustomFieldEntries,\n CustomFieldValue,\n CustomValidator,\n} from './models';\n\nexport const sadotInitState: SadotInitializationState = new SadotInitializationState();\n\n/**\n * Internal implementation of custom fields initialization\n * Contains all the business logic without state tracking\n */\nconst internalUseCustomFields = async (\n app: Pick<Application, 'use'> | null,\n getModel: ModelFetcher,\n options: CustomFieldOptions,\n): Promise<Sequelize> => {\n tryAddingTraceIdMiddleware();\n const { models, useCustomFieldsEntries, useModelTypeMapping, matPathManager, isMatPathActive } = options;\n if (app) {\n app.use('/api', api);\n }\n const sequelize = options.sequelize ?? initDB(options.databaseConfig);\n if (process.env.NODE_ENV === 'test') {\n await initTestModels(sequelize);\n }\n // The order is important\n addHooks(models, getModel, { useCustomFieldsEntries, matPathManager, isMatPathActive });\n await initTables(sequelize, options.getUser, { useCustomFieldsEntries, useModelTypeMapping });\n addScopes(models, getModel, { useCustomFieldsEntries });\n applyCustomAssociation(models);\n\n logger.debug('sadot - custom fields finished initializing with models', models);\n return sequelize;\n};\n\n/**\n * Adding custom fields enrichment to the models inside the MODELS_FILE_NAME json file\n * @see {@link 'custom-fields/config'} for configurations\n */\nconst useCustomFields = async (\n app: Pick<Application, 'use'> | null,\n getModel: ModelFetcher,\n options: CustomFieldOptions,\n): Promise<Sequelize> => {\n const initPromise = internalUseCustomFields(app, getModel, options);\n\n sadotInitState.setInitPromise(initPromise, !options.sequelize);\n\n return await initPromise;\n};\n\nexport default useCustomFields;\n\nexport const disableCustomFields = (models: Models[], getModel: ModelFetcher): void => {\n removeHooks(models, getModel);\n};\n"],"mappings":"2lBA4BaA,EAA2C,IAAIC,EAAAA,yBAMtD,EAA0B,MAC9B,EACA,EACA,IACuB,CACvB,EAAA,4BAA4B,CAC5B,GAAM,CAAE,SAAQ,yBAAwB,sBAAqB,iBAAgB,mBAAoB,EAC7F,GACF,EAAI,IAAI,OAAQC,EAAAA,QAAI,CAEtB,IAAM,EAAY,EAAQ,WAAaC,EAAAA,QAAO,EAAQ,eAAe,CAWrE,OAVI,QAAQ,IAAI,WAAa,QAC3B,MAAMC,EAAAA,eAAe,EAAU,CAGjC,EAAA,SAAS,EAAQ,EAAU,CAAE,yBAAwB,iBAAgB,kBAAiB,CAAC,CACvF,MAAMC,EAAAA,WAAW,EAAW,EAAQ,QAAS,CAAE,yBAAwB,sBAAqB,CAAC,CAC7F,EAAA,UAAU,EAAQ,EAAU,CAAE,yBAAwB,CAAC,CACvD,EAAA,uBAAuB,EAAO,CAE9B,EAAA,QAAO,MAAM,0DAA2D,EAAO,CACxE,GAOH,EAAkB,MACtB,EACA,EACA,IACuB,CACvB,IAAM,EAAc,EAAwB,EAAK,EAAU,EAAQ,CAInE,OAFA,EAAe,eAAe,EAAa,CAAC,EAAQ,UAAU,CAEvD,MAAM,GAGf,IAAA,EAAe,EAEf,MAAa,GAAuB,EAAkB,IAAiC,CACrF,EAAA,YAAY,EAAQ,EAAS"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import e,{tryAddingTraceIdMiddleware as t}from"./utils/logger/index.js";import{CUSTOM_FIELDS_FILTER_SCOPE as n,CustomFieldDefinitionType as r,supportedEntities as i}from"./utils/constants/index.js";import a from"./models/CustomFieldValue.js";import o from"./models/CustomFieldDefinition.js";import s from"./models/CustomFieldEntries.js";import c from"./models/CustomValidator.js";import{initTables as l,initTestModels as u}from"./models/index.js";import d from"./api/index.js";import f from"./utils/db/index.js";import{generateCustomFieldSearchQueryPayload as p,generateRandomString as m}from"./utils/helpers/index.js";import{customFieldsSortScope as h}from"./scopes/filter.js";import{addHooks as g,addScopes as _,applyCustomAssociation as v,removeHooks as y}from"./utils/init.js";import{SadotInitializationState as b}from"./init-state.js";import{CustomFieldsSchema as x}from"./utils/validations/schema/custom-fields.js";const S=new b,C=async(n,r,i)=>{t();let{models:a,useCustomFieldsEntries:o,useModelTypeMapping:s}=i;n&&n.use(`/api`,d);let c=i.sequelize??f(i.databaseConfig);return process.env.NODE_ENV===`test`&&await u(c),g(a,r,{useCustomFieldsEntries:o}),await l(c,i.getUser,{useCustomFieldsEntries:o,useModelTypeMapping:s}),_(a,r,{useCustomFieldsEntries:o}),v(a),e.debug(`sadot - custom fields finished initializing with models`,a),c};var w=async(e,t,n)=>{let r=C(e,t,n);return S.setInitPromise(r,!n.sequelize),await r};const T=(e,t)=>{y(e,t)};export{n as CUSTOM_FIELDS_FILTER_SCOPE,o as CustomFieldDefinition,r as CustomFieldDefinitionType,s as CustomFieldEntries,a as CustomFieldValue,x as CustomFieldsSchema,c as CustomValidator,h as customFieldsSortScope,w as default,T as disableCustomFields,p as generateCustomFieldSearchQueryPayload,m as generateRandomString,S as sadotInitState,i as supportedEntities};
1
+ import e,{tryAddingTraceIdMiddleware as t}from"./utils/logger/index.js";import{CUSTOM_FIELDS_FILTER_SCOPE as n,CustomFieldDefinitionType as r,supportedEntities as i}from"./utils/constants/index.js";import a from"./models/CustomFieldValue.js";import o from"./models/CustomFieldDefinition.js";import s from"./models/CustomFieldEntries.js";import c from"./models/CustomValidator.js";import{initTables as l,initTestModels as u}from"./models/index.js";import d from"./api/index.js";import f from"./utils/db/index.js";import{generateCustomFieldSearchQueryPayload as p,generateRandomString as m}from"./utils/helpers/index.js";import{customFieldsSortScope as h}from"./scopes/filter.js";import{addHooks as g,addScopes as _,applyCustomAssociation as v,removeHooks as y}from"./utils/init.js";import{SadotInitializationState as b}from"./init-state.js";import{CustomFieldsSchema as x}from"./utils/validations/schema/custom-fields.js";const S=new b,C=async(n,r,i)=>{t();let{models:a,useCustomFieldsEntries:o,useModelTypeMapping:s,matPathManager:c,isMatPathActive:p}=i;n&&n.use(`/api`,d);let m=i.sequelize??f(i.databaseConfig);return process.env.NODE_ENV===`test`&&await u(m),g(a,r,{useCustomFieldsEntries:o,matPathManager:c,isMatPathActive:p}),await l(m,i.getUser,{useCustomFieldsEntries:o,useModelTypeMapping:s}),_(a,r,{useCustomFieldsEntries:o}),v(a),e.debug(`sadot - custom fields finished initializing with models`,a),m};var w=async(e,t,n)=>{let r=C(e,t,n);return S.setInitPromise(r,!n.sequelize),await r};const T=(e,t)=>{y(e,t)};export{n as CUSTOM_FIELDS_FILTER_SCOPE,o as CustomFieldDefinition,r as CustomFieldDefinitionType,s as CustomFieldEntries,a as CustomFieldValue,x as CustomFieldsSchema,c as CustomValidator,h as customFieldsSortScope,w as default,T as disableCustomFields,p as generateCustomFieldSearchQueryPayload,m as generateRandomString,S as sadotInitState,i as supportedEntities};
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["sadotInitState: SadotInitializationState","api","initDB"],"sources":["../src/index.ts"],"sourcesContent":["import type { Application } from 'express';\nimport type { Sequelize } from 'sequelize-typescript';\nimport {\n initTables, initTestModels,\n} from './models';\nimport api from './api';\nimport initDB from './utils/db';\nimport logger, { tryAddingTraceIdMiddleware } from './utils/logger';\nimport type { CustomFieldOptions, ModelFetcher, Models } from './types';\nimport {\n addHooks, addScopes, applyCustomAssociation, removeHooks,\n} from './utils/init';\nimport { SadotInitializationState } from './init-state';\n\nexport * from './utils/validations/schema/custom-fields';\n\nexport * from './utils/constants';\n\nexport * from './utils/helpers';\n\nexport { customFieldsSortScope } from './scopes/filter';\nexport {\n CustomFieldDefinition,\n CustomFieldEntries,\n CustomFieldValue,\n CustomValidator,\n} from './models';\n\nexport const sadotInitState: SadotInitializationState = new SadotInitializationState();\n\n/**\n * Internal implementation of custom fields initialization\n * Contains all the business logic without state tracking\n */\nconst internalUseCustomFields = async (\n app: Pick<Application, 'use'> | null,\n getModel: ModelFetcher,\n options: CustomFieldOptions,\n): Promise<Sequelize> => {\n tryAddingTraceIdMiddleware();\n const { models, useCustomFieldsEntries, useModelTypeMapping } = options;\n if (app) {\n app.use('/api', api);\n }\n const sequelize = options.sequelize ?? initDB(options.databaseConfig);\n if (process.env.NODE_ENV === 'test') {\n await initTestModels(sequelize);\n }\n // The order is important\n addHooks(models, getModel, { useCustomFieldsEntries });\n await initTables(sequelize, options.getUser, { useCustomFieldsEntries, useModelTypeMapping });\n addScopes(models, getModel, { useCustomFieldsEntries });\n applyCustomAssociation(models);\n\n logger.debug('sadot - custom fields finished initializing with models', models);\n return sequelize;\n};\n\n/**\n * Adding custom fields enrichment to the models inside the MODELS_FILE_NAME json file\n * @see {@link 'custom-fields/config'} for configurations\n */\nconst useCustomFields = async (\n app: Pick<Application, 'use'> | null,\n getModel: ModelFetcher,\n options: CustomFieldOptions,\n): Promise<Sequelize> => {\n const initPromise = internalUseCustomFields(app, getModel, options);\n\n sadotInitState.setInitPromise(initPromise, !options.sequelize);\n\n return await initPromise;\n};\n\nexport default useCustomFields;\n\nexport const disableCustomFields = (models: Models[], getModel: ModelFetcher): void => {\n removeHooks(models, getModel);\n};\n"],"mappings":"y5BA4BA,MAAaA,EAA2C,IAAI,EAMtD,EAA0B,MAC9B,EACA,EACA,IACuB,CACvB,GAA4B,CAC5B,GAAM,CAAE,SAAQ,yBAAwB,uBAAwB,EAC5D,GACF,EAAI,IAAI,OAAQC,EAAI,CAEtB,IAAM,EAAY,EAAQ,WAAaC,EAAO,EAAQ,eAAe,CAWrE,OAVI,QAAQ,IAAI,WAAa,QAC3B,MAAM,EAAe,EAAU,CAGjC,EAAS,EAAQ,EAAU,CAAE,yBAAwB,CAAC,CACtD,MAAM,EAAW,EAAW,EAAQ,QAAS,CAAE,yBAAwB,sBAAqB,CAAC,CAC7F,EAAU,EAAQ,EAAU,CAAE,yBAAwB,CAAC,CACvD,EAAuB,EAAO,CAE9B,EAAO,MAAM,0DAA2D,EAAO,CACxE,GAmBT,IAAA,EAZwB,MACtB,EACA,EACA,IACuB,CACvB,IAAM,EAAc,EAAwB,EAAK,EAAU,EAAQ,CAInE,OAFA,EAAe,eAAe,EAAa,CAAC,EAAQ,UAAU,CAEvD,MAAM,GAKf,MAAa,GAAuB,EAAkB,IAAiC,CACrF,EAAY,EAAQ,EAAS"}
1
+ {"version":3,"file":"index.js","names":["sadotInitState: SadotInitializationState","api","initDB"],"sources":["../src/index.ts"],"sourcesContent":["import type { Application } from 'express';\nimport type { Sequelize } from 'sequelize-typescript';\nimport {\n initTables, initTestModels,\n} from './models';\nimport api from './api';\nimport initDB from './utils/db';\nimport logger, { tryAddingTraceIdMiddleware } from './utils/logger';\nimport type { CustomFieldOptions, ModelFetcher, Models } from './types';\nimport {\n addHooks, addScopes, applyCustomAssociation, removeHooks,\n} from './utils/init';\nimport { SadotInitializationState } from './init-state';\n\nexport * from './utils/validations/schema/custom-fields';\n\nexport * from './utils/constants';\n\nexport * from './utils/helpers';\n\nexport { customFieldsSortScope } from './scopes/filter';\nexport {\n CustomFieldDefinition,\n CustomFieldEntries,\n CustomFieldValue,\n CustomValidator,\n} from './models';\n\nexport const sadotInitState: SadotInitializationState = new SadotInitializationState();\n\n/**\n * Internal implementation of custom fields initialization\n * Contains all the business logic without state tracking\n */\nconst internalUseCustomFields = async (\n app: Pick<Application, 'use'> | null,\n getModel: ModelFetcher,\n options: CustomFieldOptions,\n): Promise<Sequelize> => {\n tryAddingTraceIdMiddleware();\n const { models, useCustomFieldsEntries, useModelTypeMapping, matPathManager, isMatPathActive } = options;\n if (app) {\n app.use('/api', api);\n }\n const sequelize = options.sequelize ?? initDB(options.databaseConfig);\n if (process.env.NODE_ENV === 'test') {\n await initTestModels(sequelize);\n }\n // The order is important\n addHooks(models, getModel, { useCustomFieldsEntries, matPathManager, isMatPathActive });\n await initTables(sequelize, options.getUser, { useCustomFieldsEntries, useModelTypeMapping });\n addScopes(models, getModel, { useCustomFieldsEntries });\n applyCustomAssociation(models);\n\n logger.debug('sadot - custom fields finished initializing with models', models);\n return sequelize;\n};\n\n/**\n * Adding custom fields enrichment to the models inside the MODELS_FILE_NAME json file\n * @see {@link 'custom-fields/config'} for configurations\n */\nconst useCustomFields = async (\n app: Pick<Application, 'use'> | null,\n getModel: ModelFetcher,\n options: CustomFieldOptions,\n): Promise<Sequelize> => {\n const initPromise = internalUseCustomFields(app, getModel, options);\n\n sadotInitState.setInitPromise(initPromise, !options.sequelize);\n\n return await initPromise;\n};\n\nexport default useCustomFields;\n\nexport const disableCustomFields = (models: Models[], getModel: ModelFetcher): void => {\n removeHooks(models, getModel);\n};\n"],"mappings":"y5BA4BA,MAAaA,EAA2C,IAAI,EAMtD,EAA0B,MAC9B,EACA,EACA,IACuB,CACvB,GAA4B,CAC5B,GAAM,CAAE,SAAQ,yBAAwB,sBAAqB,iBAAgB,mBAAoB,EAC7F,GACF,EAAI,IAAI,OAAQC,EAAI,CAEtB,IAAM,EAAY,EAAQ,WAAaC,EAAO,EAAQ,eAAe,CAWrE,OAVI,QAAQ,IAAI,WAAa,QAC3B,MAAM,EAAe,EAAU,CAGjC,EAAS,EAAQ,EAAU,CAAE,yBAAwB,iBAAgB,kBAAiB,CAAC,CACvF,MAAM,EAAW,EAAW,EAAQ,QAAS,CAAE,yBAAwB,sBAAqB,CAAC,CAC7F,EAAU,EAAQ,EAAU,CAAE,yBAAwB,CAAC,CACvD,EAAuB,EAAO,CAE9B,EAAO,MAAM,0DAA2D,EAAO,CACxE,GAmBT,IAAA,EAZwB,MACtB,EACA,EACA,IACuB,CACvB,IAAM,EAAc,EAAwB,EAAK,EAAU,EAAQ,CAInE,OAFA,EAAe,eAAe,EAAa,CAAC,EAAQ,UAAU,CAEvD,MAAM,GAKf,MAAa,GAAuB,EAAkB,IAAiC,CACrF,EAAY,EAAQ,EAAS"}
@@ -1,6 +1,6 @@
1
1
  import { CustomFieldDefinition } from "../models/CustomFieldDefinition.cjs";
2
2
  import { ModelCtor, Sequelize } from "sequelize-typescript";
3
- import { IncludeOptions } from "sequelize";
3
+ import { IncludeOptions, Transaction } from "sequelize";
4
4
  import { getUser } from "@autofleet/zehut";
5
5
 
6
6
  //#region src/types/index.d.ts
@@ -42,6 +42,18 @@ interface Models {
42
42
  updateWebhookHandler?: (instance: any) => any;
43
43
  deletionWebhookHandler?: (instance: any) => any;
44
44
  }
45
+ /**
46
+ * Minimal structural type for an `@autofleet/mat-path` MatPathManager.
47
+ * Defined here to avoid taking a runtime dependency on mat-path.
48
+ *
49
+ * The scoping mode (ancestors/descendants/etc.) is configured by the consumer at
50
+ * app level via `matPathManager.setScopingMode({ <table>: <mode> })`, not per call.
51
+ */
52
+ interface MatPathLike {
53
+ withPaths<T>(callback: (transaction?: Transaction) => Promise<T>, options?: {
54
+ transaction?: Transaction;
55
+ }): Promise<T>;
56
+ }
45
57
  interface CustomFieldOptions {
46
58
  models: Models[];
47
59
  hasTypeId?: boolean;
@@ -52,6 +64,18 @@ interface CustomFieldOptions {
52
64
  useValidators?: boolean;
53
65
  useModelTypeMapping?: boolean;
54
66
  getRequiredCustomFields?: (instance: any, fieldDefinitions: CustomFieldDefinition[], options: any) => Promise<string[]> | string[];
67
+ /**
68
+ * Optional mat-path manager used to wrap CustomFieldDefinition queries in `withPaths(ANCESTORS)`,
69
+ * so RLS on joined tables (e.g. Context) filters CFDs to those visible at the caller's path
70
+ * + its ancestors.
71
+ */
72
+ matPathManager?: MatPathLike;
73
+ /**
74
+ * Optional predicate that returns true when mat-path RLS is currently active for this request
75
+ * (typically: enabled AND the request carries context paths). When it returns true, sadot's
76
+ * `userScope` becomes a no-op so RLS is the sole filter.
77
+ */
78
+ isMatPathActive?: () => boolean;
55
79
  }
56
80
  //#endregion
57
81
  export { CustomFieldOptions, ModelFetcher, Models };
@@ -1,6 +1,6 @@
1
1
  import { CustomFieldDefinition } from "../models/CustomFieldDefinition.js";
2
2
  import "../models/CustomValidator.js";
3
- import { IncludeOptions } from "sequelize";
3
+ import { IncludeOptions, Transaction } from "sequelize";
4
4
  import { getUser } from "@autofleet/zehut";
5
5
  import { ModelCtor, Sequelize } from "sequelize-typescript";
6
6
 
@@ -43,6 +43,18 @@ interface Models {
43
43
  updateWebhookHandler?: (instance: any) => any;
44
44
  deletionWebhookHandler?: (instance: any) => any;
45
45
  }
46
+ /**
47
+ * Minimal structural type for an `@autofleet/mat-path` MatPathManager.
48
+ * Defined here to avoid taking a runtime dependency on mat-path.
49
+ *
50
+ * The scoping mode (ancestors/descendants/etc.) is configured by the consumer at
51
+ * app level via `matPathManager.setScopingMode({ <table>: <mode> })`, not per call.
52
+ */
53
+ interface MatPathLike {
54
+ withPaths<T>(callback: (transaction?: Transaction) => Promise<T>, options?: {
55
+ transaction?: Transaction;
56
+ }): Promise<T>;
57
+ }
46
58
  interface CustomFieldOptions {
47
59
  models: Models[];
48
60
  hasTypeId?: boolean;
@@ -53,6 +65,18 @@ interface CustomFieldOptions {
53
65
  useValidators?: boolean;
54
66
  useModelTypeMapping?: boolean;
55
67
  getRequiredCustomFields?: (instance: any, fieldDefinitions: CustomFieldDefinition[], options: any) => Promise<string[]> | string[];
68
+ /**
69
+ * Optional mat-path manager used to wrap CustomFieldDefinition queries in `withPaths(ANCESTORS)`,
70
+ * so RLS on joined tables (e.g. Context) filters CFDs to those visible at the caller's path
71
+ * + its ancestors.
72
+ */
73
+ matPathManager?: MatPathLike;
74
+ /**
75
+ * Optional predicate that returns true when mat-path RLS is currently active for this request
76
+ * (typically: enabled AND the request carries context paths). When it returns true, sadot's
77
+ * `userScope` becomes a no-op so RLS is the sole filter.
78
+ */
79
+ isMatPathActive?: () => boolean;
56
80
  }
57
81
  //#endregion
58
82
  export { CustomFieldOptions, ModelFetcher, Models };
@@ -1 +1 @@
1
- {"version":3,"file":"init.cjs","names":["customFields","DataTypes","beforeFind","beforeBulkCreate","beforeBulkUpdate","beforeCreate","beforeUpdate","enrichResults","CustomFieldValue","customFieldsFilterScope","CUSTOM_FIELDS_SORT_SCOPE","customFieldsSortScope","CustomFieldDefinition","CustomValidator"],"sources":["../../src/utils/init.ts"],"sourcesContent":["import { DataTypes } from 'sequelize';\nimport type { ModelCtor } from 'sequelize-typescript';\nimport { customFields } from '@autofleet/common-types';\nimport { CUSTOM_FIELDS_SORT_SCOPE } from '@autofleet/common-types/lib/custom-fields';\nimport {\n CustomFieldDefinition,\n CustomFieldValue,\n CustomValidator,\n} from '../models';\nimport {\n beforeFind,\n enrichResults,\n beforeBulkUpdate,\n beforeUpdate,\n beforeCreate,\n beforeBulkCreate,\n} from '../hooks';\nimport { customFieldsFilterScope } from '../scopes';\nimport logger from './logger';\nimport type { CustomFieldOptions, ModelFetcher, Models } from '../types';\nimport { customFieldsSortScope } from '../scopes/filter';\n\nconst { CUSTOM_FIELDS_FILTER_SCOPE } = customFields;\n\nexport const addHooks = (\n models: Models[],\n getModel: ModelFetcher,\n sadotOptions: { useCustomFieldsEntries?: boolean; } = { useCustomFieldsEntries: false },\n): void => {\n models.forEach(async ({\n name, scopeAttributes, modelOptions, hasTypeId, getRequiredCustomFields,\n }) => {\n try {\n const model = getModel(name);\n if (!model) {\n logger.warn('sadot - tried to addHooks to a model that does not exist yet', {\n name,\n scopeAttributes,\n });\n return;\n }\n model.rawAttributes.customFields = {\n type: DataTypes.VIRTUAL,\n };\n model.refreshAttributes();\n\n const enrichOptions = {\n ...sadotOptions,\n hasTypeId: hasTypeId ?? false,\n getRequiredCustomFields,\n };\n\n // TODO: Uncomment after tests are passed\n // model.addHook('afterFind', workaround);\n model.addHook('beforeFind', 'sadot-beforeFind', beforeFind(scopeAttributes));\n model.addHook('beforeBulkCreate', 'sadot-beforeBulkCreate', beforeBulkCreate);\n model.addHook('beforeBulkUpdate', 'sadot-beforeBulkUpdate', beforeBulkUpdate);\n model.addHook('beforeCreate', 'sadot-beforeCreate', beforeCreate(scopeAttributes, modelOptions, enrichOptions));\n model.addHook('beforeUpdate', 'sadot-beforeUpdate', beforeUpdate(scopeAttributes, modelOptions, enrichOptions));\n model.addHook('afterFind', 'sadot-afterFind', enrichResults(name, scopeAttributes, 'afterFind', modelOptions, enrichOptions));\n model.addHook('afterUpdate', 'sadot-afterUpdate', enrichResults(name, scopeAttributes, undefined, modelOptions, enrichOptions));\n model.addHook('afterCreate', 'sadot-afterCreate', enrichResults(name, scopeAttributes, undefined, modelOptions, enrichOptions));\n } catch (e) {\n logger.error(`Could not add custom fields hook to model ${name}. `, e);\n }\n });\n};\n\nexport const removeHooks = (models: Models[], getModel: ModelFetcher): void => {\n models.forEach(async ({ name }) => {\n try {\n const model = getModel(name);\n if (!model) return;\n if (model.rawAttributes.customFields) {\n delete model.rawAttributes.customFields;\n model.refreshAttributes();\n }\n // model.removeHook('afterFind', 'sadot-workaround');\n model.removeHook('beforeFind', 'sadot-beforeFind');\n model.removeHook('beforeBulkCreate', 'sadot-beforeBulkCreate');\n model.removeHook('beforeBulkUpdate', 'sadot-beforeBulkUpdate');\n model.removeHook('beforeCreate', 'sadot-beforeCreate');\n model.removeHook('beforeUpdate', 'sadot-beforeUpdate');\n model.removeHook('afterFind', 'sadot-afterFind');\n model.removeHook('afterUpdate', 'sadot-afterUpdate');\n } catch (e) {\n logger.error(`Could not add custom fields hook to model ${name}. `, e);\n }\n });\n};\n\n/**\n * Necessary associations for the {@link customFieldsFilterScope} scope\n */\nconst addAssociations = (model: ModelCtor, modelName: string, options: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>): void => {\n if (options?.useCustomFieldsEntries) return;\n model.hasMany(CustomFieldValue, { foreignKey: 'modelId', as: 'customFieldValue' });\n // TBC: maybe can be removed\n CustomFieldValue.belongsTo(model, { foreignKey: 'modelId', as: modelName });\n};\n\nexport const addScopes = (models: Models[], getModel: ModelFetcher, options: Pick<CustomFieldOptions, 'useCustomFieldsEntries'> = { useCustomFieldsEntries: false }): void => {\n models.forEach(async ({ name, scopeAttributes }) => {\n try {\n const model = getModel(name);\n if (!model) {\n logger.warn('sadot - tried to addScopes to a model that does not exist yet', {\n name,\n scopeAttributes,\n });\n return;\n }\n // Necessary associations for the filtering scope\n addAssociations(model, name, options);\n // Add filter scope\n model.addScope(CUSTOM_FIELDS_FILTER_SCOPE, customFieldsFilterScope(name, options));\n model.addScope(CUSTOM_FIELDS_SORT_SCOPE, customFieldsSortScope(name, options));\n } catch (e) {\n logger.error(`Could not add custom fields scopes to model ${name}. `, e);\n }\n });\n};\n\nexport const applyCustomAssociation = (models: Models[]): void => {\n models.forEach(({ modelOptions }) => {\n modelOptions?.customAssociation?.(CustomFieldDefinition);\n modelOptions?.customAssociation?.(CustomValidator);\n });\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"init.cjs","names":["customFields","DataTypes","beforeFind","beforeBulkCreate","beforeBulkUpdate","beforeCreate","beforeUpdate","enrichResults","CustomFieldValue","customFieldsFilterScope","CUSTOM_FIELDS_SORT_SCOPE","customFieldsSortScope","CustomFieldDefinition","CustomValidator"],"sources":["../../src/utils/init.ts"],"sourcesContent":["import { DataTypes } from 'sequelize';\nimport type { ModelCtor } from 'sequelize-typescript';\nimport { customFields } from '@autofleet/common-types';\nimport { CUSTOM_FIELDS_SORT_SCOPE } from '@autofleet/common-types/lib/custom-fields';\nimport {\n CustomFieldDefinition,\n CustomFieldValue,\n CustomValidator,\n} from '../models';\nimport {\n beforeFind,\n enrichResults,\n beforeBulkUpdate,\n beforeUpdate,\n beforeCreate,\n beforeBulkCreate,\n} from '../hooks';\nimport { customFieldsFilterScope } from '../scopes';\nimport logger from './logger';\nimport type { CustomFieldOptions, ModelFetcher, Models } from '../types';\nimport { customFieldsSortScope } from '../scopes/filter';\n\nconst { CUSTOM_FIELDS_FILTER_SCOPE } = customFields;\n\ntype AddHooksOptions = {\n useCustomFieldsEntries?: boolean;\n matPathManager?: CustomFieldOptions['matPathManager'];\n isMatPathActive?: CustomFieldOptions['isMatPathActive'];\n};\n\nexport const addHooks = (\n models: Models[],\n getModel: ModelFetcher,\n sadotOptions: AddHooksOptions = { useCustomFieldsEntries: false },\n): void => {\n models.forEach(async ({\n name, scopeAttributes, modelOptions, hasTypeId, getRequiredCustomFields,\n }) => {\n try {\n const model = getModel(name);\n if (!model) {\n logger.warn('sadot - tried to addHooks to a model that does not exist yet', {\n name,\n scopeAttributes,\n });\n return;\n }\n model.rawAttributes.customFields = {\n type: DataTypes.VIRTUAL,\n };\n model.refreshAttributes();\n\n const enrichOptions = {\n ...sadotOptions,\n hasTypeId: hasTypeId ?? false,\n getRequiredCustomFields,\n };\n\n // TODO: Uncomment after tests are passed\n // model.addHook('afterFind', workaround);\n model.addHook('beforeFind', 'sadot-beforeFind', beforeFind(scopeAttributes));\n model.addHook('beforeBulkCreate', 'sadot-beforeBulkCreate', beforeBulkCreate);\n model.addHook('beforeBulkUpdate', 'sadot-beforeBulkUpdate', beforeBulkUpdate);\n model.addHook('beforeCreate', 'sadot-beforeCreate', beforeCreate(scopeAttributes, modelOptions, enrichOptions));\n model.addHook('beforeUpdate', 'sadot-beforeUpdate', beforeUpdate(scopeAttributes, modelOptions, enrichOptions));\n model.addHook('afterFind', 'sadot-afterFind', enrichResults(name, scopeAttributes, 'afterFind', modelOptions, enrichOptions));\n model.addHook('afterUpdate', 'sadot-afterUpdate', enrichResults(name, scopeAttributes, undefined, modelOptions, enrichOptions));\n model.addHook('afterCreate', 'sadot-afterCreate', enrichResults(name, scopeAttributes, undefined, modelOptions, enrichOptions));\n } catch (e) {\n logger.error(`Could not add custom fields hook to model ${name}. `, e);\n }\n });\n};\n\nexport const removeHooks = (models: Models[], getModel: ModelFetcher): void => {\n models.forEach(async ({ name }) => {\n try {\n const model = getModel(name);\n if (!model) return;\n if (model.rawAttributes.customFields) {\n delete model.rawAttributes.customFields;\n model.refreshAttributes();\n }\n // model.removeHook('afterFind', 'sadot-workaround');\n model.removeHook('beforeFind', 'sadot-beforeFind');\n model.removeHook('beforeBulkCreate', 'sadot-beforeBulkCreate');\n model.removeHook('beforeBulkUpdate', 'sadot-beforeBulkUpdate');\n model.removeHook('beforeCreate', 'sadot-beforeCreate');\n model.removeHook('beforeUpdate', 'sadot-beforeUpdate');\n model.removeHook('afterFind', 'sadot-afterFind');\n model.removeHook('afterUpdate', 'sadot-afterUpdate');\n } catch (e) {\n logger.error(`Could not add custom fields hook to model ${name}. `, e);\n }\n });\n};\n\n/**\n * Necessary associations for the {@link customFieldsFilterScope} scope\n */\nconst addAssociations = (model: ModelCtor, modelName: string, options: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>): void => {\n if (options?.useCustomFieldsEntries) return;\n model.hasMany(CustomFieldValue, { foreignKey: 'modelId', as: 'customFieldValue' });\n // TBC: maybe can be removed\n CustomFieldValue.belongsTo(model, { foreignKey: 'modelId', as: modelName });\n};\n\nexport const addScopes = (models: Models[], getModel: ModelFetcher, options: Pick<CustomFieldOptions, 'useCustomFieldsEntries'> = { useCustomFieldsEntries: false }): void => {\n models.forEach(async ({ name, scopeAttributes }) => {\n try {\n const model = getModel(name);\n if (!model) {\n logger.warn('sadot - tried to addScopes to a model that does not exist yet', {\n name,\n scopeAttributes,\n });\n return;\n }\n // Necessary associations for the filtering scope\n addAssociations(model, name, options);\n // Add filter scope\n model.addScope(CUSTOM_FIELDS_FILTER_SCOPE, customFieldsFilterScope(name, options));\n model.addScope(CUSTOM_FIELDS_SORT_SCOPE, customFieldsSortScope(name, options));\n } catch (e) {\n logger.error(`Could not add custom fields scopes to model ${name}. `, e);\n }\n });\n};\n\nexport const applyCustomAssociation = (models: Models[]): void => {\n models.forEach(({ modelOptions }) => {\n modelOptions?.customAssociation?.(CustomFieldDefinition);\n modelOptions?.customAssociation?.(CustomValidator);\n });\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","names":["enrichResults","CustomFieldValue","CustomFieldDefinition","CustomValidator"],"sources":["../../src/utils/init.ts"],"sourcesContent":["import { DataTypes } from 'sequelize';\nimport type { ModelCtor } from 'sequelize-typescript';\nimport { customFields } from '@autofleet/common-types';\nimport { CUSTOM_FIELDS_SORT_SCOPE } from '@autofleet/common-types/lib/custom-fields';\nimport {\n CustomFieldDefinition,\n CustomFieldValue,\n CustomValidator,\n} from '../models';\nimport {\n beforeFind,\n enrichResults,\n beforeBulkUpdate,\n beforeUpdate,\n beforeCreate,\n beforeBulkCreate,\n} from '../hooks';\nimport { customFieldsFilterScope } from '../scopes';\nimport logger from './logger';\nimport type { CustomFieldOptions, ModelFetcher, Models } from '../types';\nimport { customFieldsSortScope } from '../scopes/filter';\n\nconst { CUSTOM_FIELDS_FILTER_SCOPE } = customFields;\n\nexport const addHooks = (\n models: Models[],\n getModel: ModelFetcher,\n sadotOptions: { useCustomFieldsEntries?: boolean; } = { useCustomFieldsEntries: false },\n): void => {\n models.forEach(async ({\n name, scopeAttributes, modelOptions, hasTypeId, getRequiredCustomFields,\n }) => {\n try {\n const model = getModel(name);\n if (!model) {\n logger.warn('sadot - tried to addHooks to a model that does not exist yet', {\n name,\n scopeAttributes,\n });\n return;\n }\n model.rawAttributes.customFields = {\n type: DataTypes.VIRTUAL,\n };\n model.refreshAttributes();\n\n const enrichOptions = {\n ...sadotOptions,\n hasTypeId: hasTypeId ?? false,\n getRequiredCustomFields,\n };\n\n // TODO: Uncomment after tests are passed\n // model.addHook('afterFind', workaround);\n model.addHook('beforeFind', 'sadot-beforeFind', beforeFind(scopeAttributes));\n model.addHook('beforeBulkCreate', 'sadot-beforeBulkCreate', beforeBulkCreate);\n model.addHook('beforeBulkUpdate', 'sadot-beforeBulkUpdate', beforeBulkUpdate);\n model.addHook('beforeCreate', 'sadot-beforeCreate', beforeCreate(scopeAttributes, modelOptions, enrichOptions));\n model.addHook('beforeUpdate', 'sadot-beforeUpdate', beforeUpdate(scopeAttributes, modelOptions, enrichOptions));\n model.addHook('afterFind', 'sadot-afterFind', enrichResults(name, scopeAttributes, 'afterFind', modelOptions, enrichOptions));\n model.addHook('afterUpdate', 'sadot-afterUpdate', enrichResults(name, scopeAttributes, undefined, modelOptions, enrichOptions));\n model.addHook('afterCreate', 'sadot-afterCreate', enrichResults(name, scopeAttributes, undefined, modelOptions, enrichOptions));\n } catch (e) {\n logger.error(`Could not add custom fields hook to model ${name}. `, e);\n }\n });\n};\n\nexport const removeHooks = (models: Models[], getModel: ModelFetcher): void => {\n models.forEach(async ({ name }) => {\n try {\n const model = getModel(name);\n if (!model) return;\n if (model.rawAttributes.customFields) {\n delete model.rawAttributes.customFields;\n model.refreshAttributes();\n }\n // model.removeHook('afterFind', 'sadot-workaround');\n model.removeHook('beforeFind', 'sadot-beforeFind');\n model.removeHook('beforeBulkCreate', 'sadot-beforeBulkCreate');\n model.removeHook('beforeBulkUpdate', 'sadot-beforeBulkUpdate');\n model.removeHook('beforeCreate', 'sadot-beforeCreate');\n model.removeHook('beforeUpdate', 'sadot-beforeUpdate');\n model.removeHook('afterFind', 'sadot-afterFind');\n model.removeHook('afterUpdate', 'sadot-afterUpdate');\n } catch (e) {\n logger.error(`Could not add custom fields hook to model ${name}. `, e);\n }\n });\n};\n\n/**\n * Necessary associations for the {@link customFieldsFilterScope} scope\n */\nconst addAssociations = (model: ModelCtor, modelName: string, options: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>): void => {\n if (options?.useCustomFieldsEntries) return;\n model.hasMany(CustomFieldValue, { foreignKey: 'modelId', as: 'customFieldValue' });\n // TBC: maybe can be removed\n CustomFieldValue.belongsTo(model, { foreignKey: 'modelId', as: modelName });\n};\n\nexport const addScopes = (models: Models[], getModel: ModelFetcher, options: Pick<CustomFieldOptions, 'useCustomFieldsEntries'> = { useCustomFieldsEntries: false }): void => {\n models.forEach(async ({ name, scopeAttributes }) => {\n try {\n const model = getModel(name);\n if (!model) {\n logger.warn('sadot - tried to addScopes to a model that does not exist yet', {\n name,\n scopeAttributes,\n });\n return;\n }\n // Necessary associations for the filtering scope\n addAssociations(model, name, options);\n // Add filter scope\n model.addScope(CUSTOM_FIELDS_FILTER_SCOPE, customFieldsFilterScope(name, options));\n model.addScope(CUSTOM_FIELDS_SORT_SCOPE, customFieldsSortScope(name, options));\n } catch (e) {\n logger.error(`Could not add custom fields scopes to model ${name}. `, e);\n }\n });\n};\n\nexport const applyCustomAssociation = (models: Models[]): void => {\n models.forEach(({ modelOptions }) => {\n modelOptions?.customAssociation?.(CustomFieldDefinition);\n modelOptions?.customAssociation?.(CustomValidator);\n });\n};\n"],"mappings":"ssBAsBA,KAAM,CAAE,8BAA+B,EAE1B,GACX,EACA,EACA,EAAsD,CAAE,uBAAwB,GAAO,GAC9E,CACT,EAAO,QAAQ,MAAO,CACpB,OAAM,kBAAiB,eAAc,YAAW,6BAC5C,CACJ,GAAI,CACF,IAAM,EAAQ,EAAS,EAAK,CAC5B,GAAI,CAAC,EAAO,CACV,EAAO,KAAK,+DAAgE,CAC1E,OACA,kBACD,CAAC,CACF,OAEF,EAAM,cAAc,aAAe,CACjC,KAAM,EAAU,QACjB,CACD,EAAM,mBAAmB,CAEzB,IAAM,EAAgB,CACpB,GAAG,EACH,UAAW,GAAa,GACxB,0BACD,CAID,EAAM,QAAQ,aAAc,mBAAoB,EAAW,EAAgB,CAAC,CAC5E,EAAM,QAAQ,mBAAoB,yBAA0B,EAAiB,CAC7E,EAAM,QAAQ,mBAAoB,yBAA0B,EAAiB,CAC7E,EAAM,QAAQ,eAAgB,qBAAsB,EAAa,EAAiB,EAAc,EAAc,CAAC,CAC/G,EAAM,QAAQ,eAAgB,qBAAsB,EAAa,EAAiB,EAAc,EAAc,CAAC,CAC/G,EAAM,QAAQ,YAAa,kBAAmBA,EAAc,EAAM,EAAiB,YAAa,EAAc,EAAc,CAAC,CAC7H,EAAM,QAAQ,cAAe,oBAAqBA,EAAc,EAAM,EAAiB,IAAA,GAAW,EAAc,EAAc,CAAC,CAC/H,EAAM,QAAQ,cAAe,oBAAqBA,EAAc,EAAM,EAAiB,IAAA,GAAW,EAAc,EAAc,CAAC,OACxH,EAAG,CACV,EAAO,MAAM,6CAA6C,EAAK,IAAK,EAAE,GAExE,EAGS,GAAe,EAAkB,IAAiC,CAC7E,EAAO,QAAQ,MAAO,CAAE,UAAW,CACjC,GAAI,CACF,IAAM,EAAQ,EAAS,EAAK,CAC5B,GAAI,CAAC,EAAO,OACR,EAAM,cAAc,eACtB,OAAO,EAAM,cAAc,aAC3B,EAAM,mBAAmB,EAG3B,EAAM,WAAW,aAAc,mBAAmB,CAClD,EAAM,WAAW,mBAAoB,yBAAyB,CAC9D,EAAM,WAAW,mBAAoB,yBAAyB,CAC9D,EAAM,WAAW,eAAgB,qBAAqB,CACtD,EAAM,WAAW,eAAgB,qBAAqB,CACtD,EAAM,WAAW,YAAa,kBAAkB,CAChD,EAAM,WAAW,cAAe,oBAAoB,OAC7C,EAAG,CACV,EAAO,MAAM,6CAA6C,EAAK,IAAK,EAAE,GAExE,EAME,GAAmB,EAAkB,EAAmB,IAAsE,CAC9H,GAAS,yBACb,EAAM,QAAQC,EAAkB,CAAE,WAAY,UAAW,GAAI,mBAAoB,CAAC,CAElF,EAAiB,UAAU,EAAO,CAAE,WAAY,UAAW,GAAI,EAAW,CAAC,GAGhE,GAAa,EAAkB,EAAwB,EAA8D,CAAE,uBAAwB,GAAO,GAAW,CAC5K,EAAO,QAAQ,MAAO,CAAE,OAAM,qBAAsB,CAClD,GAAI,CACF,IAAM,EAAQ,EAAS,EAAK,CAC5B,GAAI,CAAC,EAAO,CACV,EAAO,KAAK,gEAAiE,CAC3E,OACA,kBACD,CAAC,CACF,OAGF,EAAgB,EAAO,EAAM,EAAQ,CAErC,EAAM,SAAS,EAA4B,EAAwB,EAAM,EAAQ,CAAC,CAClF,EAAM,SAAS,EAA0B,EAAsB,EAAM,EAAQ,CAAC,OACvE,EAAG,CACV,EAAO,MAAM,+CAA+C,EAAK,IAAK,EAAE,GAE1E,EAGS,EAA0B,GAA2B,CAChE,EAAO,SAAS,CAAE,kBAAmB,CACnC,GAAc,oBAAoBC,EAAsB,CACxD,GAAc,oBAAoBC,EAAgB,EAClD"}
1
+ {"version":3,"file":"init.js","names":["enrichResults","CustomFieldValue","CustomFieldDefinition","CustomValidator"],"sources":["../../src/utils/init.ts"],"sourcesContent":["import { DataTypes } from 'sequelize';\nimport type { ModelCtor } from 'sequelize-typescript';\nimport { customFields } from '@autofleet/common-types';\nimport { CUSTOM_FIELDS_SORT_SCOPE } from '@autofleet/common-types/lib/custom-fields';\nimport {\n CustomFieldDefinition,\n CustomFieldValue,\n CustomValidator,\n} from '../models';\nimport {\n beforeFind,\n enrichResults,\n beforeBulkUpdate,\n beforeUpdate,\n beforeCreate,\n beforeBulkCreate,\n} from '../hooks';\nimport { customFieldsFilterScope } from '../scopes';\nimport logger from './logger';\nimport type { CustomFieldOptions, ModelFetcher, Models } from '../types';\nimport { customFieldsSortScope } from '../scopes/filter';\n\nconst { CUSTOM_FIELDS_FILTER_SCOPE } = customFields;\n\ntype AddHooksOptions = {\n useCustomFieldsEntries?: boolean;\n matPathManager?: CustomFieldOptions['matPathManager'];\n isMatPathActive?: CustomFieldOptions['isMatPathActive'];\n};\n\nexport const addHooks = (\n models: Models[],\n getModel: ModelFetcher,\n sadotOptions: AddHooksOptions = { useCustomFieldsEntries: false },\n): void => {\n models.forEach(async ({\n name, scopeAttributes, modelOptions, hasTypeId, getRequiredCustomFields,\n }) => {\n try {\n const model = getModel(name);\n if (!model) {\n logger.warn('sadot - tried to addHooks to a model that does not exist yet', {\n name,\n scopeAttributes,\n });\n return;\n }\n model.rawAttributes.customFields = {\n type: DataTypes.VIRTUAL,\n };\n model.refreshAttributes();\n\n const enrichOptions = {\n ...sadotOptions,\n hasTypeId: hasTypeId ?? false,\n getRequiredCustomFields,\n };\n\n // TODO: Uncomment after tests are passed\n // model.addHook('afterFind', workaround);\n model.addHook('beforeFind', 'sadot-beforeFind', beforeFind(scopeAttributes));\n model.addHook('beforeBulkCreate', 'sadot-beforeBulkCreate', beforeBulkCreate);\n model.addHook('beforeBulkUpdate', 'sadot-beforeBulkUpdate', beforeBulkUpdate);\n model.addHook('beforeCreate', 'sadot-beforeCreate', beforeCreate(scopeAttributes, modelOptions, enrichOptions));\n model.addHook('beforeUpdate', 'sadot-beforeUpdate', beforeUpdate(scopeAttributes, modelOptions, enrichOptions));\n model.addHook('afterFind', 'sadot-afterFind', enrichResults(name, scopeAttributes, 'afterFind', modelOptions, enrichOptions));\n model.addHook('afterUpdate', 'sadot-afterUpdate', enrichResults(name, scopeAttributes, undefined, modelOptions, enrichOptions));\n model.addHook('afterCreate', 'sadot-afterCreate', enrichResults(name, scopeAttributes, undefined, modelOptions, enrichOptions));\n } catch (e) {\n logger.error(`Could not add custom fields hook to model ${name}. `, e);\n }\n });\n};\n\nexport const removeHooks = (models: Models[], getModel: ModelFetcher): void => {\n models.forEach(async ({ name }) => {\n try {\n const model = getModel(name);\n if (!model) return;\n if (model.rawAttributes.customFields) {\n delete model.rawAttributes.customFields;\n model.refreshAttributes();\n }\n // model.removeHook('afterFind', 'sadot-workaround');\n model.removeHook('beforeFind', 'sadot-beforeFind');\n model.removeHook('beforeBulkCreate', 'sadot-beforeBulkCreate');\n model.removeHook('beforeBulkUpdate', 'sadot-beforeBulkUpdate');\n model.removeHook('beforeCreate', 'sadot-beforeCreate');\n model.removeHook('beforeUpdate', 'sadot-beforeUpdate');\n model.removeHook('afterFind', 'sadot-afterFind');\n model.removeHook('afterUpdate', 'sadot-afterUpdate');\n } catch (e) {\n logger.error(`Could not add custom fields hook to model ${name}. `, e);\n }\n });\n};\n\n/**\n * Necessary associations for the {@link customFieldsFilterScope} scope\n */\nconst addAssociations = (model: ModelCtor, modelName: string, options: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>): void => {\n if (options?.useCustomFieldsEntries) return;\n model.hasMany(CustomFieldValue, { foreignKey: 'modelId', as: 'customFieldValue' });\n // TBC: maybe can be removed\n CustomFieldValue.belongsTo(model, { foreignKey: 'modelId', as: modelName });\n};\n\nexport const addScopes = (models: Models[], getModel: ModelFetcher, options: Pick<CustomFieldOptions, 'useCustomFieldsEntries'> = { useCustomFieldsEntries: false }): void => {\n models.forEach(async ({ name, scopeAttributes }) => {\n try {\n const model = getModel(name);\n if (!model) {\n logger.warn('sadot - tried to addScopes to a model that does not exist yet', {\n name,\n scopeAttributes,\n });\n return;\n }\n // Necessary associations for the filtering scope\n addAssociations(model, name, options);\n // Add filter scope\n model.addScope(CUSTOM_FIELDS_FILTER_SCOPE, customFieldsFilterScope(name, options));\n model.addScope(CUSTOM_FIELDS_SORT_SCOPE, customFieldsSortScope(name, options));\n } catch (e) {\n logger.error(`Could not add custom fields scopes to model ${name}. `, e);\n }\n });\n};\n\nexport const applyCustomAssociation = (models: Models[]): void => {\n models.forEach(({ modelOptions }) => {\n modelOptions?.customAssociation?.(CustomFieldDefinition);\n modelOptions?.customAssociation?.(CustomValidator);\n });\n};\n"],"mappings":"ssBAsBA,KAAM,CAAE,8BAA+B,EAQ1B,GACX,EACA,EACA,EAAgC,CAAE,uBAAwB,GAAO,GACxD,CACT,EAAO,QAAQ,MAAO,CACpB,OAAM,kBAAiB,eAAc,YAAW,6BAC5C,CACJ,GAAI,CACF,IAAM,EAAQ,EAAS,EAAK,CAC5B,GAAI,CAAC,EAAO,CACV,EAAO,KAAK,+DAAgE,CAC1E,OACA,kBACD,CAAC,CACF,OAEF,EAAM,cAAc,aAAe,CACjC,KAAM,EAAU,QACjB,CACD,EAAM,mBAAmB,CAEzB,IAAM,EAAgB,CACpB,GAAG,EACH,UAAW,GAAa,GACxB,0BACD,CAID,EAAM,QAAQ,aAAc,mBAAoB,EAAW,EAAgB,CAAC,CAC5E,EAAM,QAAQ,mBAAoB,yBAA0B,EAAiB,CAC7E,EAAM,QAAQ,mBAAoB,yBAA0B,EAAiB,CAC7E,EAAM,QAAQ,eAAgB,qBAAsB,EAAa,EAAiB,EAAc,EAAc,CAAC,CAC/G,EAAM,QAAQ,eAAgB,qBAAsB,EAAa,EAAiB,EAAc,EAAc,CAAC,CAC/G,EAAM,QAAQ,YAAa,kBAAmBA,EAAc,EAAM,EAAiB,YAAa,EAAc,EAAc,CAAC,CAC7H,EAAM,QAAQ,cAAe,oBAAqBA,EAAc,EAAM,EAAiB,IAAA,GAAW,EAAc,EAAc,CAAC,CAC/H,EAAM,QAAQ,cAAe,oBAAqBA,EAAc,EAAM,EAAiB,IAAA,GAAW,EAAc,EAAc,CAAC,OACxH,EAAG,CACV,EAAO,MAAM,6CAA6C,EAAK,IAAK,EAAE,GAExE,EAGS,GAAe,EAAkB,IAAiC,CAC7E,EAAO,QAAQ,MAAO,CAAE,UAAW,CACjC,GAAI,CACF,IAAM,EAAQ,EAAS,EAAK,CAC5B,GAAI,CAAC,EAAO,OACR,EAAM,cAAc,eACtB,OAAO,EAAM,cAAc,aAC3B,EAAM,mBAAmB,EAG3B,EAAM,WAAW,aAAc,mBAAmB,CAClD,EAAM,WAAW,mBAAoB,yBAAyB,CAC9D,EAAM,WAAW,mBAAoB,yBAAyB,CAC9D,EAAM,WAAW,eAAgB,qBAAqB,CACtD,EAAM,WAAW,eAAgB,qBAAqB,CACtD,EAAM,WAAW,YAAa,kBAAkB,CAChD,EAAM,WAAW,cAAe,oBAAoB,OAC7C,EAAG,CACV,EAAO,MAAM,6CAA6C,EAAK,IAAK,EAAE,GAExE,EAME,GAAmB,EAAkB,EAAmB,IAAsE,CAC9H,GAAS,yBACb,EAAM,QAAQC,EAAkB,CAAE,WAAY,UAAW,GAAI,mBAAoB,CAAC,CAElF,EAAiB,UAAU,EAAO,CAAE,WAAY,UAAW,GAAI,EAAW,CAAC,GAGhE,GAAa,EAAkB,EAAwB,EAA8D,CAAE,uBAAwB,GAAO,GAAW,CAC5K,EAAO,QAAQ,MAAO,CAAE,OAAM,qBAAsB,CAClD,GAAI,CACF,IAAM,EAAQ,EAAS,EAAK,CAC5B,GAAI,CAAC,EAAO,CACV,EAAO,KAAK,gEAAiE,CAC3E,OACA,kBACD,CAAC,CACF,OAGF,EAAgB,EAAO,EAAM,EAAQ,CAErC,EAAM,SAAS,EAA4B,EAAwB,EAAM,EAAQ,CAAC,CAClF,EAAM,SAAS,EAA0B,EAAsB,EAAM,EAAQ,CAAC,OACvE,EAAG,CACV,EAAO,MAAM,+CAA+C,EAAK,IAAK,EAAE,GAE1E,EAGS,EAA0B,GAA2B,CAChE,EAAO,SAAS,CAAE,kBAAmB,CACnC,GAAc,oBAAoBC,EAAsB,CACxD,GAAc,oBAAoBC,EAAgB,EAClD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autofleet/sadot",
3
- "version": "1.4.20",
3
+ "version": "1.4.21-beta-e58014c3.0",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -52,9 +52,9 @@
52
52
  "express": "^4.21.2",
53
53
  "npm-watch": "^0.11.0",
54
54
  "supertest": "^7.0.0",
55
- "@autofleet/errors": "^3.1.49",
56
- "@autofleet/logger": "^4.3.3",
57
55
  "@autofleet/node-common": "^4.3.9",
56
+ "@autofleet/logger": "^4.3.3",
57
+ "@autofleet/errors": "^3.1.49",
58
58
  "@autofleet/zehut": "^4.12.2"
59
59
  },
60
60
  "peerDependencies": {