@autofleet/sadot 1.9.0 → 1.10.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.
Files changed (56) hide show
  1. package/dist/hooks/enrich.cjs +1 -1
  2. package/dist/hooks/enrich.cjs.map +1 -1
  3. package/dist/hooks/enrich.js +1 -1
  4. package/dist/hooks/enrich.js.map +1 -1
  5. package/dist/hooks/hooks.cjs +1 -1
  6. package/dist/hooks/hooks.cjs.map +1 -1
  7. package/dist/hooks/hooks.js +1 -1
  8. package/dist/hooks/hooks.js.map +1 -1
  9. package/dist/hooks/utils/updateInstanceValues.cjs +1 -1
  10. package/dist/hooks/utils/updateInstanceValues.cjs.map +1 -1
  11. package/dist/hooks/utils/updateInstanceValues.js +1 -1
  12. package/dist/hooks/utils/updateInstanceValues.js.map +1 -1
  13. package/dist/index.cjs +1 -1
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.d.cts +3 -1
  16. package/dist/index.d.ts +3 -1
  17. package/dist/index.js +1 -1
  18. package/dist/index.js.map +1 -1
  19. package/dist/migrations/index.cjs +1 -1
  20. package/dist/migrations/index.cjs.map +1 -1
  21. package/dist/migrations/index.d.cts +2 -2
  22. package/dist/migrations/index.d.ts +2 -2
  23. package/dist/migrations/index.js +1 -1
  24. package/dist/migrations/index.js.map +1 -1
  25. package/dist/models/index.cjs +1 -1
  26. package/dist/models/index.cjs.map +1 -1
  27. package/dist/models/index.js +1 -1
  28. package/dist/models/index.js.map +1 -1
  29. package/dist/repository/backfill.cjs +34 -0
  30. package/dist/repository/backfill.cjs.map +1 -0
  31. package/dist/repository/backfill.d.cts +32 -0
  32. package/dist/repository/backfill.d.ts +32 -0
  33. package/dist/repository/backfill.js +34 -0
  34. package/dist/repository/backfill.js.map +1 -0
  35. package/dist/scopes/filter.cjs +1 -1
  36. package/dist/scopes/filter.cjs.map +1 -1
  37. package/dist/scopes/filter.d.cts +1 -1
  38. package/dist/scopes/filter.d.ts +1 -1
  39. package/dist/scopes/filter.js +1 -1
  40. package/dist/scopes/filter.js.map +1 -1
  41. package/dist/types/index.d.cts +12 -1
  42. package/dist/types/index.d.ts +14 -3
  43. package/dist/utils/custom-fields-mode.cjs +2 -0
  44. package/dist/utils/custom-fields-mode.cjs.map +1 -0
  45. package/dist/utils/custom-fields-mode.d.cts +27 -0
  46. package/dist/utils/custom-fields-mode.d.ts +27 -0
  47. package/dist/utils/custom-fields-mode.js +2 -0
  48. package/dist/utils/custom-fields-mode.js.map +1 -0
  49. package/dist/utils/db/index.js +1 -1
  50. package/dist/utils/db/index.js.map +1 -1
  51. package/dist/utils/helpers/index.js.map +1 -1
  52. package/dist/utils/init.cjs +1 -1
  53. package/dist/utils/init.cjs.map +1 -1
  54. package/dist/utils/init.js +1 -1
  55. package/dist/utils/init.js.map +1 -1
  56. package/package.json +4 -4
@@ -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';\nimport { matPathState } from './mat-path-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';\n\nexport { runSadotMigrations } from './migrations';\n\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 {\n models,\n useCustomFieldsEntries,\n useModelTypeMapping,\n isMatPathEnabled,\n runLegacyMigrations,\n skipMigrations,\n } = options;\n matPathState.isMatPathEnabled = isMatPathEnabled;\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(\n sequelize,\n options.getUser,\n {\n useCustomFieldsEntries,\n useModelTypeMapping,\n isMatPathEnabled,\n runLegacyMigrations,\n skipMigrations,\n }\n );\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":"iqBAgCaA,EAA2C,IAAIC,EAAAA,yBAMtD,EAA0B,MAC9B,EACA,EACA,IACuB,CACvB,EAAA,4BAA4B,CAC5B,GAAM,CACJ,SACA,yBACA,sBACA,mBACA,sBACA,kBACE,EACJ,EAAA,aAAa,iBAAmB,EAC5B,GACF,EAAI,IAAI,OAAQC,EAAAA,QAAI,CAEtB,IAAM,EAAY,EAAQ,WAAaC,EAAAA,QAAO,EAAQ,eAAe,CAqBrE,OApBI,QAAQ,IAAI,WAAa,QAC3B,MAAMC,EAAAA,eAAe,EAAU,CAGjC,EAAA,SAAS,EAAQ,EAAU,CAAE,yBAAwB,CAAC,CACtD,MAAMC,EAAAA,WACJ,EACA,EAAQ,QACR,CACE,yBACA,sBACA,mBACA,sBACA,iBACD,CACF,CACD,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","resolveCustomFieldsEntriesMode","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';\nimport { matPathState } from './mat-path-state';\nimport { resolveCustomFieldsEntriesMode } from './utils/custom-fields-mode';\n\nexport { CUSTOM_FIELDS_ENTRIES_MODE } from './utils/custom-fields-mode';\n\nexport type { CustomFieldsEntriesMode } from './utils/custom-fields-mode';\n\nexport * from './utils/validations/schema/custom-fields';\n\nexport * from './utils/constants';\n\nexport * from './utils/helpers';\n\nexport { customFieldsSortScope } from './scopes/filter';\n\nexport { runSadotMigrations } from './migrations';\n\nexport { backfillCustomFieldEntries } from './repository/backfill';\n\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 {\n models,\n useModelTypeMapping,\n isMatPathEnabled,\n runLegacyMigrations,\n skipMigrations,\n } = options;\n // Resolved once here so every downstream call site receives a concrete mode.\n // The old boolean relied on `undefined` being falsy; an enum has no falsy \"off\".\n const customFieldsEntriesMode = resolveCustomFieldsEntriesMode(options);\n logger.info(`sadot custom-fields mode: ${customFieldsEntriesMode}`);\n matPathState.isMatPathEnabled = isMatPathEnabled;\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, { customFieldsEntriesMode });\n await initTables(\n sequelize,\n options.getUser,\n {\n customFieldsEntriesMode,\n useModelTypeMapping,\n isMatPathEnabled,\n runLegacyMigrations,\n skipMigrations,\n }\n );\n addScopes(models, getModel, { customFieldsEntriesMode });\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":"ovBAuCaA,EAA2C,IAAIC,EAAAA,yBAMtD,EAA0B,MAC9B,EACA,EACA,IACuB,CACvB,EAAA,4BAA4B,CAC5B,GAAM,CACJ,SACA,sBACA,mBACA,sBACA,kBACE,EAGE,EAA0BC,EAAAA,+BAA+B,EAAQ,CACvE,EAAA,QAAO,KAAK,6BAA6B,IAA0B,CACnE,EAAA,aAAa,iBAAmB,EAC5B,GACF,EAAI,IAAI,OAAQC,EAAAA,QAAI,CAEtB,IAAM,EAAY,EAAQ,WAAaC,EAAAA,QAAO,EAAQ,eAAe,CAqBrE,OApBI,QAAQ,IAAI,WAAa,QAC3B,MAAMC,EAAAA,eAAe,EAAU,CAGjC,EAAA,SAAS,EAAQ,EAAU,CAAE,0BAAyB,CAAC,CACvD,MAAMC,EAAAA,WACJ,EACA,EAAQ,QACR,CACE,0BACA,sBACA,mBACA,sBACA,iBACD,CACF,CACD,EAAA,UAAU,EAAQ,EAAU,CAAE,0BAAyB,CAAC,CACxD,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.d.cts CHANGED
@@ -2,12 +2,14 @@ import { CUSTOM_FIELDS_FILTER_SCOPE, CustomFieldDefinitionType, supportedEntitie
2
2
  import { CustomFieldValue } from "./models/CustomFieldValue.cjs";
3
3
  import { CustomFieldDefinition } from "./models/CustomFieldDefinition.cjs";
4
4
  import { CustomValidator } from "./models/CustomValidator.cjs";
5
+ import { CUSTOM_FIELDS_ENTRIES_MODE, CustomFieldsEntriesMode } from "./utils/custom-fields-mode.cjs";
5
6
  import { CustomFieldOptions, ModelFetcher, Models } from "./types/index.cjs";
6
7
  import { SadotInitializationState } from "./init-state.cjs";
7
8
  import { CustomFieldsSchema } from "./utils/validations/schema/custom-fields.cjs";
8
9
  import { generateCustomFieldSearchQueryPayload, generateRandomString } from "./utils/helpers/index.cjs";
9
10
  import { customFieldsSortScope } from "./scopes/filter.cjs";
10
11
  import { runSadotMigrations } from "./migrations/index.cjs";
12
+ import { backfillCustomFieldEntries } from "./repository/backfill.cjs";
11
13
  import { CustomFieldEntries } from "./models/CustomFieldEntries.cjs";
12
14
  import "./models/index.cjs";
13
15
  import { Application } from "express";
@@ -22,5 +24,5 @@ declare const sadotInitState: SadotInitializationState;
22
24
  declare const useCustomFields: (app: Pick<Application, "use"> | null, getModel: ModelFetcher, options: CustomFieldOptions) => Promise<Sequelize>;
23
25
  declare const disableCustomFields: (models: Models[], getModel: ModelFetcher) => void;
24
26
  //#endregion
25
- export { CUSTOM_FIELDS_FILTER_SCOPE, CustomFieldDefinition, CustomFieldDefinitionType, CustomFieldEntries, CustomFieldValue, CustomFieldsSchema, CustomValidator, customFieldsSortScope, useCustomFields as default, disableCustomFields, generateCustomFieldSearchQueryPayload, generateRandomString, runSadotMigrations, sadotInitState, supportedEntities };
27
+ export { CUSTOM_FIELDS_ENTRIES_MODE, CUSTOM_FIELDS_FILTER_SCOPE, CustomFieldDefinition, CustomFieldDefinitionType, CustomFieldEntries, CustomFieldValue, type CustomFieldsEntriesMode, CustomFieldsSchema, CustomValidator, backfillCustomFieldEntries, customFieldsSortScope, useCustomFields as default, disableCustomFields, generateCustomFieldSearchQueryPayload, generateRandomString, runSadotMigrations, sadotInitState, supportedEntities };
26
28
  //# sourceMappingURL=index.d.cts.map
package/dist/index.d.ts CHANGED
@@ -2,12 +2,14 @@ import { CUSTOM_FIELDS_FILTER_SCOPE, CustomFieldDefinitionType, supportedEntitie
2
2
  import { CustomFieldValue } from "./models/CustomFieldValue.js";
3
3
  import { CustomFieldDefinition } from "./models/CustomFieldDefinition.js";
4
4
  import { CustomValidator } from "./models/CustomValidator.js";
5
+ import { CUSTOM_FIELDS_ENTRIES_MODE, CustomFieldsEntriesMode } from "./utils/custom-fields-mode.js";
5
6
  import { CustomFieldOptions, ModelFetcher, Models } from "./types/index.js";
6
7
  import { SadotInitializationState } from "./init-state.js";
7
8
  import { CustomFieldsSchema } from "./utils/validations/schema/custom-fields.js";
8
9
  import { generateCustomFieldSearchQueryPayload, generateRandomString } from "./utils/helpers/index.js";
9
10
  import { customFieldsSortScope } from "./scopes/filter.js";
10
11
  import { runSadotMigrations } from "./migrations/index.js";
12
+ import { backfillCustomFieldEntries } from "./repository/backfill.js";
11
13
  import { CustomFieldEntries } from "./models/CustomFieldEntries.js";
12
14
  import "./models/index.js";
13
15
  import { Sequelize } from "sequelize-typescript";
@@ -22,5 +24,5 @@ declare const sadotInitState: SadotInitializationState;
22
24
  declare const useCustomFields: (app: Pick<Application, "use"> | null, getModel: ModelFetcher, options: CustomFieldOptions) => Promise<Sequelize>;
23
25
  declare const disableCustomFields: (models: Models[], getModel: ModelFetcher) => void;
24
26
  //#endregion
25
- export { CUSTOM_FIELDS_FILTER_SCOPE, CustomFieldDefinition, CustomFieldDefinitionType, CustomFieldEntries, CustomFieldValue, CustomFieldsSchema, CustomValidator, customFieldsSortScope, useCustomFields as default, disableCustomFields, generateCustomFieldSearchQueryPayload, generateRandomString, runSadotMigrations, sadotInitState, supportedEntities };
27
+ export { CUSTOM_FIELDS_ENTRIES_MODE, CUSTOM_FIELDS_FILTER_SCOPE, CustomFieldDefinition, CustomFieldDefinitionType, CustomFieldEntries, CustomFieldValue, type CustomFieldsEntriesMode, CustomFieldsSchema, CustomValidator, backfillCustomFieldEntries, customFieldsSortScope, useCustomFields as default, disableCustomFields, generateCustomFieldSearchQueryPayload, generateRandomString, runSadotMigrations, sadotInitState, supportedEntities };
26
28
  //# sourceMappingURL=index.d.ts.map
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{runSadotMigrations as l}from"./migrations/index.js";import{initTables as u,initTestModels as d}from"./models/index.js";import{matPathState as f}from"./mat-path-state.js";import p from"./api/index.js";import m from"./utils/db/index.js";import{generateCustomFieldSearchQueryPayload as h,generateRandomString as g}from"./utils/helpers/index.js";import{customFieldsSortScope as _}from"./scopes/filter.js";import{addHooks as v,addScopes as y,applyCustomAssociation as b,removeHooks as x}from"./utils/init.js";import{SadotInitializationState as S}from"./init-state.js";import{CustomFieldsSchema as C}from"./utils/validations/schema/custom-fields.js";const w=new S,T=async(n,r,i)=>{t();let{models:a,useCustomFieldsEntries:o,useModelTypeMapping:s,isMatPathEnabled:c,runLegacyMigrations:l,skipMigrations:h}=i;f.isMatPathEnabled=c,n&&n.use(`/api`,p);let g=i.sequelize??m(i.databaseConfig);return process.env.NODE_ENV===`test`&&await d(g),v(a,r,{useCustomFieldsEntries:o}),await u(g,i.getUser,{useCustomFieldsEntries:o,useModelTypeMapping:s,isMatPathEnabled:c,runLegacyMigrations:l,skipMigrations:h}),y(a,r,{useCustomFieldsEntries:o}),b(a),e.debug(`sadot - custom fields finished initializing with models`,a),g};var E=async(e,t,n)=>{let r=T(e,t,n);return w.setInitPromise(r,!n.sequelize),await r};const D=(e,t)=>{x(e,t)};export{n as CUSTOM_FIELDS_FILTER_SCOPE,o as CustomFieldDefinition,r as CustomFieldDefinitionType,s as CustomFieldEntries,a as CustomFieldValue,C as CustomFieldsSchema,c as CustomValidator,_ as customFieldsSortScope,E as default,D as disableCustomFields,h as generateCustomFieldSearchQueryPayload,g as generateRandomString,l as runSadotMigrations,w 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{CUSTOM_FIELDS_ENTRIES_MODE as l,resolveCustomFieldsEntriesMode as u}from"./utils/custom-fields-mode.js";import{runSadotMigrations as d}from"./migrations/index.js";import{initTables as f,initTestModels as p}from"./models/index.js";import{matPathState as m}from"./mat-path-state.js";import h from"./api/index.js";import g from"./utils/db/index.js";import{generateCustomFieldSearchQueryPayload as _,generateRandomString as v}from"./utils/helpers/index.js";import{customFieldsSortScope as y}from"./scopes/filter.js";import{addHooks as b,addScopes as x,applyCustomAssociation as S,removeHooks as C}from"./utils/init.js";import{SadotInitializationState as w}from"./init-state.js";import{CustomFieldsSchema as T}from"./utils/validations/schema/custom-fields.js";import{backfillCustomFieldEntries as E}from"./repository/backfill.js";const D=new w,O=async(n,r,i)=>{t();let{models:a,useModelTypeMapping:o,isMatPathEnabled:s,runLegacyMigrations:c,skipMigrations:l}=i,d=u(i);e.info(`sadot custom-fields mode: ${d}`),m.isMatPathEnabled=s,n&&n.use(`/api`,h);let _=i.sequelize??g(i.databaseConfig);return process.env.NODE_ENV===`test`&&await p(_),b(a,r,{customFieldsEntriesMode:d}),await f(_,i.getUser,{customFieldsEntriesMode:d,useModelTypeMapping:o,isMatPathEnabled:s,runLegacyMigrations:c,skipMigrations:l}),x(a,r,{customFieldsEntriesMode:d}),S(a),e.debug(`sadot - custom fields finished initializing with models`,a),_};var k=async(e,t,n)=>{let r=O(e,t,n);return D.setInitPromise(r,!n.sequelize),await r};const A=(e,t)=>{C(e,t)};export{l as CUSTOM_FIELDS_ENTRIES_MODE,n as CUSTOM_FIELDS_FILTER_SCOPE,o as CustomFieldDefinition,r as CustomFieldDefinitionType,s as CustomFieldEntries,a as CustomFieldValue,T as CustomFieldsSchema,c as CustomValidator,E as backfillCustomFieldEntries,y as customFieldsSortScope,k as default,A as disableCustomFields,_ as generateCustomFieldSearchQueryPayload,v as generateRandomString,d as runSadotMigrations,D 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';\nimport { matPathState } from './mat-path-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';\n\nexport { runSadotMigrations } from './migrations';\n\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 {\n models,\n useCustomFieldsEntries,\n useModelTypeMapping,\n isMatPathEnabled,\n runLegacyMigrations,\n skipMigrations,\n } = options;\n matPathState.isMatPathEnabled = isMatPathEnabled;\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(\n sequelize,\n options.getUser,\n {\n useCustomFieldsEntries,\n useModelTypeMapping,\n isMatPathEnabled,\n runLegacyMigrations,\n skipMigrations,\n }\n );\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":"ugCAgCA,MAAaA,EAA2C,IAAI,EAMtD,EAA0B,MAC9B,EACA,EACA,IACuB,CACvB,GAA4B,CAC5B,GAAM,CACJ,SACA,yBACA,sBACA,mBACA,sBACA,kBACE,EACJ,EAAa,iBAAmB,EAC5B,GACF,EAAI,IAAI,OAAQC,EAAI,CAEtB,IAAM,EAAY,EAAQ,WAAaC,EAAO,EAAQ,eAAe,CAqBrE,OApBI,QAAQ,IAAI,WAAa,QAC3B,MAAM,EAAe,EAAU,CAGjC,EAAS,EAAQ,EAAU,CAAE,yBAAwB,CAAC,CACtD,MAAM,EACJ,EACA,EAAQ,QACR,CACE,yBACA,sBACA,mBACA,sBACA,iBACD,CACF,CACD,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';\nimport { matPathState } from './mat-path-state';\nimport { resolveCustomFieldsEntriesMode } from './utils/custom-fields-mode';\n\nexport { CUSTOM_FIELDS_ENTRIES_MODE } from './utils/custom-fields-mode';\n\nexport type { CustomFieldsEntriesMode } from './utils/custom-fields-mode';\n\nexport * from './utils/validations/schema/custom-fields';\n\nexport * from './utils/constants';\n\nexport * from './utils/helpers';\n\nexport { customFieldsSortScope } from './scopes/filter';\n\nexport { runSadotMigrations } from './migrations';\n\nexport { backfillCustomFieldEntries } from './repository/backfill';\n\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 {\n models,\n useModelTypeMapping,\n isMatPathEnabled,\n runLegacyMigrations,\n skipMigrations,\n } = options;\n // Resolved once here so every downstream call site receives a concrete mode.\n // The old boolean relied on `undefined` being falsy; an enum has no falsy \"off\".\n const customFieldsEntriesMode = resolveCustomFieldsEntriesMode(options);\n logger.info(`sadot custom-fields mode: ${customFieldsEntriesMode}`);\n matPathState.isMatPathEnabled = isMatPathEnabled;\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, { customFieldsEntriesMode });\n await initTables(\n sequelize,\n options.getUser,\n {\n customFieldsEntriesMode,\n useModelTypeMapping,\n isMatPathEnabled,\n runLegacyMigrations,\n skipMigrations,\n }\n );\n addScopes(models, getModel, { customFieldsEntriesMode });\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":"4rCAuCA,MAAaA,EAA2C,IAAI,EAMtD,EAA0B,MAC9B,EACA,EACA,IACuB,CACvB,GAA4B,CAC5B,GAAM,CACJ,SACA,sBACA,mBACA,sBACA,kBACE,EAGE,EAA0B,EAA+B,EAAQ,CACvE,EAAO,KAAK,6BAA6B,IAA0B,CACnE,EAAa,iBAAmB,EAC5B,GACF,EAAI,IAAI,OAAQC,EAAI,CAEtB,IAAM,EAAY,EAAQ,WAAaC,EAAO,EAAQ,eAAe,CAqBrE,OApBI,QAAQ,IAAI,WAAa,QAC3B,MAAM,EAAe,EAAU,CAGjC,EAAS,EAAQ,EAAU,CAAE,0BAAyB,CAAC,CACvD,MAAM,EACJ,EACA,EAAQ,QACR,CACE,0BACA,sBACA,mBACA,sBACA,iBACD,CACF,CACD,EAAU,EAAQ,EAAU,CAAE,0BAAyB,CAAC,CACxD,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,2 +1,2 @@
1
- const e=require(`../_virtual/rolldown_runtime.cjs`),t=require(`../utils/logger/index.cjs`),n=require(`./001-create-core-tables.cjs`),r=require(`./002-create-custom-field-entries.cjs`),i=require(`./003-create-custom-field-model-type-map.cjs`);let a=require(`node:timers/promises`);const{Umzug:o,SequelizeStorage:s}=require(`umzug`),c=e=>{let{useCustomFieldsEntries:t=!1,useModelTypeMapping:a=!1}=e;return[{name:`001-create-core-tables`,up:n.up,down:n.down},...t?[{name:`002-create-custom-field-entries`,up:r.up,down:r.down}]:[],...a?[{name:`003-create-custom-field-model-type-map`,up:i.up,down:i.down}]:[]]},l=839274628,u=async(e,n={})=>{let{withLock:r=!0}=n,i=e.getQueryInterface(),u=new s({sequelize:e,tableName:`sadot_migrations`,modelName:`SadotMigrations`}),d=new o({migrations:c(n),context:i,storage:u,logger:{info:e=>t.default.info(`[sadot] ${JSON.stringify(e)}`),warn:e=>t.default.warn(`[sadot] ${JSON.stringify(e)}`),error:e=>t.default.error(`[sadot] ${JSON.stringify(e)}`),debug:e=>t.default.debug(`[sadot] ${JSON.stringify(e)}`)}}),f=await d.pending();if(f.length===0){t.default.info(`[sadot] no pending migrations, skipping`);return}if(t.default.info(`[sadot] pending migrations detected`,{pending:f.map(e=>e.name)}),!r){await d.up();return}if((e.options?.pool?.max??5)<2){t.default.info(`[sadot] connection pool too small for advisory lock, running migrations directly`),await d.up();return}t.default.info(`[sadot] acquiring advisory lock`);let p=await e.connectionManager.getConnection({type:`write`});try{let e=!1;for(;!e;)e=(await p.query(`SELECT pg_try_advisory_lock(${l}) AS acquired`)).rows[0].acquired,e||await(0,a.setTimeout)(1e3);t.default.info(`[sadot] advisory lock acquired`),(await d.pending()).length>0?await d.up():t.default.info(`[sadot] migrations already applied by another instance, skipping`)}finally{try{await p.query(`SELECT pg_advisory_unlock(${l})`),t.default.info(`[sadot] advisory lock released`)}finally{e.connectionManager.releaseConnection(p)}}};exports.runSadotMigrations=u;
1
+ const e=require(`../_virtual/rolldown_runtime.cjs`),t=require(`../utils/logger/index.cjs`),n=require(`../utils/custom-fields-mode.cjs`),r=require(`./001-create-core-tables.cjs`),i=require(`./002-create-custom-field-entries.cjs`),a=require(`./003-create-custom-field-model-type-map.cjs`);let o=require(`node:timers/promises`);const{Umzug:s,SequelizeStorage:c}=require(`umzug`),l=e=>{let{useModelTypeMapping:t=!1}=e,o=n.writesEntries(n.resolveCustomFieldsEntriesMode(e));return[{name:`001-create-core-tables`,up:r.up,down:r.down},...o?[{name:`002-create-custom-field-entries`,up:i.up,down:i.down}]:[],...t?[{name:`003-create-custom-field-model-type-map`,up:a.up,down:a.down}]:[]]},u=839274628,d=async(e,n={})=>{let{withLock:r=!0}=n,i=e.getQueryInterface(),a=new c({sequelize:e,tableName:`sadot_migrations`,modelName:`SadotMigrations`}),d=new s({migrations:l(n),context:i,storage:a,logger:{info:e=>t.default.info(`[sadot] ${JSON.stringify(e)}`),warn:e=>t.default.warn(`[sadot] ${JSON.stringify(e)}`),error:e=>t.default.error(`[sadot] ${JSON.stringify(e)}`),debug:e=>t.default.debug(`[sadot] ${JSON.stringify(e)}`)}}),f=await d.pending();if(f.length===0){t.default.info(`[sadot] no pending migrations, skipping`);return}if(t.default.info(`[sadot] pending migrations detected`,{pending:f.map(e=>e.name)}),!r){await d.up();return}if((e.options?.pool?.max??5)<2){t.default.info(`[sadot] connection pool too small for advisory lock, running migrations directly`),await d.up();return}t.default.info(`[sadot] acquiring advisory lock`);let p=await e.connectionManager.getConnection({type:`write`});try{let e=!1;for(;!e;)e=(await p.query(`SELECT pg_try_advisory_lock(${u}) AS acquired`)).rows[0].acquired,e||await(0,o.setTimeout)(1e3);t.default.info(`[sadot] advisory lock acquired`),(await d.pending()).length>0?await d.up():t.default.info(`[sadot] migrations already applied by another instance, skipping`)}finally{try{await p.query(`SELECT pg_advisory_unlock(${u})`),t.default.info(`[sadot] advisory lock released`)}finally{e.connectionManager.releaseConnection(p)}}};exports.runSadotMigrations=d;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["logger"],"sources":["../../src/migrations/index.ts"],"sourcesContent":["import type { InputMigrations } from 'umzug';\nimport type { QueryInterface } from 'sequelize';\nimport type { Sequelize } from 'sequelize-typescript';\nimport { setTimeout } from 'node:timers/promises';\nimport logger from '../utils/logger';\nimport * as migration001 from './001-create-core-tables';\nimport * as migration002 from './002-create-custom-field-entries';\nimport * as migration003 from './003-create-custom-field-model-type-map';\n\n// umzug is CJS. Static ESM named imports break in vitest after vi.resetModules()\n// because Vite's SSR transform re-evaluates the module outside the inline bundle.\n// require() goes through Node's native CJS loader and is stable across resets.\n\n// eslint-disable-next-line import/no-commonjs\nconst { Umzug, SequelizeStorage } = require('umzug') as typeof import('umzug');\n\ninterface MigratorOptions {\n useCustomFieldsEntries?: boolean;\n useModelTypeMapping?: boolean;\n withLock?: boolean;\n}\n\nconst buildMigrationList = (options: MigratorOptions): InputMigrations<QueryInterface> => {\n const { useCustomFieldsEntries = false, useModelTypeMapping = false } = options;\n return [\n { name: '001-create-core-tables', up: migration001.up, down: migration001.down },\n ...(useCustomFieldsEntries ? [{ name: '002-create-custom-field-entries', up: migration002.up, down: migration002.down }] : []),\n ...(useModelTypeMapping ? [{ name: '003-create-custom-field-model-type-map', up: migration003.up, down: migration003.down }] : []),\n ];\n};\n\n// Stable advisory-lock ID for sadot migrations. Chosen arbitrarily; must not\n// collide with other advisory locks in the same database.\nconst SADOT_MIGRATION_LOCK_ID = 839274628;\n\n/**\n * Runs sadot migrations via umzug. All migrations use IF NOT EXISTS / IF EXISTS,\n * so they are fully idempotent — safe to run against both fresh and existing\n * databases (including DBs previously managed by the legacy sync() path).\n *\n * When `withLock: true`, a PostgreSQL advisory lock is acquired before running\n * migrations so that when multiple pods start concurrently only one of them\n * executes the migrations. The remaining pods block until the lock is released,\n * then proceed — Umzug will see the migrations have already been applied and\n * skip them.\n *\n * @param options - Migration execution options.\n * @param options.withLock - Whether to acquire a PostgreSQL advisory lock before running the migrations. Defaults to true.\n * @returns A promise that resolves when the migrations have completed. \n */\nconst runSadotMigrations = async (sequelize: Sequelize, options: MigratorOptions = {}): Promise<void> => {\n // Need to add a new migration? full migration guide here; https://www.notion.so/autofleet/How-to-Add-a-New-Migration-to-Sadot-36db603f40b98023b239d3c61aa22b00\n const { withLock = true } = options;\n const queryInterface = sequelize.getQueryInterface() as unknown as QueryInterface;\n const storage = new SequelizeStorage({ sequelize: sequelize as never, tableName: 'sadot_migrations', modelName: 'SadotMigrations' });\n\n const umzugLogger = {\n info: (msg: Record<string, unknown>) => logger.info(`[sadot] ${JSON.stringify(msg)}`),\n warn: (msg: Record<string, unknown>) => logger.warn(`[sadot] ${JSON.stringify(msg)}`),\n error: (msg: Record<string, unknown>) => logger.error(`[sadot] ${JSON.stringify(msg)}`),\n debug: (msg: Record<string, unknown>) => logger.debug(`[sadot] ${JSON.stringify(msg)}`),\n };\n\n const migrator = new Umzug<QueryInterface>({\n migrations: buildMigrationList(options),\n context: queryInterface,\n storage,\n logger: umzugLogger,\n });\n\n const pending = await migrator.pending();\n if (pending.length === 0) {\n logger.info('[sadot] no pending migrations, skipping');\n return;\n }\n\n logger.info('[sadot] pending migrations detected', { pending: pending.map(m => m.name) });\n\n if (!withLock) {\n await migrator.up();\n return;\n }\n\n // The advisory lock holds a connection for its entire duration while\n // migrator.up() needs additional pool connections for queries. With\n // pool.max < 2 (common in test environments) this deadlocks.\n // Migrations are idempotent (IF NOT EXISTS / IF EXISTS) so running\n // without the lock is safe — just potentially duplicated work.\n const poolMax = (sequelize.options as any)?.pool?.max ?? 5;\n if (poolMax < 2) {\n logger.info('[sadot] connection pool too small for advisory lock, running migrations directly');\n await migrator.up();\n return;\n }\n\n // Use a dedicated raw connection (not a transaction) to hold the advisory lock.\n // A transaction connection sitting idle while migrator.up() runs on other pool\n // connections would be killed by idle_in_transaction_session_timeout, releasing\n // the lock prematurely and allowing a second replica to start migrations concurrently.\n logger.info('[sadot] acquiring advisory lock');\n const lockConnection = await (sequelize.connectionManager as any).getConnection({ type: 'write' });\n try {\n // Poll with pg_try_advisory_lock so the connection stays idle between attempts rather\n // than holding an active statement for the full wait duration. DDL operations that track\n // active backends between internal phases (e.g. CREATE INDEX CONCURRENTLY, VACUUM,\n // REINDEX CONCURRENTLY) wait for all active statements to finish before proceeding —\n // a long-blocking lock attempt would stall them for the entire wait.\n let lockAcquired = false;\n while (!lockAcquired) {\n const result = await lockConnection.query(`SELECT pg_try_advisory_lock(${SADOT_MIGRATION_LOCK_ID}) AS acquired`);\n lockAcquired = result.rows[0].acquired;\n if (!lockAcquired) await setTimeout(1000);\n }\n logger.info('[sadot] advisory lock acquired');\n\n // Re-check after acquiring the lock — another pod may have already\n // applied the migrations while we were waiting.\n const stillPending = await migrator.pending();\n if (stillPending.length > 0) {\n await migrator.up();\n } else {\n logger.info('[sadot] migrations already applied by another instance, skipping');\n }\n } finally {\n try {\n await lockConnection.query(`SELECT pg_advisory_unlock(${SADOT_MIGRATION_LOCK_ID})`);\n logger.info('[sadot] advisory lock released');\n } finally {\n (sequelize.connectionManager as any).releaseConnection(lockConnection);\n }\n }\n};\n\nexport { runSadotMigrations };\n"],"mappings":"wRAcA,KAAM,CAAE,QAAO,oBAAqB,QAAQ,QAAQ,CAQ9C,EAAsB,GAA8D,CACxF,GAAM,CAAE,yBAAyB,GAAO,sBAAsB,IAAU,EACxE,MAAO,CACL,CAAE,KAAM,yBAA0B,GAAA,EAAA,GAAqB,KAAA,EAAA,KAAyB,CAChF,GAAI,EAAyB,CAAC,CAAE,KAAM,kCAAmC,GAAA,EAAA,GAAqB,KAAA,EAAA,KAAyB,CAAC,CAAG,EAAE,CAC7H,GAAI,EAAsB,CAAC,CAAE,KAAM,yCAA0C,GAAA,EAAA,GAAqB,KAAA,EAAA,KAAyB,CAAC,CAAG,EAAE,CAClI,EAKG,EAA0B,UAiB1B,EAAqB,MAAO,EAAsB,EAA2B,EAAE,GAAoB,CAEvG,GAAM,CAAE,WAAW,IAAS,EACtB,EAAiB,EAAU,mBAAmB,CAC9C,EAAU,IAAI,EAAiB,CAAa,YAAoB,UAAW,mBAAoB,UAAW,kBAAmB,CAAC,CAS9H,EAAW,IAAI,EAAsB,CACzC,WAAY,EAAmB,EAAQ,CACvC,QAAS,EACT,UACA,OAXkB,CAClB,KAAO,GAAiCA,EAAAA,QAAO,KAAK,WAAW,KAAK,UAAU,EAAI,GAAG,CACrF,KAAO,GAAiCA,EAAAA,QAAO,KAAK,WAAW,KAAK,UAAU,EAAI,GAAG,CACrF,MAAQ,GAAiCA,EAAAA,QAAO,MAAM,WAAW,KAAK,UAAU,EAAI,GAAG,CACvF,MAAQ,GAAiCA,EAAAA,QAAO,MAAM,WAAW,KAAK,UAAU,EAAI,GAAG,CACxF,CAOA,CAAC,CAEI,EAAU,MAAM,EAAS,SAAS,CACxC,GAAI,EAAQ,SAAW,EAAG,CACxB,EAAA,QAAO,KAAK,0CAA0C,CACtD,OAKF,GAFA,EAAA,QAAO,KAAK,sCAAuC,CAAE,QAAS,EAAQ,IAAI,GAAK,EAAE,KAAK,CAAE,CAAC,CAErF,CAAC,EAAU,CACb,MAAM,EAAS,IAAI,CACnB,OASF,IADiB,EAAU,SAAiB,MAAM,KAAO,GAC3C,EAAG,CACf,EAAA,QAAO,KAAK,mFAAmF,CAC/F,MAAM,EAAS,IAAI,CACnB,OAOF,EAAA,QAAO,KAAK,kCAAkC,CAC9C,IAAM,EAAiB,MAAO,EAAU,kBAA0B,cAAc,CAAE,KAAM,QAAS,CAAC,CAClG,GAAI,CAMF,IAAI,EAAe,GACnB,KAAO,CAAC,GAEN,GADe,MAAM,EAAe,MAAM,+BAA+B,EAAwB,eAAe,EAC1F,KAAK,GAAG,SACzB,GAAc,MAAA,EAAA,EAAA,YAAiB,IAAK,CAE3C,EAAA,QAAO,KAAK,iCAAiC,EAIxB,MAAM,EAAS,SAAS,EAC5B,OAAS,EACxB,MAAM,EAAS,IAAI,CAEnB,EAAA,QAAO,KAAK,mEAAmE,QAEzE,CACR,GAAI,CACF,MAAM,EAAe,MAAM,6BAA6B,EAAwB,GAAG,CACnF,EAAA,QAAO,KAAK,iCAAiC,QACrC,CACP,EAAU,kBAA0B,kBAAkB,EAAe"}
1
+ {"version":3,"file":"index.cjs","names":["writesEntries","resolveCustomFieldsEntriesMode","logger"],"sources":["../../src/migrations/index.ts"],"sourcesContent":["import type { InputMigrations } from 'umzug';\nimport type { QueryInterface } from 'sequelize';\nimport type { Sequelize } from 'sequelize-typescript';\nimport { setTimeout } from 'node:timers/promises';\nimport logger from '../utils/logger';\nimport { type CustomFieldsEntriesModeOptions, resolveCustomFieldsEntriesMode, writesEntries } from '../utils/custom-fields-mode';\nimport * as migration001 from './001-create-core-tables';\nimport * as migration002 from './002-create-custom-field-entries';\nimport * as migration003 from './003-create-custom-field-model-type-map';\n\n// umzug is CJS. Static ESM named imports break in vitest after vi.resetModules()\n// because Vite's SSR transform re-evaluates the module outside the inline bundle.\n// require() goes through Node's native CJS loader and is stable across resets.\n\n// eslint-disable-next-line import/no-commonjs\nconst { Umzug, SequelizeStorage } = require('umzug') as typeof import('umzug');\n\ninterface MigratorOptions extends CustomFieldsEntriesModeOptions {\n useModelTypeMapping?: boolean;\n withLock?: boolean;\n}\n\nconst buildMigrationList = (options: MigratorOptions): InputMigrations<QueryInterface> => {\n const { useModelTypeMapping = false } = options;\n // The table is needed as soon as anything writes to it, and every mode that reads\n // entries also writes them, so `writesEntries` is the widest gate. Keying this off\n // `readsEntries` would leave a WRITE_ONLY service inserting into a missing table.\n //\n // Migrations only need this boolean — WRITE_ONLY and READ_AND_WRITE are the same\n // answer here. The full mode is accepted anyway so a service passes one shared\n // constant to both this and useCustomFields(), rather than keeping a separate\n // migration-only boolean in sync with the runtime mode.\n const shouldRunEntriesTableMigration = writesEntries(resolveCustomFieldsEntriesMode(options));\n return [\n { name: '001-create-core-tables', up: migration001.up, down: migration001.down },\n ...(shouldRunEntriesTableMigration ? [{ name: '002-create-custom-field-entries', up: migration002.up, down: migration002.down }] : []),\n ...(useModelTypeMapping ? [{ name: '003-create-custom-field-model-type-map', up: migration003.up, down: migration003.down }] : []),\n ];\n};\n\n// Stable advisory-lock ID for sadot migrations. Chosen arbitrarily; must not\n// collide with other advisory locks in the same database.\nconst SADOT_MIGRATION_LOCK_ID = 839274628;\n\n/**\n * Runs sadot migrations via umzug. All migrations use IF NOT EXISTS / IF EXISTS,\n * so they are fully idempotent — safe to run against both fresh and existing\n * databases (including DBs previously managed by the legacy sync() path).\n *\n * When `withLock: true`, a PostgreSQL advisory lock is acquired before running\n * migrations so that when multiple pods start concurrently only one of them\n * executes the migrations. The remaining pods block until the lock is released,\n * then proceed — Umzug will see the migrations have already been applied and\n * skip them.\n *\n * @param options - Migration execution options.\n * @param options.withLock - Whether to acquire a PostgreSQL advisory lock before running the migrations. Defaults to true.\n * @returns A promise that resolves when the migrations have completed. \n */\nconst runSadotMigrations = async (sequelize: Sequelize, options: MigratorOptions = {}): Promise<void> => {\n // Need to add a new migration? full migration guide here; https://www.notion.so/autofleet/How-to-Add-a-New-Migration-to-Sadot-36db603f40b98023b239d3c61aa22b00\n const { withLock = true } = options;\n const queryInterface = sequelize.getQueryInterface() as unknown as QueryInterface;\n const storage = new SequelizeStorage({ sequelize: sequelize as never, tableName: 'sadot_migrations', modelName: 'SadotMigrations' });\n\n const umzugLogger = {\n info: (msg: Record<string, unknown>) => logger.info(`[sadot] ${JSON.stringify(msg)}`),\n warn: (msg: Record<string, unknown>) => logger.warn(`[sadot] ${JSON.stringify(msg)}`),\n error: (msg: Record<string, unknown>) => logger.error(`[sadot] ${JSON.stringify(msg)}`),\n debug: (msg: Record<string, unknown>) => logger.debug(`[sadot] ${JSON.stringify(msg)}`),\n };\n\n const migrator = new Umzug<QueryInterface>({\n migrations: buildMigrationList(options),\n context: queryInterface,\n storage,\n logger: umzugLogger,\n });\n\n const pending = await migrator.pending();\n if (pending.length === 0) {\n logger.info('[sadot] no pending migrations, skipping');\n return;\n }\n\n logger.info('[sadot] pending migrations detected', { pending: pending.map(m => m.name) });\n\n if (!withLock) {\n await migrator.up();\n return;\n }\n\n // The advisory lock holds a connection for its entire duration while\n // migrator.up() needs additional pool connections for queries. With\n // pool.max < 2 (common in test environments) this deadlocks.\n // Migrations are idempotent (IF NOT EXISTS / IF EXISTS) so running\n // without the lock is safe — just potentially duplicated work.\n const poolMax = (sequelize.options as any)?.pool?.max ?? 5;\n if (poolMax < 2) {\n logger.info('[sadot] connection pool too small for advisory lock, running migrations directly');\n await migrator.up();\n return;\n }\n\n // Use a dedicated raw connection (not a transaction) to hold the advisory lock.\n // A transaction connection sitting idle while migrator.up() runs on other pool\n // connections would be killed by idle_in_transaction_session_timeout, releasing\n // the lock prematurely and allowing a second replica to start migrations concurrently.\n logger.info('[sadot] acquiring advisory lock');\n const lockConnection = await (sequelize.connectionManager as any).getConnection({ type: 'write' });\n try {\n // Poll with pg_try_advisory_lock so the connection stays idle between attempts rather\n // than holding an active statement for the full wait duration. DDL operations that track\n // active backends between internal phases (e.g. CREATE INDEX CONCURRENTLY, VACUUM,\n // REINDEX CONCURRENTLY) wait for all active statements to finish before proceeding —\n // a long-blocking lock attempt would stall them for the entire wait.\n let lockAcquired = false;\n while (!lockAcquired) {\n const result = await lockConnection.query(`SELECT pg_try_advisory_lock(${SADOT_MIGRATION_LOCK_ID}) AS acquired`);\n lockAcquired = result.rows[0].acquired;\n if (!lockAcquired) await setTimeout(1000);\n }\n logger.info('[sadot] advisory lock acquired');\n\n // Re-check after acquiring the lock — another pod may have already\n // applied the migrations while we were waiting.\n const stillPending = await migrator.pending();\n if (stillPending.length > 0) {\n await migrator.up();\n } else {\n logger.info('[sadot] migrations already applied by another instance, skipping');\n }\n } finally {\n try {\n await lockConnection.query(`SELECT pg_advisory_unlock(${SADOT_MIGRATION_LOCK_ID})`);\n logger.info('[sadot] advisory lock released');\n } finally {\n (sequelize.connectionManager as any).releaseConnection(lockConnection);\n }\n }\n};\n\nexport { runSadotMigrations };\n"],"mappings":"qUAeA,KAAM,CAAE,QAAO,oBAAqB,QAAQ,QAAQ,CAO9C,EAAsB,GAA8D,CACxF,GAAM,CAAE,sBAAsB,IAAU,EASlC,EAAiCA,EAAAA,cAAcC,EAAAA,+BAA+B,EAAQ,CAAC,CAC7F,MAAO,CACL,CAAE,KAAM,yBAA0B,GAAA,EAAA,GAAqB,KAAA,EAAA,KAAyB,CAChF,GAAI,EAAiC,CAAC,CAAE,KAAM,kCAAmC,GAAA,EAAA,GAAqB,KAAA,EAAA,KAAyB,CAAC,CAAG,EAAE,CACrI,GAAI,EAAsB,CAAC,CAAE,KAAM,yCAA0C,GAAA,EAAA,GAAqB,KAAA,EAAA,KAAyB,CAAC,CAAG,EAAE,CAClI,EAKG,EAA0B,UAiB1B,EAAqB,MAAO,EAAsB,EAA2B,EAAE,GAAoB,CAEvG,GAAM,CAAE,WAAW,IAAS,EACtB,EAAiB,EAAU,mBAAmB,CAC9C,EAAU,IAAI,EAAiB,CAAa,YAAoB,UAAW,mBAAoB,UAAW,kBAAmB,CAAC,CAS9H,EAAW,IAAI,EAAsB,CACzC,WAAY,EAAmB,EAAQ,CACvC,QAAS,EACT,UACA,OAXkB,CAClB,KAAO,GAAiCC,EAAAA,QAAO,KAAK,WAAW,KAAK,UAAU,EAAI,GAAG,CACrF,KAAO,GAAiCA,EAAAA,QAAO,KAAK,WAAW,KAAK,UAAU,EAAI,GAAG,CACrF,MAAQ,GAAiCA,EAAAA,QAAO,MAAM,WAAW,KAAK,UAAU,EAAI,GAAG,CACvF,MAAQ,GAAiCA,EAAAA,QAAO,MAAM,WAAW,KAAK,UAAU,EAAI,GAAG,CACxF,CAOA,CAAC,CAEI,EAAU,MAAM,EAAS,SAAS,CACxC,GAAI,EAAQ,SAAW,EAAG,CACxB,EAAA,QAAO,KAAK,0CAA0C,CACtD,OAKF,GAFA,EAAA,QAAO,KAAK,sCAAuC,CAAE,QAAS,EAAQ,IAAI,GAAK,EAAE,KAAK,CAAE,CAAC,CAErF,CAAC,EAAU,CACb,MAAM,EAAS,IAAI,CACnB,OASF,IADiB,EAAU,SAAiB,MAAM,KAAO,GAC3C,EAAG,CACf,EAAA,QAAO,KAAK,mFAAmF,CAC/F,MAAM,EAAS,IAAI,CACnB,OAOF,EAAA,QAAO,KAAK,kCAAkC,CAC9C,IAAM,EAAiB,MAAO,EAAU,kBAA0B,cAAc,CAAE,KAAM,QAAS,CAAC,CAClG,GAAI,CAMF,IAAI,EAAe,GACnB,KAAO,CAAC,GAEN,GADe,MAAM,EAAe,MAAM,+BAA+B,EAAwB,eAAe,EAC1F,KAAK,GAAG,SACzB,GAAc,MAAA,EAAA,EAAA,YAAiB,IAAK,CAE3C,EAAA,QAAO,KAAK,iCAAiC,EAIxB,MAAM,EAAS,SAAS,EAC5B,OAAS,EACxB,MAAM,EAAS,IAAI,CAEnB,EAAA,QAAO,KAAK,mEAAmE,QAEzE,CACR,GAAI,CACF,MAAM,EAAe,MAAM,6BAA6B,EAAwB,GAAG,CACnF,EAAA,QAAO,KAAK,iCAAiC,QACrC,CACP,EAAU,kBAA0B,kBAAkB,EAAe"}
@@ -1,8 +1,8 @@
1
+ import { CustomFieldsEntriesModeOptions } from "../utils/custom-fields-mode.cjs";
1
2
  import { Sequelize } from "sequelize-typescript";
2
3
 
3
4
  //#region src/migrations/index.d.ts
4
- interface MigratorOptions {
5
- useCustomFieldsEntries?: boolean;
5
+ interface MigratorOptions extends CustomFieldsEntriesModeOptions {
6
6
  useModelTypeMapping?: boolean;
7
7
  withLock?: boolean;
8
8
  }
@@ -1,8 +1,8 @@
1
+ import { CustomFieldsEntriesModeOptions } from "../utils/custom-fields-mode.js";
1
2
  import { Sequelize } from "sequelize-typescript";
2
3
 
3
4
  //#region src/migrations/index.d.ts
4
- interface MigratorOptions {
5
- useCustomFieldsEntries?: boolean;
5
+ interface MigratorOptions extends CustomFieldsEntriesModeOptions {
6
6
  useModelTypeMapping?: boolean;
7
7
  withLock?: boolean;
8
8
  }
@@ -1,2 +1,2 @@
1
- import{__require as e}from"../_virtual/rolldown_runtime.js";import t from"../utils/logger/index.js";import{down as n,up as r}from"./001-create-core-tables.js";import{down as i,up as a}from"./002-create-custom-field-entries.js";import{down as o,up as s}from"./003-create-custom-field-model-type-map.js";import{setTimeout as c}from"node:timers/promises";const{Umzug:l,SequelizeStorage:u}=e(`umzug`),d=e=>{let{useCustomFieldsEntries:t=!1,useModelTypeMapping:c=!1}=e;return[{name:`001-create-core-tables`,up:r,down:n},...t?[{name:`002-create-custom-field-entries`,up:a,down:i}]:[],...c?[{name:`003-create-custom-field-model-type-map`,up:s,down:o}]:[]]},f=839274628,p=async(e,n={})=>{let{withLock:r=!0}=n,i=e.getQueryInterface(),a=new u({sequelize:e,tableName:`sadot_migrations`,modelName:`SadotMigrations`}),o=new l({migrations:d(n),context:i,storage:a,logger:{info:e=>t.info(`[sadot] ${JSON.stringify(e)}`),warn:e=>t.warn(`[sadot] ${JSON.stringify(e)}`),error:e=>t.error(`[sadot] ${JSON.stringify(e)}`),debug:e=>t.debug(`[sadot] ${JSON.stringify(e)}`)}}),s=await o.pending();if(s.length===0){t.info(`[sadot] no pending migrations, skipping`);return}if(t.info(`[sadot] pending migrations detected`,{pending:s.map(e=>e.name)}),!r){await o.up();return}if((e.options?.pool?.max??5)<2){t.info(`[sadot] connection pool too small for advisory lock, running migrations directly`),await o.up();return}t.info(`[sadot] acquiring advisory lock`);let p=await e.connectionManager.getConnection({type:`write`});try{let e=!1;for(;!e;)e=(await p.query(`SELECT pg_try_advisory_lock(${f}) AS acquired`)).rows[0].acquired,e||await c(1e3);t.info(`[sadot] advisory lock acquired`),(await o.pending()).length>0?await o.up():t.info(`[sadot] migrations already applied by another instance, skipping`)}finally{try{await p.query(`SELECT pg_advisory_unlock(${f})`),t.info(`[sadot] advisory lock released`)}finally{e.connectionManager.releaseConnection(p)}}};export{p as runSadotMigrations};
1
+ import{__require as e}from"../_virtual/rolldown_runtime.js";import t from"../utils/logger/index.js";import{resolveCustomFieldsEntriesMode as n,writesEntries as r}from"../utils/custom-fields-mode.js";import{down as i,up as a}from"./001-create-core-tables.js";import{down as o,up as s}from"./002-create-custom-field-entries.js";import{down as c,up as l}from"./003-create-custom-field-model-type-map.js";import{setTimeout as u}from"node:timers/promises";const{Umzug:d,SequelizeStorage:f}=e(`umzug`),p=e=>{let{useModelTypeMapping:t=!1}=e,u=r(n(e));return[{name:`001-create-core-tables`,up:a,down:i},...u?[{name:`002-create-custom-field-entries`,up:s,down:o}]:[],...t?[{name:`003-create-custom-field-model-type-map`,up:l,down:c}]:[]]},m=839274628,h=async(e,n={})=>{let{withLock:r=!0}=n,i=e.getQueryInterface(),a=new f({sequelize:e,tableName:`sadot_migrations`,modelName:`SadotMigrations`}),o=new d({migrations:p(n),context:i,storage:a,logger:{info:e=>t.info(`[sadot] ${JSON.stringify(e)}`),warn:e=>t.warn(`[sadot] ${JSON.stringify(e)}`),error:e=>t.error(`[sadot] ${JSON.stringify(e)}`),debug:e=>t.debug(`[sadot] ${JSON.stringify(e)}`)}}),s=await o.pending();if(s.length===0){t.info(`[sadot] no pending migrations, skipping`);return}if(t.info(`[sadot] pending migrations detected`,{pending:s.map(e=>e.name)}),!r){await o.up();return}if((e.options?.pool?.max??5)<2){t.info(`[sadot] connection pool too small for advisory lock, running migrations directly`),await o.up();return}t.info(`[sadot] acquiring advisory lock`);let c=await e.connectionManager.getConnection({type:`write`});try{let e=!1;for(;!e;)e=(await c.query(`SELECT pg_try_advisory_lock(${m}) AS acquired`)).rows[0].acquired,e||await u(1e3);t.info(`[sadot] advisory lock acquired`),(await o.pending()).length>0?await o.up():t.info(`[sadot] migrations already applied by another instance, skipping`)}finally{try{await c.query(`SELECT pg_advisory_unlock(${m})`),t.info(`[sadot] advisory lock released`)}finally{e.connectionManager.releaseConnection(c)}}};export{h as runSadotMigrations};
2
2
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["migration001.up","migration001.down","migration002.up","migration002.down","migration003.up","migration003.down","logger"],"sources":["../../src/migrations/index.ts"],"sourcesContent":["import type { InputMigrations } from 'umzug';\nimport type { QueryInterface } from 'sequelize';\nimport type { Sequelize } from 'sequelize-typescript';\nimport { setTimeout } from 'node:timers/promises';\nimport logger from '../utils/logger';\nimport * as migration001 from './001-create-core-tables';\nimport * as migration002 from './002-create-custom-field-entries';\nimport * as migration003 from './003-create-custom-field-model-type-map';\n\n// umzug is CJS. Static ESM named imports break in vitest after vi.resetModules()\n// because Vite's SSR transform re-evaluates the module outside the inline bundle.\n// require() goes through Node's native CJS loader and is stable across resets.\n\n// eslint-disable-next-line import/no-commonjs\nconst { Umzug, SequelizeStorage } = require('umzug') as typeof import('umzug');\n\ninterface MigratorOptions {\n useCustomFieldsEntries?: boolean;\n useModelTypeMapping?: boolean;\n withLock?: boolean;\n}\n\nconst buildMigrationList = (options: MigratorOptions): InputMigrations<QueryInterface> => {\n const { useCustomFieldsEntries = false, useModelTypeMapping = false } = options;\n return [\n { name: '001-create-core-tables', up: migration001.up, down: migration001.down },\n ...(useCustomFieldsEntries ? [{ name: '002-create-custom-field-entries', up: migration002.up, down: migration002.down }] : []),\n ...(useModelTypeMapping ? [{ name: '003-create-custom-field-model-type-map', up: migration003.up, down: migration003.down }] : []),\n ];\n};\n\n// Stable advisory-lock ID for sadot migrations. Chosen arbitrarily; must not\n// collide with other advisory locks in the same database.\nconst SADOT_MIGRATION_LOCK_ID = 839274628;\n\n/**\n * Runs sadot migrations via umzug. All migrations use IF NOT EXISTS / IF EXISTS,\n * so they are fully idempotent — safe to run against both fresh and existing\n * databases (including DBs previously managed by the legacy sync() path).\n *\n * When `withLock: true`, a PostgreSQL advisory lock is acquired before running\n * migrations so that when multiple pods start concurrently only one of them\n * executes the migrations. The remaining pods block until the lock is released,\n * then proceed — Umzug will see the migrations have already been applied and\n * skip them.\n *\n * @param options - Migration execution options.\n * @param options.withLock - Whether to acquire a PostgreSQL advisory lock before running the migrations. Defaults to true.\n * @returns A promise that resolves when the migrations have completed. \n */\nconst runSadotMigrations = async (sequelize: Sequelize, options: MigratorOptions = {}): Promise<void> => {\n // Need to add a new migration? full migration guide here; https://www.notion.so/autofleet/How-to-Add-a-New-Migration-to-Sadot-36db603f40b98023b239d3c61aa22b00\n const { withLock = true } = options;\n const queryInterface = sequelize.getQueryInterface() as unknown as QueryInterface;\n const storage = new SequelizeStorage({ sequelize: sequelize as never, tableName: 'sadot_migrations', modelName: 'SadotMigrations' });\n\n const umzugLogger = {\n info: (msg: Record<string, unknown>) => logger.info(`[sadot] ${JSON.stringify(msg)}`),\n warn: (msg: Record<string, unknown>) => logger.warn(`[sadot] ${JSON.stringify(msg)}`),\n error: (msg: Record<string, unknown>) => logger.error(`[sadot] ${JSON.stringify(msg)}`),\n debug: (msg: Record<string, unknown>) => logger.debug(`[sadot] ${JSON.stringify(msg)}`),\n };\n\n const migrator = new Umzug<QueryInterface>({\n migrations: buildMigrationList(options),\n context: queryInterface,\n storage,\n logger: umzugLogger,\n });\n\n const pending = await migrator.pending();\n if (pending.length === 0) {\n logger.info('[sadot] no pending migrations, skipping');\n return;\n }\n\n logger.info('[sadot] pending migrations detected', { pending: pending.map(m => m.name) });\n\n if (!withLock) {\n await migrator.up();\n return;\n }\n\n // The advisory lock holds a connection for its entire duration while\n // migrator.up() needs additional pool connections for queries. With\n // pool.max < 2 (common in test environments) this deadlocks.\n // Migrations are idempotent (IF NOT EXISTS / IF EXISTS) so running\n // without the lock is safe — just potentially duplicated work.\n const poolMax = (sequelize.options as any)?.pool?.max ?? 5;\n if (poolMax < 2) {\n logger.info('[sadot] connection pool too small for advisory lock, running migrations directly');\n await migrator.up();\n return;\n }\n\n // Use a dedicated raw connection (not a transaction) to hold the advisory lock.\n // A transaction connection sitting idle while migrator.up() runs on other pool\n // connections would be killed by idle_in_transaction_session_timeout, releasing\n // the lock prematurely and allowing a second replica to start migrations concurrently.\n logger.info('[sadot] acquiring advisory lock');\n const lockConnection = await (sequelize.connectionManager as any).getConnection({ type: 'write' });\n try {\n // Poll with pg_try_advisory_lock so the connection stays idle between attempts rather\n // than holding an active statement for the full wait duration. DDL operations that track\n // active backends between internal phases (e.g. CREATE INDEX CONCURRENTLY, VACUUM,\n // REINDEX CONCURRENTLY) wait for all active statements to finish before proceeding —\n // a long-blocking lock attempt would stall them for the entire wait.\n let lockAcquired = false;\n while (!lockAcquired) {\n const result = await lockConnection.query(`SELECT pg_try_advisory_lock(${SADOT_MIGRATION_LOCK_ID}) AS acquired`);\n lockAcquired = result.rows[0].acquired;\n if (!lockAcquired) await setTimeout(1000);\n }\n logger.info('[sadot] advisory lock acquired');\n\n // Re-check after acquiring the lock — another pod may have already\n // applied the migrations while we were waiting.\n const stillPending = await migrator.pending();\n if (stillPending.length > 0) {\n await migrator.up();\n } else {\n logger.info('[sadot] migrations already applied by another instance, skipping');\n }\n } finally {\n try {\n await lockConnection.query(`SELECT pg_advisory_unlock(${SADOT_MIGRATION_LOCK_ID})`);\n logger.info('[sadot] advisory lock released');\n } finally {\n (sequelize.connectionManager as any).releaseConnection(lockConnection);\n }\n }\n};\n\nexport { runSadotMigrations };\n"],"mappings":"gWAcA,KAAM,CAAE,QAAO,oBAAA,EAA6B,QAAQ,CAQ9C,EAAsB,GAA8D,CACxF,GAAM,CAAE,yBAAyB,GAAO,sBAAsB,IAAU,EACxE,MAAO,CACL,CAAE,KAAM,yBAA8BA,KAAuBC,OAAmB,CAChF,GAAI,EAAyB,CAAC,CAAE,KAAM,kCAAmC,GAAIC,EAAiB,KAAMC,EAAmB,CAAC,CAAG,EAAE,CAC7H,GAAI,EAAsB,CAAC,CAAE,KAAM,yCAA0C,GAAIC,EAAiB,KAAMC,EAAmB,CAAC,CAAG,EAAE,CAClI,EAKG,EAA0B,UAiB1B,EAAqB,MAAO,EAAsB,EAA2B,EAAE,GAAoB,CAEvG,GAAM,CAAE,WAAW,IAAS,EACtB,EAAiB,EAAU,mBAAmB,CAC9C,EAAU,IAAI,EAAiB,CAAa,YAAoB,UAAW,mBAAoB,UAAW,kBAAmB,CAAC,CAS9H,EAAW,IAAI,EAAsB,CACzC,WAAY,EAAmB,EAAQ,CACvC,QAAS,EACT,UACA,OAXkB,CAClB,KAAO,GAAiCC,EAAO,KAAK,WAAW,KAAK,UAAU,EAAI,GAAG,CACrF,KAAO,GAAiCA,EAAO,KAAK,WAAW,KAAK,UAAU,EAAI,GAAG,CACrF,MAAQ,GAAiCA,EAAO,MAAM,WAAW,KAAK,UAAU,EAAI,GAAG,CACvF,MAAQ,GAAiCA,EAAO,MAAM,WAAW,KAAK,UAAU,EAAI,GAAG,CACxF,CAOA,CAAC,CAEI,EAAU,MAAM,EAAS,SAAS,CACxC,GAAI,EAAQ,SAAW,EAAG,CACxB,EAAO,KAAK,0CAA0C,CACtD,OAKF,GAFA,EAAO,KAAK,sCAAuC,CAAE,QAAS,EAAQ,IAAI,GAAK,EAAE,KAAK,CAAE,CAAC,CAErF,CAAC,EAAU,CACb,MAAM,EAAS,IAAI,CACnB,OASF,IADiB,EAAU,SAAiB,MAAM,KAAO,GAC3C,EAAG,CACf,EAAO,KAAK,mFAAmF,CAC/F,MAAM,EAAS,IAAI,CACnB,OAOF,EAAO,KAAK,kCAAkC,CAC9C,IAAM,EAAiB,MAAO,EAAU,kBAA0B,cAAc,CAAE,KAAM,QAAS,CAAC,CAClG,GAAI,CAMF,IAAI,EAAe,GACnB,KAAO,CAAC,GAEN,GADe,MAAM,EAAe,MAAM,+BAA+B,EAAwB,eAAe,EAC1F,KAAK,GAAG,SACzB,GAAc,MAAM,EAAW,IAAK,CAE3C,EAAO,KAAK,iCAAiC,EAIxB,MAAM,EAAS,SAAS,EAC5B,OAAS,EACxB,MAAM,EAAS,IAAI,CAEnB,EAAO,KAAK,mEAAmE,QAEzE,CACR,GAAI,CACF,MAAM,EAAe,MAAM,6BAA6B,EAAwB,GAAG,CACnF,EAAO,KAAK,iCAAiC,QACrC,CACP,EAAU,kBAA0B,kBAAkB,EAAe"}
1
+ {"version":3,"file":"index.js","names":["migration001.up","migration001.down","migration002.up","migration002.down","migration003.up","migration003.down","logger"],"sources":["../../src/migrations/index.ts"],"sourcesContent":["import type { InputMigrations } from 'umzug';\nimport type { QueryInterface } from 'sequelize';\nimport type { Sequelize } from 'sequelize-typescript';\nimport { setTimeout } from 'node:timers/promises';\nimport logger from '../utils/logger';\nimport { type CustomFieldsEntriesModeOptions, resolveCustomFieldsEntriesMode, writesEntries } from '../utils/custom-fields-mode';\nimport * as migration001 from './001-create-core-tables';\nimport * as migration002 from './002-create-custom-field-entries';\nimport * as migration003 from './003-create-custom-field-model-type-map';\n\n// umzug is CJS. Static ESM named imports break in vitest after vi.resetModules()\n// because Vite's SSR transform re-evaluates the module outside the inline bundle.\n// require() goes through Node's native CJS loader and is stable across resets.\n\n// eslint-disable-next-line import/no-commonjs\nconst { Umzug, SequelizeStorage } = require('umzug') as typeof import('umzug');\n\ninterface MigratorOptions extends CustomFieldsEntriesModeOptions {\n useModelTypeMapping?: boolean;\n withLock?: boolean;\n}\n\nconst buildMigrationList = (options: MigratorOptions): InputMigrations<QueryInterface> => {\n const { useModelTypeMapping = false } = options;\n // The table is needed as soon as anything writes to it, and every mode that reads\n // entries also writes them, so `writesEntries` is the widest gate. Keying this off\n // `readsEntries` would leave a WRITE_ONLY service inserting into a missing table.\n //\n // Migrations only need this boolean — WRITE_ONLY and READ_AND_WRITE are the same\n // answer here. The full mode is accepted anyway so a service passes one shared\n // constant to both this and useCustomFields(), rather than keeping a separate\n // migration-only boolean in sync with the runtime mode.\n const shouldRunEntriesTableMigration = writesEntries(resolveCustomFieldsEntriesMode(options));\n return [\n { name: '001-create-core-tables', up: migration001.up, down: migration001.down },\n ...(shouldRunEntriesTableMigration ? [{ name: '002-create-custom-field-entries', up: migration002.up, down: migration002.down }] : []),\n ...(useModelTypeMapping ? [{ name: '003-create-custom-field-model-type-map', up: migration003.up, down: migration003.down }] : []),\n ];\n};\n\n// Stable advisory-lock ID for sadot migrations. Chosen arbitrarily; must not\n// collide with other advisory locks in the same database.\nconst SADOT_MIGRATION_LOCK_ID = 839274628;\n\n/**\n * Runs sadot migrations via umzug. All migrations use IF NOT EXISTS / IF EXISTS,\n * so they are fully idempotent — safe to run against both fresh and existing\n * databases (including DBs previously managed by the legacy sync() path).\n *\n * When `withLock: true`, a PostgreSQL advisory lock is acquired before running\n * migrations so that when multiple pods start concurrently only one of them\n * executes the migrations. The remaining pods block until the lock is released,\n * then proceed — Umzug will see the migrations have already been applied and\n * skip them.\n *\n * @param options - Migration execution options.\n * @param options.withLock - Whether to acquire a PostgreSQL advisory lock before running the migrations. Defaults to true.\n * @returns A promise that resolves when the migrations have completed. \n */\nconst runSadotMigrations = async (sequelize: Sequelize, options: MigratorOptions = {}): Promise<void> => {\n // Need to add a new migration? full migration guide here; https://www.notion.so/autofleet/How-to-Add-a-New-Migration-to-Sadot-36db603f40b98023b239d3c61aa22b00\n const { withLock = true } = options;\n const queryInterface = sequelize.getQueryInterface() as unknown as QueryInterface;\n const storage = new SequelizeStorage({ sequelize: sequelize as never, tableName: 'sadot_migrations', modelName: 'SadotMigrations' });\n\n const umzugLogger = {\n info: (msg: Record<string, unknown>) => logger.info(`[sadot] ${JSON.stringify(msg)}`),\n warn: (msg: Record<string, unknown>) => logger.warn(`[sadot] ${JSON.stringify(msg)}`),\n error: (msg: Record<string, unknown>) => logger.error(`[sadot] ${JSON.stringify(msg)}`),\n debug: (msg: Record<string, unknown>) => logger.debug(`[sadot] ${JSON.stringify(msg)}`),\n };\n\n const migrator = new Umzug<QueryInterface>({\n migrations: buildMigrationList(options),\n context: queryInterface,\n storage,\n logger: umzugLogger,\n });\n\n const pending = await migrator.pending();\n if (pending.length === 0) {\n logger.info('[sadot] no pending migrations, skipping');\n return;\n }\n\n logger.info('[sadot] pending migrations detected', { pending: pending.map(m => m.name) });\n\n if (!withLock) {\n await migrator.up();\n return;\n }\n\n // The advisory lock holds a connection for its entire duration while\n // migrator.up() needs additional pool connections for queries. With\n // pool.max < 2 (common in test environments) this deadlocks.\n // Migrations are idempotent (IF NOT EXISTS / IF EXISTS) so running\n // without the lock is safe — just potentially duplicated work.\n const poolMax = (sequelize.options as any)?.pool?.max ?? 5;\n if (poolMax < 2) {\n logger.info('[sadot] connection pool too small for advisory lock, running migrations directly');\n await migrator.up();\n return;\n }\n\n // Use a dedicated raw connection (not a transaction) to hold the advisory lock.\n // A transaction connection sitting idle while migrator.up() runs on other pool\n // connections would be killed by idle_in_transaction_session_timeout, releasing\n // the lock prematurely and allowing a second replica to start migrations concurrently.\n logger.info('[sadot] acquiring advisory lock');\n const lockConnection = await (sequelize.connectionManager as any).getConnection({ type: 'write' });\n try {\n // Poll with pg_try_advisory_lock so the connection stays idle between attempts rather\n // than holding an active statement for the full wait duration. DDL operations that track\n // active backends between internal phases (e.g. CREATE INDEX CONCURRENTLY, VACUUM,\n // REINDEX CONCURRENTLY) wait for all active statements to finish before proceeding —\n // a long-blocking lock attempt would stall them for the entire wait.\n let lockAcquired = false;\n while (!lockAcquired) {\n const result = await lockConnection.query(`SELECT pg_try_advisory_lock(${SADOT_MIGRATION_LOCK_ID}) AS acquired`);\n lockAcquired = result.rows[0].acquired;\n if (!lockAcquired) await setTimeout(1000);\n }\n logger.info('[sadot] advisory lock acquired');\n\n // Re-check after acquiring the lock — another pod may have already\n // applied the migrations while we were waiting.\n const stillPending = await migrator.pending();\n if (stillPending.length > 0) {\n await migrator.up();\n } else {\n logger.info('[sadot] migrations already applied by another instance, skipping');\n }\n } finally {\n try {\n await lockConnection.query(`SELECT pg_advisory_unlock(${SADOT_MIGRATION_LOCK_ID})`);\n logger.info('[sadot] advisory lock released');\n } finally {\n (sequelize.connectionManager as any).releaseConnection(lockConnection);\n }\n }\n};\n\nexport { runSadotMigrations };\n"],"mappings":"mcAeA,KAAM,CAAE,QAAO,oBAAA,EAA6B,QAAQ,CAO9C,EAAsB,GAA8D,CACxF,GAAM,CAAE,sBAAsB,IAAU,EASlC,EAAiC,EAAc,EAA+B,EAAQ,CAAC,CAC7F,MAAO,CACL,CAAE,KAAM,yBAA8BA,KAAuBC,OAAmB,CAChF,GAAI,EAAiC,CAAC,CAAE,KAAM,kCAAmC,GAAIC,EAAiB,KAAMC,EAAmB,CAAC,CAAG,EAAE,CACrI,GAAI,EAAsB,CAAC,CAAE,KAAM,yCAA0C,GAAIC,EAAiB,KAAMC,EAAmB,CAAC,CAAG,EAAE,CAClI,EAKG,EAA0B,UAiB1B,EAAqB,MAAO,EAAsB,EAA2B,EAAE,GAAoB,CAEvG,GAAM,CAAE,WAAW,IAAS,EACtB,EAAiB,EAAU,mBAAmB,CAC9C,EAAU,IAAI,EAAiB,CAAa,YAAoB,UAAW,mBAAoB,UAAW,kBAAmB,CAAC,CAS9H,EAAW,IAAI,EAAsB,CACzC,WAAY,EAAmB,EAAQ,CACvC,QAAS,EACT,UACA,OAXkB,CAClB,KAAO,GAAiCC,EAAO,KAAK,WAAW,KAAK,UAAU,EAAI,GAAG,CACrF,KAAO,GAAiCA,EAAO,KAAK,WAAW,KAAK,UAAU,EAAI,GAAG,CACrF,MAAQ,GAAiCA,EAAO,MAAM,WAAW,KAAK,UAAU,EAAI,GAAG,CACvF,MAAQ,GAAiCA,EAAO,MAAM,WAAW,KAAK,UAAU,EAAI,GAAG,CACxF,CAOA,CAAC,CAEI,EAAU,MAAM,EAAS,SAAS,CACxC,GAAI,EAAQ,SAAW,EAAG,CACxB,EAAO,KAAK,0CAA0C,CACtD,OAKF,GAFA,EAAO,KAAK,sCAAuC,CAAE,QAAS,EAAQ,IAAI,GAAK,EAAE,KAAK,CAAE,CAAC,CAErF,CAAC,EAAU,CACb,MAAM,EAAS,IAAI,CACnB,OASF,IADiB,EAAU,SAAiB,MAAM,KAAO,GAC3C,EAAG,CACf,EAAO,KAAK,mFAAmF,CAC/F,MAAM,EAAS,IAAI,CACnB,OAOF,EAAO,KAAK,kCAAkC,CAC9C,IAAM,EAAiB,MAAO,EAAU,kBAA0B,cAAc,CAAE,KAAM,QAAS,CAAC,CAClG,GAAI,CAMF,IAAI,EAAe,GACnB,KAAO,CAAC,GAEN,GADe,MAAM,EAAe,MAAM,+BAA+B,EAAwB,eAAe,EAC1F,KAAK,GAAG,SACzB,GAAc,MAAM,EAAW,IAAK,CAE3C,EAAO,KAAK,iCAAiC,EAIxB,MAAM,EAAS,SAAS,EAC5B,OAAS,EACxB,MAAM,EAAS,IAAI,CAEnB,EAAO,KAAK,mEAAmE,QAEzE,CACR,GAAI,CACF,MAAM,EAAe,MAAM,6BAA6B,EAAwB,GAAG,CACnF,EAAO,KAAK,iCAAiC,QACrC,CACP,EAAU,kBAA0B,kBAAkB,EAAe"}
@@ -1,2 +1,2 @@
1
- const e=require(`../_virtual/rolldown_runtime.cjs`),t=require(`../utils/logger/index.cjs`),n=require(`./CustomFieldValue.cjs`),r=require(`./CustomFieldDefinition.cjs`),i=require(`./tests/AssociatedTestModel.cjs`),a=require(`./tests/TestModel.cjs`),o=require(`./tests/contextAwareModels/ContextTestModel.cjs`),s=require(`./tests/contextAwareModels/ContextAwareTestModel.cjs`),c=require(`./CustomFieldEntries.cjs`),l=require(`./CustomValidator.cjs`),u=require(`./CustomFieldModelTypeMap.cjs`),d=require(`../migrations/index.cjs`);let f=require(`sequelize`);const p=[a.default,i.default,s.default,o.default],m=`sadot-migration`,h=`5f8e4a7c-9b2d-4e1f-8c3a-b6d9e2f7a4c1`,g=async(e,{schemaPrefix:i,schemaVersion:a,useCustomFieldsEntries:o,useModelTypeMapping:s})=>{let d=e.define(`SequelizeMeta`,{name:{type:f.DataTypes.STRING,allowNull:!1,unique:!0,primaryKey:!0,autoIncrement:!1}},{tableName:`SequelizeMeta`,timestamps:!1,schema:`public`});t.default.info(`custom-fields: starting migrations`);let p=await d.findAll({where:{name:{[f.Op.like]:`${i}%`}},raw:!0}),m=p.at(-1),h=p.findIndex(e=>e.name===a);if(t.default.info(`custom-fields: migrations`,{currentMigrations:p,currentSadotSchemaVersion:m,newSadotSchemaVersion:a,expectedSchemaVersionIndex:h}),!m||m.name!==a){t.default.info(`custom-fields: syncing models`);try{if(await r.default.sync({alter:!0}),t.default.info(`custom-fields: CustomFieldDefinition synced successfully`),await n.default.sync({alter:!0}),t.default.info(`custom-fields: CustomFieldValue synced successfully`),await l.default.sync({alter:!0}),t.default.info(`custom-fields: CustomValidator synced successfully`),o&&(await c.default.sync({alter:!0}),t.default.info(`custom-fields: CustomFieldEntries synced successfully`)),s&&(await u.default.sync({alter:!0}),t.default.info(`custom-fields: CustomFieldModelTypeMap synced successfully`)),h===-1&&(await d.create({name:a}),t.default.info(`custom-fields: SequelizeMeta entry created successfully`)),t.default.info(`custom-fields: models synced`),p.length&&h!==-1&&h<p.length-1){let e=p.slice(h+1);t.default.info(`custom-fields: deleting newer migrations during down migration`,{count:e.length}),await d.destroy({where:{name:{[f.Op.in]:e.map(e=>e.name)}}}),t.default.info(`custom-fields: newer migrations deleted successfully`)}}catch(e){throw t.default.error(`custom-fields: failed to sync models`,{error:e}),e}}},_=async(e,i,{schemaPrefix:a=`sadot-migration`,schemaVersion:o=`5f8e4a7c-9b2d-4e1f-8c3a-b6d9e2f7a4c1`,useCustomFieldsEntries:s=!1,useModelTypeMapping:f=!1,runLegacyMigrations:p=!1,skipMigrations:m=!1,isMatPathEnabled:h}={})=>{let _=`${a}_${o}${s?`_withEntries`:``}${f?`_withTypeMapping`:``}`;if(t.default.info(`custom-fields: initialize custom-fields tables`),!e.addModels)throw Error(`sequelize instance must have addModels function`);let v=[r.default,n.default,l.default,...s?[c.default]:[],...f?[u.default]:[]];e.addModels(v),f&&(r.default.hasMany(u.default,{foreignKey:`customFieldDefinitionId`,as:`modelTypeMappings`}),u.default.belongsTo(r.default,{foreignKey:`customFieldDefinitionId`,as:`customFieldDefinition`})),r.default.addScope(`userScope`,()=>{if(h?.())return{};let e=i();return e?.permissions?{where:{entityId:[...Object.keys(e.permissions.fleets),...Object.keys(e.permissions.businessModels),...Object.keys(e.permissions.demandSources)]}}:{}}),l.default.addScope(`userScope`,()=>{if(h?.())return{};let e=i();return e?.permissions?{where:{entityId:[...Object.keys(e.permissions.fleets),...Object.keys(e.permissions.businessModels),...Object.keys(e.permissions.demandSources)]}}:{}}),t.default.info(`custom-fields: models added`),m?t.default.info(`custom-fields: skipping migrations`):p?(t.default.info(`custom-fields: running legacy sync migrations`),await g(e,{schemaPrefix:a,schemaVersion:_,useCustomFieldsEntries:s,useModelTypeMapping:f}),t.default.info(`custom-fields: umzug legacy sync migrations completed`)):(t.default.info(`custom-fields: starting umzug migrations`),await d.runSadotMigrations(e,{useCustomFieldsEntries:s,useModelTypeMapping:f}),t.default.info(`custom-fields: umzug migrations complete`))},v=async e=>{if(t.default.info(`custom-fields: initialize custom-fields test models`),!e.addModels)throw Error(`sequelize instance must have addModels function`);e.addModels(p),await e.dropSchema(`custom-fields`,{logging:!1}),await e.createSchema(`custom-fields`,{logging:!1}),t.default.info(`custom-fields: test models added`),await a.default.sync({alter:!0}),await i.default.sync({alter:!0}),await o.default.sync({alter:!0}),await s.default.sync({alter:!0}),t.default.info(`custom-fields: test models synced`)};exports.initTables=_,exports.initTestModels=v;
1
+ const e=require(`../_virtual/rolldown_runtime.cjs`),t=require(`../utils/logger/index.cjs`),n=require(`./CustomFieldValue.cjs`),r=require(`./CustomFieldDefinition.cjs`),i=require(`./tests/AssociatedTestModel.cjs`),a=require(`./tests/TestModel.cjs`),o=require(`./tests/contextAwareModels/ContextTestModel.cjs`),s=require(`./tests/contextAwareModels/ContextAwareTestModel.cjs`),c=require(`./CustomFieldEntries.cjs`),l=require(`./CustomValidator.cjs`),u=require(`./CustomFieldModelTypeMap.cjs`),d=require(`../utils/custom-fields-mode.cjs`),f=require(`../migrations/index.cjs`);let p=require(`sequelize`);const m=[a.default,i.default,s.default,o.default],h=`sadot-migration`,g=`5f8e4a7c-9b2d-4e1f-8c3a-b6d9e2f7a4c1`,_=async(e,{schemaPrefix:i,schemaVersion:a,customFieldsEntriesMode:o,useModelTypeMapping:s})=>{let f=e.define(`SequelizeMeta`,{name:{type:p.DataTypes.STRING,allowNull:!1,unique:!0,primaryKey:!0,autoIncrement:!1}},{tableName:`SequelizeMeta`,timestamps:!1,schema:`public`});t.default.info(`custom-fields: starting migrations`);let m=await f.findAll({where:{name:{[p.Op.like]:`${i}%`}},raw:!0}),h=m.at(-1),g=m.findIndex(e=>e.name===a);if(t.default.info(`custom-fields: migrations`,{currentMigrations:m,currentSadotSchemaVersion:h,newSadotSchemaVersion:a,expectedSchemaVersionIndex:g}),!h||h.name!==a){t.default.info(`custom-fields: syncing models`);try{if(await r.default.sync({alter:!0}),t.default.info(`custom-fields: CustomFieldDefinition synced successfully`),await n.default.sync({alter:!0}),t.default.info(`custom-fields: CustomFieldValue synced successfully`),await l.default.sync({alter:!0}),t.default.info(`custom-fields: CustomValidator synced successfully`),d.writesEntries(o)&&(await c.default.sync({alter:!0}),t.default.info(`custom-fields: CustomFieldEntries synced successfully`)),s&&(await u.default.sync({alter:!0}),t.default.info(`custom-fields: CustomFieldModelTypeMap synced successfully`)),g===-1&&(await f.create({name:a}),t.default.info(`custom-fields: SequelizeMeta entry created successfully`)),t.default.info(`custom-fields: models synced`),m.length&&g!==-1&&g<m.length-1){let e=m.slice(g+1);t.default.info(`custom-fields: deleting newer migrations during down migration`,{count:e.length}),await f.destroy({where:{name:{[p.Op.in]:e.map(e=>e.name)}}}),t.default.info(`custom-fields: newer migrations deleted successfully`)}}catch(e){throw t.default.error(`custom-fields: failed to sync models`,{error:e}),e}}},v=async(e,i,{schemaPrefix:a=`sadot-migration`,schemaVersion:o=`5f8e4a7c-9b2d-4e1f-8c3a-b6d9e2f7a4c1`,customFieldsEntriesMode:s=d.CUSTOM_FIELDS_ENTRIES_MODE.DISABLED,useModelTypeMapping:p=!1,runLegacyMigrations:m=!1,skipMigrations:h=!1,isMatPathEnabled:g}={})=>{let v=d.writesEntries(s),y=`${a}_${o}${v?`_withEntries`:``}${p?`_withTypeMapping`:``}`;if(t.default.info(`custom-fields: initialize custom-fields tables`),!e.addModels)throw Error(`sequelize instance must have addModels function`);let b=[r.default,n.default,l.default,...v?[c.default]:[],...p?[u.default]:[]];e.addModels(b),p&&(r.default.hasMany(u.default,{foreignKey:`customFieldDefinitionId`,as:`modelTypeMappings`}),u.default.belongsTo(r.default,{foreignKey:`customFieldDefinitionId`,as:`customFieldDefinition`})),r.default.addScope(`userScope`,()=>{if(g?.())return{};let e=i();return e?.permissions?{where:{entityId:[...Object.keys(e.permissions.fleets),...Object.keys(e.permissions.businessModels),...Object.keys(e.permissions.demandSources)]}}:{}}),l.default.addScope(`userScope`,()=>{if(g?.())return{};let e=i();return e?.permissions?{where:{entityId:[...Object.keys(e.permissions.fleets),...Object.keys(e.permissions.businessModels),...Object.keys(e.permissions.demandSources)]}}:{}}),t.default.info(`custom-fields: models added`),h?t.default.info(`custom-fields: skipping migrations`):m?(t.default.info(`custom-fields: running legacy sync migrations`),await _(e,{schemaPrefix:a,schemaVersion:y,customFieldsEntriesMode:s,useModelTypeMapping:p}),t.default.info(`custom-fields: umzug legacy sync migrations completed`)):(t.default.info(`custom-fields: starting umzug migrations`),await f.runSadotMigrations(e,{customFieldsEntriesMode:s,useModelTypeMapping:p}),t.default.info(`custom-fields: umzug migrations complete`))},y=async e=>{if(t.default.info(`custom-fields: initialize custom-fields test models`),!e.addModels)throw Error(`sequelize instance must have addModels function`);e.addModels(m),await e.dropSchema(`custom-fields`,{logging:!1}),await e.createSchema(`custom-fields`,{logging:!1}),t.default.info(`custom-fields: test models added`),await a.default.sync({alter:!0}),await i.default.sync({alter:!0}),await o.default.sync({alter:!0}),await s.default.sync({alter:!0}),t.default.info(`custom-fields: test models synced`)};exports.initTables=v,exports.initTestModels=y;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["TestModel","AssociatedTestModel","ContextAwareTestModel","ContextTestModel","sequelize","DataTypes","Op","CustomFieldDefinition","CustomFieldValue","CustomValidator","CustomFieldEntries","CustomFieldModelTypeMap","productionModels: ProductionModel[]","runSadotMigrations"],"sources":["../../src/models/index.ts"],"sourcesContent":["import { DataTypes, Op } from 'sequelize';\nimport type { Sequelize } from 'sequelize-typescript';\nimport logger from '../utils/logger';\nimport CustomFieldDefinition from './CustomFieldDefinition';\nimport CustomFieldValue from './CustomFieldValue';\nimport TestModel from './tests/TestModel';\nimport ContextAwareTestModel from './tests/contextAwareModels/ContextAwareTestModel';\nimport ContextTestModel from './tests/contextAwareModels/ContextTestModel';\nimport AssociatedTestModel from './tests/AssociatedTestModel';\nimport type { CustomFieldOptions } from '../types';\nimport CustomFieldEntries from './CustomFieldEntries';\nimport CustomValidator from './CustomValidator';\nimport CustomFieldModelTypeMap from './CustomFieldModelTypeMap';\nimport { runSadotMigrations } from '../migrations';\n\ntype ProductionModel = typeof CustomFieldDefinition | typeof CustomFieldValue | typeof CustomFieldEntries | typeof CustomValidator | typeof CustomFieldModelTypeMap;\ninterface InitTablesOptions {\n schemaPrefix?: string;\n schemaVersion?: string;\n useCustomFieldsEntries?: boolean;\n useModelTypeMapping?: boolean;\n runLegacyMigrations?: boolean;\n skipMigrations?: boolean;\n isMatPathEnabled?: CustomFieldOptions['isMatPathEnabled'];\n}\n\nconst testModels = [TestModel, AssociatedTestModel, ContextAwareTestModel, ContextTestModel];\n\nconst SADOT_MIGRATION_PREFIX = 'sadot-migration';\nconst SCHEMA_VERSION = '5f8e4a7c-9b2d-4e1f-8c3a-b6d9e2f7a4c1';\n\n/**\n * Legacy migration approach using sequelize.sync({ alter: true }).\n * TODO: Remove this function once all consumers have migrated to umzug.\n */\nconst legacySyncMigrations = async (\n sequelize: Sequelize,\n {\n schemaPrefix,\n schemaVersion,\n useCustomFieldsEntries,\n useModelTypeMapping,\n }: { schemaPrefix: string; schemaVersion: string; useCustomFieldsEntries: boolean; useModelTypeMapping: boolean; },\n): Promise<void> => {\n const SequelizeMeta = sequelize.define(\n 'SequelizeMeta',\n {\n name: {\n type: DataTypes.STRING,\n allowNull: false,\n unique: true,\n primaryKey: true,\n autoIncrement: false,\n },\n },\n {\n tableName: 'SequelizeMeta',\n timestamps: false,\n schema: 'public',\n },\n );\n\n logger.info('custom-fields: starting migrations');\n const migrations = await SequelizeMeta.findAll({ where: { name: { [Op.like]: `${schemaPrefix}%` } }, raw: true });\n const currentSadotSchemaVersion = migrations.at(-1);\n const expectedSchemaVersionIndex = migrations.findIndex(m => (m as any).name === schemaVersion);\n\n logger.info('custom-fields: migrations', {\n currentMigrations: migrations,\n currentSadotSchemaVersion,\n newSadotSchemaVersion: schemaVersion,\n expectedSchemaVersionIndex,\n });\n if (!currentSadotSchemaVersion || (currentSadotSchemaVersion as any).name !== schemaVersion) {\n logger.info('custom-fields: syncing models');\n try {\n await CustomFieldDefinition.sync({ alter: true });\n logger.info('custom-fields: CustomFieldDefinition synced successfully');\n\n await CustomFieldValue.sync({ alter: true });\n logger.info('custom-fields: CustomFieldValue synced successfully');\n\n await CustomValidator.sync({ alter: true });\n logger.info('custom-fields: CustomValidator synced successfully');\n\n // T.Y TODO: Remove the if statement once we're ready to add the new entries table for all MS\n if (useCustomFieldsEntries) {\n await CustomFieldEntries.sync({ alter: true });\n logger.info('custom-fields: CustomFieldEntries synced successfully');\n }\n\n if (useModelTypeMapping) {\n await CustomFieldModelTypeMap.sync({ alter: true });\n logger.info('custom-fields: CustomFieldModelTypeMap synced successfully');\n }\n\n if (expectedSchemaVersionIndex === -1) {\n await SequelizeMeta.create({ name: schemaVersion });\n logger.info('custom-fields: SequelizeMeta entry created successfully');\n }\n\n logger.info('custom-fields: models synced');\n if (migrations.length && expectedSchemaVersionIndex !== -1 && expectedSchemaVersionIndex < migrations.length - 1) {\n // We have existing migrations, and we are calling `sync`.\n // This means we are in a `down` migration, and hence we should delete newer migrations to ensure we can reapply them.\n const migrationsToDelete = migrations.slice(expectedSchemaVersionIndex + 1);\n logger.info('custom-fields: deleting newer migrations during down migration', { count: migrationsToDelete.length });\n await SequelizeMeta.destroy({ where: { name: { [Op.in]: migrationsToDelete.map(m => (m as any).name) } } });\n logger.info('custom-fields: newer migrations deleted successfully');\n }\n } catch (error) {\n logger.error('custom-fields: failed to sync models', { error });\n throw error;\n }\n }\n};\n\nconst initTables = async (\n sequelize: Sequelize,\n getUser: CustomFieldOptions['getUser'],\n {\n schemaPrefix = SADOT_MIGRATION_PREFIX,\n schemaVersion = SCHEMA_VERSION,\n useCustomFieldsEntries = false,\n useModelTypeMapping = false,\n runLegacyMigrations = false,\n skipMigrations = false,\n isMatPathEnabled,\n }: InitTablesOptions = {},\n): Promise<void> => {\n const CUSTOM_FIELDS_SCHEMA_VERSION = `${schemaPrefix}_${schemaVersion}${useCustomFieldsEntries ? '_withEntries' : ''}${useModelTypeMapping ? '_withTypeMapping' : ''}`;\n logger.info('custom-fields: initialize custom-fields tables');\n // Detect models and import them to the orm\n if (!sequelize.addModels) {\n throw new Error('sequelize instance must have addModels function');\n }\n const productionModels: ProductionModel[] = [\n CustomFieldDefinition,\n CustomFieldValue,\n CustomValidator,\n ...(useCustomFieldsEntries ? [CustomFieldEntries] : []),\n ...(useModelTypeMapping ? [CustomFieldModelTypeMap] : []),\n ];\n\n sequelize.addModels(productionModels);\n\n // Add the association only when useModelTypeMapping is enabled\n if (useModelTypeMapping) {\n CustomFieldDefinition.hasMany(CustomFieldModelTypeMap, {\n foreignKey: 'customFieldDefinitionId',\n as: 'modelTypeMappings',\n });\n CustomFieldModelTypeMap.belongsTo(CustomFieldDefinition, {\n foreignKey: 'customFieldDefinitionId',\n as: 'customFieldDefinition',\n });\n }\n\n CustomFieldDefinition.addScope('userScope', () => {\n // When mat-path is active, the consumer is responsible for restricting entityIds\n // (typically by expanding the request's entityIds to include ancestor paths the\n // caller can see). Bypass the legacy permission filter so partner/ancestor\n // entityIds are not dropped.\n if (isMatPathEnabled?.()) return {};\n const user = getUser();\n if (!user?.permissions) {\n return {};\n }\n return {\n where: {\n entityId: [\n ...Object.keys(user.permissions.fleets),\n ...Object.keys(user.permissions.businessModels),\n ...Object.keys(user.permissions.demandSources),\n ],\n },\n };\n });\n\n CustomValidator.addScope('userScope', () => {\n if (isMatPathEnabled?.()) return {};\n const user = getUser();\n if (!user?.permissions) {\n return {};\n }\n return {\n where: {\n entityId: [\n ...Object.keys(user.permissions.fleets),\n ...Object.keys(user.permissions.businessModels),\n ...Object.keys(user.permissions.demandSources),\n ],\n },\n };\n });\n\n logger.info('custom-fields: models added');\n\n if (skipMigrations) {\n logger.info('custom-fields: skipping migrations');\n } else if (runLegacyMigrations) {\n logger.info('custom-fields: running legacy sync migrations');\n await legacySyncMigrations(sequelize, { schemaPrefix, schemaVersion: CUSTOM_FIELDS_SCHEMA_VERSION, useCustomFieldsEntries, useModelTypeMapping });\n logger.info('custom-fields: umzug legacy sync migrations completed');\n } else {\n logger.info('custom-fields: starting umzug migrations');\n await runSadotMigrations(sequelize, { useCustomFieldsEntries, useModelTypeMapping });\n logger.info('custom-fields: umzug migrations complete');\n }\n};\n\nconst initTestModels = async (sequelize: Sequelize): Promise<void> => {\n logger.info('custom-fields: initialize custom-fields test models');\n // Detect models and import them to the orm\n if (!sequelize.addModels) {\n throw new Error('sequelize instance must have addModels function');\n }\n\n sequelize.addModels(testModels);\n await sequelize.dropSchema('custom-fields', { logging: false });\n await sequelize.createSchema('custom-fields', { logging: false });\n\n logger.info('custom-fields: test models added');\n await TestModel.sync({ alter: true });\n await AssociatedTestModel.sync({ alter: true });\n await ContextTestModel.sync({ alter: true });\n await ContextAwareTestModel.sync({ alter: true });\n logger.info('custom-fields: test models synced');\n};\n\nexport {\n CustomFieldValue,\n CustomFieldDefinition,\n CustomFieldEntries,\n CustomValidator,\n CustomFieldModelTypeMap,\n TestModel,\n AssociatedTestModel,\n ContextAwareTestModel,\n ContextTestModel,\n initTables,\n initTestModels,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["TestModel","AssociatedTestModel","ContextAwareTestModel","ContextTestModel","sequelize","DataTypes","Op","CustomFieldDefinition","CustomFieldValue","CustomValidator","writesEntries","CustomFieldEntries","CustomFieldModelTypeMap","CUSTOM_FIELDS_ENTRIES_MODE","productionModels: ProductionModel[]","runSadotMigrations"],"sources":["../../src/models/index.ts"],"sourcesContent":["import { DataTypes, Op } from 'sequelize';\nimport type { Sequelize } from 'sequelize-typescript';\nimport logger from '../utils/logger';\nimport CustomFieldDefinition from './CustomFieldDefinition';\nimport CustomFieldValue from './CustomFieldValue';\nimport TestModel from './tests/TestModel';\nimport ContextAwareTestModel from './tests/contextAwareModels/ContextAwareTestModel';\nimport ContextTestModel from './tests/contextAwareModels/ContextTestModel';\nimport AssociatedTestModel from './tests/AssociatedTestModel';\nimport type { CustomFieldOptions } from '../types';\nimport CustomFieldEntries from './CustomFieldEntries';\nimport CustomValidator from './CustomValidator';\nimport CustomFieldModelTypeMap from './CustomFieldModelTypeMap';\nimport { runSadotMigrations } from '../migrations';\nimport { CUSTOM_FIELDS_ENTRIES_MODE, type CustomFieldsEntriesMode, writesEntries } from '../utils/custom-fields-mode';\n\ntype ProductionModel = typeof CustomFieldDefinition | typeof CustomFieldValue | typeof CustomFieldEntries | typeof CustomValidator | typeof CustomFieldModelTypeMap;\ninterface InitTablesOptions {\n schemaPrefix?: string;\n schemaVersion?: string;\n customFieldsEntriesMode?: CustomFieldsEntriesMode;\n useModelTypeMapping?: boolean;\n runLegacyMigrations?: boolean;\n skipMigrations?: boolean;\n isMatPathEnabled?: CustomFieldOptions['isMatPathEnabled'];\n}\n\nconst testModels = [TestModel, AssociatedTestModel, ContextAwareTestModel, ContextTestModel];\n\nconst SADOT_MIGRATION_PREFIX = 'sadot-migration';\nconst SCHEMA_VERSION = '5f8e4a7c-9b2d-4e1f-8c3a-b6d9e2f7a4c1';\n\n/**\n * Legacy migration approach using sequelize.sync({ alter: true }).\n * TODO: Remove this function once all consumers have migrated to umzug.\n */\nconst legacySyncMigrations = async (\n sequelize: Sequelize,\n {\n schemaPrefix,\n schemaVersion,\n customFieldsEntriesMode,\n useModelTypeMapping,\n }: { schemaPrefix: string; schemaVersion: string; customFieldsEntriesMode: CustomFieldsEntriesMode; useModelTypeMapping: boolean; },\n): Promise<void> => {\n const SequelizeMeta = sequelize.define(\n 'SequelizeMeta',\n {\n name: {\n type: DataTypes.STRING,\n allowNull: false,\n unique: true,\n primaryKey: true,\n autoIncrement: false,\n },\n },\n {\n tableName: 'SequelizeMeta',\n timestamps: false,\n schema: 'public',\n },\n );\n\n logger.info('custom-fields: starting migrations');\n const migrations = await SequelizeMeta.findAll({ where: { name: { [Op.like]: `${schemaPrefix}%` } }, raw: true });\n const currentSadotSchemaVersion = migrations.at(-1);\n const expectedSchemaVersionIndex = migrations.findIndex(m => (m as any).name === schemaVersion);\n\n logger.info('custom-fields: migrations', {\n currentMigrations: migrations,\n currentSadotSchemaVersion,\n newSadotSchemaVersion: schemaVersion,\n expectedSchemaVersionIndex,\n });\n if (!currentSadotSchemaVersion || (currentSadotSchemaVersion as any).name !== schemaVersion) {\n logger.info('custom-fields: syncing models');\n try {\n await CustomFieldDefinition.sync({ alter: true });\n logger.info('custom-fields: CustomFieldDefinition synced successfully');\n\n await CustomFieldValue.sync({ alter: true });\n logger.info('custom-fields: CustomFieldValue synced successfully');\n\n await CustomValidator.sync({ alter: true });\n logger.info('custom-fields: CustomValidator synced successfully');\n\n // T.Y TODO: Remove the if statement once we're ready to add the new entries table for all MS\n if (writesEntries(customFieldsEntriesMode)) {\n await CustomFieldEntries.sync({ alter: true });\n logger.info('custom-fields: CustomFieldEntries synced successfully');\n }\n\n if (useModelTypeMapping) {\n await CustomFieldModelTypeMap.sync({ alter: true });\n logger.info('custom-fields: CustomFieldModelTypeMap synced successfully');\n }\n\n if (expectedSchemaVersionIndex === -1) {\n await SequelizeMeta.create({ name: schemaVersion });\n logger.info('custom-fields: SequelizeMeta entry created successfully');\n }\n\n logger.info('custom-fields: models synced');\n if (migrations.length && expectedSchemaVersionIndex !== -1 && expectedSchemaVersionIndex < migrations.length - 1) {\n // We have existing migrations, and we are calling `sync`.\n // This means we are in a `down` migration, and hence we should delete newer migrations to ensure we can reapply them.\n const migrationsToDelete = migrations.slice(expectedSchemaVersionIndex + 1);\n logger.info('custom-fields: deleting newer migrations during down migration', { count: migrationsToDelete.length });\n await SequelizeMeta.destroy({ where: { name: { [Op.in]: migrationsToDelete.map(m => (m as any).name) } } });\n logger.info('custom-fields: newer migrations deleted successfully');\n }\n } catch (error) {\n logger.error('custom-fields: failed to sync models', { error });\n throw error;\n }\n }\n};\n\nconst initTables = async (\n sequelize: Sequelize,\n getUser: CustomFieldOptions['getUser'],\n {\n schemaPrefix = SADOT_MIGRATION_PREFIX,\n schemaVersion = SCHEMA_VERSION,\n customFieldsEntriesMode = CUSTOM_FIELDS_ENTRIES_MODE.DISABLED,\n useModelTypeMapping = false,\n runLegacyMigrations = false,\n skipMigrations = false,\n isMatPathEnabled,\n }: InitTablesOptions = {},\n): Promise<void> => {\n const entriesEnabled = writesEntries(customFieldsEntriesMode);\n // The suffix describes the schema, not the read path, so 'write-only' and 'read-and-write'\n // share it — a third suffix would force a legacy re-sync on services using\n // runLegacyMigrations, for a schema that is identical in both modes.\n const CUSTOM_FIELDS_SCHEMA_VERSION = `${schemaPrefix}_${schemaVersion}${entriesEnabled ? '_withEntries' : ''}${useModelTypeMapping ? '_withTypeMapping' : ''}`;\n logger.info('custom-fields: initialize custom-fields tables');\n // Detect models and import them to the orm\n if (!sequelize.addModels) {\n throw new Error('sequelize instance must have addModels function');\n }\n const productionModels: ProductionModel[] = [\n CustomFieldDefinition,\n CustomFieldValue,\n CustomValidator,\n ...(entriesEnabled ? [CustomFieldEntries] : []),\n ...(useModelTypeMapping ? [CustomFieldModelTypeMap] : []),\n ];\n\n sequelize.addModels(productionModels);\n\n // Add the association only when useModelTypeMapping is enabled\n if (useModelTypeMapping) {\n CustomFieldDefinition.hasMany(CustomFieldModelTypeMap, {\n foreignKey: 'customFieldDefinitionId',\n as: 'modelTypeMappings',\n });\n CustomFieldModelTypeMap.belongsTo(CustomFieldDefinition, {\n foreignKey: 'customFieldDefinitionId',\n as: 'customFieldDefinition',\n });\n }\n\n CustomFieldDefinition.addScope('userScope', () => {\n // When mat-path is active, the consumer is responsible for restricting entityIds\n // (typically by expanding the request's entityIds to include ancestor paths the\n // caller can see). Bypass the legacy permission filter so partner/ancestor\n // entityIds are not dropped.\n if (isMatPathEnabled?.()) return {};\n const user = getUser();\n if (!user?.permissions) {\n return {};\n }\n return {\n where: {\n entityId: [\n ...Object.keys(user.permissions.fleets),\n ...Object.keys(user.permissions.businessModels),\n ...Object.keys(user.permissions.demandSources),\n ],\n },\n };\n });\n\n CustomValidator.addScope('userScope', () => {\n if (isMatPathEnabled?.()) return {};\n const user = getUser();\n if (!user?.permissions) {\n return {};\n }\n return {\n where: {\n entityId: [\n ...Object.keys(user.permissions.fleets),\n ...Object.keys(user.permissions.businessModels),\n ...Object.keys(user.permissions.demandSources),\n ],\n },\n };\n });\n\n logger.info('custom-fields: models added');\n\n if (skipMigrations) {\n logger.info('custom-fields: skipping migrations');\n } else if (runLegacyMigrations) {\n logger.info('custom-fields: running legacy sync migrations');\n await legacySyncMigrations(sequelize, { schemaPrefix, schemaVersion: CUSTOM_FIELDS_SCHEMA_VERSION, customFieldsEntriesMode, useModelTypeMapping });\n logger.info('custom-fields: umzug legacy sync migrations completed');\n } else {\n logger.info('custom-fields: starting umzug migrations');\n await runSadotMigrations(sequelize, { customFieldsEntriesMode, useModelTypeMapping });\n logger.info('custom-fields: umzug migrations complete');\n }\n};\n\nconst initTestModels = async (sequelize: Sequelize): Promise<void> => {\n logger.info('custom-fields: initialize custom-fields test models');\n // Detect models and import them to the orm\n if (!sequelize.addModels) {\n throw new Error('sequelize instance must have addModels function');\n }\n\n sequelize.addModels(testModels);\n await sequelize.dropSchema('custom-fields', { logging: false });\n await sequelize.createSchema('custom-fields', { logging: false });\n\n logger.info('custom-fields: test models added');\n await TestModel.sync({ alter: true });\n await AssociatedTestModel.sync({ alter: true });\n await ContextTestModel.sync({ alter: true });\n await ContextAwareTestModel.sync({ alter: true });\n logger.info('custom-fields: test models synced');\n};\n\nexport {\n CustomFieldValue,\n CustomFieldDefinition,\n CustomFieldEntries,\n CustomValidator,\n CustomFieldModelTypeMap,\n TestModel,\n AssociatedTestModel,\n ContextAwareTestModel,\n ContextTestModel,\n initTables,\n initTestModels,\n};\n"],"mappings":"wlBA2BA,MAAM,EAAa,CAACA,EAAAA,QAAWC,EAAAA,QAAqBC,EAAAA,QAAuBC,EAAAA,QAAiB,CAEtF,EAAyB,kBACzB,EAAiB,uCAMjB,EAAuB,MAC3B,EACA,CACE,eACA,gBACA,0BACA,yBAEgB,CAClB,IAAM,EAAgBC,EAAU,OAC9B,gBACA,CACE,KAAM,CACJ,KAAMC,EAAAA,UAAU,OAChB,UAAW,GACX,OAAQ,GACR,WAAY,GACZ,cAAe,GAChB,CACF,CACD,CACE,UAAW,gBACX,WAAY,GACZ,OAAQ,SACT,CACF,CAED,EAAA,QAAO,KAAK,qCAAqC,CACjD,IAAM,EAAa,MAAM,EAAc,QAAQ,CAAE,MAAO,CAAE,KAAM,EAAGC,EAAAA,GAAG,MAAO,GAAG,EAAa,GAAI,CAAE,CAAE,IAAK,GAAM,CAAC,CAC3G,EAA4B,EAAW,GAAG,GAAG,CAC7C,EAA6B,EAAW,UAAU,GAAM,EAAU,OAAS,EAAc,CAQ/F,GANA,EAAA,QAAO,KAAK,4BAA6B,CACvC,kBAAmB,EACnB,4BACA,sBAAuB,EACvB,6BACD,CAAC,CACE,CAAC,GAA8B,EAAkC,OAAS,EAAe,CAC3F,EAAA,QAAO,KAAK,gCAAgC,CAC5C,GAAI,CA2BF,GA1BA,MAAMC,EAAAA,QAAsB,KAAK,CAAE,MAAO,GAAM,CAAC,CACjD,EAAA,QAAO,KAAK,2DAA2D,CAEvE,MAAMC,EAAAA,QAAiB,KAAK,CAAE,MAAO,GAAM,CAAC,CAC5C,EAAA,QAAO,KAAK,sDAAsD,CAElE,MAAMC,EAAAA,QAAgB,KAAK,CAAE,MAAO,GAAM,CAAC,CAC3C,EAAA,QAAO,KAAK,qDAAqD,CAG7DC,EAAAA,cAAc,EAAwB,GACxC,MAAMC,EAAAA,QAAmB,KAAK,CAAE,MAAO,GAAM,CAAC,CAC9C,EAAA,QAAO,KAAK,wDAAwD,EAGlE,IACF,MAAMC,EAAAA,QAAwB,KAAK,CAAE,MAAO,GAAM,CAAC,CACnD,EAAA,QAAO,KAAK,6DAA6D,EAGvE,IAA+B,KACjC,MAAM,EAAc,OAAO,CAAE,KAAM,EAAe,CAAC,CACnD,EAAA,QAAO,KAAK,0DAA0D,EAGxE,EAAA,QAAO,KAAK,+BAA+B,CACvC,EAAW,QAAU,IAA+B,IAAM,EAA6B,EAAW,OAAS,EAAG,CAGhH,IAAM,EAAqB,EAAW,MAAM,EAA6B,EAAE,CAC3E,EAAA,QAAO,KAAK,iEAAkE,CAAE,MAAO,EAAmB,OAAQ,CAAC,CACnH,MAAM,EAAc,QAAQ,CAAE,MAAO,CAAE,KAAM,EAAGN,EAAAA,GAAG,IAAK,EAAmB,IAAI,GAAM,EAAU,KAAK,CAAE,CAAE,CAAE,CAAC,CAC3G,EAAA,QAAO,KAAK,uDAAuD,QAE9D,EAAO,CAEd,MADA,EAAA,QAAO,MAAM,uCAAwC,CAAE,QAAO,CAAC,CACzD,KAKN,EAAa,MACjB,EACA,EACA,CACE,eAAe,kBACf,gBAAgB,uCAChB,0BAA0BO,EAAAA,2BAA2B,SACrD,sBAAsB,GACtB,sBAAsB,GACtB,iBAAiB,GACjB,oBACqB,EAAE,GACP,CAClB,IAAM,EAAiBH,EAAAA,cAAc,EAAwB,CAIvD,EAA+B,GAAG,EAAa,GAAG,IAAgB,EAAiB,eAAiB,KAAK,EAAsB,mBAAqB,KAG1J,GAFA,EAAA,QAAO,KAAK,iDAAiD,CAEzD,CAACN,EAAU,UACb,MAAU,MAAM,kDAAkD,CAEpE,IAAMU,EAAsC,CAC1CP,EAAAA,QACAC,EAAAA,QACAC,EAAAA,QACA,GAAI,EAAiB,CAACE,EAAAA,QAAmB,CAAG,EAAE,CAC9C,GAAI,EAAsB,CAACC,EAAAA,QAAwB,CAAG,EAAE,CACzD,CAED,EAAU,UAAU,EAAiB,CAGjC,IACF,EAAA,QAAsB,QAAQA,EAAAA,QAAyB,CACrD,WAAY,0BACZ,GAAI,oBACL,CAAC,CACF,EAAA,QAAwB,UAAUL,EAAAA,QAAuB,CACvD,WAAY,0BACZ,GAAI,wBACL,CAAC,EAGJ,EAAA,QAAsB,SAAS,gBAAmB,CAKhD,GAAI,KAAoB,CAAE,MAAO,EAAE,CACnC,IAAM,EAAO,GAAS,CAItB,OAHK,GAAM,YAGJ,CACL,MAAO,CACL,SAAU,CACR,GAAG,OAAO,KAAK,EAAK,YAAY,OAAO,CACvC,GAAG,OAAO,KAAK,EAAK,YAAY,eAAe,CAC/C,GAAG,OAAO,KAAK,EAAK,YAAY,cAAc,CAC/C,CACF,CACF,CAVQ,EAAE,EAWX,CAEF,EAAA,QAAgB,SAAS,gBAAmB,CAC1C,GAAI,KAAoB,CAAE,MAAO,EAAE,CACnC,IAAM,EAAO,GAAS,CAItB,OAHK,GAAM,YAGJ,CACL,MAAO,CACL,SAAU,CACR,GAAG,OAAO,KAAK,EAAK,YAAY,OAAO,CACvC,GAAG,OAAO,KAAK,EAAK,YAAY,eAAe,CAC/C,GAAG,OAAO,KAAK,EAAK,YAAY,cAAc,CAC/C,CACF,CACF,CAVQ,EAAE,EAWX,CAEF,EAAA,QAAO,KAAK,8BAA8B,CAEtC,EACF,EAAA,QAAO,KAAK,qCAAqC,CACxC,GACT,EAAA,QAAO,KAAK,gDAAgD,CAC5D,MAAM,EAAqBH,EAAW,CAAE,eAAc,cAAe,EAA8B,0BAAyB,sBAAqB,CAAC,CAClJ,EAAA,QAAO,KAAK,wDAAwD,GAEpE,EAAA,QAAO,KAAK,2CAA2C,CACvD,MAAMW,EAAAA,mBAAmBX,EAAW,CAAE,0BAAyB,sBAAqB,CAAC,CACrF,EAAA,QAAO,KAAK,2CAA2C,GAIrD,EAAiB,KAAO,IAAwC,CAGpE,GAFA,EAAA,QAAO,KAAK,sDAAsD,CAE9D,CAACA,EAAU,UACb,MAAU,MAAM,kDAAkD,CAGpE,EAAU,UAAU,EAAW,CAC/B,MAAMA,EAAU,WAAW,gBAAiB,CAAE,QAAS,GAAO,CAAC,CAC/D,MAAMA,EAAU,aAAa,gBAAiB,CAAE,QAAS,GAAO,CAAC,CAEjE,EAAA,QAAO,KAAK,mCAAmC,CAC/C,MAAMJ,EAAAA,QAAU,KAAK,CAAE,MAAO,GAAM,CAAC,CACrC,MAAMC,EAAAA,QAAoB,KAAK,CAAE,MAAO,GAAM,CAAC,CAC/C,MAAME,EAAAA,QAAiB,KAAK,CAAE,MAAO,GAAM,CAAC,CAC5C,MAAMD,EAAAA,QAAsB,KAAK,CAAE,MAAO,GAAM,CAAC,CACjD,EAAA,QAAO,KAAK,oCAAoC"}
@@ -1,2 +1,2 @@
1
- import e from"../utils/logger/index.js";import t from"./CustomFieldValue.js";import n from"./CustomFieldDefinition.js";import r from"./tests/AssociatedTestModel.js";import i from"./tests/TestModel.js";import a from"./tests/contextAwareModels/ContextTestModel.js";import o from"./tests/contextAwareModels/ContextAwareTestModel.js";import s from"./CustomFieldEntries.js";import c from"./CustomValidator.js";import l from"./CustomFieldModelTypeMap.js";import{runSadotMigrations as u}from"../migrations/index.js";import{DataTypes as d,Op as f}from"sequelize";const p=[i,r,o,a],m=async(r,{schemaPrefix:i,schemaVersion:a,useCustomFieldsEntries:o,useModelTypeMapping:u})=>{let p=r.define(`SequelizeMeta`,{name:{type:d.STRING,allowNull:!1,unique:!0,primaryKey:!0,autoIncrement:!1}},{tableName:`SequelizeMeta`,timestamps:!1,schema:`public`});e.info(`custom-fields: starting migrations`);let m=await p.findAll({where:{name:{[f.like]:`${i}%`}},raw:!0}),h=m.at(-1),g=m.findIndex(e=>e.name===a);if(e.info(`custom-fields: migrations`,{currentMigrations:m,currentSadotSchemaVersion:h,newSadotSchemaVersion:a,expectedSchemaVersionIndex:g}),!h||h.name!==a){e.info(`custom-fields: syncing models`);try{if(await n.sync({alter:!0}),e.info(`custom-fields: CustomFieldDefinition synced successfully`),await t.sync({alter:!0}),e.info(`custom-fields: CustomFieldValue synced successfully`),await c.sync({alter:!0}),e.info(`custom-fields: CustomValidator synced successfully`),o&&(await s.sync({alter:!0}),e.info(`custom-fields: CustomFieldEntries synced successfully`)),u&&(await l.sync({alter:!0}),e.info(`custom-fields: CustomFieldModelTypeMap synced successfully`)),g===-1&&(await p.create({name:a}),e.info(`custom-fields: SequelizeMeta entry created successfully`)),e.info(`custom-fields: models synced`),m.length&&g!==-1&&g<m.length-1){let t=m.slice(g+1);e.info(`custom-fields: deleting newer migrations during down migration`,{count:t.length}),await p.destroy({where:{name:{[f.in]:t.map(e=>e.name)}}}),e.info(`custom-fields: newer migrations deleted successfully`)}}catch(t){throw e.error(`custom-fields: failed to sync models`,{error:t}),t}}},h=async(r,i,{schemaPrefix:a=`sadot-migration`,schemaVersion:o=`5f8e4a7c-9b2d-4e1f-8c3a-b6d9e2f7a4c1`,useCustomFieldsEntries:d=!1,useModelTypeMapping:f=!1,runLegacyMigrations:p=!1,skipMigrations:h=!1,isMatPathEnabled:g}={})=>{let _=`${a}_${o}${d?`_withEntries`:``}${f?`_withTypeMapping`:``}`;if(e.info(`custom-fields: initialize custom-fields tables`),!r.addModels)throw Error(`sequelize instance must have addModels function`);let v=[n,t,c,...d?[s]:[],...f?[l]:[]];r.addModels(v),f&&(n.hasMany(l,{foreignKey:`customFieldDefinitionId`,as:`modelTypeMappings`}),l.belongsTo(n,{foreignKey:`customFieldDefinitionId`,as:`customFieldDefinition`})),n.addScope(`userScope`,()=>{if(g?.())return{};let e=i();return e?.permissions?{where:{entityId:[...Object.keys(e.permissions.fleets),...Object.keys(e.permissions.businessModels),...Object.keys(e.permissions.demandSources)]}}:{}}),c.addScope(`userScope`,()=>{if(g?.())return{};let e=i();return e?.permissions?{where:{entityId:[...Object.keys(e.permissions.fleets),...Object.keys(e.permissions.businessModels),...Object.keys(e.permissions.demandSources)]}}:{}}),e.info(`custom-fields: models added`),h?e.info(`custom-fields: skipping migrations`):p?(e.info(`custom-fields: running legacy sync migrations`),await m(r,{schemaPrefix:a,schemaVersion:_,useCustomFieldsEntries:d,useModelTypeMapping:f}),e.info(`custom-fields: umzug legacy sync migrations completed`)):(e.info(`custom-fields: starting umzug migrations`),await u(r,{useCustomFieldsEntries:d,useModelTypeMapping:f}),e.info(`custom-fields: umzug migrations complete`))},g=async t=>{if(e.info(`custom-fields: initialize custom-fields test models`),!t.addModels)throw Error(`sequelize instance must have addModels function`);t.addModels(p),await t.dropSchema(`custom-fields`,{logging:!1}),await t.createSchema(`custom-fields`,{logging:!1}),e.info(`custom-fields: test models added`),await i.sync({alter:!0}),await r.sync({alter:!0}),await a.sync({alter:!0}),await o.sync({alter:!0}),e.info(`custom-fields: test models synced`)};export{h as initTables,g as initTestModels};
1
+ import e from"../utils/logger/index.js";import t from"./CustomFieldValue.js";import n from"./CustomFieldDefinition.js";import r from"./tests/AssociatedTestModel.js";import i from"./tests/TestModel.js";import a from"./tests/contextAwareModels/ContextTestModel.js";import o from"./tests/contextAwareModels/ContextAwareTestModel.js";import s from"./CustomFieldEntries.js";import c from"./CustomValidator.js";import l from"./CustomFieldModelTypeMap.js";import{CUSTOM_FIELDS_ENTRIES_MODE as u,writesEntries as d}from"../utils/custom-fields-mode.js";import{runSadotMigrations as f}from"../migrations/index.js";import{DataTypes as p,Op as m}from"sequelize";const h=[i,r,o,a],g=async(r,{schemaPrefix:i,schemaVersion:a,customFieldsEntriesMode:o,useModelTypeMapping:u})=>{let f=r.define(`SequelizeMeta`,{name:{type:p.STRING,allowNull:!1,unique:!0,primaryKey:!0,autoIncrement:!1}},{tableName:`SequelizeMeta`,timestamps:!1,schema:`public`});e.info(`custom-fields: starting migrations`);let h=await f.findAll({where:{name:{[m.like]:`${i}%`}},raw:!0}),g=h.at(-1),_=h.findIndex(e=>e.name===a);if(e.info(`custom-fields: migrations`,{currentMigrations:h,currentSadotSchemaVersion:g,newSadotSchemaVersion:a,expectedSchemaVersionIndex:_}),!g||g.name!==a){e.info(`custom-fields: syncing models`);try{if(await n.sync({alter:!0}),e.info(`custom-fields: CustomFieldDefinition synced successfully`),await t.sync({alter:!0}),e.info(`custom-fields: CustomFieldValue synced successfully`),await c.sync({alter:!0}),e.info(`custom-fields: CustomValidator synced successfully`),d(o)&&(await s.sync({alter:!0}),e.info(`custom-fields: CustomFieldEntries synced successfully`)),u&&(await l.sync({alter:!0}),e.info(`custom-fields: CustomFieldModelTypeMap synced successfully`)),_===-1&&(await f.create({name:a}),e.info(`custom-fields: SequelizeMeta entry created successfully`)),e.info(`custom-fields: models synced`),h.length&&_!==-1&&_<h.length-1){let t=h.slice(_+1);e.info(`custom-fields: deleting newer migrations during down migration`,{count:t.length}),await f.destroy({where:{name:{[m.in]:t.map(e=>e.name)}}}),e.info(`custom-fields: newer migrations deleted successfully`)}}catch(t){throw e.error(`custom-fields: failed to sync models`,{error:t}),t}}},_=async(r,i,{schemaPrefix:a=`sadot-migration`,schemaVersion:o=`5f8e4a7c-9b2d-4e1f-8c3a-b6d9e2f7a4c1`,customFieldsEntriesMode:p=u.DISABLED,useModelTypeMapping:m=!1,runLegacyMigrations:h=!1,skipMigrations:_=!1,isMatPathEnabled:v}={})=>{let y=d(p),b=`${a}_${o}${y?`_withEntries`:``}${m?`_withTypeMapping`:``}`;if(e.info(`custom-fields: initialize custom-fields tables`),!r.addModels)throw Error(`sequelize instance must have addModels function`);let x=[n,t,c,...y?[s]:[],...m?[l]:[]];r.addModels(x),m&&(n.hasMany(l,{foreignKey:`customFieldDefinitionId`,as:`modelTypeMappings`}),l.belongsTo(n,{foreignKey:`customFieldDefinitionId`,as:`customFieldDefinition`})),n.addScope(`userScope`,()=>{if(v?.())return{};let e=i();return e?.permissions?{where:{entityId:[...Object.keys(e.permissions.fleets),...Object.keys(e.permissions.businessModels),...Object.keys(e.permissions.demandSources)]}}:{}}),c.addScope(`userScope`,()=>{if(v?.())return{};let e=i();return e?.permissions?{where:{entityId:[...Object.keys(e.permissions.fleets),...Object.keys(e.permissions.businessModels),...Object.keys(e.permissions.demandSources)]}}:{}}),e.info(`custom-fields: models added`),_?e.info(`custom-fields: skipping migrations`):h?(e.info(`custom-fields: running legacy sync migrations`),await g(r,{schemaPrefix:a,schemaVersion:b,customFieldsEntriesMode:p,useModelTypeMapping:m}),e.info(`custom-fields: umzug legacy sync migrations completed`)):(e.info(`custom-fields: starting umzug migrations`),await f(r,{customFieldsEntriesMode:p,useModelTypeMapping:m}),e.info(`custom-fields: umzug migrations complete`))},v=async t=>{if(e.info(`custom-fields: initialize custom-fields test models`),!t.addModels)throw Error(`sequelize instance must have addModels function`);t.addModels(h),await t.dropSchema(`custom-fields`,{logging:!1}),await t.createSchema(`custom-fields`,{logging:!1}),e.info(`custom-fields: test models added`),await i.sync({alter:!0}),await r.sync({alter:!0}),await a.sync({alter:!0}),await o.sync({alter:!0}),e.info(`custom-fields: test models synced`)};export{_ as initTables,v as initTestModels};
2
2
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["TestModel","AssociatedTestModel","ContextAwareTestModel","ContextTestModel","CustomFieldDefinition","CustomFieldValue","CustomValidator","CustomFieldEntries","CustomFieldModelTypeMap","productionModels: ProductionModel[]"],"sources":["../../src/models/index.ts"],"sourcesContent":["import { DataTypes, Op } from 'sequelize';\nimport type { Sequelize } from 'sequelize-typescript';\nimport logger from '../utils/logger';\nimport CustomFieldDefinition from './CustomFieldDefinition';\nimport CustomFieldValue from './CustomFieldValue';\nimport TestModel from './tests/TestModel';\nimport ContextAwareTestModel from './tests/contextAwareModels/ContextAwareTestModel';\nimport ContextTestModel from './tests/contextAwareModels/ContextTestModel';\nimport AssociatedTestModel from './tests/AssociatedTestModel';\nimport type { CustomFieldOptions } from '../types';\nimport CustomFieldEntries from './CustomFieldEntries';\nimport CustomValidator from './CustomValidator';\nimport CustomFieldModelTypeMap from './CustomFieldModelTypeMap';\nimport { runSadotMigrations } from '../migrations';\n\ntype ProductionModel = typeof CustomFieldDefinition | typeof CustomFieldValue | typeof CustomFieldEntries | typeof CustomValidator | typeof CustomFieldModelTypeMap;\ninterface InitTablesOptions {\n schemaPrefix?: string;\n schemaVersion?: string;\n useCustomFieldsEntries?: boolean;\n useModelTypeMapping?: boolean;\n runLegacyMigrations?: boolean;\n skipMigrations?: boolean;\n isMatPathEnabled?: CustomFieldOptions['isMatPathEnabled'];\n}\n\nconst testModels = [TestModel, AssociatedTestModel, ContextAwareTestModel, ContextTestModel];\n\nconst SADOT_MIGRATION_PREFIX = 'sadot-migration';\nconst SCHEMA_VERSION = '5f8e4a7c-9b2d-4e1f-8c3a-b6d9e2f7a4c1';\n\n/**\n * Legacy migration approach using sequelize.sync({ alter: true }).\n * TODO: Remove this function once all consumers have migrated to umzug.\n */\nconst legacySyncMigrations = async (\n sequelize: Sequelize,\n {\n schemaPrefix,\n schemaVersion,\n useCustomFieldsEntries,\n useModelTypeMapping,\n }: { schemaPrefix: string; schemaVersion: string; useCustomFieldsEntries: boolean; useModelTypeMapping: boolean; },\n): Promise<void> => {\n const SequelizeMeta = sequelize.define(\n 'SequelizeMeta',\n {\n name: {\n type: DataTypes.STRING,\n allowNull: false,\n unique: true,\n primaryKey: true,\n autoIncrement: false,\n },\n },\n {\n tableName: 'SequelizeMeta',\n timestamps: false,\n schema: 'public',\n },\n );\n\n logger.info('custom-fields: starting migrations');\n const migrations = await SequelizeMeta.findAll({ where: { name: { [Op.like]: `${schemaPrefix}%` } }, raw: true });\n const currentSadotSchemaVersion = migrations.at(-1);\n const expectedSchemaVersionIndex = migrations.findIndex(m => (m as any).name === schemaVersion);\n\n logger.info('custom-fields: migrations', {\n currentMigrations: migrations,\n currentSadotSchemaVersion,\n newSadotSchemaVersion: schemaVersion,\n expectedSchemaVersionIndex,\n });\n if (!currentSadotSchemaVersion || (currentSadotSchemaVersion as any).name !== schemaVersion) {\n logger.info('custom-fields: syncing models');\n try {\n await CustomFieldDefinition.sync({ alter: true });\n logger.info('custom-fields: CustomFieldDefinition synced successfully');\n\n await CustomFieldValue.sync({ alter: true });\n logger.info('custom-fields: CustomFieldValue synced successfully');\n\n await CustomValidator.sync({ alter: true });\n logger.info('custom-fields: CustomValidator synced successfully');\n\n // T.Y TODO: Remove the if statement once we're ready to add the new entries table for all MS\n if (useCustomFieldsEntries) {\n await CustomFieldEntries.sync({ alter: true });\n logger.info('custom-fields: CustomFieldEntries synced successfully');\n }\n\n if (useModelTypeMapping) {\n await CustomFieldModelTypeMap.sync({ alter: true });\n logger.info('custom-fields: CustomFieldModelTypeMap synced successfully');\n }\n\n if (expectedSchemaVersionIndex === -1) {\n await SequelizeMeta.create({ name: schemaVersion });\n logger.info('custom-fields: SequelizeMeta entry created successfully');\n }\n\n logger.info('custom-fields: models synced');\n if (migrations.length && expectedSchemaVersionIndex !== -1 && expectedSchemaVersionIndex < migrations.length - 1) {\n // We have existing migrations, and we are calling `sync`.\n // This means we are in a `down` migration, and hence we should delete newer migrations to ensure we can reapply them.\n const migrationsToDelete = migrations.slice(expectedSchemaVersionIndex + 1);\n logger.info('custom-fields: deleting newer migrations during down migration', { count: migrationsToDelete.length });\n await SequelizeMeta.destroy({ where: { name: { [Op.in]: migrationsToDelete.map(m => (m as any).name) } } });\n logger.info('custom-fields: newer migrations deleted successfully');\n }\n } catch (error) {\n logger.error('custom-fields: failed to sync models', { error });\n throw error;\n }\n }\n};\n\nconst initTables = async (\n sequelize: Sequelize,\n getUser: CustomFieldOptions['getUser'],\n {\n schemaPrefix = SADOT_MIGRATION_PREFIX,\n schemaVersion = SCHEMA_VERSION,\n useCustomFieldsEntries = false,\n useModelTypeMapping = false,\n runLegacyMigrations = false,\n skipMigrations = false,\n isMatPathEnabled,\n }: InitTablesOptions = {},\n): Promise<void> => {\n const CUSTOM_FIELDS_SCHEMA_VERSION = `${schemaPrefix}_${schemaVersion}${useCustomFieldsEntries ? '_withEntries' : ''}${useModelTypeMapping ? '_withTypeMapping' : ''}`;\n logger.info('custom-fields: initialize custom-fields tables');\n // Detect models and import them to the orm\n if (!sequelize.addModels) {\n throw new Error('sequelize instance must have addModels function');\n }\n const productionModels: ProductionModel[] = [\n CustomFieldDefinition,\n CustomFieldValue,\n CustomValidator,\n ...(useCustomFieldsEntries ? [CustomFieldEntries] : []),\n ...(useModelTypeMapping ? [CustomFieldModelTypeMap] : []),\n ];\n\n sequelize.addModels(productionModels);\n\n // Add the association only when useModelTypeMapping is enabled\n if (useModelTypeMapping) {\n CustomFieldDefinition.hasMany(CustomFieldModelTypeMap, {\n foreignKey: 'customFieldDefinitionId',\n as: 'modelTypeMappings',\n });\n CustomFieldModelTypeMap.belongsTo(CustomFieldDefinition, {\n foreignKey: 'customFieldDefinitionId',\n as: 'customFieldDefinition',\n });\n }\n\n CustomFieldDefinition.addScope('userScope', () => {\n // When mat-path is active, the consumer is responsible for restricting entityIds\n // (typically by expanding the request's entityIds to include ancestor paths the\n // caller can see). Bypass the legacy permission filter so partner/ancestor\n // entityIds are not dropped.\n if (isMatPathEnabled?.()) return {};\n const user = getUser();\n if (!user?.permissions) {\n return {};\n }\n return {\n where: {\n entityId: [\n ...Object.keys(user.permissions.fleets),\n ...Object.keys(user.permissions.businessModels),\n ...Object.keys(user.permissions.demandSources),\n ],\n },\n };\n });\n\n CustomValidator.addScope('userScope', () => {\n if (isMatPathEnabled?.()) return {};\n const user = getUser();\n if (!user?.permissions) {\n return {};\n }\n return {\n where: {\n entityId: [\n ...Object.keys(user.permissions.fleets),\n ...Object.keys(user.permissions.businessModels),\n ...Object.keys(user.permissions.demandSources),\n ],\n },\n };\n });\n\n logger.info('custom-fields: models added');\n\n if (skipMigrations) {\n logger.info('custom-fields: skipping migrations');\n } else if (runLegacyMigrations) {\n logger.info('custom-fields: running legacy sync migrations');\n await legacySyncMigrations(sequelize, { schemaPrefix, schemaVersion: CUSTOM_FIELDS_SCHEMA_VERSION, useCustomFieldsEntries, useModelTypeMapping });\n logger.info('custom-fields: umzug legacy sync migrations completed');\n } else {\n logger.info('custom-fields: starting umzug migrations');\n await runSadotMigrations(sequelize, { useCustomFieldsEntries, useModelTypeMapping });\n logger.info('custom-fields: umzug migrations complete');\n }\n};\n\nconst initTestModels = async (sequelize: Sequelize): Promise<void> => {\n logger.info('custom-fields: initialize custom-fields test models');\n // Detect models and import them to the orm\n if (!sequelize.addModels) {\n throw new Error('sequelize instance must have addModels function');\n }\n\n sequelize.addModels(testModels);\n await sequelize.dropSchema('custom-fields', { logging: false });\n await sequelize.createSchema('custom-fields', { logging: false });\n\n logger.info('custom-fields: test models added');\n await TestModel.sync({ alter: true });\n await AssociatedTestModel.sync({ alter: true });\n await ContextTestModel.sync({ alter: true });\n await ContextAwareTestModel.sync({ alter: true });\n logger.info('custom-fields: test models synced');\n};\n\nexport {\n CustomFieldValue,\n CustomFieldDefinition,\n CustomFieldEntries,\n CustomValidator,\n CustomFieldModelTypeMap,\n TestModel,\n AssociatedTestModel,\n ContextAwareTestModel,\n ContextTestModel,\n initTables,\n initTestModels,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["TestModel","AssociatedTestModel","ContextAwareTestModel","ContextTestModel","CustomFieldDefinition","CustomFieldValue","CustomValidator","CustomFieldEntries","CustomFieldModelTypeMap","productionModels: ProductionModel[]"],"sources":["../../src/models/index.ts"],"sourcesContent":["import { DataTypes, Op } from 'sequelize';\nimport type { Sequelize } from 'sequelize-typescript';\nimport logger from '../utils/logger';\nimport CustomFieldDefinition from './CustomFieldDefinition';\nimport CustomFieldValue from './CustomFieldValue';\nimport TestModel from './tests/TestModel';\nimport ContextAwareTestModel from './tests/contextAwareModels/ContextAwareTestModel';\nimport ContextTestModel from './tests/contextAwareModels/ContextTestModel';\nimport AssociatedTestModel from './tests/AssociatedTestModel';\nimport type { CustomFieldOptions } from '../types';\nimport CustomFieldEntries from './CustomFieldEntries';\nimport CustomValidator from './CustomValidator';\nimport CustomFieldModelTypeMap from './CustomFieldModelTypeMap';\nimport { runSadotMigrations } from '../migrations';\nimport { CUSTOM_FIELDS_ENTRIES_MODE, type CustomFieldsEntriesMode, writesEntries } from '../utils/custom-fields-mode';\n\ntype ProductionModel = typeof CustomFieldDefinition | typeof CustomFieldValue | typeof CustomFieldEntries | typeof CustomValidator | typeof CustomFieldModelTypeMap;\ninterface InitTablesOptions {\n schemaPrefix?: string;\n schemaVersion?: string;\n customFieldsEntriesMode?: CustomFieldsEntriesMode;\n useModelTypeMapping?: boolean;\n runLegacyMigrations?: boolean;\n skipMigrations?: boolean;\n isMatPathEnabled?: CustomFieldOptions['isMatPathEnabled'];\n}\n\nconst testModels = [TestModel, AssociatedTestModel, ContextAwareTestModel, ContextTestModel];\n\nconst SADOT_MIGRATION_PREFIX = 'sadot-migration';\nconst SCHEMA_VERSION = '5f8e4a7c-9b2d-4e1f-8c3a-b6d9e2f7a4c1';\n\n/**\n * Legacy migration approach using sequelize.sync({ alter: true }).\n * TODO: Remove this function once all consumers have migrated to umzug.\n */\nconst legacySyncMigrations = async (\n sequelize: Sequelize,\n {\n schemaPrefix,\n schemaVersion,\n customFieldsEntriesMode,\n useModelTypeMapping,\n }: { schemaPrefix: string; schemaVersion: string; customFieldsEntriesMode: CustomFieldsEntriesMode; useModelTypeMapping: boolean; },\n): Promise<void> => {\n const SequelizeMeta = sequelize.define(\n 'SequelizeMeta',\n {\n name: {\n type: DataTypes.STRING,\n allowNull: false,\n unique: true,\n primaryKey: true,\n autoIncrement: false,\n },\n },\n {\n tableName: 'SequelizeMeta',\n timestamps: false,\n schema: 'public',\n },\n );\n\n logger.info('custom-fields: starting migrations');\n const migrations = await SequelizeMeta.findAll({ where: { name: { [Op.like]: `${schemaPrefix}%` } }, raw: true });\n const currentSadotSchemaVersion = migrations.at(-1);\n const expectedSchemaVersionIndex = migrations.findIndex(m => (m as any).name === schemaVersion);\n\n logger.info('custom-fields: migrations', {\n currentMigrations: migrations,\n currentSadotSchemaVersion,\n newSadotSchemaVersion: schemaVersion,\n expectedSchemaVersionIndex,\n });\n if (!currentSadotSchemaVersion || (currentSadotSchemaVersion as any).name !== schemaVersion) {\n logger.info('custom-fields: syncing models');\n try {\n await CustomFieldDefinition.sync({ alter: true });\n logger.info('custom-fields: CustomFieldDefinition synced successfully');\n\n await CustomFieldValue.sync({ alter: true });\n logger.info('custom-fields: CustomFieldValue synced successfully');\n\n await CustomValidator.sync({ alter: true });\n logger.info('custom-fields: CustomValidator synced successfully');\n\n // T.Y TODO: Remove the if statement once we're ready to add the new entries table for all MS\n if (writesEntries(customFieldsEntriesMode)) {\n await CustomFieldEntries.sync({ alter: true });\n logger.info('custom-fields: CustomFieldEntries synced successfully');\n }\n\n if (useModelTypeMapping) {\n await CustomFieldModelTypeMap.sync({ alter: true });\n logger.info('custom-fields: CustomFieldModelTypeMap synced successfully');\n }\n\n if (expectedSchemaVersionIndex === -1) {\n await SequelizeMeta.create({ name: schemaVersion });\n logger.info('custom-fields: SequelizeMeta entry created successfully');\n }\n\n logger.info('custom-fields: models synced');\n if (migrations.length && expectedSchemaVersionIndex !== -1 && expectedSchemaVersionIndex < migrations.length - 1) {\n // We have existing migrations, and we are calling `sync`.\n // This means we are in a `down` migration, and hence we should delete newer migrations to ensure we can reapply them.\n const migrationsToDelete = migrations.slice(expectedSchemaVersionIndex + 1);\n logger.info('custom-fields: deleting newer migrations during down migration', { count: migrationsToDelete.length });\n await SequelizeMeta.destroy({ where: { name: { [Op.in]: migrationsToDelete.map(m => (m as any).name) } } });\n logger.info('custom-fields: newer migrations deleted successfully');\n }\n } catch (error) {\n logger.error('custom-fields: failed to sync models', { error });\n throw error;\n }\n }\n};\n\nconst initTables = async (\n sequelize: Sequelize,\n getUser: CustomFieldOptions['getUser'],\n {\n schemaPrefix = SADOT_MIGRATION_PREFIX,\n schemaVersion = SCHEMA_VERSION,\n customFieldsEntriesMode = CUSTOM_FIELDS_ENTRIES_MODE.DISABLED,\n useModelTypeMapping = false,\n runLegacyMigrations = false,\n skipMigrations = false,\n isMatPathEnabled,\n }: InitTablesOptions = {},\n): Promise<void> => {\n const entriesEnabled = writesEntries(customFieldsEntriesMode);\n // The suffix describes the schema, not the read path, so 'write-only' and 'read-and-write'\n // share it — a third suffix would force a legacy re-sync on services using\n // runLegacyMigrations, for a schema that is identical in both modes.\n const CUSTOM_FIELDS_SCHEMA_VERSION = `${schemaPrefix}_${schemaVersion}${entriesEnabled ? '_withEntries' : ''}${useModelTypeMapping ? '_withTypeMapping' : ''}`;\n logger.info('custom-fields: initialize custom-fields tables');\n // Detect models and import them to the orm\n if (!sequelize.addModels) {\n throw new Error('sequelize instance must have addModels function');\n }\n const productionModels: ProductionModel[] = [\n CustomFieldDefinition,\n CustomFieldValue,\n CustomValidator,\n ...(entriesEnabled ? [CustomFieldEntries] : []),\n ...(useModelTypeMapping ? [CustomFieldModelTypeMap] : []),\n ];\n\n sequelize.addModels(productionModels);\n\n // Add the association only when useModelTypeMapping is enabled\n if (useModelTypeMapping) {\n CustomFieldDefinition.hasMany(CustomFieldModelTypeMap, {\n foreignKey: 'customFieldDefinitionId',\n as: 'modelTypeMappings',\n });\n CustomFieldModelTypeMap.belongsTo(CustomFieldDefinition, {\n foreignKey: 'customFieldDefinitionId',\n as: 'customFieldDefinition',\n });\n }\n\n CustomFieldDefinition.addScope('userScope', () => {\n // When mat-path is active, the consumer is responsible for restricting entityIds\n // (typically by expanding the request's entityIds to include ancestor paths the\n // caller can see). Bypass the legacy permission filter so partner/ancestor\n // entityIds are not dropped.\n if (isMatPathEnabled?.()) return {};\n const user = getUser();\n if (!user?.permissions) {\n return {};\n }\n return {\n where: {\n entityId: [\n ...Object.keys(user.permissions.fleets),\n ...Object.keys(user.permissions.businessModels),\n ...Object.keys(user.permissions.demandSources),\n ],\n },\n };\n });\n\n CustomValidator.addScope('userScope', () => {\n if (isMatPathEnabled?.()) return {};\n const user = getUser();\n if (!user?.permissions) {\n return {};\n }\n return {\n where: {\n entityId: [\n ...Object.keys(user.permissions.fleets),\n ...Object.keys(user.permissions.businessModels),\n ...Object.keys(user.permissions.demandSources),\n ],\n },\n };\n });\n\n logger.info('custom-fields: models added');\n\n if (skipMigrations) {\n logger.info('custom-fields: skipping migrations');\n } else if (runLegacyMigrations) {\n logger.info('custom-fields: running legacy sync migrations');\n await legacySyncMigrations(sequelize, { schemaPrefix, schemaVersion: CUSTOM_FIELDS_SCHEMA_VERSION, customFieldsEntriesMode, useModelTypeMapping });\n logger.info('custom-fields: umzug legacy sync migrations completed');\n } else {\n logger.info('custom-fields: starting umzug migrations');\n await runSadotMigrations(sequelize, { customFieldsEntriesMode, useModelTypeMapping });\n logger.info('custom-fields: umzug migrations complete');\n }\n};\n\nconst initTestModels = async (sequelize: Sequelize): Promise<void> => {\n logger.info('custom-fields: initialize custom-fields test models');\n // Detect models and import them to the orm\n if (!sequelize.addModels) {\n throw new Error('sequelize instance must have addModels function');\n }\n\n sequelize.addModels(testModels);\n await sequelize.dropSchema('custom-fields', { logging: false });\n await sequelize.createSchema('custom-fields', { logging: false });\n\n logger.info('custom-fields: test models added');\n await TestModel.sync({ alter: true });\n await AssociatedTestModel.sync({ alter: true });\n await ContextTestModel.sync({ alter: true });\n await ContextAwareTestModel.sync({ alter: true });\n logger.info('custom-fields: test models synced');\n};\n\nexport {\n CustomFieldValue,\n CustomFieldDefinition,\n CustomFieldEntries,\n CustomValidator,\n CustomFieldModelTypeMap,\n TestModel,\n AssociatedTestModel,\n ContextAwareTestModel,\n ContextTestModel,\n initTables,\n initTestModels,\n};\n"],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ const e=require(`../_virtual/rolldown_runtime.cjs`),t=require(`../utils/logger/index.cjs`);let n=require(`sequelize`);const r=async(e,{modelType:r,tableName:i,scopeColumn:a,primaryKeyColumn:o=`id`,transaction:s})=>{let[c]=await e.query(`SELECT to_regclass('custom_field_entries') AS entries_table,
2
+ to_regclass('custom_field_values') AS values_table`,{type:n.QueryTypes.SELECT,transaction:s});if(!c.entries_table&&c.values_table)throw Error(`custom-fields backfill: custom_field_entries is missing while custom_field_values exists — run the sadot migrations that create it (useCustomFieldsEntries) before backfilling`);if(!c.entries_table)return t.default.info(`custom-fields: sadot tables absent, nothing to backfill for ${r}`),0;if(!c.values_table)return t.default.info(`custom-fields: custom_field_values absent, nothing to backfill for ${r}`),0;let l=e.getQueryInterface().quoteIdentifier.bind(e.getQueryInterface()),u=l(i),d=l(o),f=l(a),[,p]=await e.query(`
3
+ INSERT INTO custom_field_entries (model_id, entity_id, model_type, custom_fields, created_at, updated_at)
4
+ SELECT
5
+ t.${d},
6
+ agg.entity_id,
7
+ :modelType,
8
+ agg.custom_fields,
9
+ COALESCE(t.created_at, now()),
10
+ now()
11
+ FROM (
12
+ SELECT
13
+ cfv.model_id,
14
+ cfd.entity_id,
15
+ jsonb_object_agg(cfd.name, cfv.value) AS custom_fields
16
+ FROM custom_field_values cfv
17
+ INNER JOIN custom_field_definitions cfd
18
+ ON cfd.id = cfv.custom_field_definition_id
19
+ AND cfd.deleted_at IS NULL
20
+ AND cfd.model_type = :modelType
21
+ WHERE cfv.deleted_at IS NULL
22
+ AND cfv.value IS NOT NULL
23
+ GROUP BY cfv.model_id, cfd.entity_id
24
+ ) agg
25
+ INNER JOIN ${u} t
26
+ ON t.${d} = agg.model_id
27
+ AND t.${f} = agg.entity_id
28
+ AND t.deleted_at IS NULL
29
+ ON CONFLICT (model_id) DO UPDATE
30
+ SET custom_fields = EXCLUDED.custom_fields,
31
+ entity_id = EXCLUDED.entity_id,
32
+ updated_at = now()
33
+ `,{replacements:{modelType:r},type:n.QueryTypes.INSERT,transaction:s}),m=typeof p==`number`?p:p?.rowCount??0;return t.default.info(`custom-fields: backfilled ${m} ${r} rows into custom_field_entries`),m};exports.backfillCustomFieldEntries=r;
34
+ //# sourceMappingURL=backfill.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backfill.cjs","names":["sequelize","QueryTypes"],"sources":["../../src/repository/backfill.ts"],"sourcesContent":["import { QueryTypes, type Sequelize, type Transaction } from 'sequelize';\nimport logger from '../utils/logger';\n\ninterface BackfillParams {\n /** custom_field_definitions.model_type value (e.g. 'Vehicle'). */\n modelType: string;\n /** Table to backfill from (e.g. 'vehicles'). */\n tableName: string;\n /** DB column matching custom_field_definitions.entity_id (e.g. 'fleet_id'), so backfilled rows stay filterable. */\n scopeColumn: string;\n /** Defaults to 'id'. */\n primaryKeyColumn?: string;\n transaction?: Transaction;\n}\n\n/**\n * Backfills custom_field_entries from custom_field_values for every live row of the table.\n * Idempotent — safe to re-run to complete rows partially written during WRITE_ONLY.\n *\n * Call after dual-write is deployed, before reads switch to entries.\n * Assumes the table has created_at and deleted_at columns.\n * Returns the number of rows inserted or updated.\n */\nexport const backfillCustomFieldEntries = async (\n sequelize: Sequelize,\n {\n modelType, tableName, scopeColumn, primaryKeyColumn = 'id', transaction,\n }: BackfillParams,\n): Promise<number> => {\n // Sadot's migrations may not have run yet — check rather than assume.\n const [tables] = await sequelize.query(\n `SELECT to_regclass('custom_field_entries') AS entries_table,\n to_regclass('custom_field_values') AS values_table`,\n { type: QueryTypes.SELECT, transaction },\n ) as [{ entries_table: string | null; values_table: string | null; }];\n\n // Values exist but entries doesn't — backfilling before the table was created.\n // Skipping silently would let the later migration record as applied with no data moved.\n if (!tables.entries_table && tables.values_table) {\n throw new Error(\n 'custom-fields backfill: custom_field_entries is missing while custom_field_values exists — '\n + 'run the sadot migrations that create it (useCustomFieldsEntries) before backfilling',\n );\n }\n\n // No sadot tables at all — nothing to backfill.\n if (!tables.entries_table) {\n logger.info(`custom-fields: sadot tables absent, nothing to backfill for ${modelType}`);\n return 0;\n }\n\n // Entries exists but values doesn't (e.g. after a later cleanup phase drops it) —\n // nothing to backfill from.\n if (!tables.values_table) {\n logger.info(`custom-fields: custom_field_values absent, nothing to backfill for ${modelType}`);\n return 0;\n }\n\n const quote = sequelize.getQueryInterface().quoteIdentifier.bind(sequelize.getQueryInterface());\n const table = quote(tableName);\n const pk = quote(primaryKeyColumn);\n const scope = quote(scopeColumn);\n\n const [, meta] = await sequelize.query(\n `\n INSERT INTO custom_field_entries (model_id, entity_id, model_type, custom_fields, created_at, updated_at)\n SELECT\n t.${pk},\n agg.entity_id,\n :modelType,\n agg.custom_fields,\n COALESCE(t.created_at, now()),\n now()\n FROM (\n SELECT\n cfv.model_id,\n cfd.entity_id,\n jsonb_object_agg(cfd.name, cfv.value) AS custom_fields\n FROM custom_field_values cfv\n INNER JOIN custom_field_definitions cfd\n ON cfd.id = cfv.custom_field_definition_id\n AND cfd.deleted_at IS NULL\n AND cfd.model_type = :modelType\n WHERE cfv.deleted_at IS NULL\n AND cfv.value IS NOT NULL\n GROUP BY cfv.model_id, cfd.entity_id\n ) agg\n INNER JOIN ${table} t\n ON t.${pk} = agg.model_id\n AND t.${scope} = agg.entity_id\n AND t.deleted_at IS NULL\n ON CONFLICT (model_id) DO UPDATE\n SET custom_fields = EXCLUDED.custom_fields,\n entity_id = EXCLUDED.entity_id,\n updated_at = now()\n `,\n {\n replacements: { modelType },\n type: QueryTypes.INSERT,\n transaction,\n },\n );\n\n const backfilledCount = typeof meta === 'number' ? meta : ((meta as any)?.rowCount ?? 0);\n logger.info(`custom-fields: backfilled ${backfilledCount} ${modelType} rows into custom_field_entries`);\n return backfilledCount;\n};\n"],"mappings":"sHAuBA,MAAa,EAA6B,MACxC,EACA,CACE,YAAW,YAAW,cAAa,mBAAmB,KAAM,iBAE1C,CAEpB,GAAM,CAAC,GAAU,MAAMA,EAAU,MAC/B;iEAEA,CAAE,KAAMC,EAAAA,WAAW,OAAQ,cAAa,CACzC,CAID,GAAI,CAAC,EAAO,eAAiB,EAAO,aAClC,MAAU,MACR,iLAED,CAIH,GAAI,CAAC,EAAO,cAEV,OADA,EAAA,QAAO,KAAK,+DAA+D,IAAY,CAChF,EAKT,GAAI,CAAC,EAAO,aAEV,OADA,EAAA,QAAO,KAAK,sEAAsE,IAAY,CACvF,EAGT,IAAM,EAAQD,EAAU,mBAAmB,CAAC,gBAAgB,KAAKA,EAAU,mBAAmB,CAAC,CACzF,EAAQ,EAAM,EAAU,CACxB,EAAK,EAAM,EAAiB,CAC5B,EAAQ,EAAM,EAAY,CAE1B,EAAG,GAAQ,MAAMA,EAAU,MAC/B;;;UAGM,EAAG;;;;;;;;;;;;;;;;;;;;iBAoBI,EAAM;aACV,EAAG;aACH,EAAM;;;;;;MAOf,CACE,aAAc,CAAE,YAAW,CAC3B,KAAMC,EAAAA,WAAW,OACjB,cACD,CACF,CAEK,EAAkB,OAAO,GAAS,SAAW,EAAS,GAAc,UAAY,EAEtF,OADA,EAAA,QAAO,KAAK,6BAA6B,EAAgB,GAAG,EAAU,iCAAiC,CAChG"}
@@ -0,0 +1,32 @@
1
+ import { Sequelize, Transaction } from "sequelize";
2
+
3
+ //#region src/repository/backfill.d.ts
4
+ interface BackfillParams {
5
+ /** custom_field_definitions.model_type value (e.g. 'Vehicle'). */
6
+ modelType: string;
7
+ /** Table to backfill from (e.g. 'vehicles'). */
8
+ tableName: string;
9
+ /** DB column matching custom_field_definitions.entity_id (e.g. 'fleet_id'), so backfilled rows stay filterable. */
10
+ scopeColumn: string;
11
+ /** Defaults to 'id'. */
12
+ primaryKeyColumn?: string;
13
+ transaction?: Transaction;
14
+ }
15
+ /**
16
+ * Backfills custom_field_entries from custom_field_values for every live row of the table.
17
+ * Idempotent — safe to re-run to complete rows partially written during WRITE_ONLY.
18
+ *
19
+ * Call after dual-write is deployed, before reads switch to entries.
20
+ * Assumes the table has created_at and deleted_at columns.
21
+ * Returns the number of rows inserted or updated.
22
+ */
23
+ declare const backfillCustomFieldEntries: (sequelize: Sequelize, {
24
+ modelType,
25
+ tableName,
26
+ scopeColumn,
27
+ primaryKeyColumn,
28
+ transaction
29
+ }: BackfillParams) => Promise<number>;
30
+ //#endregion
31
+ export { backfillCustomFieldEntries };
32
+ //# sourceMappingURL=backfill.d.cts.map
@@ -0,0 +1,32 @@
1
+ import { Sequelize, Transaction } from "sequelize";
2
+
3
+ //#region src/repository/backfill.d.ts
4
+ interface BackfillParams {
5
+ /** custom_field_definitions.model_type value (e.g. 'Vehicle'). */
6
+ modelType: string;
7
+ /** Table to backfill from (e.g. 'vehicles'). */
8
+ tableName: string;
9
+ /** DB column matching custom_field_definitions.entity_id (e.g. 'fleet_id'), so backfilled rows stay filterable. */
10
+ scopeColumn: string;
11
+ /** Defaults to 'id'. */
12
+ primaryKeyColumn?: string;
13
+ transaction?: Transaction;
14
+ }
15
+ /**
16
+ * Backfills custom_field_entries from custom_field_values for every live row of the table.
17
+ * Idempotent — safe to re-run to complete rows partially written during WRITE_ONLY.
18
+ *
19
+ * Call after dual-write is deployed, before reads switch to entries.
20
+ * Assumes the table has created_at and deleted_at columns.
21
+ * Returns the number of rows inserted or updated.
22
+ */
23
+ declare const backfillCustomFieldEntries: (sequelize: Sequelize, {
24
+ modelType,
25
+ tableName,
26
+ scopeColumn,
27
+ primaryKeyColumn,
28
+ transaction
29
+ }: BackfillParams) => Promise<number>;
30
+ //#endregion
31
+ export { backfillCustomFieldEntries };
32
+ //# sourceMappingURL=backfill.d.ts.map